Skip to content

Commit 3a2bdf5

Browse files
ayc1facebook-github-bot
authored andcommitted
Move Fabric JSC bindings to oss
Reviewed By: mdvacca Differential Revision: D7205065 fbshipit-source-id: 5876cb3e08ee96e39b80e6b377c60600f404ca21
1 parent bec97dc commit 3a2bdf5

File tree

6 files changed

+416
-0
lines changed

6 files changed

+416
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
load("@xplat//ReactNative:DEFS.bzl", "react_native_dep", "react_native_target", "rn_android_library", "IS_OSS_BUILD")
2+
3+
rn_android_library(
4+
name = "jsc",
5+
srcs = glob(["**/*.java"]),
6+
exported_deps = [
7+
react_native_dep("java/com/facebook/jni:jni"),
8+
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
9+
],
10+
provided_deps = [
11+
react_native_dep("third-party/android/support/v4:lib-support-v4"),
12+
],
13+
required_for_source_only_abi = True,
14+
visibility = [
15+
"PUBLIC",
16+
],
17+
deps = [
18+
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
19+
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
20+
react_native_target("java/com/facebook/react/bridge:bridge"),
21+
react_native_target("java/com/facebook/react/fabric:fabric"),
22+
react_native_target("java/com/facebook/react/fabric/jsc/jni:jni"),
23+
],
24+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2004-present Facebook. All Rights Reserved.
2+
3+
package com.facebook.react.fabric.jsc;
4+
5+
import com.facebook.jni.HybridData;
6+
import com.facebook.proguard.annotations.DoNotStrip;
7+
import com.facebook.react.bridge.JavaScriptContextHolder;
8+
import com.facebook.react.fabric.FabricBinding;
9+
import com.facebook.react.fabric.FabricUIManager;
10+
import com.facebook.soloader.SoLoader;
11+
12+
@DoNotStrip
13+
public class FabricJSCBinding implements FabricBinding {
14+
15+
static {
16+
SoLoader.loadLibrary("fabricjscjni");
17+
}
18+
19+
// used from native
20+
@SuppressWarnings("unused")
21+
private final HybridData mHybridData;
22+
23+
private static native HybridData initHybrid();
24+
25+
private native void installFabric(long jsContextNativePointer, Object fabricModule);
26+
27+
public FabricJSCBinding() {
28+
mHybridData = initHybrid();
29+
}
30+
31+
@Override
32+
public void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule) {
33+
installFabric(jsContext.get(), fabricModule);
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
load("@xplat//ReactNative:DEFS.bzl", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID")
2+
3+
rn_xplat_cxx_library(
4+
name = "jni",
5+
srcs = glob(["*.cpp"]),
6+
headers = glob(["*.h"]),
7+
compiler_flags = [
8+
"-Wall",
9+
"-fexceptions",
10+
"-std=gnu++1y",
11+
],
12+
platforms = ANDROID,
13+
soname = "libfabricjscjni.$(ext)",
14+
visibility = ["PUBLIC"],
15+
deps = [
16+
FBJNI_TARGET,
17+
react_native_xplat_target("jschelpers:jschelpers"),
18+
react_native_target("jni/react/jni:jni"),
19+
],
20+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
// Copyright 2004-present Facebook. All Rights Reserved.
2+
3+
#include "FabricJSCBinding.h"
4+
#include <fb/fbjni.h>
5+
#include <react/jni/ReadableNativeMap.h>
6+
#include <jschelpers/JavaScriptCore.h>
7+
#include <jschelpers/Unicode.h>
8+
9+
using namespace facebook::jni;
10+
11+
namespace facebook {
12+
namespace react {
13+
14+
namespace {
15+
16+
bool useCustomJSC = false;
17+
18+
struct JList : public JavaClass<JList> {
19+
static constexpr auto kJavaDescriptor = "Ljava/util/List;";
20+
};
21+
22+
struct JShadowNode : public JavaClass<JShadowNode> {
23+
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/uimanager/ReactShadowNode;";
24+
};
25+
26+
typedef struct FabricJSCUIManager {
27+
FabricJSCUIManager(alias_ref<jobject> module, JSClassRef classRef, bool customJSC)
28+
: wrapperObjectClassRef(classRef)
29+
, useCustomJSC(customJSC) {
30+
fabricUiManager = make_global(module);
31+
}
32+
global_ref<jobject> fabricUiManager;
33+
JSClassRef wrapperObjectClassRef;
34+
bool useCustomJSC;
35+
} FabricJSCUIManager;
36+
37+
jobject makePlainGlobalRef(jobject object) {
38+
// When storing the global reference we need it to be a plain
39+
// pointer. That's why we use plain jni instead of fbjni here.
40+
return Environment::current()->NewGlobalRef(object);
41+
}
42+
43+
local_ref<JString> JSValueToJString(JSContextRef ctx, JSValueRef value) {
44+
JSStringRef strRef = JSC_JSValueToStringCopy(ctx, value, NULL);
45+
const size_t size = JSStringGetMaximumUTF8CStringSize(strRef);
46+
char buffer[size];
47+
JSStringGetUTF8CString(strRef, buffer, size);
48+
JSC_JSStringRelease(ctx, strRef);
49+
return make_jstring(buffer);
50+
}
51+
52+
local_ref<JShadowNode> JSValueToJShadowNode(JSContextRef ctx, JSValueRef value) {
53+
JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL);
54+
auto node = static_cast<JShadowNode::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj));
55+
return make_local(node);
56+
}
57+
58+
local_ref<JList> JSValueToJList(JSContextRef ctx, JSValueRef value) {
59+
JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL);
60+
auto node = static_cast<JList::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj));
61+
return make_local(node);
62+
}
63+
64+
local_ref<ReadableNativeMap::jhybridobject> JSValueToReadableMapViaJSON(JSContextRef ctx, JSValueRef value) {
65+
JSStringRef jsonRef = JSC_JSValueCreateJSONString(ctx, value, 0, NULL);
66+
size_t size = JSC_JSStringGetLength(ctx, jsonRef);
67+
const JSChar* utf16 = JSC_JSStringGetCharactersPtr(ctx, jsonRef);
68+
std::string json = unicode::utf16toUTF8(utf16, size);
69+
JSC_JSStringRelease(ctx, jsonRef);
70+
folly::dynamic dynamicValue = folly::parseJson(json);
71+
return ReadableNativeMap::newObjectCxxArgs(std::move(dynamicValue));
72+
}
73+
74+
JSValueRef createNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
75+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
76+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
77+
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
78+
79+
static auto createNode =
80+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
81+
->getMethod<alias_ref<JShadowNode>(jint, jstring, jint, ReadableNativeMap::javaobject)>("createNode");
82+
83+
int reactTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
84+
auto viewName = JSValueToJString(ctx, arguments[1]);
85+
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[2], NULL);
86+
auto props = JSC_JSValueIsNull(ctx, arguments[3]) ? local_ref<ReadableNativeMap::jhybridobject>(nullptr) :
87+
JSValueToReadableMapViaJSON(ctx, arguments[3]);;
88+
89+
// TODO: Retain object in arguments[4] using a weak ref.
90+
91+
auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get());
92+
93+
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(node.get()));
94+
}
95+
96+
JSValueRef cloneNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
97+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
98+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
99+
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
100+
101+
static auto cloneNode =
102+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
103+
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNode");
104+
105+
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
106+
auto newNode = cloneNode(manager, previousNode.get());
107+
108+
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
109+
}
110+
111+
JSValueRef cloneNodeWithNewChildren(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
112+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
113+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
114+
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
115+
116+
static auto cloneNodeWithNewChildren =
117+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
118+
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNodeWithNewChildren");
119+
120+
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
121+
auto newNode = cloneNodeWithNewChildren(manager, previousNode.get());
122+
123+
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
124+
}
125+
126+
JSValueRef cloneNodeWithNewProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
127+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
128+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
129+
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
130+
131+
static auto cloneNodeWithNewProps =
132+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
133+
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewProps");
134+
135+
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
136+
auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]);
137+
auto newNode = cloneNodeWithNewProps(manager, previousNode.get(), props.get());
138+
139+
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
140+
}
141+
142+
JSValueRef cloneNodeWithNewChildrenAndProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
143+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
144+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
145+
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
146+
147+
static auto cloneNodeWithNewChildrenAndProps =
148+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
149+
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewChildrenAndProps");
150+
151+
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
152+
auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]);
153+
auto newNode = cloneNodeWithNewChildrenAndProps(manager, previousNode.get(), props.get());
154+
155+
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
156+
}
157+
158+
JSValueRef appendChild(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
159+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
160+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
161+
162+
static auto appendChild =
163+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
164+
->getMethod<void(JShadowNode::javaobject, JShadowNode::javaobject)>("appendChild");
165+
166+
auto parentNode = JSValueToJShadowNode(ctx, arguments[0]);
167+
auto childNode = JSValueToJShadowNode(ctx, arguments[1]);
168+
169+
appendChild(manager, parentNode.get(), childNode.get());
170+
171+
return JSC_JSValueMakeUndefined(ctx);
172+
}
173+
174+
JSValueRef createChildSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
175+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
176+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
177+
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
178+
179+
static auto createChildSet =
180+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
181+
->getMethod<alias_ref<JList>(jint)>("createChildSet");
182+
183+
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
184+
auto childSet = createChildSet(manager, rootTag);
185+
186+
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(childSet.get()));
187+
}
188+
189+
JSValueRef appendChildToSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
190+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
191+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
192+
193+
static auto appendChildToSet =
194+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
195+
->getMethod<void(JList::javaobject, JShadowNode::javaobject)>("appendChildToSet");
196+
197+
auto childSet = JSValueToJList(ctx, arguments[0]);
198+
auto childNode = JSValueToJShadowNode(ctx, arguments[1]);
199+
200+
appendChildToSet(manager, childSet.get(), childNode.get());
201+
202+
return JSC_JSValueMakeUndefined(ctx);
203+
}
204+
205+
JSValueRef completeRoot(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
206+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
207+
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
208+
209+
static auto completeRoot =
210+
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
211+
->getMethod<void(jint, JList::javaobject)>("completeRoot");
212+
213+
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
214+
auto childSet = JSValueToJList(ctx, arguments[1]);
215+
216+
completeRoot(manager, rootTag, childSet.get());
217+
218+
return JSC_JSValueMakeUndefined(ctx);
219+
}
220+
221+
void finalizeJNIObject(JSObjectRef object) {
222+
// Release whatever global ref object we're storing here.
223+
jobject globalRef = (jobject)JSC_JSObjectGetPrivate(useCustomJSC, object);
224+
Environment::current()->DeleteGlobalRef(globalRef);
225+
}
226+
227+
void finalizeWrapper(JSObjectRef object) {
228+
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, object);
229+
delete managerWrapper;
230+
}
231+
232+
void addFabricMethod(
233+
JSContextRef context,
234+
jni::alias_ref<jobject> fabricModule,
235+
JSClassRef nodeClassRef,
236+
JSObjectRef module,
237+
const char *name,
238+
JSObjectCallAsFunctionCallback callback
239+
) {
240+
JSClassDefinition definition = kJSClassDefinitionEmpty;
241+
definition.callAsFunction = callback;
242+
definition.finalize = finalizeWrapper;
243+
JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition);
244+
FabricJSCUIManager *managerWrapper = new FabricJSCUIManager(fabricModule, nodeClassRef, useCustomJSC);
245+
JSObjectRef functionRef = JSC_JSObjectMake(context, classRef, managerWrapper);
246+
JSC_JSClassRelease(useCustomJSC, classRef);
247+
248+
JSStringRef nameStr = JSC_JSStringCreateWithUTF8CString(context, name);
249+
JSC_JSObjectSetProperty(context, module, nameStr, functionRef, kJSPropertyAttributeNone, NULL);
250+
JSC_JSStringRelease(context, nameStr);
251+
}
252+
253+
}
254+
255+
jni::local_ref<FabricJSCBinding::jhybriddata> FabricJSCBinding::initHybrid(
256+
jni::alias_ref<jclass>) {
257+
return makeCxxInstance();
258+
}
259+
260+
void FabricJSCBinding::installFabric(jlong jsContextNativePointer,
261+
jni::alias_ref<jobject> fabricModule) {
262+
JSContextRef context = (JSContextRef)jsContextNativePointer;
263+
useCustomJSC = facebook::react::isCustomJSCPtr(context);
264+
265+
JSObjectRef module = JSC_JSObjectMake(context, NULL, NULL);
266+
267+
// Class definition for wrapper objects around nodes and sets
268+
JSClassDefinition definition = kJSClassDefinitionEmpty;
269+
definition.finalize = finalizeJNIObject;
270+
JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition);
271+
272+
addFabricMethod(context, fabricModule, classRef, module, "createNode", createNode);
273+
addFabricMethod(context, fabricModule, classRef, module, "cloneNode", cloneNode);
274+
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildren", cloneNodeWithNewChildren);
275+
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewProps", cloneNodeWithNewProps);
276+
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildrenAndProps", cloneNodeWithNewChildrenAndProps);
277+
addFabricMethod(context, fabricModule, classRef, module, "appendChild", appendChild);
278+
addFabricMethod(context, fabricModule, classRef, module, "createChildSet", createChildSet);
279+
addFabricMethod(context, fabricModule, classRef, module, "appendChildToSet", appendChildToSet);
280+
addFabricMethod(context, fabricModule, classRef, module, "completeRoot", completeRoot);
281+
282+
JSObjectRef globalObject = JSC_JSContextGetGlobalObject(context);
283+
JSStringRef globalName = JSC_JSStringCreateWithUTF8CString(context, "nativeFabricUIManager");
284+
JSC_JSObjectSetProperty(context, globalObject, globalName, module, kJSPropertyAttributeNone, NULL);
285+
JSC_JSStringRelease(context, globalName);
286+
}
287+
288+
void FabricJSCBinding::registerNatives() {
289+
registerHybrid({
290+
makeNativeMethod("initHybrid", FabricJSCBinding::initHybrid),
291+
makeNativeMethod("installFabric", FabricJSCBinding::installFabric),
292+
});
293+
}
294+
295+
}
296+
}

0 commit comments

Comments
 (0)