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

@ -46,8 +46,11 @@ Object.keys(RemoteModules).forEach((moduleName) => {
get: () => {
let module = RemoteModules[moduleName];
if (module && typeof module.moduleID === 'number' && global.nativeRequireModuleConfig) {
const json = global.nativeRequireModuleConfig(moduleName);
const config = json && JSON.parse(json);
// The old bridge (still used by iOS) will send the config as
// a JSON string that needs parsing, so we set config according
// to the type of response we got.
const rawConfig = global.nativeRequireModuleConfig(moduleName);
const config = typeof rawConfig === 'string' ? JSON.parse(rawConfig) : rawConfig;
module = config && BatchedBridge.processModuleConfig(config, module.moduleID);
RemoteModules[moduleName] = module;
}

View File

@ -596,7 +596,7 @@ JSValueRef JSCExecutor::nativeRequireModuleConfig(
std::string moduleName = Value(m_context, arguments[0]).toString().str();
folly::dynamic config = m_delegate->getModuleConfig(moduleName);
return JSValueMakeString(m_context, String(folly::toJson(config).c_str()));
return Value::fromDynamic(m_context, config);
}
JSValueRef JSCExecutor::nativeFlushQueueImmediate(
@ -681,7 +681,7 @@ JSValueRef JSCExecutor::nativeCallSyncHook(
if (result.isUndefined) {
return JSValueMakeUndefined(m_context);
}
return Value::fromJSON(m_context, String(folly::toJson(result.result).c_str()));
return Value::fromDynamic(m_context, result.result);
}
static JSValueRef nativeInjectHMRUpdate(

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() {

View File

@ -284,11 +284,12 @@ public:
std::string toJSONString(unsigned indent = 0) const throw(JSException);
static Value fromJSON(JSContextRef ctx, const String& json) throw(JSException);
static Value fromDynamic(JSContextRef ctx, folly::dynamic value) throw(JSException);
static JSValueRef fromDynamic(JSContextRef ctx, const folly::dynamic& value);
JSContextRef context() const;
protected:
JSContextRef m_context;
JSValueRef m_value;
static JSValueRef fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj);
};
} }