mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Changelog: [internal] ### Why does the crash happen? The crash can happen if runtime is destroyed before background executor lambda is run. Destroying a shadow node after runtime leads to a crash through the chain of ownerships. Chain of ownership: `ShadowNode -> ShadowNodeFamily -> EventEmitter -> EventTarget -> Pointer` Pointer tries to call `invalidate` method on raw pointer to the runtime which is gone. https://www.internalfb.com/intern/diffusion/FBS/browse/master/xplat/js/react-native-github/ReactCommon/jsi/jsi/jsi.h?commit=2ee3ae0c6a64&lines=335-339 To work around this, weak pointers are passed to lambda. This way the lambda is less likely to be the last owner of shadow nodes. Possibility of race still exists but it less likely to happen. ## Other solution Alternatively, we could make sure native Runnable queue in Java is emptied as part of tear down process. We can even implement both solutions as they are semantically correct. Reviewed By: shergin Differential Revision: D26582554 fbshipit-source-id: b1b8a92237902bc4c40376176f575caa24a41a05
137 lines
3.8 KiB
C++
137 lines
3.8 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its 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 <folly/dynamic.h>
|
|
#include <jsi/JSIDynamic.h>
|
|
#include <jsi/jsi.h>
|
|
#include <react/renderer/core/EventHandler.h>
|
|
#include <react/renderer/core/ShadowNode.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
using BackgroundExecutor =
|
|
std::function<void(std::function<void()> &&callback)>;
|
|
|
|
struct EventHandlerWrapper : public EventHandler {
|
|
EventHandlerWrapper(jsi::Function eventHandler)
|
|
: callback(std::move(eventHandler)) {}
|
|
|
|
jsi::Function callback;
|
|
};
|
|
|
|
struct ShadowNodeWrapper : public jsi::HostObject {
|
|
ShadowNodeWrapper(SharedShadowNode shadowNode)
|
|
: shadowNode(std::move(shadowNode)) {}
|
|
|
|
ShadowNode::Shared shadowNode;
|
|
};
|
|
|
|
struct ShadowNodeListWrapper : public jsi::HostObject {
|
|
ShadowNodeListWrapper(SharedShadowNodeUnsharedList shadowNodeList)
|
|
: shadowNodeList(shadowNodeList) {}
|
|
|
|
SharedShadowNodeUnsharedList shadowNodeList;
|
|
};
|
|
|
|
inline static ShadowNode::Shared shadowNodeFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &value) {
|
|
if (value.isNull()) {
|
|
return nullptr;
|
|
}
|
|
|
|
return value.getObject(runtime)
|
|
.getHostObject<ShadowNodeWrapper>(runtime)
|
|
->shadowNode;
|
|
}
|
|
|
|
inline static jsi::Value valueFromShadowNode(
|
|
jsi::Runtime &runtime,
|
|
const ShadowNode::Shared &shadowNode) {
|
|
return jsi::Object::createFromHostObject(
|
|
runtime, std::make_shared<ShadowNodeWrapper>(shadowNode));
|
|
}
|
|
|
|
inline static SharedShadowNodeUnsharedList shadowNodeListFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &value) {
|
|
return value.getObject(runtime)
|
|
.getHostObject<ShadowNodeListWrapper>(runtime)
|
|
->shadowNodeList;
|
|
}
|
|
|
|
inline static ShadowNode::UnsharedListOfShared shadowNodeListFromWeakList(
|
|
ShadowNode::UnsharedListOfWeak const &weakShadowNodeList) {
|
|
auto result = std::make_shared<ShadowNode::ListOfShared>();
|
|
for (auto const &weakShadowNode : *weakShadowNodeList) {
|
|
auto sharedShadowNode = weakShadowNode.lock();
|
|
if (!sharedShadowNode) {
|
|
return nullptr;
|
|
}
|
|
result->push_back(sharedShadowNode);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline static ShadowNode::UnsharedListOfWeak weakShadowNodeListFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &value) {
|
|
auto shadowNodeList = value.getObject(runtime)
|
|
.getHostObject<ShadowNodeListWrapper>(runtime)
|
|
->shadowNodeList;
|
|
|
|
auto weakShadowNodeList = std::make_shared<ShadowNode::ListOfWeak>();
|
|
for (auto const &shadowNode : *shadowNodeList) {
|
|
weakShadowNodeList->push_back(shadowNode);
|
|
}
|
|
|
|
return weakShadowNodeList;
|
|
}
|
|
|
|
inline static jsi::Value valueFromShadowNodeList(
|
|
jsi::Runtime &runtime,
|
|
const SharedShadowNodeUnsharedList &shadowNodeList) {
|
|
return jsi::Object::createFromHostObject(
|
|
runtime, std::make_unique<ShadowNodeListWrapper>(shadowNodeList));
|
|
}
|
|
|
|
inline static SharedEventTarget eventTargetFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &eventTargetValue,
|
|
jsi::Value const &tagValue) {
|
|
return std::make_shared<EventTarget>(
|
|
runtime, eventTargetValue, tagValue.getNumber());
|
|
}
|
|
|
|
inline static Tag tagFromValue(jsi::Runtime &runtime, jsi::Value const &value) {
|
|
return (Tag)value.getNumber();
|
|
}
|
|
|
|
inline static SurfaceId surfaceIdFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &value) {
|
|
return (SurfaceId)value.getNumber();
|
|
}
|
|
|
|
inline static std::string stringFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &value) {
|
|
return value.getString(runtime).utf8(runtime);
|
|
}
|
|
|
|
inline static folly::dynamic commandArgsFromValue(
|
|
jsi::Runtime &runtime,
|
|
jsi::Value const &value) {
|
|
return jsi::dynamicFromValue(runtime, value);
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|