Skip to content

Commit

Permalink
Make shareable HostObject code more generic (#4024)
Browse files Browse the repository at this point in the history
## Summary

This PR changes code that was used to handle host objects such that it
applies to all kinds of host objects, not only on Fabric and not only to
ShadowNodeWrapper classes. This simplifies the codebase a bit, because
we get rid of a few code branches with fabric specific checks as well as
allows for other types of Host Objects to be made shareable.

Changes that were made cover:
1) changes in shareables c++ code where we remove fabric specific shadow
wrapper shareable type and replace it with generic HostObjectType
2) changes on the JS side in shareables.ts where we detect if host
object is provided and then we let it be processed by
`makeShareableClone` method directly. For this purpose we add code for
recognizing whether a given object is a host object or not.
3) we get rid of JS code that was preparing shadow node objects to be
made "shareable" (`makeShareableShadowNodeWrapper`) in favor of the
generic code added in shareables.ts described above

## Test plan

Run FabricExample both on Hermes and JSC
  • Loading branch information
kmagiera authored Feb 2, 2023
1 parent ddd2fbb commit f88ac36
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 39 deletions.
8 changes: 3 additions & 5 deletions Common/cpp/NativeModules/NativeReanimatedModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,9 @@ jsi::Value NativeReanimatedModule::makeShareableClone(
} else {
shareable = std::make_shared<ShareableArray>(rt, object.asArray(rt));
}
#ifdef RCT_NEW_ARCH_ENABLED
} else if (object.isHostObject<ShadowNodeWrapper>(rt)) {
shareable = std::make_shared<ShareableShadowNodeWrapper>(
runtimeHelper, rt, object);
#endif
} else if (object.isHostObject(rt)) {
shareable = std::make_shared<ShareableHostObject>(
runtimeHelper, rt, object.getHostObject(rt));
} else {
if (shouldRetainRemote.isBool() && shouldRetainRemote.getBool()) {
shareable = std::make_shared<RetainingShareable<ShareableObject>>(
Expand Down
26 changes: 9 additions & 17 deletions Common/cpp/SharedItems/Shareables.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@ class Shareable {
RemoteFunctionType,
HandleType,
SynchronizedDataHolder,
#ifdef RCT_NEW_ARCH_ENABLED
ShadowNode,
#endif
HostObjectType,
};

explicit Shareable(ValueType valueType) : valueType_(valueType) {}
Expand Down Expand Up @@ -266,26 +264,20 @@ class ShareableObject : public Shareable {
std::vector<std::pair<std::string, std::shared_ptr<Shareable>>> data_;
};

#ifdef RCT_NEW_ARCH_ENABLED
class ShareableShadowNodeWrapper : public Shareable {
private:
react::ShadowNode::Shared shadowNode_;

class ShareableHostObject : public Shareable {
public:
ShareableShadowNodeWrapper(
ShareableHostObject(
const std::shared_ptr<JSRuntimeHelper> &runtimeHelper,
jsi::Runtime &rt,
const jsi::Object &wrapperObject)
: Shareable(ShadowNode) {
shadowNode_ =
wrapperObject.getHostObject<ShadowNodeWrapper>(rt)->shadowNode;
}
const std::shared_ptr<jsi::HostObject> &hostObject)
: Shareable(HostObjectType), hostObject_(hostObject) {}
jsi::Value toJSValue(jsi::Runtime &rt) override {
return jsi::Object::createFromHostObject(
rt, std::make_shared<ShadowNodeWrapper>(shadowNode_));
return jsi::Object::createFromHostObject(rt, hostObject_);
}

protected:
std::shared_ptr<jsi::HostObject> hostObject_;
};
#endif

class ShareableWorklet : public ShareableObject {
private:
Expand Down
5 changes: 1 addition & 4 deletions src/createAnimatedComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {
ViewRefSet,
} from './reanimated2/ViewDescriptorsSet';
import { getShadowNodeWrapperFromRef } from './reanimated2/fabricUtils';
import { makeShareableShadowNodeWrapper } from './reanimated2/shareables';

function dummyListener() {
// empty listener we use to assign to listener properties for which animated
Expand Down Expand Up @@ -342,9 +341,7 @@ export default function createAnimatedComponent(
}

if (global._IS_FABRIC) {
shadowNodeWrapper = makeShareableShadowNodeWrapper(
getShadowNodeWrapperFromRef(this)
);
shadowNodeWrapper = getShadowNodeWrapperFromRef(this);
}
}
this._viewTag = viewTag as number;
Expand Down
5 changes: 1 addition & 4 deletions src/reanimated2/hook/useAnimatedRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@ import { getTag } from '../NativeMethods';
import { getShadowNodeWrapperFromHostInstance } from '../fabricUtils';
import {
makeShareableCloneRecursive,
makeShareableShadowNodeWrapper,
registerShareableMapping,
} from '../shareables';

function getShareableShadowNodeFromComponent(
component: Component
): ShadowNodeWrapper {
return makeShareableShadowNodeWrapper(
getShadowNodeWrapperFromHostInstance(component)
);
return getShadowNodeWrapperFromHostInstance(component);
}

const getTagValueFunction = global._IS_FABRIC
Expand Down
24 changes: 15 additions & 9 deletions src/reanimated2/shareables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ const _shareableCache = new WeakMap<
// this is used to allow for a converted shareable to be passed to makeShareableClone
const _shareableFlag = Symbol('shareable flag');

const MAGIC_KEY = 'REANIMATED_MAGIC_KEY';

function isHostObject(value: any): boolean {
// We could use JSI to determine whether an object is a host object, however
// the below workaround works well and is way faster than an additional JSI call.
// We use the fact that host objects have broken implementation of `hasOwnProperty`
// and hence return true for all `in` checks regardless of the key we ask for.
return MAGIC_KEY in value;
}

export function registerShareableMapping(
shareable: any,
shareableRef?: ShareableRef<any>
Expand All @@ -27,15 +37,6 @@ export function registerShareableMapping(
_shareableCache.set(shareable, shareableRef || _shareableFlag);
}

export function makeShareableShadowNodeWrapper<T>(shadowNodeWrapper: T): T {
const adoptedSNW = NativeReanimatedModule.makeShareableClone(
shadowNodeWrapper,
false
);
registerShareableMapping(shadowNodeWrapper, adoptedSNW);
return shadowNodeWrapper;
}

export function makeShareableCloneRecursive<T>(
value: any,
shouldPersistRemote = false
Expand All @@ -58,6 +59,11 @@ export function makeShareableCloneRecursive<T>(
} else if (type === 'function' && value.__workletHash === undefined) {
// this is a remote function
toAdapt = value;
} else if (isHostObject(value)) {
// for host objects we pass the reference to the object as shareable and
// then recreate new host object wrapping the same instance on the UI thread.
// there is no point of iterating over keys as we do for regular objects.
toAdapt = value;
} else {
toAdapt = {};
if (value.__workletHash !== undefined) {
Expand Down

0 comments on commit f88ac36

Please sign in to comment.