Skip to content

Commit 654e4be

Browse files
dcaspiFacebook Github Bot 0
authored andcommitted
Better folly::dynamic ==> JSValue conversion
Reviewed By: lexs Differential Revision: D3347854 fbshipit-source-id: 95b81152d1b0d5fe41e01991c44f5d1110be7ddb
1 parent e1b3bbd commit 654e4be

File tree

4 files changed

+82
-6
lines changed

4 files changed

+82
-6
lines changed

Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ Object.keys(RemoteModules).forEach((moduleName) => {
4646
get: () => {
4747
let module = RemoteModules[moduleName];
4848
if (module && typeof module.moduleID === 'number' && global.nativeRequireModuleConfig) {
49-
const json = global.nativeRequireModuleConfig(moduleName);
50-
const config = json && JSON.parse(json);
49+
// The old bridge (still used by iOS) will send the config as
50+
// a JSON string that needs parsing, so we set config according
51+
// to the type of response we got.
52+
const rawConfig = global.nativeRequireModuleConfig(moduleName);
53+
const config = typeof rawConfig === 'string' ? JSON.parse(rawConfig) : rawConfig;
5154
module = config && BatchedBridge.processModuleConfig(config, module.moduleID);
5255
RemoteModules[moduleName] = module;
5356
}

ReactCommon/cxxreact/JSCExecutor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ JSValueRef JSCExecutor::nativeRequireModuleConfig(
596596

597597
std::string moduleName = Value(m_context, arguments[0]).toString().str();
598598
folly::dynamic config = m_delegate->getModuleConfig(moduleName);
599-
return JSValueMakeString(m_context, String(folly::toJson(config).c_str()));
599+
return Value::fromDynamic(m_context, config);
600600
}
601601

602602
JSValueRef JSCExecutor::nativeFlushQueueImmediate(
@@ -681,7 +681,7 @@ JSValueRef JSCExecutor::nativeCallSyncHook(
681681
if (result.isUndefined) {
682682
return JSValueMakeUndefined(m_context);
683683
}
684-
return Value::fromJSON(m_context, String(folly::toJson(result.result).c_str()));
684+
return Value::fromDynamic(m_context, result.result);
685685
}
686686

687687
static JSValueRef nativeInjectHMRUpdate(

ReactCommon/cxxreact/Value.cpp

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
#include "JSCHelpers.h"
88

9+
// See the comment under Value::fromDynamic()
10+
#define USE_FAST_FOLLY_DYNAMIC_CONVERSION !defined(__APPLE__) && defined(WITH_FB_JSC_TUNING)
11+
912
namespace facebook {
1013
namespace react {
1114

@@ -51,9 +54,78 @@ Value Value::fromJSON(JSContextRef ctx, const String& json) throw(JSException) {
5154
return Value(ctx, result);
5255
}
5356

54-
Value Value::fromDynamic(JSContextRef ctx, folly::dynamic value) throw(JSException) {
57+
JSValueRef Value::fromDynamic(JSContextRef ctx, const folly::dynamic& value) {
58+
// JavaScriptCore's iOS APIs have their own version of this direct conversion.
59+
// In addition, using this requires exposing some of JSC's private APIs,
60+
// so it's limited to non-apple platforms and to builds that use the custom JSC.
61+
// Otherwise, we use the old way of converting through JSON.
62+
#if USE_FAST_FOLLY_DYNAMIC_CONVERSION
63+
// Defer GC during the creation of the JSValue, as we don't want
64+
// intermediate objects to be collected.
65+
// We could use JSValueProtect(), but it will make the process much slower.
66+
JSDeferredGCRef deferGC = JSDeferGarbageCollection(ctx);
67+
// Set a global lock for the whole process,
68+
// instead of re-acquiring the lock for each operation.
69+
JSLock(ctx);
70+
JSValueRef jsVal = Value::fromDynamicInner(ctx, value);
71+
JSUnlock(ctx);
72+
JSResumeGarbageCollection(ctx, deferGC);
73+
return jsVal;
74+
#else
5575
auto json = folly::toJson(value);
5676
return fromJSON(ctx, String(json.c_str()));
77+
#endif
78+
}
79+
80+
JSValueRef Value::fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj) {
81+
switch (obj.type()) {
82+
// For premitive types (and strings), just create and return an equivalent JSValue
83+
case folly::dynamic::Type::NULLT:
84+
return JSValueMakeNull(ctx);
85+
86+
case folly::dynamic::Type::BOOL:
87+
return JSValueMakeBoolean(ctx, obj.getBool());
88+
89+
case folly::dynamic::Type::DOUBLE:
90+
return JSValueMakeNumber(ctx, obj.getDouble());
91+
92+
case folly::dynamic::Type::INT64:
93+
return JSValueMakeNumber(ctx, obj.asDouble());
94+
95+
case folly::dynamic::Type::STRING:
96+
return JSValueMakeString(ctx, String(obj.getString().c_str()));
97+
98+
case folly::dynamic::Type::ARRAY: {
99+
// Collect JSValue for every element in the array
100+
JSValueRef vals[obj.size()];
101+
for (size_t i = 0; i < obj.size(); ++i) {
102+
vals[i] = fromDynamicInner(ctx, obj[i]);
103+
}
104+
// Create a JSArray with the values
105+
JSValueRef arr = JSObjectMakeArray(ctx, obj.size(), vals, nullptr);
106+
return arr;
107+
}
108+
109+
case folly::dynamic::Type::OBJECT: {
110+
// Create an empty object
111+
JSObjectRef jsObj = JSObjectMake(ctx, nullptr, nullptr);
112+
// Create a JSValue for each of the object's children and set them in the object
113+
for (auto it = obj.items().begin(); it != obj.items().end(); ++it) {
114+
JSObjectSetProperty(
115+
ctx,
116+
jsObj,
117+
String(it->first.asString().c_str()),
118+
fromDynamicInner(ctx, it->second),
119+
kJSPropertyAttributeNone,
120+
nullptr);
121+
}
122+
return jsObj;
123+
}
124+
default:
125+
// Assert not reached
126+
LOG(FATAL) << "Trying to convert a folly object of unsupported type.";
127+
return JSValueMakeNull(ctx);
128+
}
57129
}
58130

59131
Object Value::asObject() {

ReactCommon/cxxreact/Value.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,12 @@ class Value : public noncopyable {
284284

285285
std::string toJSONString(unsigned indent = 0) const throw(JSException);
286286
static Value fromJSON(JSContextRef ctx, const String& json) throw(JSException);
287-
static Value fromDynamic(JSContextRef ctx, folly::dynamic value) throw(JSException);
287+
static JSValueRef fromDynamic(JSContextRef ctx, const folly::dynamic& value);
288288
JSContextRef context() const;
289289
protected:
290290
JSContextRef m_context;
291291
JSValueRef m_value;
292+
static JSValueRef fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj);
292293
};
293294

294295
} }

0 commit comments

Comments
 (0)