Move Fabric JSC bindings to oss

Reviewed By: mdvacca

Differential Revision: D7205065

fbshipit-source-id: 5876cb3e08ee96e39b80e6b377c60600f404ca21
This commit is contained in:
Andrew Chen (Eng) 2018-03-14 11:31:27 -07:00 committed by Facebook Github Bot
parent bec97dc243
commit 3a2bdf5c50
6 changed files with 416 additions and 0 deletions

View File

@ -0,0 +1,24 @@
load("@xplat//ReactNative:DEFS.bzl", "react_native_dep", "react_native_target", "rn_android_library", "IS_OSS_BUILD")
rn_android_library(
name = "jsc",
srcs = glob(["**/*.java"]),
exported_deps = [
react_native_dep("java/com/facebook/jni:jni"),
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
],
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
],
required_for_source_only_abi = True,
visibility = [
"PUBLIC",
],
deps = [
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/fabric:fabric"),
react_native_target("java/com/facebook/react/fabric/jsc/jni:jni"),
],
)

View File

@ -0,0 +1,35 @@
// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react.fabric.jsc;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.fabric.FabricBinding;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.soloader.SoLoader;
@DoNotStrip
public class FabricJSCBinding implements FabricBinding {
static {
SoLoader.loadLibrary("fabricjscjni");
}
// used from native
@SuppressWarnings("unused")
private final HybridData mHybridData;
private static native HybridData initHybrid();
private native void installFabric(long jsContextNativePointer, Object fabricModule);
public FabricJSCBinding() {
mHybridData = initHybrid();
}
@Override
public void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule) {
installFabric(jsContext.get(), fabricModule);
}
}

View File

@ -0,0 +1,20 @@
load("@xplat//ReactNative:DEFS.bzl", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "FBJNI_TARGET", "ANDROID")
rn_xplat_cxx_library(
name = "jni",
srcs = glob(["*.cpp"]),
headers = glob(["*.h"]),
compiler_flags = [
"-Wall",
"-fexceptions",
"-std=gnu++1y",
],
platforms = ANDROID,
soname = "libfabricjscjni.$(ext)",
visibility = ["PUBLIC"],
deps = [
FBJNI_TARGET,
react_native_xplat_target("jschelpers:jschelpers"),
react_native_target("jni/react/jni:jni"),
],
)

View File

