commit 3fe4e28cbeb4ea573e07c3a9a9b61c8d6a4c91fe
parent b2fee3b5a19cfa559c0bca81ac98165260530d72
Author: Nazım Can Altınova <canaltinova@gmail.com>
Date: Tue, 21 Oct 2025 23:59:08 +0000
Bug 1979114 - Fetch retrievable sources while converting sources to JS objects inside the parent process r=mstange,profiler-reviewers,iain
There were some ScriptSources with the `Retrievable` source type, that
we couldn't retrieve in the child process. Now that we are in the parent
process, we can actually request them in here from the JS engine.
JS engine uses the sourceHook to fetch this data and return it to us.
Then we put it inside this JS object
Differential Revision: https://phabricator.services.mozilla.com/D259269
Diffstat:
3 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/js/public/ProfilingSources.h b/js/public/ProfilingSources.h
@@ -91,6 +91,13 @@ struct JS_PUBLIC_API ProfilerJSSourceData {
filePathLength_(pathLen),
data_(SourceTextUTF16{std::move(chars), length}) {}
+ // For the cases where no sourceId and filepath are needed.
+ ProfilerJSSourceData(JS::UniqueChars&& chars, size_t length)
+ : sourceId_(0),
+ filePath_(nullptr),
+ filePathLength_(0),
+ data_(SourceTextUTF8{std::move(chars), length}) {}
+
ProfilerJSSourceData()
: sourceId_(0), filePathLength_(0), data_(Unavailable{}) {}
@@ -161,6 +168,13 @@ using ProfilerJSSources =
*/
JS_PUBLIC_API ProfilerJSSources GetProfilerScriptSources(JSRuntime* rt);
+/**
+ * Retrieve the JS sources that are only retrievable from the parent process.
+ * See RetrievableFile struct for more information.
+ * */
+JS_PUBLIC_API ProfilerJSSourceData
+RetrieveProfilerSourceContent(JSContext* cx, const char* filename);
+
} // namespace js
#endif /* js_ProfilingSources_h */
diff --git a/js/src/vm/GeckoProfiler.cpp b/js/src/vm/GeckoProfiler.cpp
@@ -16,7 +16,7 @@
#include "jit/JitRuntime.h"
#include "jit/JSJitFrameIter.h"
#include "jit/PerfSpewer.h"
-#include "js/ProfilingStack.h"
+#include "js/experimental/SourceHook.h"
#include "vm/FrameIter.h" // js::OnlyJSJitFrameIter
#include "vm/JitActivation.h"
#include "vm/JSScript.h"
@@ -671,6 +671,38 @@ JS_PUBLIC_API js::ProfilerJSSources js::GetProfilerScriptSources(
return rt->geckoProfiler().getProfilerScriptSources();
}
+JS_PUBLIC_API ProfilerJSSourceData
+js::RetrieveProfilerSourceContent(JSContext* cx, const char* filename) {
+ MOZ_ASSERT(filename && strlen(filename));
+ if (!cx) {
+ return ProfilerJSSourceData(); // Return unavailable
+ }
+
+ // Check if source hook is available
+ if (!cx->runtime()->sourceHook.ref()) {
+ return ProfilerJSSourceData(); // Return unavailable
+ }
+
+ size_t sourceLength = 0;
+ char* utf8Source = nullptr;
+
+ bool loadSuccess = cx->runtime()->sourceHook->load(
+ cx, filename, nullptr, &utf8Source, &sourceLength);
+
+ if (!loadSuccess) {
+ // Clear the pending exception that have been set by the source hook.
+ JS_ClearPendingException(cx);
+ return ProfilerJSSourceData(); // Return unavailable
+ }
+
+ if (utf8Source) {
+ return ProfilerJSSourceData(JS::UniqueChars(utf8Source), sourceLength);
+ }
+
+ // Hook returned success but no source data. Return unavailable.
+ return ProfilerJSSourceData();
+}
+
AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSContext* cx)
: cx_(cx), previouslyEnabled_(cx->isProfilerSamplingEnabled()) {
if (previouslyEnabled_) {
diff --git a/tools/profiler/core/ProfileAdditionalInformation.cpp b/tools/profiler/core/ProfileAdditionalInformation.cpp
@@ -10,6 +10,7 @@
#include "js/JSON.h"
#include "js/PropertyAndElement.h"
#include "js/Value.h"
+#include "mozilla/Assertions.h"
#include "mozilla/JSONStringWriteFuncs.h"
#include "mozilla/ipc/IPDLParamTraits.h"
@@ -28,8 +29,14 @@ mozilla::ProfileGenerationAdditionalInformation::CreateJSStringFromSourceData(
return JS_NewStringCopyN(aCx, srcText.chars().get(), srcText.length());
},
[&](const ProfilerJSSourceData::RetrievableFile&) -> JSString* {
- // FIXME: Implement this later.
- return JS_NewStringCopyZ(aCx, "[unavailable]");
+ ProfilerJSSourceData retrievedData =
+ js::RetrieveProfilerSourceContent(aCx, aSourceData.filePath());
+ const auto& data = retrievedData.data();
+ MOZ_RELEASE_ASSERT(data.is<ProfilerJSSourceData::SourceTextUTF8>(),
+ "Retrieved JS source has to be utf-8");
+
+ const auto& srcText = data.as<ProfilerJSSourceData::SourceTextUTF8>();
+ return JS_NewStringCopyN(aCx, srcText.chars().get(), srcText.length());
},
[&](const ProfilerJSSourceData::Unavailable&) -> JSString* {
return JS_NewStringCopyZ(aCx, "[unavailable]");