|
6 | 6 |
|
7 | 7 | #include "JSCHelpers.h"
|
8 | 8 |
|
| 9 | +// See the comment under Value::fromDynamic() |
| 10 | +#define USE_FAST_FOLLY_DYNAMIC_CONVERSION !defined(__APPLE__) && defined(WITH_FB_JSC_TUNING) |
| 11 | + |
9 | 12 | namespace facebook {
|
10 | 13 | namespace react {
|
11 | 14 |
|
@@ -51,9 +54,78 @@ Value Value::fromJSON(JSContextRef ctx, const String& json) throw(JSException) {
|
51 | 54 | return Value(ctx, result);
|
52 | 55 | }
|
53 | 56 |
|
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 |
55 | 75 | auto json = folly::toJson(value);
|
56 | 76 | 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 | + } |
57 | 129 | }
|
58 | 130 |
|
59 | 131 | Object Value::asObject() {
|
|
0 commit comments