@ -0,0 +1,296 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "FabricJSCBinding.h"
#include <fb/fbjni.h>
#include <react/jni/ReadableNativeMap.h>
#include <jschelpers/JavaScriptCore.h>
#include <jschelpers/Unicode.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
namespace {
bool useCustomJSC = false;
struct JList : public JavaClass<JList> {
static constexpr auto kJavaDescriptor = "Ljava/util/List;";
};
struct JShadowNode : public JavaClass<JShadowNode> {
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/uimanager/ReactShadowNode;";
};
typedef struct FabricJSCUIManager {
FabricJSCUIManager(alias_ref<jobject> module, JSClassRef classRef, bool customJSC)
: wrapperObjectClassRef(classRef)
, useCustomJSC(customJSC) {
fabricUiManager = make_global(module);
}
global_ref<jobject> fabricUiManager;
JSClassRef wrapperObjectClassRef;
bool useCustomJSC;
} FabricJSCUIManager;
jobject makePlainGlobalRef(jobject object) {
// When storing the global reference we need it to be a plain
// pointer. That's why we use plain jni instead of fbjni here.
return Environment::current()->NewGlobalRef(object);
}
local_ref<JString> JSValueToJString(JSContextRef ctx, JSValueRef value) {
JSStringRef strRef = JSC_JSValueToStringCopy(ctx, value, NULL);
const size_t size = JSStringGetMaximumUTF8CStringSize(strRef);
char buffer[size];
JSStringGetUTF8CString(strRef, buffer, size);
JSC_JSStringRelease(ctx, strRef);
return make_jstring(buffer);
}
local_ref<JShadowNode> JSValueToJShadowNode(JSContextRef ctx, JSValueRef value) {
JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL);
auto node = static_cast<JShadowNode::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj));
return make_local(node);
}
local_ref<JList> JSValueToJList(JSContextRef ctx, JSValueRef value) {
JSObjectRef obj = JSC_JSValueToObject(ctx, value, NULL);
auto node = static_cast<JList::javaobject>(JSC_JSObjectGetPrivate(useCustomJSC, obj));
return make_local(node);
}
local_ref<ReadableNativeMap::jhybridobject> JSValueToReadableMapViaJSON(JSContextRef ctx, JSValueRef value) {
JSStringRef jsonRef = JSC_JSValueCreateJSONString(ctx, value, 0, NULL);
size_t size = JSC_JSStringGetLength(ctx, jsonRef);
const JSChar* utf16 = JSC_JSStringGetCharactersPtr(ctx, jsonRef);
std::string json = unicode::utf16toUTF8(utf16, size);
JSC_JSStringRelease(ctx, jsonRef);
folly::dynamic dynamicValue = folly::parseJson(json);
return ReadableNativeMap::newObjectCxxArgs(std::move(dynamicValue));
}
JSValueRef createNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
static auto createNode =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<alias_ref<JShadowNode>(jint, jstring, jint, ReadableNativeMap::javaobject)>("createNode");
int reactTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
auto viewName = JSValueToJString(ctx, arguments[1]);
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[2], NULL);
auto props = JSC_JSValueIsNull(ctx, arguments[3]) ? local_ref<ReadableNativeMap::jhybridobject>(nullptr) :
JSValueToReadableMapViaJSON(ctx, arguments[3]);;
// TODO: Retain object in arguments[4] using a weak ref.
auto node = createNode(manager, reactTag, viewName.get(), rootTag, props.get());
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(node.get()));
}
JSValueRef cloneNode(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
static auto cloneNode =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNode");
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
auto newNode = cloneNode(manager, previousNode.get());
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
}
JSValueRef cloneNodeWithNewChildren(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
static auto cloneNodeWithNewChildren =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject)>("cloneNodeWithNewChildren");
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
auto newNode = cloneNodeWithNewChildren(manager, previousNode.get());
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
}
JSValueRef cloneNodeWithNewProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
static auto cloneNodeWithNewProps =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewProps");
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]);
auto newNode = cloneNodeWithNewProps(manager, previousNode.get(), props.get());
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
}
JSValueRef cloneNodeWithNewChildrenAndProps(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
static auto cloneNodeWithNewChildrenAndProps =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<alias_ref<JShadowNode>(JShadowNode::javaobject, ReadableNativeMap::javaobject)>("cloneNodeWithNewChildrenAndProps");
auto previousNode = JSValueToJShadowNode(ctx, arguments[0]);
auto props = JSValueToReadableMapViaJSON(ctx, arguments[1]);
auto newNode = cloneNodeWithNewChildrenAndProps(manager, previousNode.get(), props.get());
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(newNode.get()));
}
JSValueRef appendChild(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
static auto appendChild =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<void(JShadowNode::javaobject, JShadowNode::javaobject)>("appendChild");
auto parentNode = JSValueToJShadowNode(ctx, arguments[0]);
auto childNode = JSValueToJShadowNode(ctx, arguments[1]);
appendChild(manager, parentNode.get(), childNode.get());
return JSC_JSValueMakeUndefined(ctx);
}
JSValueRef createChildSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
JSClassRef classRef = managerWrapper->wrapperObjectClassRef;
static auto createChildSet =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<alias_ref<JList>(jint)>("createChildSet");
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
auto childSet = createChildSet(manager, rootTag);
return JSC_JSObjectMake(ctx, classRef, makePlainGlobalRef(childSet.get()));
}
JSValueRef appendChildToSet(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
static auto appendChildToSet =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<void(JList::javaobject, JShadowNode::javaobject)>("appendChildToSet");
auto childSet = JSValueToJList(ctx, arguments[0]);
auto childNode = JSValueToJShadowNode(ctx, arguments[1]);
appendChildToSet(manager, childSet.get(), childNode.get());
return JSC_JSValueMakeUndefined(ctx);
}
JSValueRef completeRoot(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, function);
alias_ref<jobject> manager = managerWrapper->fabricUiManager;
static auto completeRoot =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
->getMethod<void(jint, JList::javaobject)>("completeRoot");
int rootTag = (int)JSC_JSValueToNumber(ctx, arguments[0], NULL);
auto childSet = JSValueToJList(ctx, arguments[1]);
completeRoot(manager, rootTag, childSet.get());
return JSC_JSValueMakeUndefined(ctx);
}
void finalizeJNIObject(JSObjectRef object) {
// Release whatever global ref object we're storing here.
jobject globalRef = (jobject)JSC_JSObjectGetPrivate(useCustomJSC, object);
Environment::current()->DeleteGlobalRef(globalRef);
}
void finalizeWrapper(JSObjectRef object) {
FabricJSCUIManager *managerWrapper = (FabricJSCUIManager *)JSC_JSObjectGetPrivate(useCustomJSC, object);
delete managerWrapper;
}
void addFabricMethod(
JSContextRef context,
jni::alias_ref<jobject> fabricModule,
JSClassRef nodeClassRef,
JSObjectRef module,
const char *name,
JSObjectCallAsFunctionCallback callback
) {
JSClassDefinition definition = kJSClassDefinitionEmpty;
definition.callAsFunction = callback;
definition.finalize = finalizeWrapper;
JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition);
FabricJSCUIManager *managerWrapper = new FabricJSCUIManager(fabricModule, nodeClassRef, useCustomJSC);
JSObjectRef functionRef = JSC_JSObjectMake(context, classRef, managerWrapper);
JSC_JSClassRelease(useCustomJSC, classRef);
JSStringRef nameStr = JSC_JSStringCreateWithUTF8CString(context, name);
JSC_JSObjectSetProperty(context, module, nameStr, functionRef, kJSPropertyAttributeNone, NULL);
JSC_JSStringRelease(context, nameStr);
}
}
jni::local_ref<FabricJSCBinding::jhybriddata> FabricJSCBinding::initHybrid(
jni::alias_ref<jclass>) {
return makeCxxInstance();
}
void FabricJSCBinding::installFabric(jlong jsContextNativePointer,
jni::alias_ref<jobject> fabricModule) {
JSContextRef context = (JSContextRef)jsContextNativePointer;
useCustomJSC = facebook::react::isCustomJSCPtr(context);
JSObjectRef module = JSC_JSObjectMake(context, NULL, NULL);
// Class definition for wrapper objects around nodes and sets
JSClassDefinition definition = kJSClassDefinitionEmpty;
definition.finalize = finalizeJNIObject;
JSClassRef classRef = JSC_JSClassCreate(useCustomJSC, &definition);
addFabricMethod(context, fabricModule, classRef, module, "createNode", createNode);
addFabricMethod(context, fabricModule, classRef, module, "cloneNode", cloneNode);
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildren", cloneNodeWithNewChildren);
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewProps", cloneNodeWithNewProps);
addFabricMethod(context, fabricModule, classRef, module, "cloneNodeWithNewChildrenAndProps", cloneNodeWithNewChildrenAndProps);
addFabricMethod(context, fabricModule, classRef, module, "appendChild", appendChild);
addFabricMethod(context, fabricModule, classRef, module, "createChildSet", createChildSet);
addFabricMethod(context, fabricModule, classRef, module, "appendChildToSet", appendChildToSet);
addFabricMethod(context, fabricModule, classRef, module, "completeRoot", completeRoot);
JSObjectRef globalObject = JSC_JSContextGetGlobalObject(context);
JSStringRef globalName = JSC_JSStringCreateWithUTF8CString(context, "nativeFabricUIManager");
JSC_JSObjectSetProperty(context, globalObject, globalName, module, kJSPropertyAttributeNone, NULL);
JSC_JSStringRelease(context, globalName);
}
void FabricJSCBinding::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", FabricJSCBinding::initHybrid),
makeNativeMethod("installFabric", FabricJSCBinding::installFabric),
});
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <memory>
#include <fb/fbjni.h>
namespace facebook {
namespace react {
class Instance;
class FabricJSCBinding : public jni::HybridClass<FabricJSCBinding> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/jsc/FabricJSCBinding;";
static void registerNatives();
private:
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
void installFabric(jlong jsContextNativePointer, jni::alias_ref<jobject> fabricModule);
};
}
}

View File

@ -0,0 +1,12 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <fb/fbjni.h>
#include <fb/xplat_init.h>
#include "FabricJSCBinding.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::xplat::initialize(vm, [] {
facebook::react::FabricJSCBinding::registerNatives();
});
}