Refactor console API implementation to use tryExecuteSync for clarity (#54069)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54069

Changelog: [Internal]

D83238216 added a `tryExecuteSync` function for use with `EnableExecutorFromThis` objects - concretely, for calling functions on  a `weak_ptr<RuntimeTarget>` from the JS thread while ensuring the `RuntimeTarget` is always destroyed on the inspector thread.

`tryExecuteSync` is a generalisation of the lambda-based `delegateExecutorSync` helper from `RuntimeTargetConsole`, so in this diff we refactor the latter to use the more general and better-documented function.

Reviewed By: huntie

Differential Revision: D83838062

fbshipit-source-id: 85fd5a43e204cc634b573e2a3bda47a9ec523fca
This commit is contained in:
Moti Zilberman
2025-10-08 17:38:42 -07:00
committed by meta-codesync[bot]
parent 81d652543b
commit 5c7cbebfee
@@ -525,30 +525,6 @@ void RuntimeTarget::installConsoleHandler() {
auto console = objectCreate(runtime, std::move(consolePrototype));
auto state = std::make_shared<ConsoleState>();
/**
* An executor that runs synchronously and provides a safe reference to our
* RuntimeTargetDelegate for use on the JS thread.
* \see RuntimeTargetDelegate for information on which methods are safe to
* call on the JS thread.
* \warning The callback will not run if the RuntimeTarget has been
* destroyed.
*/
auto delegateExecutorSync =
[selfWeak,
selfExecutor](std::invocable<RuntimeTargetDelegate&> auto func) {
if (auto self = selfWeak.lock()) {
// Q: Why is it safe to use self->delegate_ here?
// A: Because the caller of InspectorTarget::registerRuntime
// is explicitly required to guarantee that the delegate not
// only outlives the target, but also outlives all JS code
// execution that occurs on the JS thread.
func(self->delegate_);
// To ensure we never destroy `self` on the JS thread, send
// our shared_ptr back to the inspector thread.
selfExecutor([self = std::move(self)](auto&) { (void)self; });
}
};
/**
* Install a console method with the given name and body. The body receives
* the usual JSI host function parameters plus a ConsoleState reference, a
@@ -569,20 +545,26 @@ void RuntimeTarget::installConsoleHandler() {
forwardToOriginalConsole(
originalConsole,
methodName,
[body = std::move(body), state, delegateExecutorSync](
[body = std::move(body), state, selfWeak](
jsi::Runtime& runtime,
const jsi::Value& /*thisVal*/,
const jsi::Value* args,
size_t count) {
auto timestampMs = getTimestampMs();
delegateExecutorSync([&](auto& runtimeTargetDelegate) {
auto stackTrace = runtimeTargetDelegate.captureStackTrace(
tryExecuteSync(selfWeak, [&](auto& self) {
// Q: Why is it safe to use self->delegate_ here?
// A: Because the caller of
// InspectorTarget::registerRuntime is explicitly required
// to guarantee that the delegate not only outlives the
// target, but also outlives all JS code execution that
// occurs on the JS thread.
auto stackTrace = self.delegate_.captureStackTrace(
runtime, /* framesToSkip */ 1);
body(
runtime,
args,
count,
runtimeTargetDelegate,
self.delegate_,
*state,
timestampMs,
std::move(stackTrace));