Better folly::dynamic ==> JSValue conversion

Reviewed By: lexs

Differential Revision: D3347854

fbshipit-source-id: 95b81152d1b0d5fe41e01991c44f5d1110be7ddb
This commit is contained in:
Dan Caspi
2016-07-20 04:25:53 -07:00
committed by Facebook Github Bot 0
parent e1b3bbdb04
commit 654e4bed2e
4 changed files with 82 additions and 6 deletions

View File

@@ -6,6 +6,9 @@
#include "JSCHelpers.h"
// See the comment under Value::fromDynamic()
#define USE_FAST_FOLLY_DYNAMIC_CONVERSION !defined(__APPLE__) && defined(WITH_FB_JSC_TUNING)
namespace facebook {
namespace react {
@@ -51,9 +54,78 @@ Value Value::fromJSON(JSContextRef ctx, const String& json) throw(JSException) {
return Value(ctx, result);
}
Value Value::fromDynamic(JSContextRef ctx, folly::dynamic value) throw(JSException) {
JSValueRef Value::fromDynamic(JSContextRef ctx, const folly::dynamic& value) {
// JavaScriptCore's iOS APIs have their own version of this direct conversion.
// In addition, using this requires exposing some of JSC's private APIs,
// so it's limited to non-apple platforms and to builds that use the custom JSC.
// Otherwise, we use the old way of converting through JSON.
#if USE_FAST_FOLLY_DYNAMIC_CONVERSION
// Defer GC during the creation of the JSValue, as we don't want
// intermediate objects to be collected.
// We could use JSValueProtect(), but it will make the process much slower.
JSDeferredGCRef deferGC = JSDeferGarbageCollection(ctx);
// Set a global lock for the whole process,
// instead of re-acquiring the lock for each operation.
JSLock(ctx);
JSValueRef jsVal = Value::fromDynamicInner(ctx, value);
JSUnlock(ctx);
JSResumeGarbageCollection(ctx, deferGC);
return jsVal;
#else
auto json = folly::toJson(value);
return fromJSON(ctx, String(json.c_str()));
#endif
}
JSValueRef Value::fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj) {
switch (obj.type()) {
// For premitive types (and strings), just create and return an equivalent JSValue
case folly::dynamic::Type::NULLT:
return JSValueMakeNull(ctx);
case folly::dynamic::Type::BOOL:
return JSValueMakeBoolean(ctx, obj.getBool());
case folly::dynamic::Type::DOUBLE:
return JSValueMakeNumber(ctx, obj.getDouble());
case folly::dynamic::Type::INT64:
return JSValueMakeNumber(ctx, obj.asDouble());
case folly::dynamic::Type::STRING:
return JSValueMakeString(ctx, String(obj.getString().c_str()));
case folly::dynamic::Type::ARRAY: {
// Collect JSValue for every element in the array
JSValueRef vals[obj.size()];
for (size_t i = 0; i < obj.size(); ++i) {
vals[i] = fromDynamicInner(ctx, obj[i]);
}
// Create a JSArray with the values
JSValueRef arr = JSObjectMakeArray(ctx, obj.size(), vals, nullptr);
return arr;
}
case folly::dynamic::Type::OBJECT: {
// Create an empty object
JSObjectRef jsObj = JSObjectMake(ctx, nullptr, nullptr);
// Create a JSValue for each of the object's children and set them in the object
for (auto it = obj.items().begin(); it != obj.items().end(); ++it) {
JSObjectSetProperty(
ctx,
jsObj,
String(it->first.asString().c_str()),
fromDynamicInner(ctx, it->second),
kJSPropertyAttributeNone,
nullptr);
}
return jsObj;
}
default:
// Assert not reached
LOG(FATAL) << "Trying to convert a folly object of unsupported type.";
return JSValueMakeNull(ctx);
}
}
Object Value::asObject() {