in src/bun.js/bindings/webcore/SerializedScriptValue.cpp [4474:4930]
JSValue readTerminal()
{
SerializationTag tag = readTag();
// if (!isTypeExposedToGlobalObject(*m_globalObject, tag))
// return JSValue();
// read bun types
if (auto value = StructuredCloneableDeserialize::fromTagDeserialize(tag, m_lexicalGlobalObject, m_ptr, m_end)) {
JSValue deserialized = JSValue::decode(value.value());
if (deserialized.isEmpty()) {
fail();
return JSValue();
}
return deserialized;
}
switch (tag) {
case UndefinedTag:
return jsUndefined();
case NullTag:
return jsNull();
case IntTag: {
int32_t i;
if (!read(i))
return JSValue();
return jsNumber(i);
}
case ZeroTag:
return jsNumber(0);
case OneTag:
return jsNumber(1);
case FalseTag:
return jsBoolean(false);
case TrueTag:
return jsBoolean(true);
case FalseObjectTag: {
BooleanObject* obj = BooleanObject::create(m_lexicalGlobalObject->vm(), m_globalObject->booleanObjectStructure());
obj->setInternalValue(m_lexicalGlobalObject->vm(), jsBoolean(false));
m_gcBuffer.appendWithCrashOnOverflow(obj);
return obj;
}
case TrueObjectTag: {
BooleanObject* obj = BooleanObject::create(m_lexicalGlobalObject->vm(), m_globalObject->booleanObjectStructure());
obj->setInternalValue(m_lexicalGlobalObject->vm(), jsBoolean(true));
m_gcBuffer.appendWithCrashOnOverflow(obj);
return obj;
}
case DoubleTag: {
double d;
if (!read(d))
return JSValue();
return jsNumber(purifyNaN(d));
}
case BigIntTag:
return readBigInt();
case NumberObjectTag: {
double d;
if (!read(d))
return JSValue();
NumberObject* obj = constructNumber(m_globalObject, jsNumber(purifyNaN(d)));
m_gcBuffer.appendWithCrashOnOverflow(obj);
return obj;
}
case BigIntObjectTag: {
JSValue bigInt = readBigInt();
if (!bigInt)
return JSValue();
ASSERT(bigInt.isBigInt());
BigIntObject* obj = BigIntObject::create(m_lexicalGlobalObject->vm(), m_globalObject, bigInt);
m_gcBuffer.appendWithCrashOnOverflow(obj);
return obj;
}
case DateTag: {
double d;
if (!read(d))
return JSValue();
return DateInstance::create(m_lexicalGlobalObject->vm(), m_globalObject->dateStructure(), d);
}
// case FileTag: {
// RefPtr<File> file;
// if (!readFile(file))
// return JSValue();
// if (!m_canCreateDOMObject)
// return jsNull();
// return toJS(m_lexicalGlobalObject, jsCast<JSDOMGlobalObject*>(m_globalObject), file.get());
// }
// case FileListTag: {
// unsigned length = 0;
// if (!read(length))
// return JSValue();
// ASSERT(m_globalObject->inherits<JSDOMGlobalObject>());
// Vector<Ref<File>> files;
// for (unsigned i = 0; i < length; i++) {
// RefPtr<File> file;
// if (!readFile(file))
// return JSValue();
// if (m_canCreateDOMObject)
// files.append(file.releaseNonNull());
// }
// if (!m_canCreateDOMObject)
// return jsNull();
// return getJSValue(FileList::create(WTFMove(files)).get());
// }
// case ImageDataTag: {
// uint32_t width;
// if (!read(width))
// return JSValue();
// if (width == ImageDataPoolTag) {
// auto index = readImageDataIndex();
// if (!index || *index >= m_imageDataPool.size()) {
// fail();
// return JSValue();
// }
// return getJSValue(m_imageDataPool[*index]);
// }
// uint32_t height;
// if (!read(height))
// return JSValue();
// uint32_t length;
// if (!read(length))
// return JSValue();
// if (static_cast<uint32_t>(m_end - m_ptr) < length) {
// fail();
// return JSValue();
// }
// auto bufferStart = m_ptr;
// m_ptr += length;
// auto resultColorSpace = PredefinedColorSpace::SRGB;
// if (m_version > 7) {
// if (!read(resultColorSpace))
// return JSValue();
// }
// if (length && (IntSize(width, height).area() * 4) != length) {
// fail();
// return JSValue();
// }
// if (!m_isDOMGlobalObject)
// return jsNull();
// auto result = ImageData::createUninitialized(width, height, resultColorSpace);
// if (result.hasException()) {
// fail();
// return JSValue();
// }
// if (length)
// memcpy(result.returnValue()->data().data(), bufferStart, length);
// else
// result.returnValue()->data().zeroFill();
// m_imageDataPool.append(result.returnValue().copyRef());
// return getJSValue(result.releaseReturnValue());
// }
// case BlobTag: {
// CachedStringRef url;
// if (!readStringData(url))
// return JSValue();
// CachedStringRef type;
// if (!readStringData(type))
// return JSValue();
// uint64_t size = 0;
// if (!read(size))
// return JSValue();
// uint64_t memoryCost = 0;
// if (m_version >= 11 && !read(memoryCost))
// return JSValue();
// if (!m_canCreateDOMObject)
// return jsNull();
// return getJSValue(Blob::deserialize(executionContext(m_lexicalGlobalObject), URL { url->string() }, type->string(), size, memoryCost, blobFilePathForBlobURL(url->string())).get());
// }
case StringTag: {
CachedStringRef cachedString;
if (!readStringData(cachedString))
return JSValue();
return cachedString->jsString(m_lexicalGlobalObject);
}
case EmptyStringTag:
return jsEmptyString(m_lexicalGlobalObject->vm());
case StringObjectTag: {
CachedStringRef cachedString;
if (!readStringData(cachedString))
return JSValue();
StringObject* obj = constructString(m_lexicalGlobalObject->vm(), m_globalObject, cachedString->jsString(m_lexicalGlobalObject));
m_gcBuffer.appendWithCrashOnOverflow(obj);
return obj;
}
case EmptyStringObjectTag: {
VM& vm = m_lexicalGlobalObject->vm();
StringObject* obj = constructString(vm, m_globalObject, jsEmptyString(vm));
m_gcBuffer.appendWithCrashOnOverflow(obj);
return obj;
}
case RegExpTag: {
CachedStringRef pattern;
if (!readStringData(pattern))
return JSValue();
CachedStringRef flags;
if (!readStringData(flags))
return JSValue();
auto reFlags = Yarr::parseFlags(flags->string());
ASSERT(reFlags.has_value());
VM& vm = m_lexicalGlobalObject->vm();
RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags.value());
return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
}
case ErrorInstanceTag: {
SerializableErrorType serializedErrorType;
if (!read(serializedErrorType)) {
fail();
return JSValue();
}
String message;
if (!readNullableString(message)) {
fail();
return JSValue();
}
uint32_t line;
if (!read(line)) {
fail();
return JSValue();
}
uint32_t column;
if (!read(column)) {
fail();
return JSValue();
}
String sourceURL;
if (!readNullableString(sourceURL)) {
fail();
return JSValue();
}
String stackString;
if (!readNullableString(stackString)) {
fail();
return JSValue();
}
return ErrorInstance::create(m_lexicalGlobalObject, WTFMove(message), toErrorType(serializedErrorType), { line, column }, WTFMove(sourceURL), WTFMove(stackString));
}
case ObjectReferenceTag: {
auto index = readConstantPoolIndex(m_gcBuffer);
if (!index) {
fail();
return JSValue();
}
return m_gcBuffer.at(*index);
}
case MessagePortReferenceTag: {
uint32_t index;
bool indexSuccessfullyRead = read(index);
if (!indexSuccessfullyRead || index >= m_messagePorts.size()) {
fail();
return JSValue();
}
return getJSValue(m_messagePorts[index].get());
}
#if ENABLE(WEBASSEMBLY)
case WasmModuleTag: {
if (m_version >= 12) {
// https://webassembly.github.io/spec/web-api/index.html#serialization
CachedStringRef agentClusterID;
bool agentClusterIDSuccessfullyRead = readStringData(agentClusterID);
if (!agentClusterIDSuccessfullyRead || agentClusterID->string() != agentClusterIDFromGlobalObject(*m_globalObject)) {
fail();
return JSValue();
}
}
uint32_t index;
bool indexSuccessfullyRead = read(index);
if (!indexSuccessfullyRead || !m_wasmModules || index >= m_wasmModules->size()) {
fail();
return JSValue();
}
return JSC::JSWebAssemblyModule::create(m_lexicalGlobalObject->vm(), m_globalObject->webAssemblyModuleStructure(), Ref { *m_wasmModules->at(index) });
}
case WasmMemoryTag: {
if (m_version >= 12) {
CachedStringRef agentClusterID;
bool agentClusterIDSuccessfullyRead = readStringData(agentClusterID);
if (!agentClusterIDSuccessfullyRead || agentClusterID->string() != agentClusterIDFromGlobalObject(*m_globalObject)) {
fail();
return JSValue();
}
}
uint32_t index;
bool indexSuccessfullyRead = read(index);
if (!indexSuccessfullyRead || !m_wasmMemoryHandles || index >= m_wasmMemoryHandles->size() || !JSC::Options::useSharedArrayBuffer()) {
fail();
return JSValue();
}
auto& vm = m_lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSWebAssemblyMemory* result = JSC::JSWebAssemblyMemory::tryCreate(m_lexicalGlobalObject, vm, m_globalObject->webAssemblyMemoryStructure());
// Since we are cloning a JSWebAssemblyMemory, it's impossible for that
// module to not have been a valid module. Therefore, createStub should
// not throw.
scope.releaseAssertNoException();
RefPtr<Wasm::Memory> memory;
auto handler = [&vm, result](Wasm::Memory::GrowSuccess, PageCount oldPageCount, PageCount newPageCount) { result->growSuccessCallback(vm, oldPageCount, newPageCount); };
if (RefPtr<SharedArrayBufferContents> contents = m_wasmMemoryHandles->at(index)) {
if (!contents->memoryHandle()) {
fail();
return JSValue();
}
memory = Wasm::Memory::create(vm, contents.releaseNonNull(), WTFMove(handler));
} else {
// zero size & max-size.
memory = Wasm::Memory::createZeroSized(vm, JSC::MemorySharingMode::Shared, WTFMove(handler));
}
result->adopt(memory.releaseNonNull());
m_gcBuffer.appendWithCrashOnOverflow(result);
return result;
}
#endif
case ArrayBufferTag: {
RefPtr<ArrayBuffer> arrayBuffer;
if (!readArrayBuffer(arrayBuffer)) {
fail();
return JSValue();
}
Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode());
// A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared
// array buffers while the sender is. In that case, we would see a null structure here.
if (UNLIKELY(!structure)) {
fail();
return JSValue();
}
JSValue result = JSArrayBuffer::create(m_lexicalGlobalObject->vm(), structure, WTFMove(arrayBuffer));
m_gcBuffer.appendWithCrashOnOverflow(result);
return result;
}
case ResizableArrayBufferTag: {
RefPtr<ArrayBuffer> arrayBuffer;
if (!readResizableNonSharedArrayBuffer(arrayBuffer)) {
fail();
return JSValue();
}
Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode());
// A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared
// array buffers while the sender is. In that case, we would see a null structure here.
if (UNLIKELY(!structure)) {
fail();
return JSValue();
}
JSValue result = JSArrayBuffer::create(m_lexicalGlobalObject->vm(), structure, WTFMove(arrayBuffer));
m_gcBuffer.appendWithCrashOnOverflow(result);
return result;
}
case ArrayBufferTransferTag: {
uint32_t index;
bool indexSuccessfullyRead = read(index);
if (!indexSuccessfullyRead || index >= m_arrayBuffers.size()) {
fail();
return JSValue();
}
if (!m_arrayBuffers[index])
m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index)));
return getJSValue(m_arrayBuffers[index].get());
}
case SharedArrayBufferTag: {
// https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize
uint32_t index = UINT_MAX;
bool indexSuccessfullyRead = read(index);
if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size() || !JSC::Options::useSharedArrayBuffer()) {
fail();
return JSValue();
}
RELEASE_ASSERT(m_sharedBuffers->at(index));
auto buffer = ArrayBuffer::create(WTFMove(m_sharedBuffers->at(index)));
JSValue result = getJSValue(buffer.get());
m_gcBuffer.appendWithCrashOnOverflow(result);
return result;
}
case ArrayBufferViewTag: {
JSValue arrayBufferView;
if (!readArrayBufferView(m_lexicalGlobalObject->vm(), arrayBufferView)) {
fail();
return JSValue();
}
m_gcBuffer.appendWithCrashOnOverflow(arrayBufferView);
return arrayBufferView;
}
#if ENABLE(WEB_CRYPTO)
case CryptoKeyTag: {
Vector<uint8_t> wrappedKey;
if (!read(wrappedKey)) {
fail();
return JSValue();
}
Vector<uint8_t> serializedKey;
if (!unwrapCryptoKey(m_lexicalGlobalObject, wrappedKey, serializedKey)) {
fail();
return JSValue();
}
JSValue cryptoKey;
// Vector<RefPtr<MessagePort>> dummyMessagePorts;
// CloneDeserializer rawKeyDeserializer(m_lexicalGlobalObject, m_globalObject, dummyMessagePorts, nullptr, {}, serializedKey);
CloneDeserializer rawKeyDeserializer(m_lexicalGlobalObject, m_globalObject, {}, nullptr, serializedKey);
if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) {
fail();
return JSValue();
}
m_gcBuffer.appendWithCrashOnOverflow(cryptoKey);
return cryptoKey;
}
#endif
// case DOMPointReadOnlyTag:
// return readDOMPoint<DOMPointReadOnly>();
// case DOMPointTag:
// return readDOMPoint<DOMPoint>();
// case DOMRectReadOnlyTag:
// return readDOMRect<DOMRectReadOnly>();
// case DOMRectTag:
// return readDOMRect<DOMRect>();
// case DOMMatrixReadOnlyTag:
// return readDOMMatrix<DOMMatrixReadOnly>();
// case DOMMatrixTag:
// return readDOMMatrix<DOMMatrix>();
// case DOMQuadTag:
// return readDOMQuad();
// case ImageBitmapTransferTag:
// return readTransferredImageBitmap();
#if ENABLE(WEB_RTC)
case RTCCertificateTag:
return readRTCCertificate();
#endif
// case ImageBitmapTag:
// return readImageBitmap();
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
case OffscreenCanvasTransferTag:
return readOffscreenCanvas();
#endif
#if ENABLE(WEB_RTC)
case RTCDataChannelTransferTag:
return readRTCDataChannel();
#endif
#if ENABLE(WEB_CODECS)
case WebCodecsEncodedVideoChunkTag:
return readWebCodecsEncodedVideoChunk();
case WebCodecsVideoFrameTag:
return readWebCodecsVideoFrame();
#endif
case DOMExceptionTag:
return readDOMException();
default:
m_ptr--; // Push the tag back
return JSValue();
}
}