first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_renderer_leakchecker_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_renderer_leakchecker STATIC ${react_renderer_leakchecker_SRC})
target_include_directories(react_renderer_leakchecker PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_renderer_leakchecker
glog
react_renderer_core
runtimeexecutor)
target_compile_reactnative_options(react_renderer_leakchecker PRIVATE)
target_compile_options(react_renderer_leakchecker PRIVATE -Wpedantic)

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "LeakChecker.h"
#include <glog/logging.h>
#include <jsi/instrumentation.h>
#include <utility>
namespace facebook::react {
LeakChecker::LeakChecker(RuntimeExecutor runtimeExecutor)
: runtimeExecutor_(std::move(runtimeExecutor)) {}
void LeakChecker::uiManagerDidCreateShadowNodeFamily(
const ShadowNodeFamily::Shared& shadowNodeFamily) const {
registry_.add(shadowNodeFamily);
}
void LeakChecker::stopSurface(SurfaceId surfaceId) {
if (previouslyStoppedSurface_ > 0) {
// Dispatch the check onto JavaScript thread to make sure all other
// cleanup code has had chance to run.
runtimeExecutor_([previouslyStoppedSurface = previouslyStoppedSurface_,
this](jsi::Runtime& runtime) {
runtime.instrumentation().collectGarbage("LeakChecker");
// For now check the previous surface because React uses double
// buffering which keeps the surface that was just stopped in
// memory. This is a documented problem in the last point of
// https://github.com/facebook/react/issues/16087
checkSurfaceForLeaks(previouslyStoppedSurface);
});
}
previouslyStoppedSurface_ = surfaceId;
}
void LeakChecker::checkSurfaceForLeaks(SurfaceId surfaceId) const {
auto weakFamilies = registry_.weakFamiliesForSurfaceId(surfaceId);
unsigned int numberOfLeaks = 0;
for (const auto& weakFamily : weakFamilies) {
auto strong = weakFamily.lock();
if (strong) {
++numberOfLeaks;
}
}
if (numberOfLeaks > 0) {
LOG(ERROR) << "[LeakChecker] Surface with id: " << surfaceId
<< " has leaked " << numberOfLeaks << " components out of "
<< weakFamilies.size();
}
registry_.removeFamiliesWithSurfaceId(surfaceId);
}
} // namespace facebook::react

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <ReactCommon/RuntimeExecutor.h>
#include <react/renderer/core/ReactPrimitives.h>
#include <react/renderer/core/ShadowNodeFamily.h>
#include <react/renderer/leakchecker/WeakFamilyRegistry.h>
#include <vector>
namespace facebook::react {
using GarbageCollectionTrigger = std::function<void()>;
class LeakChecker final {
public:
LeakChecker(RuntimeExecutor runtimeExecutor);
void uiManagerDidCreateShadowNodeFamily(const ShadowNodeFamily::Shared &shadowNodeFamily) const;
void stopSurface(SurfaceId surfaceId);
private:
void checkSurfaceForLeaks(SurfaceId surfaceId) const;
const RuntimeExecutor runtimeExecutor_{};
WeakFamilyRegistry registry_{};
SurfaceId previouslyStoppedSurface_{};
};
} // namespace facebook::react

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "WeakFamilyRegistry.h"
namespace facebook::react {
void WeakFamilyRegistry::add(
const ShadowNodeFamily::Shared& shadowNodeFamily) const {
std::scoped_lock lock(familiesMutex_);
ShadowNodeFamily::Weak weakFamily = shadowNodeFamily;
families_[shadowNodeFamily->getSurfaceId()].push_back(weakFamily);
}
void WeakFamilyRegistry::removeFamiliesWithSurfaceId(
SurfaceId surfaceId) const {
std::scoped_lock lock(familiesMutex_);
families_.erase(surfaceId);
}
WeakFamilyRegistry::WeakFamilies WeakFamilyRegistry::weakFamiliesForSurfaceId(
SurfaceId surfaceId) const {
std::scoped_lock lock(familiesMutex_);
if (families_.find(surfaceId) != families_.end()) {
return families_[surfaceId];
}
return {};
}
} // namespace facebook::react

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <react/renderer/core/ReactPrimitives.h>
#include <react/renderer/core/ShadowNodeFamily.h>
#include <unordered_map>
#include <vector>
namespace facebook::react {
class WeakFamilyRegistry final {
public:
using WeakFamilies = std::vector<ShadowNodeFamily::Weak>;
void add(const ShadowNodeFamily::Shared &shadowNodeFamily) const;
void removeFamiliesWithSurfaceId(SurfaceId surfaceId) const;
WeakFamilies weakFamiliesForSurfaceId(SurfaceId surfaceId) const;
private:
/**
* Mutex protecting `families_` property.
*/
mutable std::mutex familiesMutex_;
/**
* A map of ShadowNodeFamily used on surface.
*/
mutable std::unordered_map<SurfaceId, WeakFamilies> families_{};
};
} // namespace facebook::react