tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 74799a8be169c8745dc7189b74f5d18643fbf873
parent 4157a13ac228a5fcd0490475edb35c71c835c327
Author: Nazım Can Altınova <canaltinova@gmail.com>
Date:   Tue, 21 Oct 2025 21:15:34 +0000

Bug 1979114 - Add IPC serialization and deserialization methods for the JS sources r=mstange,profiler-reviewers

Since we would like to send the JS source information directly to the
parent process through IPC, we need a serialization and deserialization
code to transfer this data.

Differential Revision: https://phabricator.services.mozilla.com/D259264

Diffstat:
Mtools/profiler/core/ProfileAdditionalInformation.cpp | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtools/profiler/public/ProfileAdditionalInformation.h | 1+
2 files changed, 144 insertions(+), 0 deletions(-)

diff --git a/tools/profiler/core/ProfileAdditionalInformation.cpp b/tools/profiler/core/ProfileAdditionalInformation.cpp @@ -56,6 +56,14 @@ struct ParamTraits<SharedLibraryInfo> { static bool Read(MessageReader* aReader, paramType* aResult); }; +template <> +struct ParamTraits<ProfilerJSSourceData> { + typedef ProfilerJSSourceData paramType; + + static void Write(MessageWriter* aWriter, const paramType& aParam); + static bool Read(MessageReader* aReader, paramType* aResult); +}; + void IPC::ParamTraits<SharedLibrary>::Write(MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.mStart); @@ -97,6 +105,141 @@ bool IPC::ParamTraits<SharedLibraryInfo>::Read(MessageReader* aReader, return ReadParam(aReader, &aResult->mEntries); } +// Type tags for ProfilerJSSourceData IPC serialization +constexpr uint8_t kSourceTextUTF16Tag = 0; +constexpr uint8_t kSourceTextUTF8Tag = 1; +constexpr uint8_t kRetrievableFileTag = 2; +constexpr uint8_t kUnavailableTag = 3; + +void IPC::ParamTraits<ProfilerJSSourceData>::Write(MessageWriter* aWriter, + const paramType& aParam) { + // Write sourceId and filePath first + WriteParam(aWriter, aParam.sourceId()); + WriteParam(aWriter, aParam.filePathLength()); + if (aParam.filePathLength() > 0) { + aWriter->WriteBytes(aParam.filePath(), + aParam.filePathLength() * sizeof(char)); + } + + // Then write the specific data type + aParam.data().match( + [&](const ProfilerJSSourceData::SourceTextUTF16& srcText) { + WriteParam(aWriter, kSourceTextUTF16Tag); + WriteParam(aWriter, srcText.length()); + if (srcText.length() > 0) { + aWriter->WriteBytes(srcText.chars().get(), + srcText.length() * sizeof(char16_t)); + } + }, + [&](const ProfilerJSSourceData::SourceTextUTF8& srcText) { + WriteParam(aWriter, kSourceTextUTF8Tag); + WriteParam(aWriter, srcText.length()); + if (srcText.length() > 0) { + aWriter->WriteBytes(srcText.chars().get(), + srcText.length() * sizeof(char)); + } + }, + [&](const ProfilerJSSourceData::RetrievableFile&) { + WriteParam(aWriter, kRetrievableFileTag); + }, + [&](const ProfilerJSSourceData::Unavailable&) { + WriteParam(aWriter, kUnavailableTag); + }); +} + +bool IPC::ParamTraits<ProfilerJSSourceData>::Read(MessageReader* aReader, + paramType* aResult) { + // Read sourceId and filePath first + uint32_t sourceId; + size_t pathLength; + if (!ReadParam(aReader, &sourceId) || !ReadParam(aReader, &pathLength)) { + return false; + } + + // Read filePath if present + JS::UniqueChars filePath; + if (pathLength > 0) { + char* chars = + static_cast<char*>(js_malloc((pathLength + 1) * sizeof(char))); + if (!chars || !aReader->ReadBytesInto(chars, pathLength * sizeof(char))) { + js_free(chars); + return false; + } + chars[pathLength] = '\0'; + filePath.reset(chars); + } + + // Then read the specific data type + uint8_t typeTag; + if (!ReadParam(aReader, &typeTag)) { + return false; + } + + switch (typeTag) { + case kSourceTextUTF16Tag: { + size_t length; + if (!ReadParam(aReader, &length)) { + return false; + } + if (length > 0) { + // Allocate one extra element for null terminator + char16_t* chars = + static_cast<char16_t*>(js_malloc((length + 1) * sizeof(char16_t))); + if (!chars || + !aReader->ReadBytesInto(chars, length * sizeof(char16_t))) { + js_free(chars); + return false; + } + // Ensure null termination + chars[length] = u'\0'; + *aResult = + ProfilerJSSourceData(sourceId, JS::UniqueTwoByteChars(chars), + length, std::move(filePath), pathLength); + } else { + *aResult = ProfilerJSSourceData(sourceId, JS::UniqueTwoByteChars(), 0, + std::move(filePath), pathLength); + } + return true; + } + case kSourceTextUTF8Tag: { + size_t length; + if (!ReadParam(aReader, &length)) { + return false; + } + if (length > 0) { + // Allocate one extra byte for null terminator + char* chars = + static_cast<char*>(js_malloc((length + 1) * sizeof(char))); + if (!chars || !aReader->ReadBytesInto(chars, length * sizeof(char))) { + js_free(chars); + return false; + } + // Ensure null termination + chars[length] = '\0'; + *aResult = + ProfilerJSSourceData(sourceId, JS::UniqueChars(chars), length, + std::move(filePath), pathLength); + } else { + *aResult = ProfilerJSSourceData(sourceId, JS::UniqueChars(), 0, + std::move(filePath), pathLength); + } + return true; + } + case kRetrievableFileTag: { + *aResult = ProfilerJSSourceData::CreateRetrievableFile( + sourceId, std::move(filePath), pathLength); + return true; + } + case kUnavailableTag: { + *aResult = + ProfilerJSSourceData(sourceId, std::move(filePath), pathLength); + return true; + } + default: + return false; + } +} + void IPC::ParamTraits<mozilla::ProfileGenerationAdditionalInformation>::Write( MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.mSharedLibraries); diff --git a/tools/profiler/public/ProfileAdditionalInformation.h b/tools/profiler/public/ProfileAdditionalInformation.h @@ -16,6 +16,7 @@ #include "SharedLibraries.h" #include "js/Value.h" +#include "js/ProfilingSources.h" #include "nsString.h" namespace IPC {