v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
value-serializer.cc
Go to the documentation of this file.
1// Copyright 2016 the V8 project 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
6
7#include <type_traits>
8
9#include "include/v8-maybe.h"
12#include "include/v8-wasm.h"
13#include "src/api/api-inl.h"
14#include "src/base/logging.h"
17#include "src/flags/flags.h"
22#include "src/heap/factory.h"
34#include "src/objects/objects.h"
39#include "src/objects/smi.h"
41#include "src/regexp/regexp.h"
43
44#if V8_ENABLE_WEBASSEMBLY
46#endif // V8_ENABLE_WEBASSEMBLY
47
48namespace v8 {
49namespace internal {
50
51// WARNING: This serialization format MUST remain backward compatible!
52//
53// This format is used by APIs to persist values to disk, e.g. IndexedDB.
54//
55// Backward compatibility means that when the format changes, deserializing
56// valid values in the older format must behave identically as before the
57// change. To maintain compatibility, either a format change does not affect the
58// deserializing behavior of valid values in the older format, or the
59// kLatestVersion constant is bumped.
60//
61// Adding a new tag is backwards compatible because no valid serialized value in
62// older formats would contain the new object tag.
63//
64// On the other hand, changing the format of a particular tag is backwards
65// incompatible and the version must be bumped. For example, a JSArrayBufferView
66// tag prior to version 14 was followed by the sub-tag, the byte offset, and the
67// byte length. Starting with version 14, a JSArrayBufferView tag is followed by
68// the sub-tag, the byte offset, the byte length, and flags. Due the addition of
69// flags, older valid serialized values for JSArrayBufferViews would be
70// misinterpreted by newer deserializers. This requires the version to be bumped
71// and the deserializer to handle both the old and new formats depending on the
72// version.
73
74// Version 9: (imported from Blink)
75// Version 10: one-byte (Latin-1) strings
76// Version 11: properly separate undefined from the hole in arrays
77// Version 12: regexp and string objects share normal string encoding
78// Version 13: host objects have an explicit tag (rather than handling all
79// unknown tags)
80// Version 14: flags for JSArrayBufferViews
81// Version 15: support for shared objects with an explicit tag
82//
83// WARNING: Increasing this value is a change which cannot safely be rolled
84// back without breaking compatibility with data stored on disk. It is
85// strongly recommended that you do not make such changes near a release
86// milestone branch point.
87//
88// Recent changes are routinely reverted in preparation for branch, and this
89// has been the cause of at least one bug in the past.
90static const uint32_t kLatestVersion = 15;
92 "Exported format version must match latest version.");
93
94namespace {
95// For serializing JSArrayBufferView flags. Instead of serializing /
96// deserializing the flags directly, we serialize them bit by bit. This is for
97// ensuring backwards compatibility in the case where the representation
98// changes. Note that the ValueSerializer data can be stored on disk.
99using JSArrayBufferViewIsLengthTracking = base::BitField<bool, 0, 1>;
100using JSArrayBufferViewIsBackedByRab =
101 JSArrayBufferViewIsLengthTracking::Next<bool, 1>;
102
103} // namespace
104
105template <typename T>
106static size_t BytesNeededForVarint(T value) {
107 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
108 "Only unsigned integer types can be written as varints.");
109 size_t result = 0;
110 do {
111 result++;
112 value >>= 7;
113 } while (value);
114 return result;
115}
116
117enum class SerializationTag : uint8_t {
118 // version:uint32_t (if at beginning of data, sets version > 0)
119 kVersion = 0xFF,
120 // ignore
121 kPadding = '\0',
122 // refTableSize:uint32_t (previously used for sanity checks; safe to ignore)
123 kVerifyObjectCount = '?',
124 // Oddballs (no data).
125 kTheHole = '-',
126 kUndefined = '_',
127 kNull = '0',
128 kTrue = 'T',
129 kFalse = 'F',
130 // Number represented as 32-bit integer, ZigZag-encoded
131 // (like sint32 in protobuf)
132 kInt32 = 'I',
133 // Number represented as 32-bit unsigned integer, varint-encoded
134 // (like uint32 in protobuf)
135 kUint32 = 'U',
136 // Number represented as a 64-bit double.
137 // Host byte order is used (N.B. this makes the format non-portable).
138 kDouble = 'N',
139 // BigInt. Bitfield:uint32_t, then raw digits storage.
140 kBigInt = 'Z',
141 // byteLength:uint32_t, then raw data
142 kUtf8String = 'S',
143 kOneByteString = '"',
144 kTwoByteString = 'c',
145 // Reference to a serialized object. objectID:uint32_t
146 kObjectReference = '^',
147 // Beginning of a JS object.
148 kBeginJSObject = 'o',
149 // End of a JS object. numProperties:uint32_t
150 kEndJSObject = '{',
151 // Beginning of a sparse JS array. length:uint32_t
152 // Elements and properties are written as key/value pairs, like objects.
154 // End of a sparse JS array. numProperties:uint32_t length:uint32_t
155 kEndSparseJSArray = '@',
156 // Beginning of a dense JS array. length:uint32_t
157 // |length| elements, followed by properties as key/value pairs
158 kBeginDenseJSArray = 'A',
159 // End of a dense JS array. numProperties:uint32_t length:uint32_t
160 kEndDenseJSArray = '$',
161 // Date. millisSinceEpoch:double
162 kDate = 'D',
163 // Boolean object. No data.
164 kTrueObject = 'y',
165 kFalseObject = 'x',
166 // Number object. value:double
167 kNumberObject = 'n',
168 // BigInt object. Bitfield:uint32_t, then raw digits storage.
169 kBigIntObject = 'z',
170 // String object, UTF-8 encoding. byteLength:uint32_t, then raw data.
171 kStringObject = 's',
172 // Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data,
173 // flags:uint32_t.
174 kRegExp = 'R',
175 // Beginning of a JS map.
176 kBeginJSMap = ';',
177 // End of a JS map. length:uint32_t.
178 kEndJSMap = ':',
179 // Beginning of a JS set.
180 kBeginJSSet = '\'',
181 // End of a JS set. length:uint32_t.
182 kEndJSSet = ',',
183 // Array buffer. byteLength:uint32_t, then raw data.
184 kArrayBuffer = 'B',
185 // Resizable ArrayBuffer.
187 // Array buffer (transferred). transferID:uint32_t
189 // View into an array buffer.
190 // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t
191 // For typed arrays, byteOffset and byteLength must be divisible by the size
192 // of the element.
193 // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an
194 // ObjectReference to one) serialized just before it. This is a quirk arising
195 // from the previous stack-based implementation.
196 kArrayBufferView = 'V',
197 // Shared array buffer. transferID:uint32_t
198 kSharedArrayBuffer = 'u',
199 // A HeapObject shared across Isolates. sharedValueID:uint32_t
200 kSharedObject = 'p',
201 // A wasm module object transfer. next value is its index.
203 // The delegate is responsible for processing all following data.
204 // This "escapes" to whatever wire format the delegate chooses.
205 kHostObject = '\\',
206 // A transferred WebAssembly.Memory object. maximumPages:int32_t, then by
207 // SharedArrayBuffer tag and its data.
209 // A list of (subtag: ErrorTag, [subtag dependent data]). See ErrorTag for
210 // details.
211 kError = 'r',
212
213 // The following tags are reserved because they were in use in Chromium before
214 // the kHostObject tag was introduced in format version 13, at
215 // v8 refs/heads/master@{#43466}
216 // chromium/src refs/heads/master@{#453568}
217 //
218 // They must not be reused without a version check to prevent old values from
219 // starting to deserialize incorrectly. For simplicity, it's recommended to
220 // avoid them altogether.
221 //
222 // This is the set of tags that existed in SerializationTag.h at that time and
223 // still exist at the time of this writing (i.e., excluding those that were
224 // removed on the Chromium side because there should be no real user data
225 // containing them).
226 //
227 // It might be possible to also free up other tags which were never persisted
228 // (e.g. because they were used only for transfer) in the future.
243};
244
245namespace {
246
247enum class ArrayBufferViewTag : uint8_t {
248 kInt8Array = 'b',
249 kUint8Array = 'B',
250 kUint8ClampedArray = 'C',
251 kInt16Array = 'w',
252 kUint16Array = 'W',
253 kInt32Array = 'd',
254 kUint32Array = 'D',
255 kFloat16Array = 'h',
256 kFloat32Array = 'f',
257 kFloat64Array = 'F',
258 kBigInt64Array = 'q',
259 kBigUint64Array = 'Q',
260 kDataView = '?',
261};
262
263// Sub-tags only meaningful for error serialization.
264enum class ErrorTag : uint8_t {
265 // The error is an EvalError. No accompanying data.
266 kEvalErrorPrototype = 'E',
267 // The error is a RangeError. No accompanying data.
268 kRangeErrorPrototype = 'R',
269 // The error is a ReferenceError. No accompanying data.
270 kReferenceErrorPrototype = 'F',
271 // The error is a SyntaxError. No accompanying data.
272 kSyntaxErrorPrototype = 'S',
273 // The error is a TypeError. No accompanying data.
274 kTypeErrorPrototype = 'T',
275 // The error is a URIError. No accompanying data.
276 kUriErrorPrototype = 'U',
277 // Followed by message: string.
278 kMessage = 'm',
279 // Followed by a JS object: cause.
280 kCause = 'c',
281 // Followed by stack: string.
282 kStack = 's',
283 // The end of this error information.
284 kEnd = '.',
285};
286
287enum class WasmMemoryArrayBufferTag : uint8_t {
288 kFixedLength = 'f',
289 kResizableNotFollowedByWasmMemory = 'r',
290 kResizableFollowedByWasmMemory = 'w'
291};
292
293} // namespace
294
297 : isolate_(isolate),
298 delegate_(delegate),
299 zone_(isolate->allocator(), ZONE_NAME),
300 id_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)),
301 array_buffer_transfer_map_(isolate->heap(),
303 if (delegate_) {
304 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
306 }
307}
308
310 if (buffer_) {
311 if (delegate_) {
313 } else {
315 }
316 }
317}
318
323
327
329 uint8_t raw_tag = static_cast<uint8_t>(tag);
330 WriteRawBytes(&raw_tag, sizeof(raw_tag));
331}
332
333template <typename T>
335 // Writes an unsigned integer as a base-128 varint.
336 // The number is written, 7 bits at a time, from the least significant to the
337 // most significant 7 bits. Each byte, except the last, has the MSB set.
338 // See also https://developers.google.com/protocol-buffers/docs/encoding
339 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
340 "Only unsigned integer types can be written as varints.");
341 uint8_t stack_buffer[sizeof(T) * 8 / 7 + 1];
342 uint8_t* next_byte = &stack_buffer[0];
343 do {
344 *next_byte = (value & 0x7F) | 0x80;
345 next_byte++;
346 value >>= 7;
347 } while (value);
348 *(next_byte - 1) &= 0x7F;
349 WriteRawBytes(stack_buffer, next_byte - stack_buffer);
350}
351
352template <typename T>
354 // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
355 // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
356 // See also https://developers.google.com/protocol-buffers/docs/encoding
357 // Note that this implementation relies on the right shift being arithmetic.
358 static_assert(std::is_integral_v<T> && std::is_signed_v<T>,
359 "Only signed integer types can be written as zigzag.");
360 using UnsignedT = std::make_unsigned_t<T>;
361 WriteVarint((static_cast<UnsignedT>(value) << 1) ^
362 (value >> (8 * sizeof(T) - 1)));
363}
364
367
368void ValueSerializer::WriteDouble(double value) {
369 // Warning: this uses host endianness.
370 WriteRawBytes(&value, sizeof(value));
371}
372
375 WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t));
376}
377
379 // Warning: this uses host endianness.
380 WriteVarint<uint32_t>(chars.length() * sizeof(base::uc16));
381 WriteRawBytes(chars.begin(), chars.length() * sizeof(base::uc16));
382}
383
385 uint32_t bitfield = bigint->GetBitfieldForSerialization();
386 size_t bytelength = BigInt::DigitsByteLengthForBitfield(bitfield);
387 WriteVarint<uint32_t>(bitfield);
388 uint8_t* dest;
389 if (ReserveRawBytes(bytelength).To(&dest)) {
390 bigint->SerializeDigits(dest, bytelength);
391 }
392}
393
394void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
395 uint8_t* dest;
396 if (ReserveRawBytes(length).To(&dest) && length > 0) {
397 memcpy(dest, source, length);
398 }
399}
400
402 size_t old_size = buffer_size_;
403 size_t new_size = old_size + bytes;
404 if (V8_UNLIKELY(new_size > buffer_capacity_)) {
405 bool ok;
406 if (!ExpandBuffer(new_size).To(&ok)) {
407 return Nothing<uint8_t*>();
408 }
409 }
410 buffer_size_ = new_size;
411 return Just(&buffer_[old_size]);
412}
413
415 DCHECK_GT(required_capacity, buffer_capacity_);
416 size_t requested_capacity =
417 std::max(required_capacity, buffer_capacity_ * 2) + 64;
418 size_t provided_capacity = 0;
419 void* new_buffer = nullptr;
420 if (delegate_) {
421 new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity,
422 &provided_capacity);
423 } else {
424 new_buffer = base::Realloc(buffer_, requested_capacity);
425 provided_capacity = requested_capacity;
426 }
427 if (new_buffer) {
428 DCHECK(provided_capacity >= requested_capacity);
429 buffer_ = reinterpret_cast<uint8_t*>(new_buffer);
430 buffer_capacity_ = provided_capacity;
431 return Just(true);
432 } else {
433 out_of_memory_ = true;
434 return Nothing<bool>();
435 }
436}
437
438void ValueSerializer::WriteByte(uint8_t value) {
439 uint8_t* dest;
440 if (ReserveRawBytes(sizeof(uint8_t)).To(&dest)) {
441 *dest = value;
442 }
443}
444
445void ValueSerializer::WriteUint32(uint32_t value) {
447}
448
449void ValueSerializer::WriteUint64(uint64_t value) {
451}
452
453std::pair<uint8_t*, size_t> ValueSerializer::Release() {
454 auto result = std::make_pair(buffer_, buffer_size_);
455 buffer_ = nullptr;
456 buffer_size_ = 0;
458 return result;
459}
460
462 uint32_t transfer_id, DirectHandle<JSArrayBuffer> array_buffer) {
463 DCHECK(!array_buffer_transfer_map_.Find(array_buffer));
464 DCHECK(!array_buffer->is_shared());
465 array_buffer_transfer_map_.Insert(array_buffer, transfer_id);
466}
467
469 // There is no sense in trying to proceed if we've previously run out of
470 // memory. Bail immediately, as this likely implies that some write has
471 // previously failed and so the buffer is corrupt.
473
474 if (IsSmi(*object)) {
475 WriteSmi(Cast<Smi>(*object));
476 return ThrowIfOutOfMemory();
477 }
478
479 DCHECK(IsHeapObject(*object));
480 InstanceType instance_type =
481 Cast<HeapObject>(*object)->map(isolate_)->instance_type();
482 switch (instance_type) {
483 case ODDBALL_TYPE:
484 WriteOddball(Cast<Oddball>(*object));
485 return ThrowIfOutOfMemory();
486 case HEAP_NUMBER_TYPE:
488 return ThrowIfOutOfMemory();
489 case BIGINT_TYPE:
490 WriteBigInt(Cast<BigInt>(*object));
491 return ThrowIfOutOfMemory();
492 case JS_TYPED_ARRAY_TYPE:
493 case JS_DATA_VIEW_TYPE:
494 case JS_RAB_GSAB_DATA_VIEW_TYPE: {
495 // Despite being JSReceivers, these have their wrapped buffer serialized
496 // first. That makes this logic a little quirky, because it needs to
497 // happen before we assign object IDs.
498 // TODO(jbroman): It may be possible to avoid materializing a typed
499 // array's buffer here.
503 InstanceTypeChecker::IsJSTypedArray(instance_type)
504 ? Cast<JSTypedArray>(view)->GetBuffer()
505 : direct_handle(Cast<JSArrayBuffer>(view->buffer()), isolate_));
506 if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>();
507 }
508 return WriteJSReceiver(view);
509 }
510 default:
511 if (InstanceTypeChecker::IsString(instance_type)) {
512 WriteString(Cast<String>(object));
513 return ThrowIfOutOfMemory();
514 } else if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
515 return WriteJSReceiver(Cast<JSReceiver>(object));
516 } else {
517 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
518 }
519 }
520}
521
524 switch (oddball->kind()) {
527 break;
528 case Oddball::kFalse:
530 break;
531 case Oddball::kTrue:
533 break;
534 case Oddball::kNull:
536 break;
537 default:
538 UNREACHABLE();
539 }
540 WriteTag(tag);
541}
542
544 static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits.");
546 WriteZigZag<int32_t>(smi.value());
547}
548
553
558
560 string = String::Flatten(isolate_, string);
562 String::FlatContent flat = string->GetFlatContent(no_gc);
563 DCHECK(flat.IsFlat());
564 if (flat.IsOneByte()) {
567 WriteOneByteString(chars);
568 } else if (flat.IsTwoByte()) {
570 uint32_t byte_length = chars.length() * sizeof(base::uc16);
571 // The existing reading code expects 16-byte strings to be aligned.
572 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1)
575 WriteTwoByteString(chars);
576 } else {
577 UNREACHABLE();
578 }
579}
580
583 // If the object has already been serialized, just write its ID.
584 auto find_result = id_map_.FindOrInsert(receiver);
585 if (find_result.already_exists) {
587 WriteVarint(*find_result.entry - 1);
588 return ThrowIfOutOfMemory();
589 }
590
591 // Otherwise, allocate an ID for it.
592 uint32_t id = next_id_++;
593 *find_result.entry = id + 1;
594
595 // Eliminate callable and exotic objects, which should not be serialized.
596 InstanceType instance_type = receiver->map()->instance_type();
597 if (IsCallable(*receiver) || (IsSpecialReceiverInstanceType(instance_type) &&
598 instance_type != JS_SPECIAL_API_OBJECT_TYPE)) {
599 return ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
600 }
601
602 // If we are at the end of the stack, abort. This function may recurse.
604
605 HandleScope scope(isolate_);
606 switch (instance_type) {
607 case JS_ARRAY_TYPE:
609 case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE:
610 case JS_ITERATOR_PROTOTYPE_TYPE:
611 case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
612 case JS_OBJECT_PROTOTYPE_TYPE:
613 case JS_OBJECT_TYPE:
614 case JS_PROMISE_PROTOTYPE_TYPE:
615 case JS_REG_EXP_PROTOTYPE_TYPE:
616 case JS_SET_ITERATOR_PROTOTYPE_TYPE:
617 case JS_SET_PROTOTYPE_TYPE:
618 case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
619 case JS_TYPED_ARRAY_PROTOTYPE_TYPE:
620 case JS_API_OBJECT_TYPE: {
622 Maybe<bool> is_host_object = IsHostObject(js_object);
623 if (is_host_object.IsNothing()) {
624 return is_host_object;
625 }
626 if (is_host_object.FromJust()) {
627 return WriteHostObject(js_object);
628 } else {
629 return WriteJSObject(js_object);
630 }
631 }
632 case JS_SPECIAL_API_OBJECT_TYPE:
634 case JS_DATE_TYPE:
636 return ThrowIfOutOfMemory();
637 case JS_PRIMITIVE_WRAPPER_TYPE:
639 case JS_REG_EXP_TYPE:
641 return ThrowIfOutOfMemory();
642 case JS_MAP_TYPE:
644 case JS_SET_TYPE:
646 case JS_ARRAY_BUFFER_TYPE:
648 case JS_TYPED_ARRAY_TYPE:
649 case JS_DATA_VIEW_TYPE:
650 case JS_RAB_GSAB_DATA_VIEW_TYPE:
652 case JS_ERROR_TYPE:
654 case JS_SHARED_ARRAY_TYPE:
656 case JS_SHARED_STRUCT_TYPE:
658 case JS_ATOMICS_MUTEX_TYPE:
659 case JS_ATOMICS_CONDITION_TYPE:
661#if V8_ENABLE_WEBASSEMBLY
662 case WASM_MODULE_OBJECT_TYPE:
663 return WriteWasmModule(Cast<WasmModuleObject>(receiver));
664 case WASM_MEMORY_OBJECT_TYPE:
665 return WriteWasmMemory(Cast<WasmMemoryObject>(receiver));
666#endif // V8_ENABLE_WEBASSEMBLY
667 default:
668 break;
669 }
670
671 return ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
672}
673
675 DCHECK(!IsCustomElementsReceiverMap(object->map()));
676 const bool can_serialize_fast =
677 object->HasFastProperties(isolate_) && object->elements()->length() == 0;
678 if (!can_serialize_fast) return WriteJSObjectSlow(object);
679
680 DirectHandle<Map> map(object->map(), isolate_);
682
683 // Write out fast properties as long as they are only data properties and the
684 // map doesn't change.
685 uint32_t properties_written = 0;
686 bool map_changed = false;
687 for (InternalIndex i : map->IterateOwnDescriptors()) {
688 DirectHandle<Name> key(map->instance_descriptors(isolate_)->GetKey(i),
689 isolate_);
690 if (!IsString(*key, isolate_)) continue;
691 PropertyDetails details =
692 map->instance_descriptors(isolate_)->GetDetails(i);
693 if (details.IsDontEnum()) continue;
694
696 if (V8_LIKELY(!map_changed)) map_changed = *map != object->map();
697 if (V8_LIKELY(!map_changed &&
698 details.location() == PropertyLocation::kField)) {
700 FieldIndex field_index = FieldIndex::ForDetails(*map, details);
701 value = direct_handle(object->RawFastPropertyAt(field_index), isolate_);
702 } else {
703 // This logic should essentially match WriteJSObjectPropertiesSlow.
704 // If the property is no longer found, do not serialize it.
705 // This could happen if a getter deleted the property.
707 if (!it.IsFound()) continue;
708 if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>();
709 }
710
711 if (!WriteObject(key).FromMaybe(false) ||
712 !WriteObject(value).FromMaybe(false)) {
713 return Nothing<bool>();
714 }
715 properties_written++;
716 }
717
719 WriteVarint<uint32_t>(properties_written);
720 return ThrowIfOutOfMemory();
721}
722
726 uint32_t properties_written = 0;
729 .ToHandle(&keys) ||
730 !WriteJSObjectPropertiesSlow(object, keys).To(&properties_written)) {
731 return Nothing<bool>();
732 }
734 WriteVarint<uint32_t>(properties_written);
735 return ThrowIfOutOfMemory();
736}
737
739 PtrComprCageBase cage_base(isolate_);
740 uint32_t length = 0;
741 bool valid_length = Object::ToArrayLength(array->length(), &length);
742 DCHECK(valid_length);
743 USE(valid_length);
744
745 // To keep things simple, for now we decide between dense and sparse
746 // serialization based on elements kind. A more principled heuristic could
747 // count the elements, but would need to take care to note which indices
748 // existed (as only indices which were enumerable own properties at this point
749 // should be serialized).
750 const bool should_serialize_densely =
751 array->HasFastElements(cage_base) && !array->HasHoleyElements(cage_base);
752
753 if (should_serialize_densely) {
754 DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength));
756 WriteVarint<uint32_t>(length);
757 uint32_t i = 0;
758
759 // Fast paths. Note that PACKED_ELEMENTS in particular can bail due to the
760 // structure of the elements changing.
761 switch (array->GetElementsKind(cage_base)) {
762 case PACKED_SMI_ELEMENTS: {
764 Tagged<FixedArray> elements = Cast<FixedArray>(array->elements());
765 for (i = 0; i < length; i++) {
766 WriteSmi(Cast<Smi>(elements->get(i)));
767 }
768 break;
769 }
771 // Elements are empty_fixed_array, not a FixedDoubleArray, if the array
772 // is empty. No elements to encode in this case anyhow.
773 if (length == 0) break;
775 Tagged<FixedDoubleArray> elements =
776 Cast<FixedDoubleArray>(array->elements());
777 for (i = 0; i < length; i++) {
779 WriteDouble(elements->get_scalar(i));
780 }
781 break;
782 }
783 case PACKED_ELEMENTS: {
784 DirectHandle<Object> old_length(array->length(cage_base), isolate_);
785 for (; i < length; i++) {
786 if (array->length(cage_base) != *old_length ||
787 array->GetElementsKind(cage_base) != PACKED_ELEMENTS) {
788 // Fall back to slow path.
789 break;
790 }
791 DirectHandle<Object> element(
792 Cast<FixedArray>(array->elements())->get(i), isolate_);
793 if (!WriteObject(element).FromMaybe(false)) return Nothing<bool>();
794 }
795 break;
796 }
797 default:
798 break;
799 }
800
801 // If there are elements remaining, serialize them slowly.
802 for (; i < length; i++) {
803 // Serializing the array's elements can have arbitrary side effects, so we
804 // cannot rely on still having fast elements, even if it did to begin
805 // with.
806 DirectHandle<Object> element;
807 LookupIterator it(isolate_, array, i, array, LookupIterator::OWN);
808 if (!it.IsFound()) {
809 // This can happen in the case where an array that was originally dense
810 // became sparse during serialization. It's too late to switch to the
811 // sparse format, but we can mark the elements as absent.
813 continue;
814 }
815 if (!Object::GetProperty(&it).ToHandle(&element) ||
816 !WriteObject(element).FromMaybe(false)) {
817 return Nothing<bool>();
818 }
819 }
820
825 .ToHandle(&keys)) {
826 return Nothing<bool>();
827 }
828
829 uint32_t properties_written;
830 if (!WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
831 return Nothing<bool>();
832 }
834 WriteVarint<uint32_t>(properties_written);
835 WriteVarint<uint32_t>(length);
836 } else {
838 WriteVarint<uint32_t>(length);
840 uint32_t properties_written = 0;
843 .ToHandle(&keys) ||
844 !WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
845 return Nothing<bool>();
846 }
848 WriteVarint<uint32_t>(properties_written);
849 WriteVarint<uint32_t>(length);
850 }
851 return ThrowIfOutOfMemory();
852}
853
858
861 PtrComprCageBase cage_base(isolate_);
862 {
864 Tagged<Object> inner_value = value->value();
865 if (IsTrue(inner_value, isolate_)) {
867 } else if (IsFalse(inner_value, isolate_)) {
869 } else if (IsNumber(inner_value, cage_base)) {
871 WriteDouble(Object::NumberValue(inner_value));
872 } else if (IsBigInt(inner_value, cage_base)) {
874 WriteBigIntContents(Cast<BigInt>(inner_value));
875 } else if (IsString(inner_value, cage_base)) {
878 } else {
879 AllowGarbageCollection allow_gc;
880 DCHECK(IsSymbol(inner_value));
881 return ThrowDataCloneError(MessageTemplate::kDataCloneError, value);
882 }
883 }
884 return ThrowIfOutOfMemory();
885}
886
889 WriteString(direct_handle(regexp->source(), isolate_));
890 WriteVarint(static_cast<uint32_t>(regexp->flags()));
891}
892
894 // First copy the key-value pairs, since getters could mutate them.
896 isolate_);
897 int length = table->NumberOfElements() * 2;
899 {
901 Tagged<OrderedHashMap> raw_table = *table;
902 Tagged<FixedArray> raw_entries = *entries;
903 Tagged<Hole> hash_table_hole =
904 ReadOnlyRoots(isolate_).hash_table_hole_value();
905 int result_index = 0;
906 for (InternalIndex entry : raw_table->IterateEntries()) {
907 Tagged<Object> key = raw_table->KeyAt(entry);
908 if (key == hash_table_hole) continue;
909 raw_entries->set(result_index++, key);
910 raw_entries->set(result_index++, raw_table->ValueAt(entry));
911 }
912 DCHECK_EQ(result_index, length);
913 }
914
915 // Then write it out.
917 for (int i = 0; i < length; i++) {
919 .FromMaybe(false)) {
920 return Nothing<bool>();
921 }
922 }
924 WriteVarint<uint32_t>(length);
925 return ThrowIfOutOfMemory();
926}
927
929 // First copy the element pointers, since getters could mutate them.
931 isolate_);
932 int length = table->NumberOfElements();
934 {
936 Tagged<OrderedHashSet> raw_table = *table;
937 Tagged<FixedArray> raw_entries = *entries;
938 Tagged<Hole> hash_table_hole =
939 ReadOnlyRoots(isolate_).hash_table_hole_value();
940 int result_index = 0;
941 for (InternalIndex entry : raw_table->IterateEntries()) {
942 Tagged<Object> key = raw_table->KeyAt(entry);
943 if (key == hash_table_hole) continue;
944 raw_entries->set(result_index++, key);
945 }
946 DCHECK_EQ(result_index, length);
947 }
948
949 // Then write it out.
951 for (int i = 0; i < length; i++) {
953 .FromMaybe(false)) {
954 return Nothing<bool>();
955 }
956 }
958 WriteVarint<uint32_t>(length);
959 return ThrowIfOutOfMemory();
960}
961
963 DirectHandle<JSArrayBuffer> array_buffer) {
964 if (array_buffer->is_shared()) {
965 if (!delegate_) {
966 return ThrowDataCloneError(MessageTemplate::kDataCloneError,
967 array_buffer);
968 }
969
970 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
972 v8_isolate, Utils::ToLocalShared(array_buffer));
974
976 WriteVarint(index.FromJust());
977
978#if V8_ENABLE_WEBASSEMBLY
979 // SharedArrayBuffers that are actually WebAssembly memories need special
980 // handling because they have metadata that may diverge from their
981 // BackingStore's.
982 //
983 // These are handled by also serializing/deserializing their corresponding
984 // WebAssembly.Memory object.
985 //
986 // See comment for WasmMemoryObject::FixUpResizableArrayBuffer for details.
987 auto backing_store = array_buffer->GetBackingStore();
988 if (backing_store && backing_store->is_wasm_memory()) {
989 if (array_buffer->is_resizable_by_js()) {
990 Handle<Object> memory =
992 isolate_, array_buffer,
993 isolate_->factory()->array_buffer_wasm_memory_symbol())
994 .ToHandleChecked();
995 CHECK(IsWasmMemoryObject(*memory));
996 // WebAssembly.Memory and its buffer exist in a reference cycle.
997 // Manually break the cycle, otherwise deserialization will attempt to
998 // read the same ArrayBuffer/WebAssembly.Memory recursively and fail.
999 if (!id_map_.Find(memory)) {
1000 WriteVarint(static_cast<uint8_t>(
1001 WasmMemoryArrayBufferTag::kResizableFollowedByWasmMemory));
1002 if (!WriteJSReceiver(Cast<JSReceiver>(memory)).FromMaybe(false)) {
1003 return Nothing<bool>();
1004 }
1005 } else {
1006 WriteVarint(static_cast<uint8_t>(
1007 WasmMemoryArrayBufferTag::kResizableNotFollowedByWasmMemory));
1008 }
1009 } else {
1011 static_cast<uint8_t>(WasmMemoryArrayBufferTag::kFixedLength));
1012 }
1013 }
1014#endif // V8_ENABLE_WEBASSEMBLY
1015
1016 return ThrowIfOutOfMemory();
1017 }
1018
1019 uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer);
1020 if (transfer_entry) {
1022 WriteVarint(*transfer_entry);
1023 return ThrowIfOutOfMemory();
1024 }
1025 if (array_buffer->was_detached()) {
1026 return ThrowDataCloneError(
1027 MessageTemplate::kDataCloneErrorDetachedArrayBuffer);
1028 }
1029 size_t byte_length = array_buffer->byte_length();
1030 if (byte_length > std::numeric_limits<uint32_t>::max()) {
1031 return ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
1032 }
1033 if (array_buffer->is_resizable_by_js()) {
1034 size_t max_byte_length = array_buffer->max_byte_length();
1035 if (max_byte_length > std::numeric_limits<uint32_t>::max()) {
1036 return ThrowDataCloneError(MessageTemplate::kDataCloneError,
1037 array_buffer);
1038 }
1039
1041 WriteVarint<uint32_t>(static_cast<uint32_t>(byte_length));
1042 WriteVarint<uint32_t>(static_cast<uint32_t>(max_byte_length));
1043 WriteRawBytes(array_buffer->backing_store(), byte_length);
1044 return ThrowIfOutOfMemory();
1045 }
1047 WriteVarint<uint32_t>(static_cast<uint32_t>(byte_length));
1048 WriteRawBytes(array_buffer->backing_store(), byte_length);
1049 return ThrowIfOutOfMemory();
1050}
1051
1055 return WriteHostObject(direct_handle(view, isolate_));
1056 }
1058 ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array;
1059 if (IsJSTypedArray(view)) {
1060 if (Cast<JSTypedArray>(view)->IsOutOfBounds()) {
1061 return ThrowDataCloneError(MessageTemplate::kDataCloneError,
1062 direct_handle(view, isolate_));
1063 }
1064 switch (Cast<JSTypedArray>(view)->type()) {
1065#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
1066 case kExternal##Type##Array: \
1067 tag = ArrayBufferViewTag::k##Type##Array; \
1068 break;
1070#undef TYPED_ARRAY_CASE
1071 }
1072 } else {
1073 DCHECK(IsJSDataViewOrRabGsabDataView(view));
1074 if (IsJSRabGsabDataView(view) &&
1075 Cast<JSRabGsabDataView>(view)->IsOutOfBounds()) {
1076 return ThrowDataCloneError(MessageTemplate::kDataCloneError,
1077 direct_handle(view, isolate_));
1078 }
1079
1080 tag = ArrayBufferViewTag::kDataView;
1081 }
1082 WriteVarint(static_cast<uint8_t>(tag));
1083 WriteVarint(static_cast<uint32_t>(view->byte_offset()));
1084 WriteVarint(static_cast<uint32_t>(view->byte_length()));
1085 uint32_t flags =
1086 JSArrayBufferViewIsLengthTracking::encode(view->is_length_tracking()) |
1087 JSArrayBufferViewIsBackedByRab::encode(view->is_backed_by_rab());
1088 WriteVarint(flags);
1089 return ThrowIfOutOfMemory();
1090}
1091
1094 PropertyDescriptor message_desc;
1096 isolate_, error, isolate_->factory()->message_string(), &message_desc);
1097 MAYBE_RETURN(message_found, Nothing<bool>());
1098 PropertyDescriptor cause_desc;
1100 isolate_, error, isolate_->factory()->cause_string(), &cause_desc);
1101
1103
1104 DirectHandle<Object> name_object;
1105 if (!JSObject::GetProperty(isolate_, error, "name").ToHandle(&name_object)) {
1106 return Nothing<bool>();
1107 }
1109 if (!Object::ToString(isolate_, name_object).ToHandle(&name)) {
1110 return Nothing<bool>();
1111 }
1112
1113 if (name->IsOneByteEqualTo(base::CStrVector("EvalError"))) {
1114 WriteVarint(static_cast<uint8_t>(ErrorTag::kEvalErrorPrototype));
1115 } else if (name->IsOneByteEqualTo(base::CStrVector("RangeError"))) {
1116 WriteVarint(static_cast<uint8_t>(ErrorTag::kRangeErrorPrototype));
1117 } else if (name->IsOneByteEqualTo(base::CStrVector("ReferenceError"))) {
1118 WriteVarint(static_cast<uint8_t>(ErrorTag::kReferenceErrorPrototype));
1119 } else if (name->IsOneByteEqualTo(base::CStrVector("SyntaxError"))) {
1120 WriteVarint(static_cast<uint8_t>(ErrorTag::kSyntaxErrorPrototype));
1121 } else if (name->IsOneByteEqualTo(base::CStrVector("TypeError"))) {
1122 WriteVarint(static_cast<uint8_t>(ErrorTag::kTypeErrorPrototype));
1123 } else if (name->IsOneByteEqualTo(base::CStrVector("URIError"))) {
1124 WriteVarint(static_cast<uint8_t>(ErrorTag::kUriErrorPrototype));
1125 } else {
1126 // The default prototype in the deserialization side is Error.prototype, so
1127 // we don't have to do anything here.
1128 }
1129
1130 if (message_found.FromJust() &&
1131 PropertyDescriptor::IsDataDescriptor(&message_desc)) {
1132 DirectHandle<String> message;
1133 if (!Object::ToString(isolate_, message_desc.value()).ToHandle(&message)) {
1134 return Nothing<bool>();
1135 }
1136 WriteVarint(static_cast<uint8_t>(ErrorTag::kMessage));
1137 WriteString(message);
1138 }
1139
1140 if (!Object::GetProperty(isolate_, error, isolate_->factory()->stack_string())
1141 .ToHandle(&stack)) {
1142 return Nothing<bool>();
1143 }
1144 if (IsString(*stack)) {
1145 WriteVarint(static_cast<uint8_t>(ErrorTag::kStack));
1146 WriteString(Cast<String>(stack));
1147 }
1148
1149 // The {cause} can self-reference the error. We add at the end, so that we can
1150 // create the Error first when deserializing.
1151 if (cause_found.FromJust() &&
1153 DirectHandle<Object> cause = cause_desc.value();
1154 WriteVarint(static_cast<uint8_t>(ErrorTag::kCause));
1155 if (!WriteObject(cause).FromMaybe(false)) {
1156 return Nothing<bool>();
1157 }
1158 }
1159
1160 WriteVarint(static_cast<uint8_t>(ErrorTag::kEnd));
1161 return ThrowIfOutOfMemory();
1162}
1163
1165 DirectHandle<JSSharedStruct> shared_struct) {
1166 // TODO(v8:12547): Support copying serialization for shared structs as well.
1167 return WriteSharedObject(shared_struct);
1168}
1169
1174
1175#if V8_ENABLE_WEBASSEMBLY
1176Maybe<bool> ValueSerializer::WriteWasmModule(
1178 if (delegate_ == nullptr) {
1179 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
1180 }
1181
1183 reinterpret_cast<v8::Isolate*>(isolate_), Utils::ToLocal(object));
1185 uint32_t id = 0;
1186 if (transfer_id.To(&id)) {
1189 return Just(true);
1190 }
1191 return ThrowIfOutOfMemory();
1192}
1193
1194Maybe<bool> ValueSerializer::WriteWasmMemory(
1195 DirectHandle<WasmMemoryObject> object) {
1196 if (!object->array_buffer()->is_shared()) {
1197 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
1198 }
1199
1201 object->array_buffer()->GetBackingStore());
1202
1204 WriteZigZag<int32_t>(object->maximum_pages());
1205 WriteByte(object->is_memory64() ? 1 : 0);
1206 return WriteJSReceiver(
1207 DirectHandle<JSReceiver>(object->array_buffer(), isolate_));
1208}
1209#endif // V8_ENABLE_WEBASSEMBLY
1210
1212 DirectHandle<HeapObject> object) {
1213 if (!delegate_ || !isolate_->has_shared_space()) {
1214 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
1215 }
1216
1217 DCHECK(IsShared(*object));
1218
1219 // The first time a shared object is serialized, a new conveyor is made. This
1220 // conveyor is used for every shared object in this serialization and
1221 // subsequent deserialization sessions. The embedder owns the lifetime of the
1222 // conveyor.
1224 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1225 v8::SharedValueConveyor v8_conveyor(v8_isolate);
1226 shared_object_conveyor_ = v8_conveyor.private_.get();
1227 if (!delegate_->AdoptSharedValueConveyor(v8_isolate,
1228 std::move(v8_conveyor))) {
1229 shared_object_conveyor_ = nullptr;
1231 return Nothing<bool>();
1232 }
1233 }
1234
1237
1238 return ThrowIfOutOfMemory();
1239}
1240
1243 if (!delegate_) {
1245 isolate_->error_function(), MessageTemplate::kDataCloneError, object));
1246 return Nothing<bool>();
1247 }
1248 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1250 delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object));
1252 USE(result);
1253 DCHECK(!result.IsNothing());
1254 DCHECK(result.ToChecked());
1255 return ThrowIfOutOfMemory();
1256}
1257
1260 uint32_t properties_written = 0;
1261 int length = keys->length();
1262 for (int i = 0; i < length; i++) {
1263 DirectHandle<Object> key(keys->get(i), isolate_);
1264
1265 PropertyKey lookup_key(isolate_, key);
1266 LookupIterator it(isolate_, object, lookup_key, LookupIterator::OWN);
1268 if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>();
1269
1270 // If the property is no longer found, do not serialize it.
1271 // This could happen if a getter deleted the property.
1272 if (!it.IsFound()) continue;
1273
1274 if (!WriteObject(key).FromMaybe(false) ||
1275 !WriteObject(value).FromMaybe(false)) {
1276 return Nothing<uint32_t>();
1277 }
1278
1279 properties_written++;
1280 }
1281 return Just(properties_written);
1282}
1283
1286 return Just<bool>(
1287 JSObject::GetEmbedderFieldCount(js_object->map(isolate_)));
1288 }
1290
1291 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1293 delegate_->IsHostObject(v8_isolate, Utils::ToLocal(js_object));
1295 DCHECK(!result.IsNothing());
1296
1298 return result;
1299}
1300
1302 if (out_of_memory_) {
1303 return ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory);
1304 }
1305 return Just(true);
1306}
1307
1309 MessageTemplate template_index) {
1310 return ThrowDataCloneError(template_index,
1311 isolate_->factory()->empty_string());
1312}
1313
1315 DirectHandle<Object> arg0) {
1316 DirectHandle<String> message =
1318 if (delegate_) {
1319 delegate_->ThrowDataCloneError(Utils::ToLocal(message));
1320 } else {
1321 isolate_->Throw(
1322 *isolate_->factory()->NewError(isolate_->error_function(), message));
1323 }
1324 return Nothing<bool>();
1325}
1326
1330 : isolate_(isolate),
1331 delegate_(delegate),
1332 position_(data.begin()),
1333 end_(data.end()),
1334 id_map_(isolate->global_handles()->Create(
1335 ReadOnlyRoots(isolate_).empty_fixed_array())) {}
1336
1337ValueDeserializer::ValueDeserializer(Isolate* isolate, const uint8_t* data,
1338 size_t size)
1339 : isolate_(isolate),
1340 delegate_(nullptr),
1341 position_(data),
1342 end_(data + size),
1343 id_map_(isolate->global_handles()->Create(
1344 ReadOnlyRoots(isolate_).empty_fixed_array())) {}
1345
1348 GlobalHandles::Destroy(id_map_.location());
1349
1350 IndirectHandle<Object> transfer_map_handle;
1351 if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) {
1352 GlobalHandles::Destroy(transfer_map_handle.location());
1353 }
1354}
1355
1357 if (position_ < end_ &&
1358 *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) {
1359 ReadTag().ToChecked();
1360 if (!ReadVarintLoop<uint32_t>().To(&version_) ||
1363 MessageTemplate::kDataCloneDeserializationVersionError));
1364 return Nothing<bool>();
1365 }
1366 }
1367 return Just(true);
1368}
1369
1371 const uint8_t* peek_position = position_;
1372 SerializationTag tag;
1373 do {
1374 if (peek_position >= end_) return Nothing<SerializationTag>();
1375 tag = static_cast<SerializationTag>(*peek_position);
1376 peek_position++;
1377 } while (tag == SerializationTag::kPadding);
1378 return Just(tag);
1379}
1380
1382 SerializationTag actual_tag = ReadTag().ToChecked();
1383 DCHECK(actual_tag == peeked_tag);
1384 USE(actual_tag);
1385}
1386
1388 SerializationTag tag;
1389 do {
1390 if (position_ >= end_) return Nothing<SerializationTag>();
1391 tag = static_cast<SerializationTag>(*position_);
1392 position_++;
1393 } while (tag == SerializationTag::kPadding);
1394 return Just(tag);
1395}
1396
1397template <typename T>
1399 // Reads an unsigned integer as a base-128 varint.
1400 // The number is written, 7 bits at a time, from the least significant to the
1401 // most significant 7 bits. Each byte, except the last, has the MSB set.
1402 // If the varint is larger than T, any more significant bits are discarded.
1403 // See also https://developers.google.com/protocol-buffers/docs/encoding
1404 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
1405 "Only unsigned integer types can be read as varints.");
1406 if (sizeof(T) > 4) return ReadVarintLoop<T>();
1407 auto max_read_position = position_ + sizeof(T) + 1;
1408 if (V8_UNLIKELY(max_read_position >= end_)) return ReadVarintLoop<T>();
1409#ifdef DEBUG
1410 // DCHECK code to make sure the manually unrolled loop yields the exact
1411 // same end state and result.
1412 auto previous_position = position_;
1413 Maybe<T> maybe_expected_value = ReadVarintLoop<T>();
1414 // ReadVarintLoop can't return Nothing here; all such conditions have been
1415 // checked above.
1416 T expected_value = maybe_expected_value.ToChecked();
1417 auto expected_position = position_;
1418 position_ = previous_position;
1419#endif // DEBUG
1420#define EXIT_DCHECK() \
1421 DCHECK_LE(position_, end_); \
1422 DCHECK_EQ(position_, expected_position); \
1423 DCHECK_EQ(value, expected_value)
1424
1425 T value = 0;
1426#define ITERATION_SHIFTED(shift) \
1427 if (shift < sizeof(T) * 8) { \
1428 uint8_t byte = *position_; \
1429 position_++; \
1430 if (byte < 0x80) { \
1431 value |= static_cast<T>(byte) << shift; \
1432 EXIT_DCHECK(); \
1433 return Just(value); \
1434 } else { \
1435 value |= static_cast<T>(byte & 0x7F) << shift; \
1436 } \
1437 }
1438 // Manually unroll the loop to achieve the best measured performance.
1439 // This is ~15% faster than ReadVarintLoop.
1445
1446 EXIT_DCHECK();
1447 return Just(value);
1448#undef ITERATION_SHIFTED
1449#undef EXIT_DCHECK
1450}
1451
1452template <typename T>
1454 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
1455 "Only unsigned integer types can be read as varints.");
1456 T value = 0;
1457 unsigned shift = 0;
1458 bool has_another_byte;
1459 do {
1460 if (position_ >= end_) return Nothing<T>();
1461 uint8_t byte = *position_;
1462 has_another_byte = byte & 0x80;
1463 if (V8_LIKELY(shift < sizeof(T) * 8)) {
1464 value |= static_cast<T>(byte & 0x7F) << shift;
1465 shift += 7;
1466 } else {
1467 // For consistency with the fast unrolled loop in ReadVarint we return
1468 // after we have read size(T) + 1 bytes.
1469#ifdef V8_VALUE_DESERIALIZER_HARD_FAIL
1470 CHECK(!has_another_byte);
1471#endif // V8_VALUE_DESERIALIZER_HARD_FAIL
1472 return Just(value);
1473 }
1474 position_++;
1475 } while (has_another_byte);
1476 return Just(value);
1477}
1478
1479template <typename T>
1481 // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
1482 // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
1483 // See also https://developers.google.com/protocol-buffers/docs/encoding
1484 static_assert(std::is_integral_v<T> && std::is_signed_v<T>,
1485 "Only signed integer types can be read as zigzag.");
1486 using UnsignedT = std::make_unsigned_t<T>;
1487 UnsignedT unsigned_value;
1488 if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>();
1489 return Just(static_cast<T>((unsigned_value >> 1) ^
1490 -static_cast<T>(unsigned_value & 1)));
1491}
1492
1493template EXPORT_TEMPLATE_DEFINE(
1495
1497 // Warning: this uses host endianness.
1498 if (sizeof(double) > static_cast<unsigned>(end_ - position_)) {
1499 return Nothing<double>();
1500 }
1501 double value;
1502 memcpy(&value, position_, sizeof(double));
1503 position_ += sizeof(double);
1504 if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN();
1505 return Just(value);
1506}
1507
1509 size_t size) {
1510 if (size > static_cast<size_t>(end_ - position_)) {
1512 }
1513 const uint8_t* start = position_;
1514 position_ += size;
1515 return Just(base::Vector<const uint8_t>(start, size));
1516}
1517
1519 size_t size) {
1520 if (size > static_cast<size_t>(end_ - position_) ||
1521 size % sizeof(base::uc16) != 0) {
1523 }
1524 const base::uc16* start = (const base::uc16*)(position_);
1525 position_ += size;
1526 return Just(base::Vector<const base::uc16>(start, size / sizeof(base::uc16)));
1527}
1528
1529bool ValueDeserializer::ReadByte(uint8_t* value) {
1530 if (static_cast<size_t>(end_ - position_) < sizeof(uint8_t)) return false;
1531 *value = *position_;
1532 position_++;
1533 return true;
1534}
1535
1536bool ValueDeserializer::ReadUint32(uint32_t* value) {
1537 return ReadVarint<uint32_t>().To(value);
1538}
1539
1540bool ValueDeserializer::ReadUint64(uint64_t* value) {
1541 return ReadVarint<uint64_t>().To(value);
1542}
1543
1545 return ReadDouble().To(value);
1546}
1547
1548bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
1549 if (length > static_cast<size_t>(end_ - position_)) return false;
1550 *data = position_;
1551 position_ += length;
1552 return true;
1553}
1554
1556 uint32_t transfer_id, DirectHandle<JSArrayBuffer> array_buffer) {
1557 if (array_buffer_transfer_map_.is_null()) {
1559 *SimpleNumberDictionary::New(isolate_, 0));
1560 }
1562 array_buffer_transfer_map_.ToHandleChecked();
1564 SimpleNumberDictionary::Set(isolate_, dictionary, transfer_id,
1565 array_buffer);
1566 if (!new_dictionary.is_identical_to(dictionary)) {
1567 GlobalHandles::Destroy(dictionary.location());
1569 isolate_->global_handles()->Create(*new_dictionary);
1570 }
1571}
1572
1574 // We had a bug which produced invalid version 13 data (see
1575 // crbug.com/1284506). This compatibility mode tries to first read the data
1576 // normally, and if it fails, and the version is 13, tries to read the broken
1577 // format.
1578 const uint8_t* original_position = position_;
1581
1582 // The deserialization code doesn't throw errors for invalid data. It throws
1583 // errors for stack overflows, though, and in that case we won't retry.
1584 if (result.is_null() && version_ == 13 && !isolate_->has_exception()) {
1586 position_ = original_position;
1587 result = ReadObject();
1588 }
1589
1590 if (result.is_null() && !isolate_->has_exception()) {
1592 MessageTemplate::kDataCloneDeserializationError));
1593 }
1594
1595 return result;
1596}
1597
1599 DisallowJavascriptExecution no_js(isolate_);
1600 // If we are at the end of the stack, abort. This function may recurse.
1602
1604
1605 // ArrayBufferView is special in that it consumes the value before it, even
1606 // after format version 0.
1607 DirectHandle<Object> object;
1608 SerializationTag tag;
1609 if (result.ToHandle(&object) && V8_UNLIKELY(IsJSArrayBuffer(*object)) &&
1610 PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
1613 }
1614
1615 if (result.is_null() && !suppress_deserialization_errors_ &&
1616 !isolate_->has_exception()) {
1618 MessageTemplate::kDataCloneDeserializationError));
1619 }
1620#if defined(DEBUG) && defined(VERIFY_HEAP)
1621 if (!result.is_null() && v8_flags.enable_slow_asserts &&
1622 v8_flags.verify_heap) {
1623 Object::ObjectVerify(*object, isolate_);
1624 }
1625#endif
1626
1627 return result;
1628}
1629
1631 SerializationTag tag;
1632 if (!ReadTag().To(&tag)) return MaybeDirectHandle<Object>();
1633 switch (tag) {
1635 // Read the count and ignore it.
1636 if (ReadVarint<uint32_t>().IsNothing())
1638 return ReadObject();
1640 return isolate_->factory()->undefined_value();
1642 return isolate_->factory()->null_value();
1644 return isolate_->factory()->true_value();
1646 return isolate_->factory()->false_value();
1649 if (number.IsNothing()) return MaybeDirectHandle<Object>();
1650 return isolate_->factory()->NewNumberFromInt(number.FromJust());
1651 }
1654 if (number.IsNothing()) return MaybeDirectHandle<Object>();
1655 return isolate_->factory()->NewNumberFromUint(number.FromJust());
1656 }
1658 Maybe<double> number = ReadDouble();
1659 if (number.IsNothing()) return MaybeDirectHandle<Object>();
1660 return isolate_->factory()->NewNumber(number.FromJust());
1661 }
1663 return ReadBigInt();
1665 return ReadUtf8String();
1667 return ReadOneByteString();
1669 return ReadTwoByteString();
1671 uint32_t id;
1672 if (!ReadVarint<uint32_t>().To(&id)) return MaybeDirectHandle<Object>();
1673 return GetObjectWithID(id);
1674 }
1676 return ReadJSObject();
1678 return ReadSparseJSArray();
1680 return ReadDenseJSArray();
1682 return ReadJSDate();
1688 return ReadJSPrimitiveWrapper(tag);
1690 return ReadJSRegExp();
1692 return ReadJSMap();
1694 return ReadJSSet();
1696 constexpr bool is_shared = false;
1697 constexpr bool is_resizable = false;
1698 return ReadJSArrayBuffer(is_shared, is_resizable);
1699 }
1701 constexpr bool is_shared = false;
1702 constexpr bool is_resizable = true;
1703 return ReadJSArrayBuffer(is_shared, is_resizable);
1704 }
1707 }
1709 constexpr bool is_shared = true;
1710 constexpr bool is_resizable = false;
1711 return ReadJSArrayBuffer(is_shared, is_resizable);
1712 }
1714 return ReadJSError();
1715#if V8_ENABLE_WEBASSEMBLY
1717 return ReadWasmModuleTransfer();
1719 return ReadWasmMemory();
1720#endif // V8_ENABLE_WEBASSEMBLY
1722 return ReadHostObject();
1724 if (version_ >= 15) return ReadSharedObject();
1725 // If the data doesn't support shared values because it is from an older
1726 // version, treat the tag as unknown.
1727 [[fallthrough]];
1728 default:
1729 // Before there was an explicit tag for host objects, all unknown tags
1730 // were delegated to the host.
1731 if (version_ < 13) {
1732 position_--;
1733 return ReadHostObject();
1734 }
1736 }
1737}
1738
1740 if (version_ < 12) return ReadUtf8String();
1741 DirectHandle<Object> object;
1742 if (!ReadObject().ToHandle(&object) || !IsString(*object, isolate_)) {
1744 }
1745 return Cast<String>(object);
1746}
1747
1749 uint32_t bitfield;
1750 if (!ReadVarint<uint32_t>().To(&bitfield)) return MaybeDirectHandle<BigInt>();
1751 size_t bytelength = BigInt::DigitsByteLengthForBitfield(bitfield);
1752 base::Vector<const uint8_t> digits_storage;
1753 if (!ReadRawBytes(bytelength).To(&digits_storage)) {
1755 }
1756 return BigInt::FromSerializedDigits(isolate_, bitfield, digits_storage);
1757}
1758
1760 AllocationType allocation) {
1761 uint32_t utf8_length;
1762 if (!ReadVarint<uint32_t>().To(&utf8_length)) return {};
1763 // utf8_length is checked in ReadRawBytes.
1764 base::Vector<const uint8_t> utf8_bytes;
1765 if (!ReadRawBytes(utf8_length).To(&utf8_bytes)) return {};
1767 base::Vector<const char>::cast(utf8_bytes), allocation);
1768}
1769
1771 AllocationType allocation) {
1772 uint32_t byte_length;
1774 if (!ReadVarint<uint32_t>().To(&byte_length)) return {};
1775 // byte_length is checked in ReadRawBytes.
1776 if (!ReadRawBytes(byte_length).To(&bytes)) return {};
1777 return isolate_->factory()->NewStringFromOneByte(bytes, allocation);
1778}
1779
1781 AllocationType allocation) {
1782 uint32_t byte_length;
1784 if (!ReadVarint<uint32_t>().To(&byte_length)) return {};
1785 // byte_length is checked in ReadRawBytes.
1786 if (byte_length % sizeof(base::uc16) != 0 ||
1787 !ReadRawBytes(byte_length).To(&bytes)) {
1789 }
1790
1791 // Allocate an uninitialized string so that we can do a raw memcpy into the
1792 // string on the heap (regardless of alignment).
1793 if (byte_length == 0) return isolate_->factory()->empty_string();
1795 if (!isolate_->factory()
1796 ->NewRawTwoByteString(byte_length / sizeof(base::uc16), allocation)
1797 .ToHandle(&string)) {
1799 }
1800
1801 // Copy the bytes directly into the new string.
1802 // Warning: this uses host endianness.
1804 memcpy(string->GetChars(no_gc), bytes.begin(), bytes.length());
1805 return string;
1806}
1807
1809 // If we are at the end of the stack, abort. This function may recurse.
1811
1812 uint32_t id = next_id_++;
1813 HandleScope scope(isolate_);
1814 DirectHandle<JSObject> object =
1815 isolate_->factory()->NewJSObject(isolate_->object_function());
1816 AddObjectWithID(id, object);
1817
1818 uint32_t num_properties;
1819 uint32_t expected_num_properties;
1821 .To(&num_properties) ||
1822 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1823 num_properties != expected_num_properties) {
1825 }
1826
1828 return scope.CloseAndEscape(object);
1829}
1830
1832 // If we are at the end of the stack, abort. This function may recurse.
1834
1835 uint32_t length;
1836 if (!ReadVarint<uint32_t>().To(&length)) return MaybeDirectHandle<JSArray>();
1837
1838 uint32_t id = next_id_++;
1839 HandleScope scope(isolate_);
1840 DirectHandle<JSArray> array =
1843 AddObjectWithID(id, array);
1844
1845 uint32_t num_properties;
1846 uint32_t expected_num_properties;
1847 uint32_t expected_length;
1849 .To(&num_properties) ||
1850 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1851 !ReadVarint<uint32_t>().To(&expected_length) ||
1852 num_properties != expected_num_properties || length != expected_length) {
1854 }
1855
1857 return scope.CloseAndEscape(array);
1858}
1859
1861 // If we are at the end of the stack, abort. This function may recurse.
1863
1864 // We shouldn't permit an array larger than the biggest we can request from
1865 // V8. As an additional sanity check, since each entry will take at least one
1866 // byte to encode, if there are fewer bytes than that we can also fail fast.
1867 uint32_t length;
1868 if (!ReadVarint<uint32_t>().To(&length) ||
1869 length > static_cast<uint32_t>(FixedArray::kMaxLength) ||
1870 length > static_cast<size_t>(end_ - position_)) {
1872 }
1873
1874 uint32_t id = next_id_++;
1875 HandleScope scope(isolate_);
1877 HOLEY_ELEMENTS, length, length,
1879 AddObjectWithID(id, array);
1880
1881 DirectHandle<FixedArray> elements(Cast<FixedArray>(array->elements()),
1882 isolate_);
1883 auto elements_length = static_cast<uint32_t>(elements->length());
1884 for (uint32_t i = 0; i < length; i++) {
1885 SerializationTag tag;
1886 if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) {
1888 continue;
1889 }
1890
1891 DirectHandle<Object> element;
1892 if (!ReadObject().ToHandle(&element)) return MaybeDirectHandle<JSArray>();
1893
1894 // Serialization versions less than 11 encode the hole the same as
1895 // undefined. For consistency with previous behavior, store these as the
1896 // hole. Past version 11, undefined means undefined.
1897 if (version_ < 11 && IsUndefined(*element, isolate_)) continue;
1898
1899 // Safety check.
1900 if (i >= elements_length) return MaybeDirectHandle<JSArray>();
1901
1902 elements->set(i, *element);
1903 }
1904
1905 uint32_t num_properties;
1906 uint32_t expected_num_properties;
1907 uint32_t expected_length;
1909 .To(&num_properties) ||
1910 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1911 !ReadVarint<uint32_t>().To(&expected_length) ||
1912 num_properties != expected_num_properties || length != expected_length) {
1914 }
1915
1917 return scope.CloseAndEscape(array);
1918}
1919
1921 double value;
1922 if (!ReadDouble().To(&value)) return MaybeDirectHandle<JSDate>();
1923 uint32_t id = next_id_++;
1925 if (!JSDate::New(isolate_->date_function(), isolate_->date_function(), value)
1926 .ToHandle(&date)) {
1928 }
1929 AddObjectWithID(id, date);
1930 return date;
1931}
1932
1934 SerializationTag tag) {
1935 uint32_t id = next_id_++;
1937 switch (tag) {
1940 isolate_->factory()->NewJSObject(isolate_->boolean_function()));
1941 value->set_value(ReadOnlyRoots(isolate_).true_value());
1942 break;
1945 isolate_->factory()->NewJSObject(isolate_->boolean_function()));
1946 value->set_value(ReadOnlyRoots(isolate_).false_value());
1947 break;
1949 double number;
1950 if (!ReadDouble().To(&number))
1953 isolate_->factory()->NewJSObject(isolate_->number_function()));
1954 DirectHandle<Number> number_object =
1955 isolate_->factory()->NewNumber(number);
1956 value->set_value(*number_object);
1957 break;
1958 }
1960 DirectHandle<BigInt> bigint;
1961 if (!ReadBigInt().ToHandle(&bigint))
1964 isolate_->factory()->NewJSObject(isolate_->bigint_function()));
1965 value->set_value(*bigint);
1966 break;
1967 }
1970 if (!ReadString().ToHandle(&string))
1973 isolate_->factory()->NewJSObject(isolate_->string_function()));
1974 value->set_value(*string);
1975 break;
1976 }
1977 default:
1978 UNREACHABLE();
1979 }
1980 AddObjectWithID(id, value);
1981 return value;
1982}
1983
1985 uint32_t id = next_id_++;
1987 uint32_t raw_flags;
1989 if (!ReadString().ToHandle(&pattern) ||
1990 !ReadVarint<uint32_t>().To(&raw_flags)) {
1992 }
1993
1994 // Ensure the deserialized flags are valid.
1995 uint32_t bad_flags_mask = static_cast<uint32_t>(-1) << JSRegExp::kFlagCount;
1996 // kLinear is accepted only with the appropriate flag.
1997 if (!v8_flags.enable_experimental_regexp_engine) {
1998 bad_flags_mask |= JSRegExp::kLinear;
1999 }
2000 if ((raw_flags & bad_flags_mask) ||
2001 !RegExp::VerifyFlags(static_cast<RegExpFlags>(raw_flags)) ||
2002 !JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags))
2003 .ToHandle(&regexp)) {
2005 }
2006
2007 AddObjectWithID(id, regexp);
2008 return regexp;
2009}
2010
2012 // If we are at the end of the stack, abort. This function may recurse.
2014
2015 HandleScope scope(isolate_);
2016 uint32_t id = next_id_++;
2018 AddObjectWithID(id, map);
2019
2020 DirectHandle<JSFunction> map_set = isolate_->map_set();
2021 uint32_t length = 0;
2022 while (true) {
2023 SerializationTag tag;
2024 if (!PeekTag().To(&tag)) return MaybeDirectHandle<JSMap>();
2025 if (tag == SerializationTag::kEndJSMap) {
2027 break;
2028 }
2029
2031 if (!ReadObject().ToHandle(&args[0]) || !ReadObject().ToHandle(&args[1])) {
2032 return MaybeDirectHandle<JSMap>();
2033 }
2034
2035 AllowJavascriptExecution allow_js(isolate_);
2036 if (Execution::Call(isolate_, map_set, map, base::VectorOf(args))
2037 .is_null()) {
2038 return MaybeDirectHandle<JSMap>();
2039 }
2040 length += 2;
2041 }
2042
2043 uint32_t expected_length;
2044 if (!ReadVarint<uint32_t>().To(&expected_length) ||
2045 length != expected_length) {
2046 return MaybeDirectHandle<JSMap>();
2047 }
2049 return scope.CloseAndEscape(map);
2050}
2051
2053 // If we are at the end of the stack, abort. This function may recurse.
2055
2056 HandleScope scope(isolate_);
2057 uint32_t id = next_id_++;
2059 AddObjectWithID(id, set);
2060 DirectHandle<JSFunction> set_add = isolate_->set_add();
2061 uint32_t length = 0;
2062 while (true) {
2063 SerializationTag tag;
2064 if (!PeekTag().To(&tag)) return MaybeDirectHandle<JSSet>();
2065 if (tag == SerializationTag::kEndJSSet) {
2067 break;
2068 }
2069
2071 if (!ReadObject().ToHandle(&args[0])) return MaybeDirectHandle<JSSet>();
2072
2073 AllowJavascriptExecution allow_js(isolate_);
2074 if (Execution::Call(isolate_, set_add, set, base::VectorOf(args))
2075 .is_null()) {
2076 return MaybeDirectHandle<JSSet>();
2077 }
2078 length++;
2079 }
2080
2081 uint32_t expected_length;
2082 if (!ReadVarint<uint32_t>().To(&expected_length) ||
2083 length != expected_length) {
2084 return MaybeDirectHandle<JSSet>();
2085 }
2087 return scope.CloseAndEscape(set);
2088}
2089
2091 bool is_shared, bool is_resizable) {
2092 uint32_t id = next_id_++;
2093 if (is_shared) {
2094 uint32_t clone_id;
2095 Local<SharedArrayBuffer> sab_value;
2096 if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr ||
2097 !delegate_
2098 ->GetSharedArrayBufferFromId(
2099 reinterpret_cast<v8::Isolate*>(isolate_), clone_id)
2100 .ToLocal(&sab_value)) {
2103 }
2104 DirectHandle<JSArrayBuffer> array_buffer =
2105 Utils::OpenDirectHandle(*sab_value);
2106 DCHECK_EQ(is_shared, array_buffer->is_shared());
2107 AddObjectWithID(id, array_buffer);
2108
2109#if V8_ENABLE_WEBASSEMBLY
2110 auto backing_store = array_buffer->GetBackingStore();
2111 if (backing_store && backing_store->is_wasm_memory()) {
2112 uint8_t resizable_subtag;
2113 if (!ReadVarint<uint8_t>().To(&resizable_subtag)) {
2115 }
2116 switch (static_cast<WasmMemoryArrayBufferTag>(resizable_subtag)) {
2117 case WasmMemoryArrayBufferTag::kFixedLength:
2118 // Nothing to do.
2119 break;
2120 case WasmMemoryArrayBufferTag::kResizableNotFollowedByWasmMemory:
2121 // In this case we are in the middle of constructing the
2122 // WebAssembly.Memory.
2123 array_buffer->set_is_resizable_by_js(true);
2124 break;
2125 case WasmMemoryArrayBufferTag::kResizableFollowedByWasmMemory: {
2126 array_buffer->set_is_resizable_by_js(true);
2127 DirectHandle<Object> wasm_memory_obj;
2128 if (!ReadObject().ToHandle(&wasm_memory_obj) ||
2129 !IsWasmMemoryObject(*wasm_memory_obj, isolate_)) {
2131 }
2132 break;
2133 }
2134 default:
2136 }
2137 }
2138#endif // V8_ENABLE_WEBASSEMBLY
2139
2140 return array_buffer;
2141 }
2142 uint32_t byte_length;
2143 if (!ReadVarint<uint32_t>().To(&byte_length)) {
2145 }
2146 uint32_t max_byte_length = byte_length;
2147 if (is_resizable) {
2148 if (!ReadVarint<uint32_t>().To(&max_byte_length)) {
2150 }
2151 if (byte_length > max_byte_length) {
2153 }
2154 }
2155 if (byte_length > static_cast<size_t>(end_ - position_)) {
2157 }
2160 byte_length, max_byte_length, InitializedFlag::kUninitialized,
2161 is_resizable ? ResizableFlag::kResizable
2163
2164 DirectHandle<JSArrayBuffer> array_buffer;
2165 if (!result.ToHandle(&array_buffer)) return result;
2166
2167 if (byte_length > 0) {
2168 memcpy(array_buffer->backing_store(), position_, byte_length);
2169 }
2170 position_ += byte_length;
2171 AddObjectWithID(id, array_buffer);
2172 return array_buffer;
2173}
2174
2177 uint32_t id = next_id_++;
2178 uint32_t transfer_id;
2180 if (!ReadVarint<uint32_t>().To(&transfer_id) ||
2181 !array_buffer_transfer_map_.ToHandle(&transfer_map)) {
2183 }
2184 InternalIndex index = transfer_map->FindEntry(isolate_, transfer_id);
2185 if (index.is_not_found()) {
2187 }
2188 DirectHandle<JSArrayBuffer> array_buffer(
2189 Cast<JSArrayBuffer>(transfer_map->ValueAt(index)), isolate_);
2190 AddObjectWithID(id, array_buffer);
2191 return array_buffer;
2192}
2193
2196 uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->GetByteLength());
2197 uint8_t tag = 0;
2198 uint32_t byte_offset = 0;
2199 uint32_t byte_length = 0;
2200 uint32_t flags = 0;
2201 if (!ReadVarint<uint8_t>().To(&tag) ||
2202 !ReadVarint<uint32_t>().To(&byte_offset) ||
2203 !ReadVarint<uint32_t>().To(&byte_length) ||
2204 byte_offset > buffer_byte_length ||
2205 byte_length > buffer_byte_length - byte_offset) {
2207 }
2208 const bool should_read_flags = version_ >= 14 || version_13_broken_data_mode_;
2209 if (should_read_flags && !ReadVarint<uint32_t>().To(&flags)) {
2211 }
2212 uint32_t id = next_id_++;
2213 ExternalArrayType external_array_type = kExternalInt8Array;
2214 unsigned element_size = 0;
2215
2216 switch (static_cast<ArrayBufferViewTag>(tag)) {
2217 case ArrayBufferViewTag::kDataView: {
2218 bool is_length_tracking = false;
2219 bool is_backed_by_rab = false;
2220 if (!ValidateJSArrayBufferViewFlags(*buffer, flags, is_length_tracking,
2223 }
2226 buffer, byte_offset, byte_length, is_length_tracking);
2227 CHECK_EQ(is_backed_by_rab, data_view->is_backed_by_rab());
2228 CHECK_EQ(is_length_tracking, data_view->is_length_tracking());
2229 AddObjectWithID(id, data_view);
2230 return data_view;
2231 }
2232#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
2233 case ArrayBufferViewTag::k##Type##Array: \
2234 external_array_type = kExternal##Type##Array; \
2235 element_size = sizeof(ctype); \
2236 break;
2238#undef TYPED_ARRAY_CASE
2239 case ArrayBufferViewTag::kFloat16Array: {
2240 if (i::v8_flags.js_float16array) {
2241 external_array_type = kExternalFloat16Array;
2242 element_size = sizeof(uint16_t);
2243 }
2244 break;
2245 }
2246 }
2247 if (element_size == 0 || byte_offset % element_size != 0 ||
2248 byte_length % element_size != 0) {
2250 }
2251 bool is_length_tracking = false;
2252 bool is_backed_by_rab = false;
2253 if (!ValidateJSArrayBufferViewFlags(*buffer, flags, is_length_tracking,
2256 }
2258 external_array_type, buffer, byte_offset, byte_length / element_size,
2259 is_length_tracking);
2260 CHECK_EQ(is_length_tracking, typed_array->is_length_tracking());
2261 CHECK_EQ(is_backed_by_rab, typed_array->is_backed_by_rab());
2262 AddObjectWithID(id, typed_array);
2263 return typed_array;
2264}
2265
2267 Tagged<JSArrayBuffer> buffer, uint32_t serialized_flags,
2268 bool& is_length_tracking, bool& is_backed_by_rab) {
2269 is_length_tracking =
2270 JSArrayBufferViewIsLengthTracking::decode(serialized_flags);
2271 is_backed_by_rab = JSArrayBufferViewIsBackedByRab::decode(serialized_flags);
2272
2273 // TODO(marja): When the version number is bumped the next time, check that
2274 // serialized_flags doesn't contain spurious 1-bits.
2275
2276 if (is_backed_by_rab || is_length_tracking) {
2277 if (!buffer->is_resizable_by_js()) {
2278 return false;
2279 }
2280 if (is_backed_by_rab && buffer->is_shared()) {
2281 return false;
2282 }
2283 }
2284 // The RAB-ness of the buffer and the TA's "is_backed_by_rab" need to be in
2285 // sync.
2286 if (buffer->is_resizable_by_js() && !buffer->is_shared() &&
2288 return false;
2289 }
2290 return true;
2291}
2292
2294 uint32_t id = next_id_++;
2295
2296#define READ_NEXT_ERROR_TAG() \
2297 do { \
2298 if (!ReadVarint<uint8_t>().To(&tag)) { \
2299 return MaybeDirectHandle<JSObject>(); \
2300 } \
2301 } while (false)
2302
2303 uint8_t tag;
2305
2306 // Read error type constructor.
2307 DirectHandle<JSFunction> constructor;
2308 switch (static_cast<ErrorTag>(tag)) {
2309 case ErrorTag::kEvalErrorPrototype:
2310 constructor = isolate_->eval_error_function();
2312 break;
2313 case ErrorTag::kRangeErrorPrototype:
2314 constructor = isolate_->range_error_function();
2316 break;
2317 case ErrorTag::kReferenceErrorPrototype:
2318 constructor = isolate_->reference_error_function();
2320 break;
2321 case ErrorTag::kSyntaxErrorPrototype:
2322 constructor = isolate_->syntax_error_function();
2324 break;
2325 case ErrorTag::kTypeErrorPrototype:
2326 constructor = isolate_->type_error_function();
2328 break;
2329 case ErrorTag::kUriErrorPrototype:
2330 constructor = isolate_->uri_error_function();
2332 break;
2333 default:
2334 // The default prototype in the deserialization side is Error.prototype,
2335 // so we don't have to do anything here.
2336 constructor = isolate_->error_function();
2337 break;
2338 }
2339
2340 // Check for message property.
2341 DirectHandle<Object> message = isolate_->factory()->undefined_value();
2342 if (static_cast<ErrorTag>(tag) == ErrorTag::kMessage) {
2343 DirectHandle<String> message_string;
2344 if (!ReadString().ToHandle(&message_string)) {
2346 }
2347 message = message_string;
2349 }
2350
2351 // Check for stack property.
2352 DirectHandle<Object> stack = isolate_->factory()->undefined_value();
2353 if (static_cast<ErrorTag>(tag) == ErrorTag::kStack) {
2354 DirectHandle<String> stack_string;
2355 if (!ReadString().ToHandle(&stack_string)) {
2357 }
2358 stack = stack_string;
2360 }
2361
2362 // Create error object before adding the cause property.
2364 DirectHandle<Object> no_caller;
2365 DirectHandle<Object> undefined_options =
2366 isolate_->factory()->undefined_value();
2367 if (!ErrorUtils::Construct(isolate_, constructor, constructor, message,
2368 undefined_options, SKIP_NONE, no_caller,
2370 .ToHandle(&error)) {
2372 }
2374 AddObjectWithID(id, error);
2375
2376 // Add cause property if needed.
2377 if (static_cast<ErrorTag>(tag) == ErrorTag::kCause) {
2379 if (!ReadObject().ToHandle(&cause)) {
2381 }
2382 DirectHandle<Name> cause_string = isolate_->factory()->cause_string();
2383 if (JSObject::SetOwnPropertyIgnoreAttributes(error, cause_string, cause,
2384 DONT_ENUM)
2385 .is_null()) {
2387 }
2389 }
2390
2391#undef READ_NEXT_ERROR_TAG
2392
2393 if (static_cast<ErrorTag>(tag) != ErrorTag::kEnd) {
2395 }
2396 return error;
2397}
2398
2399#if V8_ENABLE_WEBASSEMBLY
2400MaybeDirectHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() {
2401 uint32_t transfer_id = 0;
2402 Local<Value> module_value;
2403 if (!ReadVarint<uint32_t>().To(&transfer_id) || delegate_ == nullptr ||
2404 !delegate_
2405 ->GetWasmModuleFromId(reinterpret_cast<v8::Isolate*>(isolate_),
2406 transfer_id)
2407 .ToLocal(&module_value)) {
2410 }
2411 uint32_t id = next_id_++;
2412 DirectHandle<JSObject> module =
2414 AddObjectWithID(id, module);
2415 return module;
2416}
2417
2418MaybeDirectHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
2419 uint32_t id = next_id_++;
2420
2421 int32_t maximum_pages;
2422 if (!ReadZigZag<int32_t>().To(&maximum_pages)) return {};
2423 uint8_t memory64_byte;
2424 if (!ReadByte(&memory64_byte)) return {};
2425 if (memory64_byte > 1) return {};
2426 wasm::AddressType address_type =
2428
2429 DirectHandle<Object> buffer_object;
2430 if (!ReadObject().ToHandle(&buffer_object)) return {};
2431 if (!IsJSArrayBuffer(*buffer_object)) return {};
2432
2433 DirectHandle<JSArrayBuffer> buffer = Cast<JSArrayBuffer>(buffer_object);
2434 if (!buffer->is_shared()) return {};
2435
2436 DirectHandle<WasmMemoryObject> result =
2437 WasmMemoryObject::New(isolate_, buffer, maximum_pages, address_type);
2438
2440 return result;
2441}
2442#endif // V8_ENABLE_WEBASSEMBLY
2443
2444namespace {
2445
2446// Throws a generic "deserialization failed" exception by default, unless a more
2447// specific exception has already been thrown.
2448void ThrowDeserializationExceptionIfNonePending(Isolate* isolate) {
2449 if (!isolate->has_exception()) {
2450 isolate->Throw(*isolate->factory()->NewError(
2451 MessageTemplate::kDataCloneDeserializationError));
2452 }
2453 DCHECK(isolate->has_exception());
2454}
2455
2456} // namespace
2457
2460 DCHECK_GE(version_, 15);
2461
2462 uint32_t shared_object_id;
2463 if (!ReadVarint<uint32_t>().To(&shared_object_id)) {
2466 }
2467
2468 if (!delegate_) {
2469 ThrowDeserializationExceptionIfNonePending(isolate_);
2471 }
2472
2473 if (shared_object_conveyor_ == nullptr) {
2475 reinterpret_cast<v8::Isolate*>(isolate_));
2476 if (!conveyor) {
2479 }
2480 shared_object_conveyor_ = conveyor->private_.get();
2481 }
2482
2483 DirectHandle<HeapObject> shared_object(
2484 shared_object_conveyor_->GetPersisted(shared_object_id), isolate_);
2485 DCHECK(IsShared(*shared_object));
2486 return shared_object;
2487}
2488
2492 uint32_t id = next_id_++;
2493 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
2494 v8::Local<v8::Object> object;
2495 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
2498 }
2499 DirectHandle<JSObject> js_object =
2501 AddObjectWithID(id, js_object);
2502 return js_object;
2503}
2504
2505// Copies a vector of property values into an object, given the map that should
2506// be used.
2509 base::Vector<const DirectHandle<Object>> properties) {
2511 DCHECK(!object->map()->is_dictionary_map());
2512
2514 Tagged<DescriptorArray> descriptors = object->map()->instance_descriptors();
2515 for (InternalIndex i : InternalIndex::Range(properties.size())) {
2516 // Initializing store.
2517 object->WriteToField(i, descriptors->GetDetails(i),
2518 *properties[i.raw_value()]);
2519 }
2520}
2521
2522static bool IsValidObjectKey(Tagged<Object> value, Isolate* isolate) {
2523 if (IsSmi(value)) return true;
2524 auto instance_type = Cast<HeapObject>(value)->map(isolate)->instance_type();
2525 return InstanceTypeChecker::IsName(instance_type) ||
2526 InstanceTypeChecker::IsHeapNumber(instance_type);
2527}
2528
2531 bool can_use_transitions) {
2532 uint32_t num_properties = 0;
2533
2534 // Fast path (following map transitions).
2535 if (can_use_transitions) {
2536 bool transitioning = true;
2537 DirectHandle<Map> map(object->map(), isolate_);
2538 DCHECK(!map->is_dictionary_map());
2539 DCHECK_EQ(0, map->instance_descriptors(isolate_)->number_of_descriptors());
2541 properties.reserve(8);
2542
2543 while (transitioning) {
2544 // If there are no more properties, finish.
2545 SerializationTag tag;
2546 if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
2547 if (tag == end_tag) {
2548 ConsumeTag(end_tag);
2549 CommitProperties(object, map, base::VectorOf(properties));
2550 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
2551 return Just(static_cast<uint32_t>(properties.size()));
2552 }
2553
2554 // Determine the key to be used and the target map to transition to, if
2555 // possible. Transitioning may abort if the key is not a string, or if no
2556 // transition was found.
2559 bool transition_was_found = false;
2560 const uint8_t* start_position = position_;
2561 uint32_t byte_length;
2562 if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length)) {
2563 return Nothing<uint32_t>();
2564 }
2565 // Length is also checked in ReadRawBytes.
2566#ifdef V8_VALUE_DESERIALIZER_HARD_FAIL
2567 CHECK_LE(byte_length,
2568 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
2569#endif // V8_VALUE_DESERIALIZER_HARD_FAIL
2570 std::pair<DirectHandle<String>, DirectHandle<Map>> expected_transition;
2571 {
2572 TransitionsAccessor transitions(isolate_, *map);
2575 if (ReadRawBytes(byte_length).To(&key_chars)) {
2576 expected_transition = transitions.ExpectedTransition(key_chars);
2577 }
2578 } else if (tag == SerializationTag::kTwoByteString) {
2580 if (ReadRawTwoBytes(byte_length).To(&key_chars)) {
2581 expected_transition = transitions.ExpectedTransition(key_chars);
2582 }
2583 } else if (tag == SerializationTag::kUtf8String) {
2585 if (ReadRawBytes(byte_length).To(&key_chars) &&
2586 String::IsAscii(key_chars.begin(), key_chars.length())) {
2587 expected_transition = transitions.ExpectedTransition(key_chars);
2588 }
2589 }
2590 if (!expected_transition.first.is_null()) {
2591 transition_was_found = true;
2592 key = expected_transition.first;
2593 target = expected_transition.second;
2594 }
2595 }
2596 if (!transition_was_found) {
2597 position_ = start_position;
2598 if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(*key, isolate_)) {
2599 return Nothing<uint32_t>();
2600 }
2601 if (IsString(*key, isolate_)) {
2603 // Don't reuse |transitions| because it could be stale.
2604 transitioning = TransitionsAccessor(isolate_, *map)
2606 .ToHandle(&target);
2607 } else {
2608 transitioning = false;
2609 }
2610 }
2611
2612 // Read the value that corresponds to it.
2614 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
2615
2616 // If still transitioning and the value fits the field representation
2617 // (though generalization may be required), store the property value so
2618 // that we can copy them all at once. Otherwise, stop transitioning.
2619 if (transitioning) {
2620 // Deserializaton of |value| might have deprecated current |target|,
2621 // ensure we are working with the up-to-date version.
2622 target = Map::Update(isolate_, target);
2623 if (!target->is_dictionary_map()) {
2624 InternalIndex descriptor(properties.size());
2625 PropertyDetails details =
2626 target->instance_descriptors(isolate_)->GetDetails(descriptor);
2627 Representation expected_representation = details.representation();
2628 if (Object::FitsRepresentation(*value, expected_representation)) {
2629 if (expected_representation.IsHeapObject() &&
2631 target->instance_descriptors(isolate_)->GetFieldType(
2632 descriptor),
2633 value)) {
2635 *value, isolate_, expected_representation);
2636 MapUpdater::GeneralizeField(isolate_, target, descriptor,
2637 details.constness(),
2638 expected_representation, value_type);
2639 }
2641 target->instance_descriptors(isolate_)->GetFieldType(
2642 descriptor),
2643 value));
2644 properties.push_back(value);
2645 map = target;
2646 continue;
2647 }
2648 }
2649 transitioning = false;
2650 }
2651
2652 // Fell out of transitioning fast path. Commit the properties gathered so
2653 // far, and then start setting properties slowly instead.
2654 DCHECK(!transitioning);
2655 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
2656 CHECK(!map->is_dictionary_map());
2657 CommitProperties(object, map, base::VectorOf(properties));
2658 num_properties = static_cast<uint32_t>(properties.size());
2659
2660 // We checked earlier that IsValidObjectKey(key).
2661 PropertyKey lookup_key(isolate_, key);
2662 LookupIterator it(isolate_, object, lookup_key, LookupIterator::OWN);
2663 if (it.state() != LookupIterator::NOT_FOUND ||
2665 .is_null()) {
2666 return Nothing<uint32_t>();
2667 }
2668 num_properties++;
2669 }
2670
2671 // At this point, transitioning should be done, but at least one property
2672 // should have been written (in the zero-property case, there is an early
2673 // return).
2674 DCHECK(!transitioning);
2675 DCHECK_GE(num_properties, 1u);
2676 }
2677
2678 // Slow path.
2679 for (;; num_properties++) {
2680 SerializationTag tag;
2681 if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
2682 if (tag == end_tag) {
2683 ConsumeTag(end_tag);
2684 return Just(num_properties);
2685 }
2686
2688 if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(*key, isolate_)) {
2689 return Nothing<uint32_t>();
2690 }
2692 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
2693
2694 // We checked earlier that IsValidObjectKey(key).
2695 PropertyKey lookup_key(isolate_, key);
2696 LookupIterator it(isolate_, object, lookup_key, LookupIterator::OWN);
2697 if (it.state() != LookupIterator::NOT_FOUND ||
2699 .is_null()) {
2700 return Nothing<uint32_t>();
2701 }
2702 }
2703}
2704
2706 return id < static_cast<unsigned>(id_map_->length()) &&
2707 !IsTheHole(id_map_->get(id), isolate_);
2708}
2709
2711 if (id >= static_cast<unsigned>(id_map_->length())) {
2713 }
2714 Tagged<Object> value = id_map_->get(id);
2715 if (IsTheHole(value, isolate_)) return MaybeDirectHandle<JSReceiver>();
2716 DCHECK(IsJSReceiver(value));
2718}
2719
2721 DirectHandle<JSReceiver> object) {
2722 DCHECK(!HasObjectWithID(id));
2723 DirectHandle<FixedArray> new_array =
2725
2726 // If the dictionary was reallocated, update the global handle.
2727 if (!new_array.is_identical_to(id_map_)) {
2728 GlobalHandles::Destroy(id_map_.location());
2729 id_map_ = isolate_->global_handles()->Create(*new_array);
2730 }
2731}
2732
2736 uint32_t num_properties) {
2737 for (unsigned i = 0; i < 2 * num_properties; i += 2) {
2738 DirectHandle<Object> key = data[i];
2739 if (!IsValidObjectKey(*key, isolate)) return Nothing<bool>();
2740 DirectHandle<Object> value = data[i + 1];
2741 PropertyKey lookup_key(isolate, key);
2742 LookupIterator it(isolate, object, lookup_key, LookupIterator::OWN);
2743 if (it.state() != LookupIterator::NOT_FOUND ||
2745 .is_null()) {
2746 return Nothing<bool>();
2747 }
2748 }
2749 return Just(true);
2750}
2751
2752MaybeDirectHandle<Object>
2754 DCHECK_EQ(version_, 0u);
2755 HandleScope scope(isolate_);
2757 while (position_ < end_) {
2758 SerializationTag tag;
2759 if (!PeekTag().To(&tag)) break;
2760
2761 DirectHandle<Object> new_object;
2762 switch (tag) {
2765
2766 // JS Object: Read the last 2*n values from the stack and use them as
2767 // key-value pairs.
2768 uint32_t num_properties;
2769 if (!ReadVarint<uint32_t>().To(&num_properties) ||
2770 stack.size() / 2 < num_properties) {
2772 MessageTemplate::kDataCloneDeserializationError));
2774 }
2775
2776 size_t begin_properties =
2777 stack.size() - 2 * static_cast<size_t>(num_properties);
2778 DirectHandle<JSObject> js_object =
2779 isolate_->factory()->NewJSObject(isolate_->object_function());
2780 if (num_properties &&
2782 isolate_, js_object, &stack[begin_properties], num_properties)
2783 .FromMaybe(false)) {
2784 ThrowDeserializationExceptionIfNonePending(isolate_);
2786 }
2787
2788 stack.resize(begin_properties);
2789 new_object = js_object;
2790 break;
2791 }
2794
2795 // Sparse JS Array: Read the last 2*|num_properties| from the stack.
2796 uint32_t num_properties;
2797 uint32_t length;
2798 if (!ReadVarint<uint32_t>().To(&num_properties) ||
2799 !ReadVarint<uint32_t>().To(&length) ||
2800 stack.size() / 2 < num_properties) {
2802 MessageTemplate::kDataCloneDeserializationError));
2804 }
2805
2806 DirectHandle<JSArray> js_array =
2808 MAYBE_RETURN_NULL(JSArray::SetLength(js_array, length));
2809 size_t begin_properties =
2810 stack.size() - 2 * static_cast<size_t>(num_properties);
2811 if (num_properties &&
2813 isolate_, js_array, &stack[begin_properties], num_properties)
2814 .FromMaybe(false)) {
2815 ThrowDeserializationExceptionIfNonePending(isolate_);
2817 }
2818
2819 stack.resize(begin_properties);
2820 new_object = js_array;
2821 break;
2822 }
2824 // This was already broken in Chromium, and apparently wasn't missed.
2826 MessageTemplate::kDataCloneDeserializationError));
2828 }
2829 default:
2830 if (!ReadObject().ToHandle(&new_object))
2832 break;
2833 }
2834 stack.push_back(new_object);
2835 }
2836
2837// Nothing remains but padding.
2838#ifdef DEBUG
2839 while (position_ < end_) {
2840 DCHECK(*position_++ == static_cast<uint8_t>(SerializationTag::kPadding));
2841 }
2842#endif
2843 position_ = end_;
2844
2845 if (stack.size() != 1) {
2847 MessageTemplate::kDataCloneDeserializationError));
2849 }
2850 return scope.CloseAndEscape(stack[0]);
2851}
2852
2853} // namespace internal
2854} // namespace v8
Isolate * isolate_
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype)
#define T
V8_WARN_UNUSED_RESULT V8_INLINE bool To(T *out) const
Definition v8-maybe.h:55
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
V8_INLINE T ToChecked() const
Definition v8-maybe.h:41
V8_INLINE bool IsNothing() const
Definition v8-maybe.h:35
std::unique_ptr< internal::SharedObjectConveyorHandles > private_
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
virtual MaybeLocal< Object > ReadHostObject(Isolate *isolate)
Definition api.cc:3346
virtual const SharedValueConveyor * GetSharedValueConveyor(Isolate *isolate)
Definition api.cc:3374
virtual Maybe< uint32_t > GetWasmModuleTransferId(Isolate *isolate, Local< WasmModuleObject > module)
Definition api.cc:3262
virtual void ThrowDataCloneError(Local< String > message)=0
virtual bool AdoptSharedValueConveyor(Isolate *isolate, SharedValueConveyor &&conveyor)
Definition api.cc:3267
virtual Maybe< bool > IsHostObject(Isolate *isolate, Local< Object > object)
Definition api.cc:3245
virtual void FreeBufferMemory(void *buffer)
Definition api.cc:3283
virtual Maybe< bool > WriteHostObject(Isolate *isolate, Local< Object > object)
Definition api.cc:3231
virtual Maybe< uint32_t > GetSharedArrayBufferId(Isolate *isolate, Local< SharedArrayBuffer > shared_array_buffer)
Definition api.cc:3253
virtual bool HasCustomHostObject(Isolate *isolate)
Definition api.cc:3241
virtual void * ReallocateBufferMemory(void *old_buffer, size_t size, size_t *actual_size)
Definition api.cc:3276
int length() const
Definition vector.h:64
constexpr T * begin() const
Definition vector.h:96
static size_t DigitsByteLengthForBitfield(uint32_t bitfield)
Definition bigint.cc:1226
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< BigInt > FromSerializedDigits(Isolate *isolate, uint32_t bitfield, base::Vector< const uint8_t > digits_storage)
Definition bigint.cc:1251
V8_INLINE bool is_identical_to(Handle< S > other) const
Definition handles.h:716
static void SetFormattedStack(Isolate *isolate, DirectHandle< JSObject > maybe_error_object, DirectHandle< Object > formatted_stack)
Definition messages.cc:1192
static MaybeDirectHandle< JSObject > Construct(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< Object > new_target, DirectHandle< Object > message, DirectHandle< Object > options)
Definition messages.cc:528
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
MaybeHandle< String > NewStringFromOneByte(base::Vector< const uint8_t > string, AllocationType allocation=AllocationType::kYoung)
Handle< Number > NewNumberFromInt(int32_t value)
Handle< Number > NewNumberFromUint(uint32_t value)
V8_WARN_UNUSED_RESULT MaybeHandle< SeqTwoByteString > NewRawTwoByteString(int length, AllocationType allocation=AllocationType::kYoung)
Handle< Number > NewNumber(double value)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< JSArray > NewJSArray(ElementsKind elements_kind, int length, int capacity, ArrayStorageAllocationMode mode=ArrayStorageAllocationMode::DONT_INITIALIZE_ARRAY_ELEMENTS, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3211
Handle< JSTypedArray > NewJSTypedArray(ExternalArrayType type, DirectHandle< JSArrayBuffer > buffer, size_t byte_offset, size_t length, bool is_length_tracking=false)
Definition factory.cc:3656
MaybeHandle< JSArrayBuffer > NewJSArrayBufferAndBackingStore(size_t byte_length, InitializedFlag initialized, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3508
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:2985
V8_WARN_UNUSED_RESULT MaybeHandle< String > NewStringFromUtf8(base::Vector< const char > str, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:753
DirectHandle< JSSet > NewJSSet()
Definition factory.cc:3603
Handle< JSDataViewOrRabGsabDataView > NewJSDataViewOrRabGsabDataView(DirectHandle< JSArrayBuffer > buffer, size_t byte_offset, size_t byte_length, bool is_length_tracking=false)
Definition factory.cc:3700
DirectHandle< JSMap > NewJSMap()
Definition factory.cc:3596
Handle< String > InternalizeString(base::Vector< const char > str, bool convert_encoding=false)
Definition factory.h:216
Handle< JSObject > NewError(DirectHandle< JSFunction > constructor, DirectHandle< String > message, DirectHandle< Object > options={})
Definition factory.cc:2799
static FieldIndex ForDetails(Tagged< Map > map, PropertyDetails details)
static bool NowContains(Tagged< FieldType > type, Tagged< Object > value)
static constexpr int kMaxLength
static V8_EXPORT_PRIVATE HandleType< FixedArray > SetAndGrow(Isolate *isolate, HandleType< FixedArray > array, int index, DirectHandle< Object > value)
static void Register(std::shared_ptr< BackingStore > backing_store)
static void Destroy(Address *location)
IndirectHandle< Object > Create(Tagged< Object > value)
V8_INLINE Address * location() const
Definition handles.h:80
HandleType< T > CloseAndEscape(HandleType< T > handle_value)
GlobalHandles * global_handles() const
Definition isolate.h:1416
Tagged< Object > Throw(Tagged< Object > exception, MessageLocation *location=nullptr)
Definition isolate.cc:2091
bool has_shared_space() const
Definition isolate.h:2303
v8::internal::Factory * factory()
Definition isolate.h:1527
static V8_EXPORT_PRIVATE Maybe< bool > SetLength(DirectHandle< JSArray > array, uint32_t length)
Definition objects.cc:4812
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSDate > New(DirectHandle< JSFunction > constructor, DirectHandle< JSReceiver > new_target, double tv)
static V8_WARN_UNUSED_RESULT HandleType< Object >::MaybeType DefineOwnPropertyIgnoreAttributes(LookupIterator *it, HandleType< T > value, PropertyAttributes attributes, AccessorInfoHandling handling=DONT_FORCE_FIELD, EnforceDefineSemantics semantics=EnforceDefineSemantics::kSet)
int GetEmbedderFieldCount() const
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > V8_EXPORT_PRIVATE SetOwnPropertyIgnoreAttributes(DirectHandle< JSObject > object, DirectHandle< Name > name, DirectHandle< Object > value, PropertyAttributes attributes)
static void AllocateStorageForMap(DirectHandle< JSObject > object, DirectHandle< Map > map)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > GetOwnPropertyDescriptor(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Object > key, PropertyDescriptor *desc)
static V8_EXPORT_PRIVATE MaybeDirectHandle< JSRegExp > New(Isolate *isolate, DirectHandle< String > source, Flags flags, uint32_t backtrack_limit=kNoBacktrackLimit)
Definition js-regexp.cc:152
static MaybeHandle< FixedArray > GetKeys(Isolate *isolate, DirectHandle< JSReceiver > object, KeyCollectionMode mode, PropertyFilter filter, GetKeysConversion keys_conversion=GetKeysConversion::kKeepNumbers, bool is_for_in=false, bool skip_indices=false)
Definition keys.cc:97
static void GeneralizeField(Isolate *isolate, DirectHandle< Map > map, InternalIndex modify_index, PropertyConstness new_constness, Representation new_representation, DirectHandle< FieldType > new_field_type)
static V8_EXPORT_PRIVATE DirectHandle< Map > Update(Isolate *isolate, DirectHandle< Map > map)
Definition map.cc:839
static DirectHandle< String > Format(Isolate *isolate, MessageTemplate index, base::Vector< const DirectHandle< Object > > args)
Definition messages.cc:396
static bool ToArrayLength(Tagged< Object > obj, uint32_t *index)
static V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType ToString(Isolate *isolate, HandleType< T > input)
static DirectHandle< FieldType > OptimalType(Tagged< Object > obj, Isolate *isolate, Representation representation)
Definition objects.cc:224
static double NumberValue(Tagged< Number > obj)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it, bool is_global_reference=false)
Definition objects.cc:1248
static bool FitsRepresentation(Tagged< Object > obj, Representation representation, bool allow_coercion=true)
static constexpr uint8_t kNull
Definition oddball.h:56
static constexpr uint8_t kUndefined
Definition oddball.h:57
static constexpr uint8_t kFalse
Definition oddball.h:53
static constexpr uint8_t kTrue
Definition oddball.h:54
static bool IsDataDescriptor(PropertyDescriptor *desc)
PropertyLocation location() const
Representation representation() const
PropertyConstness constness() const
static V8_EXPORT_PRIVATE bool VerifyFlags(RegExpFlags flags)
Definition regexp.cc:117
constexpr bool IsHeapObject() const
uint32_t Persist(Tagged< HeapObject > shared_object)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Handle< SimpleNumberDictionary > Set(Isolate *isolate, Handle< SimpleNumberDictionary > dictionary, uint32_t key, DirectHandle< Object > value)
Definition objects.cc:5852
base::Vector< const uint8_t > ToOneByteVector() const
Definition string.h:139
base::Vector< const base::uc16 > ToUC16Vector() const
Definition string.h:145
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
static bool IsAscii(const char *chars, uint32_t length)
Definition string.h:575
MaybeHandle< Map > FindTransitionToField(DirectHandle< String > name)
MaybeDirectHandle< JSReceiver > GetObjectWithID(uint32_t id)
bool ReadByte(uint8_t *value) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< String > ReadString() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSArrayBuffer > ReadJSArrayBuffer(bool is_shared, bool is_resizable) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSRegExp > ReadJSRegExp() V8_WARN_UNUSED_RESULT
Maybe< double > ReadDouble() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSArray > ReadDenseJSArray() V8_WARN_UNUSED_RESULT
const SharedObjectConveyorHandles * shared_object_conveyor_
MaybeDirectHandle< JSArrayBuffer > ReadTransferredJSArrayBuffer() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< Object > ReadObject() V8_WARN_UNUSED_RESULT
MaybeIndirectHandle< SimpleNumberDictionary > array_buffer_transfer_map_
Maybe< bool > ReadHeader() V8_WARN_UNUSED_RESULT
bool ValidateJSArrayBufferViewFlags(Tagged< JSArrayBuffer > buffer, uint32_t serialized_flags, bool &is_length_tracking, bool &is_backed_by_rab) V8_WARN_UNUSED_RESULT
bool ReadUint64(uint64_t *value) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< Object > ReadObjectUsingEntireBufferForLegacyFormat() V8_WARN_UNUSED_RESULT
V8_NOINLINE Maybe< T > ReadVarintLoop() V8_WARN_UNUSED_RESULT
void ConsumeTag(SerializationTag peeked_tag)
MaybeDirectHandle< JSDate > ReadJSDate() V8_WARN_UNUSED_RESULT
Maybe< base::Vector< const base::uc16 > > ReadRawTwoBytes(size_t size) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< BigInt > ReadBigInt() V8_WARN_UNUSED_RESULT
bool ReadRawBytes(size_t length, const void **data) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSArrayBufferView > ReadJSArrayBufferView(DirectHandle< JSArrayBuffer > buffer) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSArray > ReadSparseJSArray() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< Object > ReadObjectWrapper() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< Object > ReadJSError() V8_WARN_UNUSED_RESULT
bool ReadUint32(uint32_t *value) V8_WARN_UNUSED_RESULT
v8::ValueDeserializer::Delegate *const delegate_
void TransferArrayBuffer(uint32_t transfer_id, DirectHandle< JSArrayBuffer > array_buffer)
MaybeDirectHandle< String > ReadOneByteString(AllocationType allocation=AllocationType::kYoung) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< HeapObject > ReadSharedObject() V8_WARN_UNUSED_RESULT
void AddObjectWithID(uint32_t id, DirectHandle< JSReceiver > object)
Maybe< SerializationTag > ReadTag() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSMap > ReadJSMap() V8_WARN_UNUSED_RESULT
IndirectHandle< FixedArray > id_map_
MaybeDirectHandle< JSPrimitiveWrapper > ReadJSPrimitiveWrapper(SerializationTag tag) V8_WARN_UNUSED_RESULT
Maybe< T > ReadZigZag() V8_WARN_UNUSED_RESULT
Maybe< uint32_t > ReadJSObjectProperties(DirectHandle< JSObject > object, SerializationTag end_tag, bool can_use_transitions)
MaybeDirectHandle< JSObject > ReadJSObject() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< String > ReadUtf8String(AllocationType allocation=AllocationType::kYoung) V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSObject > ReadHostObject() V8_WARN_UNUSED_RESULT
MaybeDirectHandle< Object > ReadObjectInternal() V8_WARN_UNUSED_RESULT
Maybe< SerializationTag > PeekTag() const V8_WARN_UNUSED_RESULT
MaybeDirectHandle< JSSet > ReadJSSet() V8_WARN_UNUSED_RESULT
ValueDeserializer(Isolate *isolate, base::Vector< const uint8_t > data, v8::ValueDeserializer::Delegate *delegate)
MaybeDirectHandle< String > ReadTwoByteString(AllocationType allocation=AllocationType::kYoung) V8_WARN_UNUSED_RESULT
V8_INLINE Maybe< T > ReadVarint() V8_WARN_UNUSED_RESULT
void WriteTag(SerializationTag tag)
Maybe< uint32_t > WriteJSObjectPropertiesSlow(DirectHandle< JSObject > object, DirectHandle< FixedArray > keys) V8_WARN_UNUSED_RESULT
Maybe< bool > WriteJSArray(DirectHandle< JSArray > array) V8_WARN_UNUSED_RESULT
Maybe< bool > ExpandBuffer(size_t required_capacity)
Maybe< bool > WriteSharedObject(DirectHandle< HeapObject > object) V8_WARN_UNUSED_RESULT
void WriteOddball(Tagged< Oddball > oddball)
Maybe< bool > WriteJSError(DirectHandle< JSObject > error) V8_WARN_UNUSED_RESULT
void WriteTwoByteString(base::Vector< const base::uc16 > chars)
Maybe< bool > WriteJSMap(DirectHandle< JSMap > map) V8_WARN_UNUSED_RESULT
void WriteHeapNumber(Tagged< HeapNumber > number)
void SetTreatArrayBufferViewsAsHostObjects(bool mode)
ValueSerializer(Isolate *isolate, v8::ValueSerializer::Delegate *delegate)
void WriteJSRegExp(DirectHandle< JSRegExp > regexp)
void WriteString(DirectHandle< String > string)
void WriteOneByteString(base::Vector< const uint8_t > chars)
Maybe< bool > WriteJSSharedStruct(DirectHandle< JSSharedStruct > shared_struct) V8_WARN_UNUSED_RESULT
Maybe< bool > WriteHostObject(DirectHandle< JSObject > object) V8_WARN_UNUSED_RESULT
Maybe< bool > WriteJSSet(DirectHandle< JSSet > map) V8_WARN_UNUSED_RESULT
v8::ValueSerializer::Delegate *const delegate_
V8_NOINLINE Maybe< bool > ThrowDataCloneError(MessageTemplate template_index) V8_WARN_UNUSED_RESULT
void WriteJSDate(Tagged< JSDate > date)
void WriteSmi(Tagged< Smi > smi)
Maybe< bool > WriteJSArrayBufferView(Tagged< JSArrayBufferView > array_buffer)
IdentityMap< uint32_t, ZoneAllocationPolicy > array_buffer_transfer_map_
Maybe< bool > WriteJSArrayBuffer(DirectHandle< JSArrayBuffer > array_buffer) V8_WARN_UNUSED_RESULT
void WriteRawBytes(const void *source, size_t length)
void WriteBigIntContents(Tagged< BigInt > bigint)
Maybe< bool > WriteJSObjectSlow(DirectHandle< JSObject > object) V8_WARN_UNUSED_RESULT
IdentityMap< uint32_t, ZoneAllocationPolicy > id_map_
void TransferArrayBuffer(uint32_t transfer_id, DirectHandle< JSArrayBuffer > array_buffer)
Maybe< bool > WriteJSObject(DirectHandle< JSObject > object) V8_WARN_UNUSED_RESULT
Maybe< bool > WriteJSReceiver(DirectHandle< JSReceiver > receiver) V8_WARN_UNUSED_RESULT
void WriteBigInt(Tagged< BigInt > bigint)
Maybe< bool > WriteJSPrimitiveWrapper(DirectHandle< JSPrimitiveWrapper > value) V8_WARN_UNUSED_RESULT
Maybe< bool > WriteObject(DirectHandle< Object > object) V8_WARN_UNUSED_RESULT
Maybe< bool > IsHostObject(DirectHandle< JSObject > object)
Maybe< uint8_t * > ReserveRawBytes(size_t bytes)
SharedObjectConveyorHandles * shared_object_conveyor_
Maybe< bool > WriteJSSharedArray(DirectHandle< JSSharedArray > shared_array) V8_WARN_UNUSED_RESULT
void WriteDouble(double value)
std::pair< uint8_t *, size_t > Release()
static V8_EXPORT_PRIVATE DirectHandle< WasmMemoryObject > New(Isolate *isolate, DirectHandle< JSArrayBuffer > buffer, int maximum, wasm::AddressType address_type)
Zone * zone_
const v8::base::TimeTicks end_
Definition sweeper.cc:54
int start
int end
const int position_
#define TYPED_ARRAYS(V)
#define TYPED_ARRAYS_BASE(V)
#define RETURN_VALUE_IF_EXCEPTION(isolate, value)
Definition isolate.h:224
#define RETURN_EXCEPTION_IF_EXCEPTION(isolate)
Definition isolate.h:235
#define STACK_CHECK(isolate, result_value)
Definition isolate.h:3067
#define MAYBE_RETURN_NULL(call)
Definition isolate.h:413
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
#define EXPORT_TEMPLATE_DEFINE(export)
TNode< Object > target
TNode< Object > receiver
std::map< const std::string, const std::string > map
std::string pattern
DateRecord date
ZoneVector< RpoNumber > & result
ZoneStack< RpoNumber > & stack
ZoneVector< Entry > entries
void * Realloc(void *memory, size_t size)
Definition memory.h:48
uint16_t uc16
Definition strings.h:18
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
Vector< const char > CStrVector(const char *data)
Definition vector.h:331
void Free(void *memory)
Definition memory.h:63
static void CommitProperties(DirectHandle< JSObject > object, DirectHandle< Map > map, base::Vector< const DirectHandle< Object > > properties)
static constexpr uint32_t kFalse
bool IsNumber(Tagged< Object > obj)
bool IsSpecialReceiverInstanceType(InstanceType instance_type)
bool IsCustomElementsReceiverMap(Tagged< Map > map)
static size_t BytesNeededForVarint(T value)
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
@ TERMINAL_FAST_ELEMENTS_KIND
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
bool IsShared(Tagged< Object > obj)
DONT_OVERRIDE DISABLE_ALLOCATION_SITES HOLEY_ELEMENTS
const int kSmiValueSize
V8_INLINE constexpr bool IsHeapObject(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:669
V8_EXPORT_PRIVATE FlagValues v8_flags
@ kExternalInt8Array
Definition globals.h:2453
@ kExternalFloat16Array
Definition globals.h:2459
return value
Definition map-inl.h:893
static Maybe< bool > SetPropertiesFromKeyValuePairs(Isolate *isolate, DirectHandle< JSObject > object, DirectHandle< Object > *data, uint32_t num_properties)
static bool IsValidObjectKey(Tagged< Object > value, Isolate *isolate)
JSArrayBuffer::IsDetachableBit is_shared
static const uint32_t kLatestVersion
template const char * string
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Maybe< T > Nothing()
Definition v8-maybe.h:112
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
constexpr uint32_t CurrentValueSerializerFormatVersion()
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define CHECK_LT(lhs, rhs)
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define READ_NEXT_ERROR_TAG()
#define EXIT_DCHECK()
#define ITERATION_SHIFTED(shift)
wasm::ValueType type
#define ZONE_NAME
Definition zone.h:22