From 73d57461229ebb398af769883bf994801943ceca Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Sun, 5 Aug 2018 16:36:09 -0700 Subject: [PATCH] Add `Unsafe` based storage backend Summary: @public Adds another version of property storage for `YogaNode`, using `sun.misc.Unsafe`. Adopts the stub concept from Litho for `Unsafe`, as it is hidden by the Android SDK. Reviewed By: pasqualeanatriello Differential Revision: D9140103 fbshipit-source-id: a4b376eca341b724a00f873467ae8bf8eaac69f4 --- ReactAndroid/BUCK | 7 + ReactAndroid/build.gradle | 1 + ReactAndroid/src/main/java/com/facebook/BUCK | 5 +- .../main/java/com/facebook/yoga/YogaNode.java | 7 + .../yoga/YogaNodePropertiesByteBuffer.java | 9 +- .../yoga/YogaNodePropertiesUnsafe.java | 580 ++++++++++++++++++ .../jni/first-party/yogajni/jni/YGJNI.cpp | 30 +- ReactAndroid/stubs/build.gradle | 10 + ReactAndroid/stubs/src/sun/misc/Unsafe.java | 27 + ReactNative/DEFS.bzl | 2 + build.gradle | 3 +- settings.gradle | 2 +- 12 files changed, 670 insertions(+), 13 deletions(-) create mode 100644 ReactAndroid/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesUnsafe.java create mode 100644 ReactAndroid/stubs/build.gradle create mode 100644 ReactAndroid/stubs/src/sun/misc/Unsafe.java diff --git a/ReactAndroid/BUCK b/ReactAndroid/BUCK new file mode 100644 index 000000000..079a6a9cf --- /dev/null +++ b/ReactAndroid/BUCK @@ -0,0 +1,7 @@ +load("//ReactNative:DEFS.bzl", "rn_android_library") + +rn_android_library( + name = "stubs", + srcs = glob(["stubs/src/**/*.java"]), + visibility = ["PUBLIC"], +) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index b05e61513..cdda93afb 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -305,6 +305,7 @@ dependencies { compile 'com.squareup.okhttp3:okhttp-urlconnection:3.10.0' compile 'com.squareup.okio:okio:1.14.0' compile 'org.webkit:android-jsc:r174650' + compileOnly project(':ReactAndroid:stubs') testCompile "junit:junit:${JUNIT_VERSION}" testCompile "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}" diff --git a/ReactAndroid/src/main/java/com/facebook/BUCK b/ReactAndroid/src/main/java/com/facebook/BUCK index bc03b864b..fc70f9fb3 100644 --- a/ReactAndroid/src/main/java/com/facebook/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/BUCK @@ -1,4 +1,4 @@ -load("//ReactNative:DEFS.bzl", "react_native_dep", "rn_android_library") +load("//ReactNative:DEFS.bzl", "react_native_dep", "rn_android_library", "JAVA_STUBS_TARGET") rn_android_library( name = "yoga", @@ -10,4 +10,7 @@ rn_android_library( react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), ], + provided_deps = [ + JAVA_STUBS_TARGET, + ] ) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 733053705..2924f0c39 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -23,6 +23,7 @@ public class YogaNode implements Cloneable { public static final int BYTE_BUFFER = 1; public static final int HYBRID = 2; + public static final int UNSAFE = 3; /** Get native instance count. Useful for testing only. */ static native int jni_YGNodeGetInstanceCount(); @@ -50,6 +51,9 @@ public class YogaNode implements Cloneable { case HYBRID: mDelegate = new YogaNodePropertiesHybrid(this); break; + case UNSAFE: + mDelegate = new YogaNodePropertiesUnsafe(this); + break; default: mDelegate = new YogaNodePropertiesJNI(this); } @@ -63,6 +67,9 @@ public class YogaNode implements Cloneable { case HYBRID: mDelegate = new YogaNodePropertiesHybrid(this, config); break; + case UNSAFE: + mDelegate = new YogaNodePropertiesUnsafe(this, config); + break; default: mDelegate = new YogaNodePropertiesJNI(this, config); } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesByteBuffer.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesByteBuffer.java index daca67dba..f189a5b41 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesByteBuffer.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesByteBuffer.java @@ -31,16 +31,16 @@ public class YogaNodePropertiesByteBuffer implements YogaNodeProperties, Cloneab private static native ByteBuffer jni_getLayoutBuffer(long nativePointer); - private static native long jni_YGNodeNewByteBuffer(YogaNode node); + private static native long jni_YGNodeNewNoProps(YogaNode node); public YogaNodePropertiesByteBuffer(YogaNode node) { - this(jni_YGNodeNewByteBuffer(node)); + this(jni_YGNodeNewNoProps(node)); } - private static native long jni_YGNodeNewByteBufferWithConfig(YogaNode node, long configPointer); + private static native long jni_YGNodeNewNoPropsWithConfig(YogaNode node, long configPointer); public YogaNodePropertiesByteBuffer(YogaNode node, YogaConfig config) { - this(jni_YGNodeNewByteBufferWithConfig(node, config.mNativePointer)); + this(jni_YGNodeNewNoPropsWithConfig(node, config.mNativePointer)); } public YogaNodePropertiesByteBuffer(long nativePointer) { @@ -84,6 +84,7 @@ public class YogaNodePropertiesByteBuffer implements YogaNodeProperties, Cloneab @Override public void reset() { mHasBorderSet = false; + mHasNewLayout = true; jni_YGNodeReset(getNativePointer()); } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesUnsafe.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesUnsafe.java new file mode 100644 index 000000000..f8af890b4 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodePropertiesUnsafe.java @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + * + */ +package com.facebook.yoga; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.soloader.SoLoader; +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +@DoNotStrip +public class YogaNodePropertiesUnsafe implements YogaNodeProperties { + + private static final int TRUE_BITS = 0x01000001; + private static final int FLOAT_SIZE = 4; + private static final int AUTO = YogaUnit.AUTO.intValue(); + private static final int POINT = YogaUnit.POINT.intValue(); + private static final int PERCENT = YogaUnit.PERCENT.intValue(); + private static final int UNDEFINED = YogaUnit.UNDEFINED.intValue(); + private static final int RTL = YogaDirection.RTL.intValue(); + private static final Unsafe UNSAFE; + + private final long mNativePointer; + private final long mStyleNativePointer; + private final long mLayoutNativePointer; + private boolean mHasBorderSet = false; + private boolean mHasNewLayout = true; + private boolean mIsFreed = false; + + static { + SoLoader.loadLibrary("yoga"); + Field instanceField = null; + try { + instanceField = Unsafe.class.getDeclaredField("theUnsafe"); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + instanceField.setAccessible(true); + try { + UNSAFE = (Unsafe) instanceField.get(null); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static native long jni_YGNodeNewNoProps(YogaNode node); + private static native long jni_YGNodeNewNoPropsWithConfig(YogaNode node, long configPointer); + private static native long jni_YGNodeStylePointer(long nativePointer); + private static native long jni_YGNodeLayoutPointer(long nativePointer); + + public YogaNodePropertiesUnsafe(YogaNode node) { + this(jni_YGNodeNewNoProps(node)); + } + + public YogaNodePropertiesUnsafe(YogaNode node, YogaConfig config) { + this(jni_YGNodeNewNoPropsWithConfig(node, config.mNativePointer)); + } + + public YogaNodePropertiesUnsafe(long nativePointer) { + mNativePointer = nativePointer; + mStyleNativePointer = jni_YGNodeStylePointer(nativePointer); + mLayoutNativePointer = jni_YGNodeLayoutPointer(nativePointer); + } + + private static native long jni_YGNodeCloneNoProps(long nativePointer, YogaNode newNode); + + @Override + public YogaNodeProperties clone(YogaNode node) { + long clonedNativePointer = jni_YGNodeCloneNoProps(getNativePointer(), node); + YogaNodePropertiesUnsafe clone = + new YogaNodePropertiesUnsafe(clonedNativePointer); + clone.mHasBorderSet = mHasBorderSet; + clone.mHasNewLayout = mHasNewLayout; + return clone; + } + + @Override + public long getNativePointer() { + return mNativePointer; + } + + @Override + public void onAfterCalculateLayout(boolean hasNewLayout) { + mHasNewLayout = hasNewLayout; + } + + private static native void jni_YGNodeReset(long nativePointer); + + @Override + public void reset() { + mHasNewLayout = true; + jni_YGNodeReset(getNativePointer()); + } + + @Override + public boolean hasNewLayout() { + return mHasNewLayout; + } + + private static native boolean jni_YGNodeIsDirty(long nativePointer); + + @Override + public boolean isDirty() { + return jni_YGNodeIsDirty(mNativePointer); + } + + @Override + public void markLayoutSeen() { + mHasNewLayout = false; + } + + @Override + public YogaDirection getStyleDirection() { + return YogaDirection.fromInt(getStyleInt(YogaNodeMemoryLayout.styleDirection)); + } + + @Override + public void setDirection(YogaDirection direction) { + putStyleInt(YogaNodeMemoryLayout.styleDirection, direction.intValue()); + } + + @Override + public YogaFlexDirection getFlexDirection() { + return YogaFlexDirection.fromInt(getStyleInt(YogaNodeMemoryLayout.styleFlexDirection)); + } + + @Override + public void setFlexDirection(YogaFlexDirection flexDirection) { + putStyleInt(YogaNodeMemoryLayout.styleFlexDirection, flexDirection.intValue()); + } + + @Override + public YogaJustify getJustifyContent() { + return YogaJustify.fromInt(getStyleInt(YogaNodeMemoryLayout.styleJustifyContent)); + } + + @Override + public void setJustifyContent(YogaJustify justifyContent) { + putStyleInt(YogaNodeMemoryLayout.styleJustifyContent, justifyContent.intValue()); + } + + @Override + public YogaAlign getAlignItems() { + return YogaAlign.fromInt(getStyleInt(YogaNodeMemoryLayout.styleAlignItems)); + } + + @Override + public void setAlignItems(YogaAlign alignItems) { + putStyleInt(YogaNodeMemoryLayout.styleAlignItems, alignItems.intValue()); + } + + @Override + public YogaAlign getAlignSelf() { + return YogaAlign.fromInt(getStyleInt(YogaNodeMemoryLayout.styleAlignSelf)); + } + + @Override + public void setAlignSelf(YogaAlign alignSelf) { + putStyleInt(YogaNodeMemoryLayout.styleAlignSelf, alignSelf.intValue()); + } + + @Override + public YogaAlign getAlignContent() { + return YogaAlign.fromInt(getStyleInt(YogaNodeMemoryLayout.styleAlignContent)); + } + + @Override + public void setAlignContent(YogaAlign alignContent) { + putStyleInt(YogaNodeMemoryLayout.styleAlignContent, alignContent.intValue()); + } + + @Override + public YogaPositionType getPositionType() { + return YogaPositionType.fromInt(getStyleInt(YogaNodeMemoryLayout.stylePositionType)); + } + + @Override + public void setPositionType(YogaPositionType positionType) { + putStyleInt(YogaNodeMemoryLayout.stylePositionType, positionType.intValue()); + } + + @Override + public void setWrap(YogaWrap flexWrap) { + putStyleInt(YogaNodeMemoryLayout.styleFlexWrap, flexWrap.intValue()); + } + + @Override + public YogaOverflow getOverflow() { + return YogaOverflow.fromInt(getStyleInt(YogaNodeMemoryLayout.styleOverflow)); + } + + @Override + public void setOverflow(YogaOverflow overflow) { + putStyleInt(YogaNodeMemoryLayout.styleOverflow, overflow.intValue()); + } + + @Override + public YogaDisplay getDisplay() { + return YogaDisplay.fromInt(getStyleInt(YogaNodeMemoryLayout.styleDisplay)); + } + + @Override + public void setDisplay(YogaDisplay display) { + putStyleInt(YogaNodeMemoryLayout.styleDisplay, display.intValue()); + } + + @Override + public void setFlex(float flex) { + putStyleOptional(YogaNodeMemoryLayout.styleFlex, flex); + } + + @Override + public float getFlexGrow() { + return getStyleFloat(YogaNodeMemoryLayout.styleFlexGrow); + } + + @Override + public void setFlexGrow(float flexGrow) { + putStyleOptional(YogaNodeMemoryLayout.styleFlexGrow, flexGrow); + } + + @Override + public float getFlexShrink() { + return getStyleFloat(YogaNodeMemoryLayout.styleFlexShrink); + } + + @Override + public void setFlexShrink(float flexShrink) { + putStyleOptional(YogaNodeMemoryLayout.styleFlexShrink, flexShrink); + } + + @Override + public YogaValue getFlexBasis() { + return getStyleValue(YogaNodeMemoryLayout.styleFlexBasis); + } + + @Override + public void setFlexBasis(float flexBasis) { + putStylePoints(YogaNodeMemoryLayout.styleFlexBasis, flexBasis); + } + + @Override + public void setFlexBasisPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleFlexBasis, percent); + } + + @Override + public void setFlexBasisAuto() { + putStyleAuto(YogaNodeMemoryLayout.styleFlexBasis); + } + + @Override + public YogaValue getMargin(YogaEdge edge) { + return getStyleValue(YogaNodeMemoryLayout.styleMarginOffset(edge)); + } + + @Override + public void setMargin(YogaEdge edge, float margin) { + putStylePoints(YogaNodeMemoryLayout.styleMarginOffset(edge), margin); + } + + @Override + public void setMarginPercent(YogaEdge edge, float percent) { + putStylePercent(YogaNodeMemoryLayout.styleMarginOffset(edge), percent); + } + + @Override + public void setMarginAuto(YogaEdge edge) { + putStyleAuto(YogaNodeMemoryLayout.styleMarginOffset(edge)); + } + + @Override + public YogaValue getPadding(YogaEdge edge) { + return getStyleValue(YogaNodeMemoryLayout.stylePaddingOffset(edge)); + } + + @Override + public void setPadding(YogaEdge edge, float padding) { + putStylePoints(YogaNodeMemoryLayout.stylePaddingOffset(edge), padding); + } + + @Override + public void setPaddingPercent(YogaEdge edge, float percent) { + putStylePercent(YogaNodeMemoryLayout.stylePaddingOffset(edge), percent); + } + + @Override + public float getBorder(YogaEdge edge) { + return mHasBorderSet + ? getStyleFloat(YogaNodeMemoryLayout.styleBorderOffset(edge)) + : YogaConstants.UNDEFINED; + } + + @Override + public void setBorder(YogaEdge edge, float border) { + mHasBorderSet = true; + putStylePoints(YogaNodeMemoryLayout.styleBorderOffset(edge), border); + } + + @Override + public YogaValue getPosition(YogaEdge edge) { + return getStyleValue(YogaNodeMemoryLayout.stylePositionOffset(edge)); + } + + @Override + public void setPosition(YogaEdge edge, float position) { + putStylePoints(YogaNodeMemoryLayout.stylePositionOffset(edge), position); + } + + @Override + public void setPositionPercent(YogaEdge edge, float percent) { + putStylePercent(YogaNodeMemoryLayout.stylePositionOffset(edge), percent); + } + + @Override + public YogaValue getWidth() { + return getStyleValue(YogaNodeMemoryLayout.styleWidth); + } + + @Override + public void setWidth(float width) { + putStylePoints(YogaNodeMemoryLayout.styleWidth, width); + } + + @Override + public void setWidthPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleWidth, percent); + } + + @Override + public void setWidthAuto() { + putStyleAuto(YogaNodeMemoryLayout.styleWidth); + } + + @Override + public YogaValue getHeight() { + return getStyleValue(YogaNodeMemoryLayout.styleHeight); + } + + @Override + public void setHeight(float height) { + putStylePoints(YogaNodeMemoryLayout.styleHeight, height); + } + + @Override + public void setHeightPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleHeight, percent); + } + + @Override + public void setHeightAuto() { + putStyleAuto(YogaNodeMemoryLayout.styleHeight); + } + + @Override + public YogaValue getMinWidth() { + return getStyleValue(YogaNodeMemoryLayout.styleMinWidth); + } + + @Override + public void setMinWidth(float minWidth) { + putStylePoints(YogaNodeMemoryLayout.styleMinWidth, minWidth); + } + + @Override + public void setMinWidthPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleMinWidth, percent); + } + + @Override + public YogaValue getMinHeight() { + return getStyleValue(YogaNodeMemoryLayout.styleMinHeight); + } + + @Override + public void setMinHeight(float minHeight) { + putStylePoints(YogaNodeMemoryLayout.styleMinHeight, minHeight); + } + + @Override + public void setMinHeightPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleMinHeight, percent); + } + + @Override + public YogaValue getMaxWidth() { + return getStyleValue(YogaNodeMemoryLayout.styleMaxWidth); + } + + @Override + public void setMaxWidth(float maxWidth) { + putStylePoints(YogaNodeMemoryLayout.styleMaxWidth, maxWidth); + } + + @Override + public void setMaxWidthPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleMaxWidth, percent); + } + + @Override + public YogaValue getMaxHeight() { + return getStyleValue(YogaNodeMemoryLayout.styleMaxHeight); + } + + @Override + public void setMaxHeight(float maxHeight) { + putStylePoints(YogaNodeMemoryLayout.styleMaxHeight, maxHeight); + } + + @Override + public void setMaxHeightPercent(float percent) { + putStylePercent(YogaNodeMemoryLayout.styleMaxHeight, percent); + } + + @Override + public float getAspectRatio() { + return getStyleOptional(YogaNodeMemoryLayout.styleAspectRatio); + } + + @Override + public void setAspectRatio(float aspectRatio) { + putStyleOptional(YogaNodeMemoryLayout.styleAspectRatio, aspectRatio); + } + + @Override + public float getLayoutX() { + return getLayoutFloat(YogaNodeMemoryLayout.layoutX); + } + + @Override + public float getLayoutY() { + return getLayoutFloat(YogaNodeMemoryLayout.layoutY); + } + + @Override + public float getLayoutWidth() { + return getLayoutFloat(YogaNodeMemoryLayout.layoutWidth); + } + + @Override + public float getLayoutHeight() { + return getLayoutFloat(YogaNodeMemoryLayout.layoutHeight); + } + + @Override + public boolean getDoesLegacyStretchFlagAffectsLayout() { + return getBool(mLayoutNativePointer + YogaNodeMemoryLayout.layoutDoesLegacyStretchFlagAffectsLayout); + } + + @Override + public float getLayoutMargin(YogaEdge edge) { + return getLayoutFloat(YogaNodeMemoryLayout.layoutMarginOffset(layoutEdge(edge))); + } + + @Override + public float getLayoutPadding(YogaEdge edge) { + return getLayoutFloat(YogaNodeMemoryLayout.layoutPaddingOffset(layoutEdge(edge))); + } + + @Override + public float getLayoutBorder(YogaEdge edge) { + return getLayoutFloat(YogaNodeMemoryLayout.layoutBorderOffset(layoutEdge(edge))); + } + + @Override + public YogaDirection getLayoutDirection() { + return YogaDirection.fromInt(getLayoutDirectionInt()); + } + + private static native void jni_YGNodeFree(long nativePointer); + + @Override + public void freeNatives() { + if (!mIsFreed) { + mIsFreed = true; + jni_YGNodeFree(mNativePointer); + } + } + + private int getLayoutDirectionInt() { + return UNSAFE.getInt(null, mLayoutNativePointer + YogaNodeMemoryLayout.layoutDirection); + } + + private YogaEdge layoutEdge(YogaEdge edge) { + int layoutDirection = getLayoutDirectionInt(); + switch (edge) { + case LEFT: + return layoutDirection == RTL ? YogaEdge.END : YogaEdge.START; + case RIGHT: + return layoutDirection == RTL ? YogaEdge.START : YogaEdge.END; + case TOP: + case BOTTOM: + case START: + case END: + return edge; + default: + throw new IllegalArgumentException("Cannot get layout properties of multi-edge shorthands"); + } + } + + private int getStyleInt(int offset) { + return UNSAFE.getInt(null, mStyleNativePointer + offset); + } + + private void putStyleInt(int offset, int value) { + UNSAFE.putInt(null, mStyleNativePointer + offset, value); + } + + private float getStyleFloat(int offset) { + return getFloat(mStyleNativePointer + offset); + } + + private void putStyleFloat(int offset, float value) { + putFloat(mStyleNativePointer + offset, value); + } + + private void putStylePoints(int offset, float value) { + putStyleValue(offset, value, POINT); + } + + private void putStylePercent(int offset, float value) { + putStyleValue(offset, value, PERCENT); + } + + private void putStyleAuto(int offset) { + putStyleValue(offset, 0, AUTO); + } + + private void putStyleValue(int offset, float value, int unit) { + if (YogaConstants.isUndefined(value)) { + value = YogaConstants.UNDEFINED; + unit = UNDEFINED; + } + putStyleFloat(offset, value); + putStyleInt(offset + FLOAT_SIZE, unit); + } + + private YogaValue getStyleValue(int offset) { + float value = getStyleFloat(offset); + int unit = getStyleInt(offset + FLOAT_SIZE); + return new YogaValue(value, YogaUnit.fromInt(unit)); + } + + private void putStyleOptional(int offset, float value) { + int isUndefinedBits = YogaConstants.isUndefined(value) ? TRUE_BITS : 0; + putStyleFloat(offset, value); + putStyleInt(offset + FLOAT_SIZE, isUndefinedBits); + } + + private float getStyleOptional(int offset) { + boolean isUndefined = getBool(mStyleNativePointer + offset + FLOAT_SIZE); + return isUndefined + ? YogaConstants.UNDEFINED + : getStyleFloat(offset); + } + + private float getLayoutFloat(int offset) { + return getFloat(mLayoutNativePointer + offset); + } + + private static float getFloat(long offset) { + int intBits = UNSAFE.getInt(null, offset); + return Float.intBitsToFloat(intBits); + } + + private static void putFloat(long offset, float value) { + int intBits = Float.floatToRawIntBits(value); + UNSAFE.putInt(null, offset, intBits); + } + + private static boolean getBool(long offset) { + // assumes little endian + return (UNSAFE.getInt(null, offset) & 0xFF) != 0; + } + +} diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 7f4dc0412..482c14aed 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -344,13 +344,11 @@ jlong jni_YGNodeNewWithConfig( return reinterpret_cast(node); } -jlong jni_YGNodeNewByteBuffer( - alias_ref, - alias_ref javaNode) { +jlong jni_YGNodeNewNoProps(alias_ref, alias_ref javaNode) { return jni_YGNodeNew(nullptr, javaNode); } -jlong jni_YGNodeNewByteBufferWithConfig( +jlong jni_YGNodeNewNoPropsWithConfig( alias_ref, alias_ref javaNode, jlong configPointer) { @@ -747,6 +745,14 @@ local_ref jni_getLayoutBuffer( reinterpret_cast(layout), sizeof(YGLayout)); } +jlong jni_YGNodeStylePointer(alias_ref, jlong nativePointer) { + return reinterpret_cast(&_jlong2YGNodeRef(nativePointer)->getStyle()); +} + +jlong jni_YGNodeLayoutPointer(alias_ref, jlong nativePointer) { + return reinterpret_cast(&_jlong2YGNodeRef(nativePointer)->getLayout()); +} + #define YGMakeNativeMethod(name) makeNativeMethod(#name, name) jint JNI_OnLoad(JavaVM* vm, void*) { @@ -860,8 +866,8 @@ jint JNI_OnLoad(JavaVM* vm, void*) { { YGMakeNativeMethod(jni_YGNodeCloneNoProps), YGMakeNativeMethod(jni_YGNodeFree), - YGMakeNativeMethod(jni_YGNodeNewByteBuffer), - YGMakeNativeMethod(jni_YGNodeNewByteBufferWithConfig), + YGMakeNativeMethod(jni_YGNodeNewNoProps), + YGMakeNativeMethod(jni_YGNodeNewNoPropsWithConfig), YGMakeNativeMethod(jni_YGNodeReset), YGMakeNativeMethod(jni_YGNodeIsDirty), YGMakeNativeMethod(jni_getStyleBuffer), @@ -872,5 +878,17 @@ jint JNI_OnLoad(JavaVM* vm, void*) { { YGMakeNativeMethod(jni_getStyleBuffer), }); + registerNatives( + "com/facebook/yoga/YogaNodePropertiesUnsafe", + { + YGMakeNativeMethod(jni_YGNodeCloneNoProps), + YGMakeNativeMethod(jni_YGNodeFree), + YGMakeNativeMethod(jni_YGNodeNewNoProps), + YGMakeNativeMethod(jni_YGNodeNewNoPropsWithConfig), + YGMakeNativeMethod(jni_YGNodeStylePointer), + YGMakeNativeMethod(jni_YGNodeLayoutPointer), + YGMakeNativeMethod(jni_YGNodeIsDirty), + YGMakeNativeMethod(jni_YGNodeReset), + }); }); } diff --git a/ReactAndroid/stubs/build.gradle b/ReactAndroid/stubs/build.gradle new file mode 100644 index 000000000..f2faa4464 --- /dev/null +++ b/ReactAndroid/stubs/build.gradle @@ -0,0 +1,10 @@ +apply plugin: 'java' + +sourceSets { + main { + java { + srcDirs = ['src'] + } + } +} + diff --git a/ReactAndroid/stubs/src/sun/misc/Unsafe.java b/ReactAndroid/stubs/src/sun/misc/Unsafe.java new file mode 100644 index 000000000..01ff08dc8 --- /dev/null +++ b/ReactAndroid/stubs/src/sun/misc/Unsafe.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + * + */ + +package sun.misc; + +/** + * Stub for sun.misc.Unsafe, which is not exposed by the Android SDK. + * + * This only contains the methods and fields we need for Yoga. + */ +public final class Unsafe { + private static final Unsafe theUnsafe = null; + + public final int getInt(Object object, long offset) { + throw new RuntimeException("Stub!"); + } + + public final void putInt(Object object, long offset, int value) { + throw new RuntimeException("Stub!"); + } +} + diff --git a/ReactNative/DEFS.bzl b/ReactNative/DEFS.bzl index 1f50344f6..a54788fe1 100644 --- a/ReactNative/DEFS.bzl +++ b/ReactNative/DEFS.bzl @@ -271,3 +271,5 @@ def jni_instrumentation_test_lib(**kwargs): def fb_xplat_cxx_test(**kwargs): """A noop stub for OSS build.""" pass + +JAVA_STUBS_TARGET = "//ReactAndroid:stubs" diff --git a/build.gradle b/build.gradle index 71634a0cb..0b249a64d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ buildscript { repositories { jcenter() + google() mavenLocal() maven { url 'https://maven.google.com/' @@ -13,7 +14,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.0.0' classpath 'de.undercouch:gradle-download-task:3.4.3' // NOTE: Do not place your application dependencies here; they belong diff --git a/settings.gradle b/settings.gradle index c68c5a20f..82bef34dc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,4 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. -include ':ReactAndroid', ':RNTester:android:app' +include ':ReactAndroid', ':RNTester:android:app', ':ReactAndroid:stubs'