Bug 1459297 - Use SDK JNI calls for boxing/unboxing GeckoBundle values; r=snorp

Instead of the helper methods in GeckoBundle, add SDK JNI calls for the
boxing/unboxing operations, and use those calls directly. Moreover, for
unboxing Boolean/Double/Integer, use their internal "value" field value
directly if possible, to avoid making a JNI method call.

MozReview-Commit-ID: Azvov1gCeje

--HG--
extra : rebase_source : 34cd4a821d2b47e48957f241bbf165439635be59
This commit is contained in:
Jim Chen 2018-05-07 10:05:56 -04:00
Родитель a2a7ef293f
Коммит 8f6ba7ef0c
4 изменённых файлов: 71 добавлений и 26 удалений

Просмотреть файл

@ -40,21 +40,6 @@ public final class GeckoBundle implements Parcelable {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final GeckoBundle[] EMPTY_BUNDLE_ARRAY = new GeckoBundle[0];
@WrapForJNI(calledFrom = "gecko")
private static Object box(boolean b) { return b; }
@WrapForJNI(calledFrom = "gecko")
private static Object box(int i) { return i; }
@WrapForJNI(calledFrom = "gecko")
private static Object box(double d) { return d; }
@WrapForJNI(calledFrom = "gecko")
private static boolean unboxBoolean(Boolean b) { return b; }
@WrapForJNI(calledFrom = "gecko")
private static int unboxInteger(Number i) { return i.intValue(); }
@WrapForJNI(calledFrom = "gecko")
private static double unboxDouble(Number d) { return d.doubleValue(); }
@WrapForJNI(calledFrom = "gecko")
private static String unboxString(Object s) { return s.toString(); }
private SimpleArrayMap<String, Object> mMap;
/**

Просмотреть файл

@ -6,6 +6,7 @@
#include "EventDispatcher.h"
#include "JavaBuiltins.h"
#include "nsAppShell.h"
#include "nsIXPConnect.h"
#include "nsJSUtils.h"
@ -272,11 +273,12 @@ BoxValue(JSContext* aCx, JS::HandleValue aData, jni::Object::LocalRef& aOut)
if (aData.isNullOrUndefined()) {
aOut = nullptr;
} else if (aData.isBoolean()) {
aOut = java::GeckoBundle::Box(aData.toBoolean());
aOut = aData.toBoolean() ? java::sdk::Boolean::TRUE()
: java::sdk::Boolean::FALSE();
} else if (aData.isInt32()) {
aOut = java::GeckoBundle::Box(aData.toInt32());
aOut = java::sdk::Integer::ValueOf(aData.toInt32());
} else if (aData.isNumber()) {
aOut = java::GeckoBundle::Box(aData.toNumber());
aOut = java::sdk::Double::New(aData.toNumber());
} else if (aData.isString()) {
return BoxString(aCx, aData, aOut);
} else if (aData.isObject()) {
@ -480,26 +482,61 @@ UnboxArrayObject(JSContext* aCx, const jni::Object::LocalRef& aData,
return NS_OK;
}
template<class T> jfieldID
GetValueFieldID(const char* aType)
{
MOZ_ASSERT(NS_IsMainThread());
JNIEnv* const env = jni::GetGeckoThreadEnv();
const jfieldID id = env->GetFieldID(
typename T::Context(env, nullptr).ClassRef(), "value", aType);
env->ExceptionClear();
return id;
}
nsresult
UnboxValue(JSContext* aCx, const jni::Object::LocalRef& aData,
JS::MutableHandleValue aOut)
{
static jfieldID booleanValueField =
GetValueFieldID<java::sdk::Boolean>("Z");
static jfieldID intValueField = GetValueFieldID<java::sdk::Integer>("I");
static jfieldID doubleValueField = GetValueFieldID<java::sdk::Double>("D");
if (!aData) {
aOut.setNull();
} else if (aData.IsInstanceOf<jni::Boolean>()) {
aOut.setBoolean(java::GeckoBundle::UnboxBoolean(aData));
} else if (aData.IsInstanceOf<jni::Integer>() ||
aData.IsInstanceOf<jni::Byte>() ||
if (booleanValueField) {
aOut.setBoolean(aData.Env()->GetBooleanField(
aData.Get(), booleanValueField) != JNI_FALSE);
MOZ_CATCH_JNI_EXCEPTION(aData.Env());
} else {
aOut.setBoolean(
java::sdk::Boolean::Ref::From(aData)->BooleanValue());
}
} else if (aData.IsInstanceOf<jni::Integer>()) {
if (intValueField) {
aOut.setInt32(aData.Env()->GetIntField(aData.Get(), intValueField));
MOZ_CATCH_JNI_EXCEPTION(aData.Env());
} else {
aOut.setInt32(java::sdk::Number::Ref::From(aData)->IntValue());
}
} else if (aData.IsInstanceOf<jni::Byte>() ||
aData.IsInstanceOf<jni::Short>()) {
aOut.setInt32(java::GeckoBundle::UnboxInteger(aData));
} else if (aData.IsInstanceOf<jni::Double>() ||
aData.IsInstanceOf<jni::Float>() ||
aOut.setInt32(java::sdk::Number::Ref::From(aData)->IntValue());
} else if (aData.IsInstanceOf<jni::Double>()) {
if (doubleValueField) {
aOut.setNumber(aData.Env()->GetDoubleField(
aData.Get(), doubleValueField));
} else {
aOut.setNumber(java::sdk::Number::Ref::From(aData)->DoubleValue());
}
} else if (aData.IsInstanceOf<jni::Float>() ||
aData.IsInstanceOf<jni::Long>()) {
aOut.setNumber(java::GeckoBundle::UnboxDouble(aData));
aOut.setNumber(java::sdk::Number::Ref::From(aData)->DoubleValue());
} else if (aData.IsInstanceOf<jni::String>()) {
return UnboxString(aCx, aData, aOut);
} else if (aData.IsInstanceOf<jni::Character>()) {
return UnboxString(aCx, java::GeckoBundle::UnboxString(aData), aOut);
return UnboxString(aCx, java::sdk::String::ValueOf(aData), aOut);
} else if (aData.IsInstanceOf<java::GeckoBundle>()) {
return UnboxBundle(aCx, aData, aOut);

Просмотреть файл

@ -0,0 +1,22 @@
[java.lang.Boolean = skip:true]
# Use static fields for boxing boolean.
TRUE =
FALSE =
booleanValue =
[java.lang.Double = skip:true]
<init>(D)V =
[java.lang.Integer = skip:true]
# Use valueOf() for boxing int; don't use constructor
# because some Integer values are cached.
valueOf(I)Ljava/lang/Integer; =
[java.lang.Number = skip:true]
# Use doubleValue() for unboxing Double/Float/Long.
doubleValue =
# Use intValue() for unboxing Byte/Int/Short.
intValue =
[java.lang.String = skip:true]
valueOf(Ljava/lang/Object;)Ljava/lang/String; =

Просмотреть файл

@ -12,6 +12,7 @@ with Files("**"):
generated = [
'AndroidBuild',
'AndroidRect',
'JavaBuiltins',
'KeyEvent',
'MediaCodec',
'MotionEvent',