bool dumpIfTerminal()

in src/bun.js/bindings/webcore/SerializedScriptValue.cpp [1538:1937]


    bool dumpIfTerminal(JSValue value, SerializationReturnCode& code)
    {
        if (!value.isCell()) {
            dumpImmediate(value, code);
            return true;
        }
        ASSERT(value.isCell());

        if (value.isString()) {
            dumpString(asString(value)->value(m_lexicalGlobalObject));
            return true;
        }

        if (value.isHeapBigInt()) {
            write(BigIntTag);
            dumpBigIntData(value);
            return true;
        }

        if (value.isSymbol()) {
            code = SerializationReturnCode::DataCloneError;
            return true;
        }

        VM& vm = m_lexicalGlobalObject->vm();
        if (isArray(value))
            return false;

        if (value.isObject()) {
            auto* obj = asObject(value);
            if (auto* dateObject = jsDynamicCast<DateInstance*>(obj)) {
                write(DateTag);
                write(dateObject->internalNumber());
                return true;
            }
            if (auto* booleanObject = jsDynamicCast<BooleanObject*>(obj)) {
                if (!startObjectInternal(booleanObject)) // handle duplicates
                    return true;
                write(booleanObject->internalValue().toBoolean(m_lexicalGlobalObject) ? TrueObjectTag : FalseObjectTag);
                return true;
            }
            if (auto* stringObject = jsDynamicCast<StringObject*>(obj)) {
                if (!startObjectInternal(stringObject)) // handle duplicates
                    return true;
                String str = asString(stringObject->internalValue())->value(m_lexicalGlobalObject);
                dumpStringObject(str);
                return true;
            }
            if (auto* numberObject = jsDynamicCast<NumberObject*>(obj)) {
                if (!startObjectInternal(numberObject)) // handle duplicates
                    return true;
                write(NumberObjectTag);
                write(numberObject->internalValue().asNumber());
                return true;
            }
            if (auto* bigIntObject = jsDynamicCast<BigIntObject*>(obj)) {
                if (!startObjectInternal(bigIntObject)) // handle duplicates
                    return true;
                JSValue bigIntValue = bigIntObject->internalValue();
                ASSERT(bigIntValue.isBigInt());
                write(BigIntObjectTag);
                dumpBigIntData(bigIntValue);
                return true;
            }
            // if (auto* file = JSFile::toWrapped(vm, obj)) {
            //     write(FileTag);
            //     write(*file);
            //     return true;
            // }
            // if (auto* list = JSFileList::toWrapped(vm, obj)) {
            //     write(FileListTag);
            //     write(list->length());
            //     for (auto& file : list->files())
            //         write(file.get());
            //     return true;
            // }

            // write bun types
            if (auto _cloneable = StructuredCloneableSerialize::fromJS(value)) {
                StructuredCloneableSerialize cloneable = WTFMove(_cloneable.value());
                write(cloneable.tag);
                cloneable.write(this, m_lexicalGlobalObject);
                return true;
            }

            // if (auto* blob = JSBlob::toWrapped(vm, obj)) {
            //     write(BlobTag);
            //     m_blobHandles.append(blob->handle().isolatedCopy());
            //     write(blob->url().string());
            //     write(blob->type());
            //     static_assert(sizeof(uint64_t) == sizeof(decltype(blob->size())));
            //     uint64_t size = blob->size();
            //     write(size);
            //     uint64_t memoryCost = blob->memoryCost();
            //     write(memoryCost);
            //     return true;
            // }
            // if (auto* data = JSImageData::toWrapped(vm, obj)) {
            //     write(ImageDataTag);
            //     auto addResult = m_imageDataPool.add(*data, m_imageDataPool.size());
            //     if (!addResult.isNewEntry) {
            //         write(ImageDataPoolTag);
            //         writeImageDataIndex(addResult.iterator->value);
            //         return true;
            //     }
            //     write(static_cast<uint32_t>(data->width()));
            //     write(static_cast<uint32_t>(data->height()));
            //     CheckedUint32 dataLength = data->data().length();
            //     if (dataLength.hasOverflowed()) {
            //         code = SerializationReturnCode::DataCloneError;
            //         return true;
            //     }
            //     write(dataLength);
            //     write(data->data().data(), dataLength);
            //     write(data->colorSpace());
            //     return true;
            // }
            if (auto* regExp = jsDynamicCast<RegExpObject*>(obj)) {
                write(RegExpTag);
                write(regExp->regExp()->pattern());
                write(String::fromLatin1(JSC::Yarr::flagsString(regExp->regExp()->flags()).data()));
                return true;
            }
            if (auto* errorInstance = jsDynamicCast<ErrorInstance*>(obj)) {
                auto& vm = m_lexicalGlobalObject->vm();
                auto scope = DECLARE_THROW_SCOPE(vm);
                auto errorTypeValue = errorInstance->get(m_lexicalGlobalObject, vm.propertyNames->name);
                RETURN_IF_EXCEPTION(scope, false);
                auto errorTypeString = errorTypeValue.toWTFString(m_lexicalGlobalObject);
                RETURN_IF_EXCEPTION(scope, false);

                String message;
                PropertyDescriptor messageDescriptor;
                if (errorInstance->getOwnPropertyDescriptor(m_lexicalGlobalObject, vm.propertyNames->message, messageDescriptor) && messageDescriptor.isDataDescriptor()) {
                    EXCEPTION_ASSERT(!scope.exception());
                    message = messageDescriptor.value().toWTFString(m_lexicalGlobalObject);
                }
                RETURN_IF_EXCEPTION(scope, false);

                unsigned line = 0;
                PropertyDescriptor lineDescriptor;
                if (errorInstance->getOwnPropertyDescriptor(m_lexicalGlobalObject, vm.propertyNames->line, lineDescriptor) && lineDescriptor.isDataDescriptor()) {
                    EXCEPTION_ASSERT(!scope.exception());
                    line = lineDescriptor.value().toNumber(m_lexicalGlobalObject);
                }
                RETURN_IF_EXCEPTION(scope, false);

                unsigned column = 0;
                PropertyDescriptor columnDescriptor;
                if (errorInstance->getOwnPropertyDescriptor(m_lexicalGlobalObject, vm.propertyNames->column, columnDescriptor) && columnDescriptor.isDataDescriptor()) {
                    EXCEPTION_ASSERT(!scope.exception());
                    column = columnDescriptor.value().toNumber(m_lexicalGlobalObject);
                }
                RETURN_IF_EXCEPTION(scope, false);

                String sourceURL;
                PropertyDescriptor sourceURLDescriptor;
                if (errorInstance->getOwnPropertyDescriptor(m_lexicalGlobalObject, vm.propertyNames->sourceURL, sourceURLDescriptor) && sourceURLDescriptor.isDataDescriptor()) {
                    EXCEPTION_ASSERT(!scope.exception());
                    sourceURL = sourceURLDescriptor.value().toWTFString(m_lexicalGlobalObject);
                }
                RETURN_IF_EXCEPTION(scope, false);

                String stack;
                PropertyDescriptor stackDescriptor;
                if (errorInstance->getOwnPropertyDescriptor(m_lexicalGlobalObject, vm.propertyNames->stack, stackDescriptor) && stackDescriptor.isDataDescriptor()) {
                    EXCEPTION_ASSERT(!scope.exception());
                    stack = stackDescriptor.value().toWTFString(m_lexicalGlobalObject);
                }
                RETURN_IF_EXCEPTION(scope, false);

                write(ErrorInstanceTag);
                write(errorNameToSerializableErrorType(errorTypeString));
                writeNullableString(message);
                write(line);
                write(column);
                writeNullableString(sourceURL);
                writeNullableString(stack);
                return true;
            }
            if (obj->inherits<JSMessagePort>()) {
                auto index = m_transferredMessagePorts.find(obj);
                if (index != m_transferredMessagePorts.end()) {
                    write(MessagePortReferenceTag);
                    write(index->value);
                    return true;
                }
                // MessagePort object could not be found in transferred message ports
                code = SerializationReturnCode::ValidationError;
                return true;
            }
            if (auto* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) {
                if (arrayBuffer->isDetached()) {
                    code = SerializationReturnCode::ValidationError;
                    return true;
                }
                auto index = m_transferredArrayBuffers.find(obj);
                if (index != m_transferredArrayBuffers.end()) {
                    write(ArrayBufferTransferTag);
                    write(index->value);
                    return true;
                }
                if (!startObjectInternal(obj)) // handle duplicates
                    return true;

                if (arrayBuffer->isShared() && m_context == SerializationContext::WorkerPostMessage) {
                    // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal
                    if (!JSC::Options::useSharedArrayBuffer()) {
                        code = SerializationReturnCode::DataCloneError;
                        return true;
                    }
                    uint32_t index = m_sharedBuffers.size();
                    ArrayBufferContents contents;
                    if (arrayBuffer->shareWith(contents)) {
                        write(SharedArrayBufferTag);
                        m_sharedBuffers.append(WTFMove(contents));
                        write(index);
                        return true;
                    }
                }

                if (arrayBuffer->isResizableOrGrowableShared()) {
                    write(ResizableArrayBufferTag);
                    uint64_t byteLength = arrayBuffer->byteLength();
                    write(byteLength);
                    uint64_t maxByteLength = arrayBuffer->maxByteLength().value_or(0);
                    write(maxByteLength);
                    write(static_cast<const uint8_t*>(arrayBuffer->data()), byteLength);
                    return true;
                }

                write(ArrayBufferTag);
                uint64_t byteLength = arrayBuffer->byteLength();
                write(byteLength);
                write(static_cast<const uint8_t*>(arrayBuffer->data()), byteLength);
                return true;
            }
            if (obj->inherits<JSArrayBufferView>()) {
                if (checkForDuplicate(obj))
                    return true;
                bool success = dumpArrayBufferView(obj, code);
                recordObject(obj);
                return success;
            }
#if ENABLE(WEB_CRYPTO)
            if (auto* key = JSCryptoKey::toWrapped(vm, obj)) {
                write(CryptoKeyTag);
                Vector<uint8_t> serializedKey;
                // Vector<URLKeepingBlobAlive> dummyBlobHandles;
                Vector<RefPtr<MessagePort>> dummyMessagePorts;
                Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers;
#if ENABLE(WEB_CODECS)
                Vector<RefPtr<WebCodecsEncodedVideoChunkStorage>> dummyVideoChunks;
                Vector<RefPtr<WebCodecsVideoFrame>> dummyVideoFrames;
#endif
#if ENABLE(WEBASSEMBLY)
                WasmModuleArray dummyModules;
                WasmMemoryHandleArray dummyMemoryHandles;
#endif
                ArrayBufferContentsArray dummySharedBuffers;
                //                 CloneSerializer rawKeySerializer(m_lexicalGlobalObject, dummyMessagePorts, dummyArrayBuffers, {},
                // #if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
                //                     {},
                // #endif
                // #if ENABLE(WEB_RTC)
                //                     {},
                // #endif
                // #if ENABLE(WEB_CODECS)
                //                     dummyVideoChunks,
                //                     dummyVideoFrames,
                // #endif
                // #if ENABLE(WEBASSEMBLY)
                //                     dummyModules,
                //                     dummyMemoryHandles,
                // #endif
                //                     dummyBlobHandles, serializedKey, SerializationContext::Default, dummySharedBuffers, m_forStorage);
                CloneSerializer rawKeySerializer(m_lexicalGlobalObject, dummyMessagePorts, dummyArrayBuffers,
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
                    {},
#endif
#if ENABLE(WEB_RTC)
                    {},
#endif
#if ENABLE(WEB_CODECS)
                    dummyVideoChunks,
                    dummyVideoFrames,
#endif
#if ENABLE(WEBASSEMBLY)
                    dummyModules,
                    dummyMemoryHandles,
#endif
                    serializedKey, SerializationContext::Default, dummySharedBuffers, m_forStorage);
                rawKeySerializer.write(key);
                Vector<uint8_t> wrappedKey;
                if (!wrapCryptoKey(m_lexicalGlobalObject, serializedKey, wrappedKey))
                    return false;
                write(wrappedKey);
                return true;
            }
#endif
#if ENABLE(WEB_RTC)
            if (auto* rtcCertificate = JSRTCCertificate::toWrapped(vm, obj)) {
                write(RTCCertificateTag);
                write(rtcCertificate->expires());
                write(rtcCertificate->pemCertificate());
                write(rtcCertificate->origin().toString());
                write(rtcCertificate->pemPrivateKey());
                write(static_cast<unsigned>(rtcCertificate->getFingerprints().size()));
                for (const auto& fingerprint : rtcCertificate->getFingerprints()) {
                    write(fingerprint.algorithm);
                    write(fingerprint.value);
                }
                return true;
            }
#endif
#if ENABLE(WEBASSEMBLY)
            if (JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(obj)) {
                if (m_context != SerializationContext::WorkerPostMessage && m_context != SerializationContext::WindowPostMessage)
                    return false;

                uint32_t index = m_wasmModules.size();
                m_wasmModules.append(&module->module());
                write(WasmModuleTag);
                write(agentClusterIDFromGlobalObject(*m_lexicalGlobalObject));
                write(index);
                return true;
            }
            if (JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(obj)) {
                if (!JSC::Options::useSharedArrayBuffer() || memory->memory().sharingMode() != JSC::MemorySharingMode::Shared) {
                    code = SerializationReturnCode::DataCloneError;
                    return true;
                }
                if (m_context != SerializationContext::WorkerPostMessage) {
                    code = SerializationReturnCode::DataCloneError;
                    return true;
                }
                uint32_t index = m_wasmMemoryHandles.size();
                m_wasmMemoryHandles.append(memory->memory().shared());
                write(WasmMemoryTag);
                write(agentClusterIDFromGlobalObject(*m_lexicalGlobalObject));
                write(index);
                return true;
            }
#endif
            // if (obj->inherits<JSDOMPointReadOnly>()) {
            //     dumpDOMPoint(obj);
            //     return true;
            // }
            // if (obj->inherits<JSDOMRectReadOnly>()) {
            //     dumpDOMRect(obj);
            //     return true;
            // }
            // if (obj->inherits<JSDOMMatrixReadOnly>()) {
            //     dumpDOMMatrix(obj);
            //     return true;
            // }
            // if (obj->inherits<JSDOMQuad>()) {
            //     dumpDOMQuad(obj);
            //     return true;
            // }
            // if (obj->inherits<JSImageBitmap>()) {
            //     dumpImageBitmap(obj, code);
            //     return true;
            // }
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
            if (obj->inherits<JSOffscreenCanvas>()) {
                dumpOffscreenCanvas(obj, code);
                return true;
            }
#endif
#if ENABLE(WEB_RTC)
            if (obj->inherits<JSRTCDataChannel>()) {
                dumpRTCDataChannel(obj, code);
                return true;
            }
#endif
            if (obj->inherits<JSDOMException>()) {
                dumpDOMException(obj, code);
                return true;
            }
#if ENABLE(WEB_CODECS)
            if (obj->inherits<JSWebCodecsEncodedVideoChunk>()) {
                if (m_forStorage == SerializationForStorage::Yes)
                    return false;
                dumpWebCodecsEncodedVideoChunk(obj);
                return true;
            }
            if (obj->inherits<JSWebCodecsVideoFrame>()) {
                if (m_forStorage == SerializationForStorage::Yes)
                    return false;
                return dumpWebCodecsVideoFrame(obj);
            }
#endif

            return false;
        }
        // Any other types are expected to serialize as null.
        write(NullTag);
        return true;
    }