mirror of
https://github.com/status-im/react-native.git
synced 2025-02-23 06:38:13 +00:00
Remove jschelpers and privatedata
Summary: JSI doesn't use any of this. Reviewed By: RSNara Differential Revision: D10229167 fbshipit-source-id: 9eaa288a1d62bafb3ff0626f9f8430e699fdad4a
This commit is contained in:
parent
c49d3653ef
commit
00381920c6
@ -147,6 +147,5 @@ rn_xplat_cxx_library(
|
|||||||
react_native_xplat_target("microprofiler:microprofiler"),
|
react_native_xplat_target("microprofiler:microprofiler"),
|
||||||
"xplat//folly:optional",
|
"xplat//folly:optional",
|
||||||
"xplat//third-party/glog:glog",
|
"xplat//third-party/glog:glog",
|
||||||
react_native_xplat_target("privatedata:privatedata"),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
LOCAL_PATH := $(call my-dir)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
LOCAL_MODULE := jschelpers
|
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
|
||||||
JSCHelpers.cpp \
|
|
||||||
Unicode.cpp \
|
|
||||||
Value.cpp \
|
|
||||||
|
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
|
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := \
|
|
||||||
-DLOG_TAG=\"ReactNative\"
|
|
||||||
|
|
||||||
LOCAL_CFLAGS += -fexceptions -frtti
|
|
||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := libfolly_json libjsc libglog
|
|
||||||
|
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
|
||||||
|
|
||||||
$(call import-module,folly)
|
|
||||||
$(call import-module,jsc)
|
|
||||||
$(call import-module,glog)
|
|
||||||
$(call import-module,privatedata)
|
|
@ -1,73 +0,0 @@
|
|||||||
load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "ANDROID_JSC_INTERNAL_DEPS", "APPLE", "APPLE_JSC_INTERNAL_DEPS", "react_native_xplat_target", "rn_xplat_cxx_library")
|
|
||||||
|
|
||||||
EXPORTED_HEADERS = [
|
|
||||||
"JavaScriptCore.h",
|
|
||||||
"JSCHelpers.h",
|
|
||||||
"JSCWrapper.h",
|
|
||||||
"noncopyable.h",
|
|
||||||
"Unicode.h",
|
|
||||||
"Value.h",
|
|
||||||
]
|
|
||||||
|
|
||||||
rn_xplat_cxx_library(
|
|
||||||
name = "jscinternalhelpers",
|
|
||||||
srcs = glob(
|
|
||||||
["*.cpp"],
|
|
||||||
exclude = ["systemJSCWrapper.cpp"],
|
|
||||||
),
|
|
||||||
headers = glob(
|
|
||||||
["*.h"],
|
|
||||||
exclude = EXPORTED_HEADERS,
|
|
||||||
),
|
|
||||||
header_namespace = "",
|
|
||||||
exported_headers = dict([
|
|
||||||
(
|
|
||||||
"jschelpers/%s" % header,
|
|
||||||
header,
|
|
||||||
)
|
|
||||||
for header in EXPORTED_HEADERS
|
|
||||||
]),
|
|
||||||
compiler_flags = [
|
|
||||||
"-Wall",
|
|
||||||
"-fexceptions",
|
|
||||||
"-frtti",
|
|
||||||
"-fvisibility=hidden",
|
|
||||||
"-std=c++1y",
|
|
||||||
],
|
|
||||||
fbandroid_deps = ANDROID_JSC_INTERNAL_DEPS,
|
|
||||||
fbobjc_deps = APPLE_JSC_INTERNAL_DEPS,
|
|
||||||
force_static = True,
|
|
||||||
platforms = (ANDROID, APPLE),
|
|
||||||
visibility = [
|
|
||||||
"PUBLIC",
|
|
||||||
],
|
|
||||||
deps = [
|
|
||||||
"xplat//folly:molly",
|
|
||||||
"xplat//third-party/glog:glog",
|
|
||||||
react_native_xplat_target("privatedata:privatedata"),
|
|
||||||
],
|
|
||||||
exported_deps = [
|
|
||||||
react_native_xplat_target("privatedata:privatedata"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
rn_xplat_cxx_library(
|
|
||||||
name = "jschelpers",
|
|
||||||
srcs = [],
|
|
||||||
compiler_flags = [
|
|
||||||
"-Wall",
|
|
||||||
"-fexceptions",
|
|
||||||
"-fvisibility=hidden",
|
|
||||||
"-std=c++1y",
|
|
||||||
],
|
|
||||||
fbobjc_frameworks = [
|
|
||||||
"$SDKROOT/System/Library/Frameworks/JavaScriptCore.framework",
|
|
||||||
],
|
|
||||||
fbobjc_srcs = ["systemJSCWrapper.cpp"],
|
|
||||||
force_static = True,
|
|
||||||
platforms = (ANDROID, APPLE),
|
|
||||||
visibility = [
|
|
||||||
"PUBLIC",
|
|
||||||
],
|
|
||||||
deps = [":jscinternalhelpers"],
|
|
||||||
)
|
|
@ -1,299 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#include "JSCHelpers.h"
|
|
||||||
|
|
||||||
#ifdef WITH_FBSYSTRACE
|
|
||||||
#include <fbsystrace.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <glog/logging.h>
|
|
||||||
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "JavaScriptCore.h"
|
|
||||||
#include "Value.h"
|
|
||||||
#include <privatedata/PrivateDataBase.h>
|
|
||||||
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
#undef ASSERT
|
|
||||||
#undef WTF_EXPORT_PRIVATE
|
|
||||||
|
|
||||||
#include <JavaScriptCore/config.h>
|
|
||||||
#include <wtf/WTFThreadData.h>
|
|
||||||
|
|
||||||
#undef TRUE
|
|
||||||
#undef FALSE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class JSFunctionPrivateData : public PrivateDataBase {
|
|
||||||
public:
|
|
||||||
explicit JSFunctionPrivateData(JSFunction&& function) : jsFunction_{std::move(function)} {}
|
|
||||||
|
|
||||||
JSFunction& getJSFunction() {
|
|
||||||
return jsFunction_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JSFunction jsFunction_;
|
|
||||||
};
|
|
||||||
|
|
||||||
JSValueRef functionCaller(
|
|
||||||
JSContextRef ctx,
|
|
||||||
JSObjectRef function,
|
|
||||||
JSObjectRef thisObject,
|
|
||||||
size_t argumentCount,
|
|
||||||
const JSValueRef arguments[],
|
|
||||||
JSValueRef* exception) {
|
|
||||||
const bool isCustomJSC = isCustomJSCPtr(ctx);
|
|
||||||
auto* privateData = PrivateDataBase::cast<JSFunctionPrivateData>(
|
|
||||||
JSC_JSObjectGetPrivate(isCustomJSC, function));
|
|
||||||
return (privateData->getJSFunction())(ctx, thisObject, argumentCount, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSClassRef createFuncClass(JSContextRef ctx) {
|
|
||||||
JSClassDefinition definition = kJSClassDefinitionEmpty;
|
|
||||||
definition.attributes |= kJSClassAttributeNoAutomaticPrototype;
|
|
||||||
|
|
||||||
// Need to duplicate the two different finalizer blocks, since there's no way
|
|
||||||
// for it to capture this static information.
|
|
||||||
const bool isCustomJSC = isCustomJSCPtr(ctx);
|
|
||||||
if (isCustomJSC) {
|
|
||||||
definition.finalize = [](JSObjectRef object) {
|
|
||||||
auto* privateData = PrivateDataBase::cast<JSFunctionPrivateData>(
|
|
||||||
JSC_JSObjectGetPrivate(true, object));
|
|
||||||
delete privateData;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
definition.finalize = [](JSObjectRef object) {
|
|
||||||
auto* privateData = PrivateDataBase::cast<JSFunctionPrivateData>(
|
|
||||||
JSC_JSObjectGetPrivate(false, object));
|
|
||||||
delete privateData;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
definition.callAsFunction = exceptionWrapMethod<&functionCaller>();
|
|
||||||
|
|
||||||
return JSC_JSClassCreate(isCustomJSC, &definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectRef makeFunction(
|
|
||||||
JSContextRef ctx,
|
|
||||||
JSStringRef name,
|
|
||||||
JSFunction function) {
|
|
||||||
static JSClassRef kClassDef = NULL, kCustomJSCClassDef = NULL;
|
|
||||||
JSClassRef *classRef = isCustomJSCPtr(ctx) ? &kCustomJSCClassDef : &kClassDef;
|
|
||||||
if (!*classRef) {
|
|
||||||
*classRef = createFuncClass(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// dealloc in kClassDef.finalize
|
|
||||||
JSFunctionPrivateData *functionDataPtr = new JSFunctionPrivateData(std::move(function));
|
|
||||||
auto functionObject = Object(ctx, JSC_JSObjectMake(ctx, *classRef, functionDataPtr));
|
|
||||||
functionObject.setProperty("name", Value(ctx, name));
|
|
||||||
return functionObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void JSException::buildMessage(JSContextRef ctx, JSValueRef exn, JSStringRef sourceURL, const char* errorMsg) {
|
|
||||||
std::ostringstream msgBuilder;
|
|
||||||
if (errorMsg && strlen(errorMsg) > 0) {
|
|
||||||
msgBuilder << errorMsg << ": ";
|
|
||||||
}
|
|
||||||
|
|
||||||
Object exnObject = Value(ctx, exn).asObject();
|
|
||||||
Value exnMessage = exnObject.getProperty("message");
|
|
||||||
msgBuilder << (exnMessage.isString() ? exnMessage : (Value)exnObject).toString().str();
|
|
||||||
|
|
||||||
// The null/empty-ness of source tells us if the JS came from a
|
|
||||||
// file/resource, or was a constructed statement. The location
|
|
||||||
// info will include that source, if any.
|
|
||||||
std::string locationInfo = sourceURL != nullptr ? String::ref(ctx, sourceURL).str() : "";
|
|
||||||
auto line = exnObject.getProperty("line");
|
|
||||||
if (line != nullptr && line.isNumber()) {
|
|
||||||
if (locationInfo.empty() && line.asInteger() != 1) {
|
|
||||||
// If there is a non-trivial line number, but there was no
|
|
||||||
// location info, we include a placeholder, and the line
|
|
||||||
// number.
|
|
||||||
locationInfo = folly::to<std::string>("<unknown file>:", line.asInteger());
|
|
||||||
} else if (!locationInfo.empty()) {
|
|
||||||
// If there is location info, we always include the line
|
|
||||||
// number, regardless of its value.
|
|
||||||
locationInfo += folly::to<std::string>(":", line.asInteger());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!locationInfo.empty()) {
|
|
||||||
msgBuilder << " (" << locationInfo << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto exceptionText = msgBuilder.str();
|
|
||||||
LOG(ERROR) << "Got JS Exception: " << exceptionText;
|
|
||||||
msg_ = std::move(exceptionText);
|
|
||||||
|
|
||||||
Value jsStack = exnObject.getProperty("stack");
|
|
||||||
if (jsStack.isString()) {
|
|
||||||
auto stackText = jsStack.toString().str();
|
|
||||||
LOG(ERROR) << "Got JS Stack: " << stackText;
|
|
||||||
stack_ = std::move(stackText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ExceptionHandling {
|
|
||||||
|
|
||||||
PlatformErrorExtractor platformErrorExtractor;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectRef makeFunction(
|
|
||||||
JSContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSFunction function) {
|
|
||||||
return makeFunction(ctx, String(ctx, name), std::move(function));
|
|
||||||
}
|
|
||||||
|
|
||||||
void installGlobalFunction(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSFunction function) {
|
|
||||||
auto jsName = String(ctx, name);
|
|
||||||
auto functionObj = makeFunction(ctx, jsName, std::move(function));
|
|
||||||
Object::getGlobalObject(ctx).setProperty(jsName, Value(ctx, functionObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObjectRef makeFunction(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSObjectCallAsFunctionCallback callback) {
|
|
||||||
auto jsName = String(ctx, name);
|
|
||||||
return JSC_JSObjectMakeFunctionWithCallback(ctx, jsName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void installGlobalFunction(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSObjectCallAsFunctionCallback callback) {
|
|
||||||
String jsName(ctx, name);
|
|
||||||
JSObjectRef functionObj = JSC_JSObjectMakeFunctionWithCallback(
|
|
||||||
ctx, jsName, callback);
|
|
||||||
Object::getGlobalObject(ctx).setProperty(jsName, Value(ctx, functionObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
void installGlobalProxy(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSObjectGetPropertyCallback callback) {
|
|
||||||
JSClassDefinition proxyClassDefintion = kJSClassDefinitionEmpty;
|
|
||||||
proxyClassDefintion.attributes |= kJSClassAttributeNoAutomaticPrototype;
|
|
||||||
proxyClassDefintion.getProperty = callback;
|
|
||||||
|
|
||||||
const bool isCustomJSC = isCustomJSCPtr(ctx);
|
|
||||||
JSClassRef proxyClass = JSC_JSClassCreate(isCustomJSC, &proxyClassDefintion);
|
|
||||||
JSObjectRef proxyObj = JSC_JSObjectMake(ctx, proxyClass, nullptr);
|
|
||||||
JSC_JSClassRelease(isCustomJSC, proxyClass);
|
|
||||||
|
|
||||||
Object::getGlobalObject(ctx).setProperty(name, Value(ctx, proxyObj));
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeGlobal(JSGlobalContextRef ctx, const char* name) {
|
|
||||||
Object::getGlobalObject(ctx).setProperty(name, Value::makeUndefined(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef sourceURL) {
|
|
||||||
JSValueRef exn, result;
|
|
||||||
result = JSC_JSEvaluateScript(context, script, NULL, sourceURL, 0, &exn);
|
|
||||||
if (result == nullptr) {
|
|
||||||
throw JSException(context, exn, sourceURL);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
JSValueRef evaluateSourceCode(JSContextRef context, JSSourceCodeRef source, JSStringRef sourceURL) {
|
|
||||||
JSValueRef exn, result;
|
|
||||||
result = JSEvaluateSourceCode(context, source, NULL, &exn);
|
|
||||||
if (result == nullptr) {
|
|
||||||
throw JSException(context, exn, sourceURL);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JSContextLock::JSContextLock(JSGlobalContextRef ctx) noexcept
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
: ctx_(ctx),
|
|
||||||
globalLock_(PTHREAD_MUTEX_INITIALIZER)
|
|
||||||
{
|
|
||||||
WTFThreadData& threadData = wtfThreadData();
|
|
||||||
|
|
||||||
// Code below is responsible for acquiring locks. It should execute
|
|
||||||
// atomically, thus none of the functions invoked from now on are allowed to
|
|
||||||
// throw an exception
|
|
||||||
try {
|
|
||||||
if (!threadData.isDebuggerThread()) {
|
|
||||||
CHECK(0 == pthread_mutex_lock(&globalLock_));
|
|
||||||
}
|
|
||||||
JSLock(ctx_);
|
|
||||||
} catch (...) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
JSContextLock::~JSContextLock() noexcept {
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
WTFThreadData& threadData = wtfThreadData();
|
|
||||||
|
|
||||||
JSUnlock(ctx_);
|
|
||||||
if (!threadData.isDebuggerThread()) {
|
|
||||||
CHECK(0 == pthread_mutex_unlock(&globalLock_));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, const char *exceptionLocation) {
|
|
||||||
try {
|
|
||||||
throw;
|
|
||||||
} catch (const std::bad_alloc& ex) {
|
|
||||||
throw; // We probably shouldn't try to handle this in JS
|
|
||||||
} catch (const std::exception& ex) {
|
|
||||||
if (ExceptionHandling::platformErrorExtractor) {
|
|
||||||
auto extractedEror = ExceptionHandling::platformErrorExtractor(ex, exceptionLocation);
|
|
||||||
if (extractedEror.message.length() > 0) {
|
|
||||||
return Value::makeError(ctx, extractedEror.message.c_str(), extractedEror.stack.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto msg = folly::to<std::string>("C++ exception in '", exceptionLocation, "'\n\n", ex.what());
|
|
||||||
return Value::makeError(ctx, msg.c_str());
|
|
||||||
} catch (const char* ex) {
|
|
||||||
auto msg = folly::to<std::string>("C++ exception (thrown as a char*) in '", exceptionLocation, "'\n\n", ex);
|
|
||||||
return Value::makeError(ctx, msg.c_str());
|
|
||||||
} catch (...) {
|
|
||||||
auto msg = folly::to<std::string>("Unknown C++ exception in '", exceptionLocation, "'");
|
|
||||||
return Value::makeError(ctx, msg.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, JSObjectRef jsFunctionCause) {
|
|
||||||
try {
|
|
||||||
auto functionName = Object(ctx, jsFunctionCause).getProperty("name").toString().str();
|
|
||||||
return translatePendingCppExceptionToJSError(ctx, functionName.c_str());
|
|
||||||
} catch (...) {
|
|
||||||
return Value::makeError(ctx, "Failed to translate native exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
@ -1,149 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <jschelpers/JavaScriptCore.h>
|
|
||||||
#include <jschelpers/Value.h>
|
|
||||||
|
|
||||||
#ifndef RN_EXPORT
|
|
||||||
#define RN_EXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
class RN_EXPORT JSException : public std::exception {
|
|
||||||
public:
|
|
||||||
explicit JSException(const char* msg)
|
|
||||||
: msg_(msg) {}
|
|
||||||
|
|
||||||
explicit JSException(JSContextRef ctx, JSValueRef exn, const char* msg) {
|
|
||||||
buildMessage(ctx, exn, nullptr, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit JSException(JSContextRef ctx, JSValueRef exn, JSStringRef sourceURL) {
|
|
||||||
buildMessage(ctx, exn, sourceURL, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& getStack() const {
|
|
||||||
return stack_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const char* what() const noexcept override {
|
|
||||||
return msg_.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string msg_;
|
|
||||||
std::string stack_;
|
|
||||||
|
|
||||||
void buildMessage(JSContextRef ctx, JSValueRef exn, JSStringRef sourceURL, const char* errorMsg);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ExceptionHandling {
|
|
||||||
struct ExtractedEror {
|
|
||||||
std::string message;
|
|
||||||
// Stacktrace formatted like JS stack
|
|
||||||
// method@filename[:line[:column]]
|
|
||||||
std::string stack;
|
|
||||||
};
|
|
||||||
typedef ExtractedEror(*PlatformErrorExtractor)(const std::exception &ex, const char *context);
|
|
||||||
extern PlatformErrorExtractor platformErrorExtractor;
|
|
||||||
}
|
|
||||||
|
|
||||||
using JSFunction = std::function<JSValueRef(JSContextRef, JSObjectRef, size_t, const JSValueRef[])>;
|
|
||||||
|
|
||||||
JSObjectRef makeFunction(
|
|
||||||
JSContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSFunction function);
|
|
||||||
|
|
||||||
RN_EXPORT void installGlobalFunction(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSFunction function);
|
|
||||||
|
|
||||||
JSObjectRef makeFunction(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSObjectCallAsFunctionCallback callback);
|
|
||||||
|
|
||||||
RN_EXPORT void installGlobalFunction(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSObjectCallAsFunctionCallback callback);
|
|
||||||
|
|
||||||
void installGlobalProxy(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
const char* name,
|
|
||||||
JSObjectGetPropertyCallback callback);
|
|
||||||
|
|
||||||
void removeGlobal(JSGlobalContextRef ctx, const char* name);
|
|
||||||
|
|
||||||
JSValueRef evaluateScript(
|
|
||||||
JSContextRef ctx,
|
|
||||||
JSStringRef script,
|
|
||||||
JSStringRef sourceURL);
|
|
||||||
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
JSValueRef evaluateSourceCode(
|
|
||||||
JSContextRef ctx,
|
|
||||||
JSSourceCodeRef source,
|
|
||||||
JSStringRef sourceURL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A lock for protecting accesses to the JSGlobalContext
|
|
||||||
* This will be a no-op for most compilations, where #if WITH_FBJSCEXTENSIONS is false,
|
|
||||||
* but avoids deadlocks in execution environments with advanced locking requirements,
|
|
||||||
* particularly with uses of the pthread mutex lock
|
|
||||||
**/
|
|
||||||
class JSContextLock {
|
|
||||||
public:
|
|
||||||
JSContextLock(JSGlobalContextRef ctx) noexcept;
|
|
||||||
~JSContextLock() noexcept;
|
|
||||||
private:
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
JSGlobalContextRef ctx_;
|
|
||||||
pthread_mutex_t globalLock_;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, const char *exceptionLocation);
|
|
||||||
JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, JSObjectRef jsFunctionCause);
|
|
||||||
|
|
||||||
template<JSValueRef (method)(JSContextRef ctx,
|
|
||||||
JSObjectRef function,
|
|
||||||
JSObjectRef thisObject,
|
|
||||||
size_t argumentCount,
|
|
||||||
const JSValueRef arguments[],
|
|
||||||
JSValueRef *exception)>
|
|
||||||
inline JSObjectCallAsFunctionCallback exceptionWrapMethod() {
|
|
||||||
struct funcWrapper {
|
|
||||||
static JSValueRef call(
|
|
||||||
JSContextRef ctx,
|
|
||||||
JSObjectRef function,
|
|
||||||
JSObjectRef thisObject,
|
|
||||||
size_t argumentCount,
|
|
||||||
const JSValueRef arguments[],
|
|
||||||
JSValueRef *exception) {
|
|
||||||
try {
|
|
||||||
return (*method)(ctx, function, thisObject, argumentCount, arguments, exception);
|
|
||||||
} catch (...) {
|
|
||||||
*exception = translatePendingCppExceptionToJSError(ctx, function);
|
|
||||||
return JSC_JSValueMakeUndefined(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return &funcWrapper::call;
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "JSCWrapper.h"
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
|
|
||||||
// TODO: use glog in OSS too
|
|
||||||
#if __has_include(<glog/logging.h>)
|
|
||||||
#define USE_GLOG 1
|
|
||||||
#include <glog/logging.h>
|
|
||||||
#else
|
|
||||||
#define USE_GLOG 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
static const JSCWrapper* s_customWrapper = nullptr;
|
|
||||||
|
|
||||||
bool isCustomJSCWrapperSet() {
|
|
||||||
return s_customWrapper != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const JSCWrapper* customJSCWrapper() {
|
|
||||||
#if USE_GLOG
|
|
||||||
CHECK(s_customWrapper != nullptr) << "Accessing custom JSC wrapper before it's set";
|
|
||||||
#endif
|
|
||||||
return s_customWrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCustomJSCWrapper(const JSCWrapper* wrapper) {
|
|
||||||
#if USE_GLOG
|
|
||||||
CHECK(s_customWrapper == nullptr) << "Can't set custom JSC wrapper multiple times";
|
|
||||||
#endif
|
|
||||||
s_customWrapper = wrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,189 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
#include <JavaScriptCore/JavaScript.h>
|
|
||||||
|
|
||||||
#if defined(JSCINTERNAL) || (!defined(__APPLE__))
|
|
||||||
#define JSC_IMPORT extern "C"
|
|
||||||
#else
|
|
||||||
#define JSC_IMPORT extern
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RN_EXPORT
|
|
||||||
#define RN_EXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
class IInspector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSC_IMPORT void JSGlobalContextEnableDebugger(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
facebook::react::IInspector &globalInspector,
|
|
||||||
const char *title,
|
|
||||||
const std::function<bool()> &checkIsInspectedRemote);
|
|
||||||
JSC_IMPORT void JSGlobalContextDisableDebugger(
|
|
||||||
JSGlobalContextRef ctx,
|
|
||||||
facebook::react::IInspector &globalInspector);
|
|
||||||
|
|
||||||
// This is used to substitute an alternate JSC implementation for
|
|
||||||
// testing. These calls must all be ABI compatible with the standard JSC.
|
|
||||||
JSC_IMPORT JSValueRef JSEvaluateBytecodeBundle(JSContextRef, JSObjectRef, int, JSStringRef, JSValueRef*);
|
|
||||||
JSC_IMPORT bool JSSamplingProfilerEnabled();
|
|
||||||
JSC_IMPORT void JSStartSamplingProfilingOnMainJSCThread(JSGlobalContextRef);
|
|
||||||
JSC_IMPORT JSValueRef JSPokeSamplingProfiler(JSContextRef);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
JSC_IMPORT void configureJSCForIOS(std::string); // TODO: replace with folly::dynamic once supported
|
|
||||||
JSC_IMPORT void FBJSContextStartGCTimers(JSContextRef);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
#include <objc/objc.h>
|
|
||||||
#include <JavaScriptCore/JSStringRefCF.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSNoBytecodeFileFormatVersion
|
|
||||||
*
|
|
||||||
* Version number indicating that bytecode is not supported by this runtime.
|
|
||||||
*/
|
|
||||||
RN_EXPORT extern const int32_t JSNoBytecodeFileFormatVersion;
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
#define JSC_WRAPPER_METHOD(m) decltype(&m) m
|
|
||||||
|
|
||||||
struct JSCWrapper {
|
|
||||||
// JSGlobalContext
|
|
||||||
JSC_WRAPPER_METHOD(JSGlobalContextCreateInGroup);
|
|
||||||
JSC_WRAPPER_METHOD(JSGlobalContextRelease);
|
|
||||||
JSC_WRAPPER_METHOD(JSGlobalContextSetName);
|
|
||||||
|
|
||||||
// JSContext
|
|
||||||
JSC_WRAPPER_METHOD(JSContextGetGlobalContext);
|
|
||||||
JSC_WRAPPER_METHOD(JSContextGetGlobalObject);
|
|
||||||
JSC_WRAPPER_METHOD(FBJSContextStartGCTimers);
|
|
||||||
|
|
||||||
// JSEvaluate
|
|
||||||
JSC_WRAPPER_METHOD(JSEvaluateScript);
|
|
||||||
JSC_WRAPPER_METHOD(JSEvaluateBytecodeBundle);
|
|
||||||
|
|
||||||
// JSString
|
|
||||||
JSC_WRAPPER_METHOD(JSStringCreateWithUTF8CString);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringCreateWithCFString);
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
JSC_WRAPPER_METHOD(JSStringCreateWithUTF8CStringExpectAscii);
|
|
||||||
#endif
|
|
||||||
JSC_WRAPPER_METHOD(JSStringCopyCFString);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringGetCharactersPtr);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringGetLength);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringGetMaximumUTF8CStringSize);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringIsEqualToUTF8CString);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringRelease);
|
|
||||||
JSC_WRAPPER_METHOD(JSStringRetain);
|
|
||||||
|
|
||||||
// JSClass
|
|
||||||
JSC_WRAPPER_METHOD(JSClassCreate);
|
|
||||||
JSC_WRAPPER_METHOD(JSClassRetain);
|
|
||||||
JSC_WRAPPER_METHOD(JSClassRelease);
|
|
||||||
|
|
||||||
// JSObject
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectCallAsConstructor);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectCallAsFunction);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectGetPrivate);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectGetProperty);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectGetPropertyAtIndex);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectIsConstructor);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectIsFunction);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectMake);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectMakeArray);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectMakeDate);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectMakeError);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectMakeFunctionWithCallback);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectSetPrivate);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectSetProperty);
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectSetPropertyAtIndex);
|
|
||||||
|
|
||||||
// JSPropertyNameArray
|
|
||||||
JSC_WRAPPER_METHOD(JSObjectCopyPropertyNames);
|
|
||||||
JSC_WRAPPER_METHOD(JSPropertyNameArrayGetCount);
|
|
||||||
JSC_WRAPPER_METHOD(JSPropertyNameArrayGetNameAtIndex);
|
|
||||||
JSC_WRAPPER_METHOD(JSPropertyNameArrayRelease);
|
|
||||||
|
|
||||||
// JSValue
|
|
||||||
JSC_WRAPPER_METHOD(JSValueCreateJSONString);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueGetType);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueMakeFromJSONString);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueMakeBoolean);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueMakeNull);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueMakeNumber);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueMakeString);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueMakeUndefined);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueProtect);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueToBoolean);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueToNumber);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueToObject);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueToStringCopy);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueUnprotect);
|
|
||||||
JSC_WRAPPER_METHOD(JSValueIsNull);
|
|
||||||
|
|
||||||
// Sampling profiler
|
|
||||||
JSC_WRAPPER_METHOD(JSSamplingProfilerEnabled);
|
|
||||||
JSC_WRAPPER_METHOD(JSPokeSamplingProfiler);
|
|
||||||
JSC_WRAPPER_METHOD(JSStartSamplingProfilingOnMainJSCThread);
|
|
||||||
|
|
||||||
JSC_WRAPPER_METHOD(JSGlobalContextEnableDebugger);
|
|
||||||
JSC_WRAPPER_METHOD(JSGlobalContextDisableDebugger);
|
|
||||||
|
|
||||||
JSC_WRAPPER_METHOD(configureJSCForIOS);
|
|
||||||
|
|
||||||
// Objective-C API
|
|
||||||
Class JSContext;
|
|
||||||
Class JSValue;
|
|
||||||
|
|
||||||
int32_t JSBytecodeFileFormatVersion;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool isCustomJSCPtr(T *x) {
|
|
||||||
return (uintptr_t)x & 0x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
RN_EXPORT bool isCustomJSCWrapperSet();
|
|
||||||
RN_EXPORT void setCustomJSCWrapper(const JSCWrapper* wrapper);
|
|
||||||
|
|
||||||
// This will return a single value for the whole life of the process.
|
|
||||||
RN_EXPORT const JSCWrapper *systemJSCWrapper();
|
|
||||||
RN_EXPORT const JSCWrapper *customJSCWrapper();
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool isCustomJSCPtr(T *x) {
|
|
||||||
// Always use system JSC pointers
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,212 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <jschelpers/JSCWrapper.h>
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
|
|
||||||
// Use for methods that are taking JSContextRef as a first param
|
|
||||||
#define __jsc_wrapper(method, ctx, ...) \
|
|
||||||
(facebook::react::isCustomJSCPtr(ctx) ? \
|
|
||||||
facebook::react::customJSCWrapper() : \
|
|
||||||
facebook::react::systemJSCWrapper() \
|
|
||||||
)->method(ctx, ## __VA_ARGS__)
|
|
||||||
|
|
||||||
// Use for methods that don't take a JSContextRef as a first param. The wrapped version
|
|
||||||
// of this method will require context as an additional param, but it will be dropped
|
|
||||||
// before calling into the JSC method.
|
|
||||||
#define __jsc_drop_ctx_wrapper(method, ctx, ...) \
|
|
||||||
(facebook::react::isCustomJSCPtr(ctx) ? \
|
|
||||||
facebook::react::customJSCWrapper() : \
|
|
||||||
facebook::react::systemJSCWrapper() \
|
|
||||||
)->method(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Use for methods were access to a JSContextRef is impractical. The first bool param
|
|
||||||
// will be dropped before the JSC method is invoked.
|
|
||||||
#define __jsc_ensure_bool(field) \
|
|
||||||
static_assert(std::is_same<typename std::decay<decltype(field)>::type, bool>::value, "useCustomJSC must be bool");
|
|
||||||
#define __jsc_bool_wrapper(method, useCustomJSC, ...) \
|
|
||||||
([]{ __jsc_ensure_bool(useCustomJSC) }, useCustomJSC ? \
|
|
||||||
facebook::react::customJSCWrapper() : \
|
|
||||||
facebook::react::systemJSCWrapper() \
|
|
||||||
)->method(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Used for wrapping properties
|
|
||||||
#define __jsc_prop_wrapper(prop, ctx) \
|
|
||||||
(facebook::react::isCustomJSCPtr(ctx) ? \
|
|
||||||
facebook::react::customJSCWrapper() : \
|
|
||||||
facebook::react::systemJSCWrapper() \
|
|
||||||
)->prop
|
|
||||||
|
|
||||||
// Poison all regular versions of the JSC API in shared code. This prevents accidental
|
|
||||||
// mixed usage of regular and custom JSC methods.
|
|
||||||
// See https://gcc.gnu.org/onlinedocs/gcc-3.3/cpp/Pragmas.html for details
|
|
||||||
#define jsc_pragma(x) _Pragma(#x)
|
|
||||||
#ifndef NO_JSC_POISON
|
|
||||||
#define jsc_poison(methods) jsc_pragma(GCC poison methods)
|
|
||||||
#else
|
|
||||||
#define jsc_poison(methods)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define __jsc_wrapper(method, ctx, ...) method(ctx, ## __VA_ARGS__)
|
|
||||||
#define __jsc_drop_ctx_wrapper(method, ctx, ...) ((void)ctx, method(__VA_ARGS__))
|
|
||||||
#define __jsc_bool_wrapper(method, useCustomJSC, ...) \
|
|
||||||
((void)useCustomJSC, method(__VA_ARGS__))
|
|
||||||
#define __jsc_prop_wrapper(prop, ctx) prop
|
|
||||||
|
|
||||||
#define jsc_pragma(x)
|
|
||||||
#define jsc_poison(methods)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// JSGlobalContext
|
|
||||||
#define JSC_JSGlobalContextCreateInGroup(...) __jsc_bool_wrapper(JSGlobalContextCreateInGroup, __VA_ARGS__)
|
|
||||||
#define JSC_JSGlobalContextRelease(...) __jsc_wrapper(JSGlobalContextRelease, __VA_ARGS__)
|
|
||||||
#define JSC_JSGlobalContextSetName(...) __jsc_wrapper(JSGlobalContextSetName, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSContextGroupCreate JSContextGroupRelease JSContextGroupRetain
|
|
||||||
JSGlobalContextCreate JSGlobalContextCreateInGroup JSGlobalContextCopyName
|
|
||||||
JSGlobalContextRelease JSGlobalContextRetain JSGlobalContextSetName)
|
|
||||||
|
|
||||||
// JSContext
|
|
||||||
#define JSC_JSContextGetGlobalContext(...) __jsc_wrapper(JSContextGetGlobalContext, __VA_ARGS__)
|
|
||||||
#define JSC_JSContextGetGlobalObject(...) __jsc_wrapper(JSContextGetGlobalObject, __VA_ARGS__)
|
|
||||||
#define JSC_FBJSContextStartGCTimers(...) __jsc_wrapper(FBJSContextStartGCTimers, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSContextGetGlobalContext JSContextGetGlobalObject JSContextGetGroup FBJSContextStartGCTimers)
|
|
||||||
|
|
||||||
// JSEvaluate
|
|
||||||
#define JSC_JSEvaluateScript(...) __jsc_wrapper(JSEvaluateScript, __VA_ARGS__)
|
|
||||||
#define JSC_JSEvaluateBytecodeBundle(...) __jsc_wrapper(JSEvaluateBytecodeBundle, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSCheckScriptSyntax JSEvaluateScript JSEvaluateBytecodeBundle JSGarbageCollect)
|
|
||||||
|
|
||||||
// JSString
|
|
||||||
#define JSC_JSStringCreateWithCFString(...) __jsc_drop_ctx_wrapper(JSStringCreateWithCFString, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringCreateWithUTF8CString(...) __jsc_drop_ctx_wrapper(JSStringCreateWithUTF8CString, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringCreateWithUTF8CStringExpectAscii(...) __jsc_drop_ctx_wrapper(JSStringCreateWithUTF8CStringExpectAscii, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringCopyCFString(...) __jsc_drop_ctx_wrapper(JSStringCopyCFString, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringGetCharactersPtr(...) __jsc_drop_ctx_wrapper(JSStringGetCharactersPtr, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringGetLength(...) __jsc_drop_ctx_wrapper(JSStringGetLength, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringGetMaximumUTF8CStringSize(...) __jsc_drop_ctx_wrapper(JSStringGetMaximumUTF8CStringSize, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringIsEqualToUTF8CString(...) __jsc_drop_ctx_wrapper(JSStringIsEqualToUTF8CString, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringRelease(...) __jsc_drop_ctx_wrapper(JSStringRelease, __VA_ARGS__)
|
|
||||||
#define JSC_JSStringRetain(...) __jsc_drop_ctx_wrapper(JSStringRetain, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSStringCopyCFString JSStringCreateWithCharacters JSStringCreateWithCFString
|
|
||||||
JSStringCreateWithUTF8CString JSStringCreateWithUTF8CStringExpectAscii
|
|
||||||
JSStringGetCharactersPtr JSStringGetLength JSStringGetMaximumUTF8CStringSize
|
|
||||||
JSStringGetUTF8CString JSStringIsEqual JSStringIsEqualToUTF8CString
|
|
||||||
JSStringRelease JSStringRetain)
|
|
||||||
|
|
||||||
// JSValueRef
|
|
||||||
#define JSC_JSValueCreateJSONString(...) __jsc_wrapper(JSValueCreateJSONString, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueGetType(...) __jsc_wrapper(JSValueGetType, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueMakeFromJSONString(...) __jsc_wrapper(JSValueMakeFromJSONString, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueMakeBoolean(...) __jsc_wrapper(JSValueMakeBoolean, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueMakeNull(...) __jsc_wrapper(JSValueMakeNull, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueMakeNumber(...) __jsc_wrapper(JSValueMakeNumber, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueMakeString(...) __jsc_wrapper(JSValueMakeString, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueMakeUndefined(...) __jsc_wrapper(JSValueMakeUndefined, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueProtect(...) __jsc_wrapper(JSValueProtect, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueToBoolean(...) __jsc_wrapper(JSValueToBoolean, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueToNumber(...) __jsc_wrapper(JSValueToNumber, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueToObject(...) __jsc_wrapper(JSValueToObject, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueToStringCopy(...) __jsc_wrapper(JSValueToStringCopy, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueUnprotect(...) __jsc_wrapper(JSValueUnprotect, __VA_ARGS__)
|
|
||||||
#define JSC_JSValueIsNull(...) __jsc_wrapper(JSValueIsNull, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSValueCreateJSONString JSValueGetType JSValueGetTypedArrayType JSValueIsArray
|
|
||||||
JSValueIsBoolean JSValueIsDate JSValueIsEqual JSValueIsInstanceOfConstructor
|
|
||||||
JSValueIsNull JSValueIsNumber JSValueIsObject JSValueIsObjectOfClass
|
|
||||||
JSValueIsStrictEqual JSValueIsString JSValueIsString JSValueIsUndefined
|
|
||||||
JSValueMakeBoolean JSValueMakeFromJSONString JSValueMakeNull JSValueMakeNumber
|
|
||||||
JSValueMakeString JSValueMakeUndefined JSValueProtect JSValueToBoolean
|
|
||||||
JSValueToNumber JSValueToObject JSValueToStringCopy JSValueUnprotect)
|
|
||||||
|
|
||||||
// JSClass
|
|
||||||
#define JSC_JSClassCreate(...) __jsc_bool_wrapper(JSClassCreate, __VA_ARGS__)
|
|
||||||
#define JSC_JSClassRetain(...) __jsc_bool_wrapper(JSClassRetain, __VA_ARGS__)
|
|
||||||
#define JSC_JSClassRelease(...) __jsc_bool_wrapper(JSClassRelease, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSClassCreate JSClassRelease JSClassRetain)
|
|
||||||
|
|
||||||
// JSObject
|
|
||||||
#define JSC_JSObjectCallAsConstructor(...) __jsc_wrapper(JSObjectCallAsConstructor, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectCallAsFunction(...) __jsc_wrapper(JSObjectCallAsFunction, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectGetPrivate(...) __jsc_bool_wrapper(JSObjectGetPrivate, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectGetProperty(...) __jsc_wrapper(JSObjectGetProperty, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectGetPropertyAtIndex(...) __jsc_wrapper(JSObjectGetPropertyAtIndex, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectIsConstructor(...) __jsc_wrapper(JSObjectIsConstructor, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectIsFunction(...) __jsc_wrapper(JSObjectIsFunction, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectMake(...) __jsc_wrapper(JSObjectMake, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectMakeArray(...) __jsc_wrapper(JSObjectMakeArray, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectMakeDate(...) __jsc_wrapper(JSObjectMakeDate, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectMakeError(...) __jsc_wrapper(JSObjectMakeError, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectMakeFunctionWithCallback(...) __jsc_wrapper(JSObjectMakeFunctionWithCallback, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectSetPrivate(...) __jsc_bool_wrapper(JSObjectSetPrivate, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectSetProperty(...) __jsc_wrapper(JSObjectSetProperty, __VA_ARGS__)
|
|
||||||
#define JSC_JSObjectSetPropertyAtIndex(...) __jsc_wrapper(JSObjectSetPropertyAtIndex, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSObjectCallAsConstructor JSObjectCallAsFunction JSObjectDeleteProperty
|
|
||||||
JSObjectGetPrivate JSObjectGetProperty JSObjectGetPropertyAtIndex
|
|
||||||
JSObjectGetPrototype JSObjectHasProperty JSObjectIsConstructor
|
|
||||||
JSObjectIsFunction JSObjectMake JSObjectMakeArray JSObjectMakeConstructor
|
|
||||||
JSObjectMakeDate JSObjectMakeError JSObjectMakeFunction
|
|
||||||
JSObjectMakeFunctionWithCallback JSObjectMakeRegExp JSObjectSetPrivate
|
|
||||||
JSObjectSetPrototype JSObjectSetProperty JSObjectSetPropertyAtIndex)
|
|
||||||
|
|
||||||
// JSPropertyNameArray
|
|
||||||
#define JSC_JSObjectCopyPropertyNames(...) __jsc_wrapper(JSObjectCopyPropertyNames, __VA_ARGS__)
|
|
||||||
#define JSC_JSPropertyNameArrayGetCount(...) __jsc_drop_ctx_wrapper(JSPropertyNameArrayGetCount, __VA_ARGS__)
|
|
||||||
#define JSC_JSPropertyNameArrayGetNameAtIndex(...) __jsc_drop_ctx_wrapper(JSPropertyNameArrayGetNameAtIndex, __VA_ARGS__)
|
|
||||||
#define JSC_JSPropertyNameArrayRelease(...) __jsc_drop_ctx_wrapper(JSPropertyNameArrayRelease, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSObjectCopyPropertyNames JSPropertyNameAccumulatorAddName
|
|
||||||
JSPropertyNameArrayGetCount JSPropertyNameArrayGetNameAtIndex
|
|
||||||
JSPropertyNameArrayRelease JSPropertyNameArrayRetain)
|
|
||||||
|
|
||||||
// JSTypedArray
|
|
||||||
jsc_poison(JSObjectMakeArrayBufferWithBytesNoCopy JSObjectMakeTypedArray
|
|
||||||
JSObjectMakeTypedArrayWithArrayBuffer
|
|
||||||
JSObjectMakeTypedArrayWithArrayBufferAndOffset
|
|
||||||
JSObjectMakeTypedArrayWithBytesNoCopy JSObjectGetTypedArrayByteLength
|
|
||||||
JSObjectGetTypedArrayByteOffset JSObjectGetTypedArrayBytesPtr
|
|
||||||
JSObjectGetTypedArrayBuffer JSObjectGetTypedArrayLength
|
|
||||||
JSObjectGetArrayBufferBytesPtr JSObjectGetArrayBufferByteLength)
|
|
||||||
|
|
||||||
// Sampling profiler
|
|
||||||
#define JSC_JSSamplingProfilerEnabled(...) __jsc_drop_ctx_wrapper(JSSamplingProfilerEnabled, __VA_ARGS__)
|
|
||||||
#define JSC_JSPokeSamplingProfiler(...) __jsc_wrapper(JSPokeSamplingProfiler, __VA_ARGS__)
|
|
||||||
#define JSC_JSStartSamplingProfilingOnMainJSCThread(...) __jsc_wrapper(JSStartSamplingProfilingOnMainJSCThread, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(JSSamplingProfilerEnabled JSPokeSamplingProfiler
|
|
||||||
JSStartSamplingProfilingOnMainJSCThread)
|
|
||||||
|
|
||||||
#define JSC_JSGlobalContextEnableDebugger(...) __jsc_wrapper(JSGlobalContextEnableDebugger, __VA_ARGS__)
|
|
||||||
// no need to poison JSGlobalContextEnableDebugger because it's not defined for System JSC / standard SDK header
|
|
||||||
// jsc_poison(JSGlobalContextEnableDebugger)
|
|
||||||
|
|
||||||
#define JSC_JSGlobalContextDisableDebugger(...) __jsc_wrapper(JSGlobalContextDisableDebugger, __VA_ARGS__)
|
|
||||||
// no need to poison JSGlobalContextDisableDebugger because it's not defined for System JSC / standard SDK header
|
|
||||||
// jsc_poison(JSGlobalContextDisableDebugger)
|
|
||||||
|
|
||||||
|
|
||||||
#define JSC_configureJSCForIOS(...) __jsc_bool_wrapper(configureJSCForIOS, __VA_ARGS__)
|
|
||||||
|
|
||||||
jsc_poison(configureJSCForIOS)
|
|
||||||
|
|
||||||
// Objective-C API
|
|
||||||
#define JSC_JSContext(ctx) __jsc_prop_wrapper(JSContext, ctx)
|
|
||||||
#define JSC_JSValue(ctx) __jsc_prop_wrapper(JSValue, ctx)
|
|
||||||
|
|
||||||
#undef jsc_poison
|
|
||||||
#undef jsc_pragma
|
|
@ -1,91 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#include "Unicode.h"
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
namespace unicode {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// TODO(12827176): Don't duplicate this code here and fbjni.
|
|
||||||
|
|
||||||
const uint16_t kUtf8OneByteBoundary = 0x80;
|
|
||||||
const uint16_t kUtf8TwoBytesBoundary = 0x800;
|
|
||||||
const uint16_t kUtf16HighSubLowBoundary = 0xD800;
|
|
||||||
const uint16_t kUtf16HighSubHighBoundary = 0xDC00;
|
|
||||||
const uint16_t kUtf16LowSubHighBoundary = 0xE000;
|
|
||||||
|
|
||||||
// Calculate how many bytes are needed to convert an UTF16 string into UTF8
|
|
||||||
// UTF16 string
|
|
||||||
size_t utf16toUTF8Length(const uint16_t* utf16String, size_t utf16StringLen) {
|
|
||||||
if (!utf16String || utf16StringLen == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t utf8StringLen = 0;
|
|
||||||
auto utf16StringEnd = utf16String + utf16StringLen;
|
|
||||||
auto idx16 = utf16String;
|
|
||||||
while (idx16 < utf16StringEnd) {
|
|
||||||
auto ch = *idx16++;
|
|
||||||
if (ch < kUtf8OneByteBoundary) {
|
|
||||||
utf8StringLen++;
|
|
||||||
} else if (ch < kUtf8TwoBytesBoundary) {
|
|
||||||
utf8StringLen += 2;
|
|
||||||
} else if (
|
|
||||||
(ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&
|
|
||||||
(idx16 < utf16StringEnd) &&
|
|
||||||
(*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {
|
|
||||||
utf8StringLen += 4;
|
|
||||||
idx16++;
|
|
||||||
} else {
|
|
||||||
utf8StringLen += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf8StringLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
std::string utf16toUTF8(const uint16_t* utf16String, size_t utf16StringLen) noexcept {
|
|
||||||
if (!utf16String || utf16StringLen <= 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string utf8String(utf16toUTF8Length(utf16String, utf16StringLen), '\0');
|
|
||||||
auto idx8 = utf8String.begin();
|
|
||||||
auto idx16 = utf16String;
|
|
||||||
auto utf16StringEnd = utf16String + utf16StringLen;
|
|
||||||
while (idx16 < utf16StringEnd) {
|
|
||||||
auto ch = *idx16++;
|
|
||||||
if (ch < kUtf8OneByteBoundary) {
|
|
||||||
*idx8++ = (ch & 0x7F);
|
|
||||||
} else if (ch < kUtf8TwoBytesBoundary) {
|
|
||||||
*idx8++ = 0b11000000 | (ch >> 6);
|
|
||||||
*idx8++ = 0b10000000 | (ch & 0x3F);
|
|
||||||
} else if (
|
|
||||||
(ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&
|
|
||||||
(idx16 < utf16StringEnd) &&
|
|
||||||
(*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {
|
|
||||||
auto ch2 = *idx16++;
|
|
||||||
uint8_t trunc_byte = (((ch >> 6) & 0x0F) + 1);
|
|
||||||
*idx8++ = 0b11110000 | (trunc_byte >> 2);
|
|
||||||
*idx8++ = 0b10000000 | ((trunc_byte & 0x03) << 4) | ((ch >> 2) & 0x0F);
|
|
||||||
*idx8++ = 0b10000000 | ((ch & 0x03) << 4) | ((ch2 >> 6) & 0x0F);
|
|
||||||
*idx8++ = 0b10000000 | (ch2 & 0x3F);
|
|
||||||
} else {
|
|
||||||
*idx8++ = 0b11100000 | (ch >> 12);
|
|
||||||
*idx8++ = 0b10000000 | ((ch >> 6) & 0x3F);
|
|
||||||
*idx8++ = 0b10000000 | (ch & 0x3F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf8String;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace unicode
|
|
||||||
} // namespace react
|
|
||||||
} // namespace facebook
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
namespace unicode {
|
|
||||||
__attribute__((visibility("default"))) std::string utf16toUTF8(const uint16_t* utf16, size_t length) noexcept;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,325 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#include "Value.h"
|
|
||||||
|
|
||||||
#include <folly/json.h>
|
|
||||||
#include <folly/Conv.h>
|
|
||||||
|
|
||||||
#include "JSCHelpers.h"
|
|
||||||
#include "JavaScriptCore.h"
|
|
||||||
|
|
||||||
// See the comment under Value::fromDynamic()
|
|
||||||
#if !defined(__APPLE__) && defined(WITH_FB_JSC_TUNING)
|
|
||||||
#define USE_FAST_FOLLY_DYNAMIC_CONVERSION 1
|
|
||||||
#else
|
|
||||||
#define USE_FAST_FOLLY_DYNAMIC_CONVERSION 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
Object Object::makeDate(JSContextRef ctx, Object::TimeType time) {
|
|
||||||
using std::chrono::duration_cast;
|
|
||||||
using std::chrono::milliseconds;
|
|
||||||
|
|
||||||
JSValueRef arguments[1];
|
|
||||||
arguments[0] = JSC_JSValueMakeNumber(
|
|
||||||
ctx,
|
|
||||||
duration_cast<milliseconds>(time.time_since_epoch()).count());
|
|
||||||
|
|
||||||
JSValueRef exn;
|
|
||||||
auto result = JSC_JSObjectMakeDate(ctx, 1, arguments, &exn);
|
|
||||||
if (!result) {
|
|
||||||
throw JSException(ctx, exn, "Failed to create Date");
|
|
||||||
}
|
|
||||||
return Object(ctx, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object Object::makeArray(JSContextRef ctx, JSValueRef* elements, unsigned length) {
|
|
||||||
JSValueRef exn;
|
|
||||||
auto arr = JSC_JSObjectMakeArray(ctx, length, elements, &exn);
|
|
||||||
if (!arr) {
|
|
||||||
throw JSException(ctx, exn, "Failed to create an Array");
|
|
||||||
}
|
|
||||||
return Object(ctx, arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::Value(JSContextRef context, JSValueRef value)
|
|
||||||
: m_context(context), m_value(value) {}
|
|
||||||
|
|
||||||
Value::Value(JSContextRef context, JSStringRef str)
|
|
||||||
: m_context(context), m_value(JSC_JSValueMakeString(context, str)) {}
|
|
||||||
|
|
||||||
JSContextRef Value::context() const {
|
|
||||||
return m_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
std::string Value::toJSONString(unsigned indent) const {
|
|
||||||
JSValueRef exn;
|
|
||||||
auto stringToAdopt = JSC_JSValueCreateJSONString(m_context, m_value, indent, &exn);
|
|
||||||
if (!stringToAdopt) {
|
|
||||||
throw JSException(m_context, exn, "Exception creating JSON string");
|
|
||||||
}
|
|
||||||
return String::adopt(m_context, stringToAdopt).str();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
Value Value::fromJSON(const String& json) {
|
|
||||||
JSContextRef ctx = json.context();
|
|
||||||
auto result = JSC_JSValueMakeFromJSONString(ctx, json);
|
|
||||||
if (!result) {
|
|
||||||
throw JSException(folly::to<std::string>(
|
|
||||||
"Failed to create Value from JSON: ", json.str()).c_str());
|
|
||||||
}
|
|
||||||
return Value(ctx, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value 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 Value(ctx, jsVal);
|
|
||||||
#else
|
|
||||||
auto json = folly::toJson(value);
|
|
||||||
return fromJSON(String(ctx, json.c_str()));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValueRef Value::fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj) {
|
|
||||||
switch (obj.type()) {
|
|
||||||
// For primitive types (and strings), just create and return an equivalent JSValue
|
|
||||||
case folly::dynamic::Type::NULLT:
|
|
||||||
return JSC_JSValueMakeNull(ctx);
|
|
||||||
|
|
||||||
case folly::dynamic::Type::BOOL:
|
|
||||||
return JSC_JSValueMakeBoolean(ctx, obj.getBool());
|
|
||||||
|
|
||||||
case folly::dynamic::Type::DOUBLE:
|
|
||||||
return JSC_JSValueMakeNumber(ctx, obj.getDouble());
|
|
||||||
|
|
||||||
case folly::dynamic::Type::INT64:
|
|
||||||
return JSC_JSValueMakeNumber(ctx, obj.asDouble());
|
|
||||||
|
|
||||||
case folly::dynamic::Type::STRING:
|
|
||||||
return JSC_JSValueMakeString(ctx, String(ctx, 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 = JSC_JSObjectMakeArray(ctx, obj.size(), vals, nullptr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
case folly::dynamic::Type::OBJECT: {
|
|
||||||
// Create an empty object
|
|
||||||
JSObjectRef jsObj = JSC_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) {
|
|
||||||
JSC_JSObjectSetProperty(
|
|
||||||
ctx,
|
|
||||||
jsObj,
|
|
||||||
String(ctx, 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 JSC_JSValueMakeNull(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object Value::asObject() const {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSObjectRef jsObj = JSC_JSValueToObject(context(), m_value, &exn);
|
|
||||||
if (!jsObj) {
|
|
||||||
throw JSException(m_context, exn, "Failed to convert to object");
|
|
||||||
}
|
|
||||||
return Object(context(), jsObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
String Value::toString() const {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSStringRef jsStr = JSC_JSValueToStringCopy(context(), m_value, &exn);
|
|
||||||
if (!jsStr) {
|
|
||||||
throw JSException(m_context, exn, "Failed to convert to string");
|
|
||||||
}
|
|
||||||
return String::adopt(context(), jsStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Value::makeError(JSContextRef ctx, const char *error, const char *stack)
|
|
||||||
{
|
|
||||||
auto errorMsg = Value(ctx, String(ctx, error));
|
|
||||||
JSValueRef args[] = {errorMsg};
|
|
||||||
if (stack) {
|
|
||||||
// Using this instead of JSObjectMakeError to actually get a stack property.
|
|
||||||
// MakeError only sets it stack when returning from the invoked function, so we
|
|
||||||
// can't extend it here.
|
|
||||||
auto errorConstructor = Object::getGlobalObject(ctx).getProperty("Error").asObject();
|
|
||||||
auto jsError = errorConstructor.callAsConstructor({errorMsg});
|
|
||||||
auto fullStack = std::string(stack) + jsError.getProperty("stack").toString().str();
|
|
||||||
jsError.setProperty("stack", String(ctx, fullStack.c_str()));
|
|
||||||
return jsError;
|
|
||||||
} else {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSObjectRef errorObj = JSC_JSObjectMakeError(ctx, 1, args, &exn);
|
|
||||||
if (!errorObj) {
|
|
||||||
throw JSException(ctx, exn, "Exception making error");
|
|
||||||
}
|
|
||||||
return Value(ctx, errorObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Value::throwTypeException(const std::string &expectedType) const {
|
|
||||||
std::string wat("TypeError: Expected ");
|
|
||||||
wat += expectedType;
|
|
||||||
wat += ", instead got '";
|
|
||||||
wat += toString().str();
|
|
||||||
wat += "'";
|
|
||||||
throw JSException(wat.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
Object::operator Value() const {
|
|
||||||
return Value(m_context, m_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::callAsFunction(std::initializer_list<JSValueRef> args) const {
|
|
||||||
return callAsFunction(nullptr, args.size(), args.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::callAsFunction(const Object& thisObj, std::initializer_list<JSValueRef> args) const {
|
|
||||||
return callAsFunction((JSObjectRef)thisObj, args.size(), args.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::callAsFunction(int nArgs, const JSValueRef args[]) const {
|
|
||||||
return callAsFunction(nullptr, nArgs, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::callAsFunction(const Object& thisObj, int nArgs, const JSValueRef args[]) const {
|
|
||||||
return callAsFunction(static_cast<JSObjectRef>(thisObj), nArgs, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSValueRef result = JSC_JSObjectCallAsFunction(m_context, m_obj, thisObj, nArgs, args, &exn);
|
|
||||||
if (!result) {
|
|
||||||
throw JSException(m_context, exn, "Exception calling object as function");
|
|
||||||
}
|
|
||||||
return Value(m_context, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object Object::callAsConstructor(std::initializer_list<JSValueRef> args) const {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSObjectRef result = JSC_JSObjectCallAsConstructor(m_context, m_obj, args.size(), args.begin(), &exn);
|
|
||||||
if (!result) {
|
|
||||||
throw JSException(m_context, exn, "Exception calling object as constructor");
|
|
||||||
}
|
|
||||||
return Object(m_context, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::getProperty(const String& propName) const {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSValueRef property = JSC_JSObjectGetProperty(m_context, m_obj, propName, &exn);
|
|
||||||
if (!property) {
|
|
||||||
throw JSException(m_context, exn, folly::to<std::string>(
|
|
||||||
"Failed to get property '", propName.str(), "'").c_str());
|
|
||||||
}
|
|
||||||
return Value(m_context, property);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::getPropertyAtIndex(unsigned int index) const {
|
|
||||||
JSValueRef exn;
|
|
||||||
JSValueRef property = JSC_JSObjectGetPropertyAtIndex(m_context, m_obj, index, &exn);
|
|
||||||
if (!property) {
|
|
||||||
throw JSException(m_context, exn, folly::to<std::string>(
|
|
||||||
"Failed to get property at index ", index).c_str());
|
|
||||||
}
|
|
||||||
return Value(m_context, property);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value Object::getProperty(const char *propName) const {
|
|
||||||
return getProperty(String(m_context, propName));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::setProperty(const String& propName, const Value& value) {
|
|
||||||
JSValueRef exn = nullptr;
|
|
||||||
JSC_JSObjectSetProperty(m_context, m_obj, propName, value, kJSPropertyAttributeNone, &exn);
|
|
||||||
if (exn) {
|
|
||||||
throw JSException(m_context, exn, folly::to<std::string>(
|
|
||||||
"Failed to set property '", propName.str(), "'").c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::setPropertyAtIndex(unsigned int index, const Value& value) {
|
|
||||||
JSValueRef exn = nullptr;
|
|
||||||
JSC_JSObjectSetPropertyAtIndex(m_context, m_obj, index, value, &exn);
|
|
||||||
if (exn) {
|
|
||||||
throw JSException(m_context, exn, folly::to<std::string>(
|
|
||||||
"Failed to set property at index ", index).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::setProperty(const char *propName, const Value& value) {
|
|
||||||
setProperty(String(m_context, propName), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<String> Object::getPropertyNames() const {
|
|
||||||
auto namesRef = JSC_JSObjectCopyPropertyNames(m_context, m_obj);
|
|
||||||
size_t count = JSC_JSPropertyNameArrayGetCount(m_context, namesRef);
|
|
||||||
std::vector<String> names;
|
|
||||||
names.reserve(count);
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
names.emplace_back(String::ref(m_context,
|
|
||||||
JSC_JSPropertyNameArrayGetNameAtIndex(m_context, namesRef, i)));
|
|
||||||
}
|
|
||||||
JSC_JSPropertyNameArrayRelease(m_context, namesRef);
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> Object::toJSONMap() const {
|
|
||||||
std::unordered_map<std::string, std::string> map;
|
|
||||||
auto namesRef = JSC_JSObjectCopyPropertyNames(m_context, m_obj);
|
|
||||||
size_t count = JSC_JSPropertyNameArrayGetCount(m_context, namesRef);
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
auto key = String::ref(m_context,
|
|
||||||
JSC_JSPropertyNameArrayGetNameAtIndex(m_context, namesRef, i));
|
|
||||||
map.emplace(key.str(), getProperty(key).toJSONString());
|
|
||||||
}
|
|
||||||
JSC_JSPropertyNameArrayRelease(m_context, namesRef);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
Object Object::create(JSContextRef ctx) {
|
|
||||||
JSObjectRef newObj = JSC_JSObjectMake(
|
|
||||||
ctx,
|
|
||||||
NULL, // create instance of default object class
|
|
||||||
NULL); // no private data
|
|
||||||
return Object(ctx, newObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
@ -1,373 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <folly/dynamic.h>
|
|
||||||
#include <jschelpers/JavaScriptCore.h>
|
|
||||||
#include <jschelpers/Unicode.h>
|
|
||||||
#include <jschelpers/noncopyable.h>
|
|
||||||
#include <privatedata/PrivateDataBase.h>
|
|
||||||
|
|
||||||
#ifndef RN_EXPORT
|
|
||||||
#define RN_EXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
class Value;
|
|
||||||
|
|
||||||
// C++ object wrapper for JSStringRef
|
|
||||||
class String : public noncopyable {
|
|
||||||
public:
|
|
||||||
explicit String(): m_context(nullptr), m_string(nullptr) {} // dummy empty constructor
|
|
||||||
|
|
||||||
explicit String(JSContextRef context, const char* utf8)
|
|
||||||
: m_context(context), m_string(JSC_JSStringCreateWithUTF8CString(context, utf8)) {}
|
|
||||||
|
|
||||||
String(String&& other) :
|
|
||||||
m_context(other.m_context), m_string(other.m_string)
|
|
||||||
{
|
|
||||||
other.m_string = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
String(const String& other) :
|
|
||||||
m_context(other.m_context), m_string(other.m_string)
|
|
||||||
{
|
|
||||||
if (m_string) {
|
|
||||||
JSC_JSStringRetain(m_context, m_string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~String() {
|
|
||||||
if (m_string) {
|
|
||||||
JSC_JSStringRelease(m_context, m_string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String& operator=(String&& other) {
|
|
||||||
if (m_string) {
|
|
||||||
JSC_JSStringRelease(m_context, m_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_context = other.m_context;
|
|
||||||
m_string = other.m_string;
|
|
||||||
other.m_string = nullptr;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator JSStringRef() const {
|
|
||||||
return m_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSContextRef context() const {
|
|
||||||
return m_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length in characters
|
|
||||||
size_t length() const {
|
|
||||||
return m_string ? JSC_JSStringGetLength(m_context, m_string) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length in bytes of a nul-terminated utf8 encoded value
|
|
||||||
size_t utf8Size() const {
|
|
||||||
return m_string ? JSC_JSStringGetMaximumUTF8CStringSize(m_context, m_string) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JavaScriptCore is built with strict utf16 -> utf8 conversion.
|
|
||||||
* This means if JSC's built-in conversion function encounters a JavaScript
|
|
||||||
* string which contains half of a 32-bit UTF-16 symbol, it produces an error
|
|
||||||
* rather than returning a string.
|
|
||||||
*
|
|
||||||
* Instead of relying on this, we use our own utf16 -> utf8 conversion function
|
|
||||||
* which is more lenient and always returns a string. When an invalid UTF-16
|
|
||||||
* string is provided, it'll likely manifest as a rendering glitch in the app for
|
|
||||||
* the invalid symbol.
|
|
||||||
*
|
|
||||||
* For details on JavaScript's unicode support see:
|
|
||||||
* https://mathiasbynens.be/notes/javascript-unicode
|
|
||||||
*/
|
|
||||||
std::string str() const {
|
|
||||||
if (!m_string) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const JSChar* utf16 = JSC_JSStringGetCharactersPtr(m_context, m_string);
|
|
||||||
size_t stringLength = JSC_JSStringGetLength(m_context, m_string);
|
|
||||||
return unicode::utf16toUTF8(utf16, stringLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assumes that utf8 is nul-terminated
|
|
||||||
bool equals(const char* utf8) {
|
|
||||||
return m_string ? JSC_JSStringIsEqualToUTF8CString(m_context, m_string, utf8) : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This assumes ascii is nul-terminated.
|
|
||||||
static String createExpectingAscii(JSContextRef context, const char* ascii, size_t len) {
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
return String(context, JSC_JSStringCreateWithUTF8CStringExpectAscii(context, ascii, len), true);
|
|
||||||
#else
|
|
||||||
return String(context, JSC_JSStringCreateWithUTF8CString(context, ascii), true);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static String createExpectingAscii(JSContextRef context, std::string const &ascii) {
|
|
||||||
return createExpectingAscii(context, ascii.c_str(), ascii.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a String wrapper and increases the refcount of the JSStringRef
|
|
||||||
static String ref(JSContextRef context, JSStringRef string) {
|
|
||||||
return String(context, string, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a String wrapper that takes over ownership of the string. The
|
|
||||||
// JSStringRef passed in must previously have been created or retained.
|
|
||||||
static String adopt(JSContextRef context, JSStringRef string) {
|
|
||||||
return String(context, string, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit String(JSContextRef context, JSStringRef string, bool adopt) :
|
|
||||||
m_context(context), m_string(string)
|
|
||||||
{
|
|
||||||
if (!adopt && string) {
|
|
||||||
JSC_JSStringRetain(context, string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSContextRef m_context;
|
|
||||||
JSStringRef m_string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// C++ object wrapper for JSObjectRef. The underlying JSObjectRef can be
|
|
||||||
// optionally protected. You must protect the object if it is ever
|
|
||||||
// heap-allocated, since otherwise you may end up with an invalid reference.
|
|
||||||
class Object : public noncopyable {
|
|
||||||
public:
|
|
||||||
using TimeType = std::chrono::time_point<std::chrono::system_clock>;
|
|
||||||
|
|
||||||
Object(JSContextRef context, JSObjectRef obj) :
|
|
||||||
m_context(context),
|
|
||||||
m_obj(obj)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Object(Object&& other) :
|
|
||||||
m_context(other.m_context),
|
|
||||||
m_obj(other.m_obj),
|
|
||||||
m_isProtected(other.m_isProtected) {
|
|
||||||
other.m_obj = nullptr;
|
|
||||||
other.m_isProtected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Object() {
|
|
||||||
if (m_isProtected && m_obj) {
|
|
||||||
JSC_JSValueUnprotect(m_context, m_obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object& operator=(Object&& other) {
|
|
||||||
std::swap(m_context, other.m_context);
|
|
||||||
std::swap(m_obj, other.m_obj);
|
|
||||||
std::swap(m_isProtected, other.m_isProtected);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator JSObjectRef() const {
|
|
||||||
return m_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator Value() const;
|
|
||||||
|
|
||||||
bool isFunction() const {
|
|
||||||
return JSC_JSObjectIsFunction(m_context, m_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value callAsFunction(std::initializer_list<JSValueRef> args) const;
|
|
||||||
Value callAsFunction(const Object& thisObj, std::initializer_list<JSValueRef> args) const;
|
|
||||||
Value callAsFunction(int nArgs, const JSValueRef args[]) const;
|
|
||||||
Value callAsFunction(const Object& thisObj, int nArgs, const JSValueRef args[]) const;
|
|
||||||
|
|
||||||
Object callAsConstructor(std::initializer_list<JSValueRef> args) const;
|
|
||||||
|
|
||||||
Value getProperty(const String& propName) const;
|
|
||||||
Value getProperty(const char *propName) const;
|
|
||||||
Value getPropertyAtIndex(unsigned int index) const;
|
|
||||||
void setProperty(const String& propName, const Value& value);
|
|
||||||
void setProperty(const char *propName, const Value& value);
|
|
||||||
void setPropertyAtIndex(unsigned int index, const Value& value);
|
|
||||||
std::vector<String> getPropertyNames() const;
|
|
||||||
std::unordered_map<std::string, std::string> toJSONMap() const;
|
|
||||||
|
|
||||||
void makeProtected() {
|
|
||||||
if (!m_isProtected && m_obj) {
|
|
||||||
JSC_JSValueProtect(m_context, m_obj);
|
|
||||||
m_isProtected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RN_EXPORT static Object makeArray(JSContextRef ctx, JSValueRef* elements, unsigned length);
|
|
||||||
RN_EXPORT static Object makeDate(JSContextRef ctx, TimeType time);
|
|
||||||
|
|
||||||
template<typename ReturnType>
|
|
||||||
ReturnType* getPrivate() const {
|
|
||||||
const bool isCustomJSC = isCustomJSCPtr(m_context);
|
|
||||||
return PrivateDataBase::cast<ReturnType>(JSC_JSObjectGetPrivate(isCustomJSC, m_obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPrivate(PrivateDataBase* data) const {
|
|
||||||
const bool isCustomJSC = isCustomJSCPtr(m_context);
|
|
||||||
JSC_JSObjectSetPrivate(isCustomJSC, m_obj, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSContextRef context() const {
|
|
||||||
return m_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object getGlobalObject(JSContextRef ctx) {
|
|
||||||
auto globalObj = JSC_JSContextGetGlobalObject(ctx);
|
|
||||||
return Object(ctx, globalObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of the default object class.
|
|
||||||
*/
|
|
||||||
static Object create(JSContextRef ctx);
|
|
||||||
|
|
||||||
private:
|
|
||||||
JSContextRef m_context;
|
|
||||||
JSObjectRef m_obj;
|
|
||||||
bool m_isProtected = false;
|
|
||||||
|
|
||||||
Value callAsFunction(JSObjectRef thisObj, int nArgs, const JSValueRef args[]) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
// C++ object wrapper for JSValueRef. The underlying JSValueRef is not
|
|
||||||
// protected, so this class should always be used as a stack-allocated
|
|
||||||
// variable.
|
|
||||||
class Value : public noncopyable {
|
|
||||||
public:
|
|
||||||
RN_EXPORT Value(JSContextRef context, JSValueRef value);
|
|
||||||
RN_EXPORT Value(JSContextRef context, JSStringRef value);
|
|
||||||
|
|
||||||
RN_EXPORT Value(const Value &o) : Value(o.m_context, o.m_value) {}
|
|
||||||
RN_EXPORT Value(const String &o) : Value(o.context(), o) {}
|
|
||||||
|
|
||||||
Value& operator=(Value&& other) {
|
|
||||||
m_context = other.m_context;
|
|
||||||
m_value = other.m_value;
|
|
||||||
other.m_value = NULL;
|
|
||||||
return *this;
|
|
||||||
};
|
|
||||||
|
|
||||||
operator JSValueRef() const {
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSType getType() const {
|
|
||||||
return JSC_JSValueGetType(m_context, m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBoolean() const {
|
|
||||||
return getType() == kJSTypeBoolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool asBoolean() const {
|
|
||||||
return JSC_JSValueToBoolean(context(), m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNumber() const {
|
|
||||||
return getType() == kJSTypeNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNull() const {
|
|
||||||
return getType() == kJSTypeNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isUndefined() const {
|
|
||||||
return getType() == kJSTypeUndefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
double asNumber() const {
|
|
||||||
if (isNumber()) {
|
|
||||||
return JSC_JSValueToNumber(context(), m_value, nullptr);
|
|
||||||
} else {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double getNumberOrThrow() const {
|
|
||||||
if (!isNumber()) {
|
|
||||||
throwTypeException("Number");
|
|
||||||
}
|
|
||||||
return JSC_JSValueToNumber(context(), m_value, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t asInteger() const {
|
|
||||||
return static_cast<int32_t>(asNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t asUnsignedInteger() const {
|
|
||||||
return static_cast<uint32_t>(asNumber());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isObject() const {
|
|
||||||
return getType() == kJSTypeObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
RN_EXPORT Object asObject() const;
|
|
||||||
|
|
||||||
bool isString() const {
|
|
||||||
return getType() == kJSTypeString;
|
|
||||||
}
|
|
||||||
|
|
||||||
RN_EXPORT String toString() const;
|
|
||||||
|
|
||||||
// Create an error, optionally adding an additional number of lines to the stack.
|
|
||||||
// Stack must be empty or newline terminated.
|
|
||||||
RN_EXPORT static Value makeError(JSContextRef ctx, const char *error, const char *stack = nullptr);
|
|
||||||
|
|
||||||
static Value makeNumber(JSContextRef ctx, double value) {
|
|
||||||
return Value(ctx, JSC_JSValueMakeNumber(ctx, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value makeUndefined(JSContextRef ctx) {
|
|
||||||
return Value(ctx, JSC_JSValueMakeUndefined(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value makeNull(JSContextRef ctx) {
|
|
||||||
return Value(ctx, JSC_JSValueMakeNull(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value makeBoolean(JSContextRef ctx, bool value) {
|
|
||||||
return Value(ctx, JSC_JSValueMakeBoolean(ctx, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Value makeString(JSContextRef ctx, const char* utf8) {
|
|
||||||
return Value(ctx, String(ctx, utf8));
|
|
||||||
}
|
|
||||||
|
|
||||||
RN_EXPORT std::string toJSONString(unsigned indent = 0) const;
|
|
||||||
RN_EXPORT static Value fromJSON(const String& json);
|
|
||||||
RN_EXPORT static Value fromDynamic(JSContextRef ctx, const folly::dynamic& value);
|
|
||||||
RN_EXPORT JSContextRef context() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
JSContextRef m_context;
|
|
||||||
JSValueRef m_value;
|
|
||||||
|
|
||||||
void throwTypeException(const std::string &expectedType) const;
|
|
||||||
static JSValueRef fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} }
|
|
@ -1,15 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
struct noncopyable {
|
|
||||||
noncopyable(const noncopyable&) = delete;
|
|
||||||
noncopyable& operator=(const noncopyable&) = delete;
|
|
||||||
protected:
|
|
||||||
noncopyable() = default;
|
|
||||||
};
|
|
||||||
}}
|
|
@ -1,154 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <jschelpers/JSCWrapper.h>
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <objc/runtime.h>
|
|
||||||
|
|
||||||
// Crash the app (with a descriptive stack trace) if a function that is not supported by
|
|
||||||
// the system JSC is called.
|
|
||||||
#define UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(FUNC_NAME) \
|
|
||||||
static void Unimplemented_##FUNC_NAME(__unused void* args...) { \
|
|
||||||
assert(false); \
|
|
||||||
}
|
|
||||||
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSEvaluateBytecodeBundle)
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSStringCreateWithUTF8CStringExpectAscii)
|
|
||||||
#endif
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSPokeSamplingProfiler)
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSStartSamplingProfilingOnMainJSCThread)
|
|
||||||
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSGlobalContextEnableDebugger)
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(JSGlobalContextDisableDebugger)
|
|
||||||
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(configureJSCForIOS)
|
|
||||||
|
|
||||||
UNIMPLEMENTED_SYSTEM_JSC_FUNCTION(FBJSContextStartGCTimers)
|
|
||||||
|
|
||||||
bool JSSamplingProfilerEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t JSNoBytecodeFileFormatVersion = -1;
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
static JSCWrapper s_systemWrapper = {};
|
|
||||||
|
|
||||||
const JSCWrapper* systemJSCWrapper() {
|
|
||||||
// Note that this is not used on Android. All methods are statically linked instead.
|
|
||||||
// Some fields are lazily initialized
|
|
||||||
static std::once_flag flag;
|
|
||||||
std::call_once(flag, []() {
|
|
||||||
s_systemWrapper = {
|
|
||||||
.JSGlobalContextCreateInGroup = JSGlobalContextCreateInGroup,
|
|
||||||
.JSGlobalContextRelease = JSGlobalContextRelease,
|
|
||||||
.JSGlobalContextSetName = JSGlobalContextSetName,
|
|
||||||
|
|
||||||
.JSContextGetGlobalContext = JSContextGetGlobalContext,
|
|
||||||
.JSContextGetGlobalObject = JSContextGetGlobalObject,
|
|
||||||
.FBJSContextStartGCTimers =
|
|
||||||
(decltype(&FBJSContextStartGCTimers))
|
|
||||||
Unimplemented_FBJSContextStartGCTimers,
|
|
||||||
|
|
||||||
.JSEvaluateScript = JSEvaluateScript,
|
|
||||||
.JSEvaluateBytecodeBundle =
|
|
||||||
(decltype(&JSEvaluateBytecodeBundle))
|
|
||||||
Unimplemented_JSEvaluateBytecodeBundle,
|
|
||||||
|
|
||||||
.JSStringCreateWithUTF8CString = JSStringCreateWithUTF8CString,
|
|
||||||
.JSStringCreateWithCFString = JSStringCreateWithCFString,
|
|
||||||
#if WITH_FBJSCEXTENSIONS
|
|
||||||
.JSStringCreateWithUTF8CStringExpectAscii =
|
|
||||||
(decltype(&JSStringCreateWithUTF8CStringExpectAscii))
|
|
||||||
Unimplemented_JSStringCreateWithUTF8CStringExpectAscii,
|
|
||||||
#endif
|
|
||||||
.JSStringCopyCFString = JSStringCopyCFString,
|
|
||||||
.JSStringGetCharactersPtr = JSStringGetCharactersPtr,
|
|
||||||
.JSStringGetLength = JSStringGetLength,
|
|
||||||
.JSStringGetMaximumUTF8CStringSize = JSStringGetMaximumUTF8CStringSize,
|
|
||||||
.JSStringIsEqualToUTF8CString = JSStringIsEqualToUTF8CString,
|
|
||||||
.JSStringRelease = JSStringRelease,
|
|
||||||
.JSStringRetain = JSStringRetain,
|
|
||||||
|
|
||||||
.JSClassCreate = JSClassCreate,
|
|
||||||
.JSClassRetain = JSClassRetain,
|
|
||||||
.JSClassRelease = JSClassRelease,
|
|
||||||
|
|
||||||
.JSObjectCallAsConstructor = JSObjectCallAsConstructor,
|
|
||||||
.JSObjectCallAsFunction = JSObjectCallAsFunction,
|
|
||||||
.JSObjectGetPrivate = JSObjectGetPrivate,
|
|
||||||
.JSObjectGetProperty = JSObjectGetProperty,
|
|
||||||
.JSObjectGetPropertyAtIndex = JSObjectGetPropertyAtIndex,
|
|
||||||
.JSObjectIsConstructor = JSObjectIsConstructor,
|
|
||||||
.JSObjectIsFunction = JSObjectIsFunction,
|
|
||||||
.JSObjectMake = JSObjectMake,
|
|
||||||
.JSObjectMakeArray = JSObjectMakeArray,
|
|
||||||
.JSObjectMakeDate = JSObjectMakeDate,
|
|
||||||
.JSObjectMakeError = JSObjectMakeError,
|
|
||||||
.JSObjectMakeFunctionWithCallback = JSObjectMakeFunctionWithCallback,
|
|
||||||
.JSObjectSetPrivate = JSObjectSetPrivate,
|
|
||||||
.JSObjectSetProperty = JSObjectSetProperty,
|
|
||||||
.JSObjectSetPropertyAtIndex = JSObjectSetPropertyAtIndex,
|
|
||||||
|
|
||||||
.JSObjectCopyPropertyNames = JSObjectCopyPropertyNames,
|
|
||||||
.JSPropertyNameArrayGetCount = JSPropertyNameArrayGetCount,
|
|
||||||
.JSPropertyNameArrayGetNameAtIndex = JSPropertyNameArrayGetNameAtIndex,
|
|
||||||
.JSPropertyNameArrayRelease = JSPropertyNameArrayRelease,
|
|
||||||
|
|
||||||
.JSValueCreateJSONString = JSValueCreateJSONString,
|
|
||||||
.JSValueGetType = JSValueGetType,
|
|
||||||
.JSValueMakeFromJSONString = JSValueMakeFromJSONString,
|
|
||||||
.JSValueMakeBoolean = JSValueMakeBoolean,
|
|
||||||
.JSValueMakeNull = JSValueMakeNull,
|
|
||||||
.JSValueMakeNumber = JSValueMakeNumber,
|
|
||||||
.JSValueMakeString = JSValueMakeString,
|
|
||||||
.JSValueMakeUndefined = JSValueMakeUndefined,
|
|
||||||
.JSValueProtect = JSValueProtect,
|
|
||||||
.JSValueToBoolean = JSValueToBoolean,
|
|
||||||
.JSValueToNumber = JSValueToNumber,
|
|
||||||
.JSValueToObject = JSValueToObject,
|
|
||||||
.JSValueToStringCopy = JSValueToStringCopy,
|
|
||||||
.JSValueUnprotect = JSValueUnprotect,
|
|
||||||
.JSValueIsNull = JSValueIsNull,
|
|
||||||
|
|
||||||
.JSSamplingProfilerEnabled = JSSamplingProfilerEnabled,
|
|
||||||
.JSPokeSamplingProfiler =
|
|
||||||
(decltype(&JSPokeSamplingProfiler))
|
|
||||||
Unimplemented_JSPokeSamplingProfiler,
|
|
||||||
.JSStartSamplingProfilingOnMainJSCThread =
|
|
||||||
(decltype(&JSStartSamplingProfilingOnMainJSCThread))
|
|
||||||
Unimplemented_JSStartSamplingProfilingOnMainJSCThread,
|
|
||||||
|
|
||||||
.JSGlobalContextEnableDebugger =
|
|
||||||
(decltype(&JSGlobalContextEnableDebugger))
|
|
||||||
Unimplemented_JSGlobalContextEnableDebugger,
|
|
||||||
.JSGlobalContextDisableDebugger =
|
|
||||||
(decltype(&JSGlobalContextDisableDebugger))
|
|
||||||
Unimplemented_JSGlobalContextDisableDebugger,
|
|
||||||
|
|
||||||
.configureJSCForIOS =
|
|
||||||
(decltype(&configureJSCForIOS))Unimplemented_configureJSCForIOS,
|
|
||||||
|
|
||||||
.JSContext = objc_getClass("JSContext"),
|
|
||||||
.JSValue = objc_getClass("JSValue"),
|
|
||||||
|
|
||||||
.JSBytecodeFileFormatVersion = JSNoBytecodeFileFormatVersion,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return &s_systemWrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||||||
LOCAL_PATH := $(call my-dir)
|
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
|
||||||
|
|
||||||
LOCAL_MODULE := privatedata
|
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
|
||||||
PrivateDataBase.cpp \
|
|
||||||
|
|
||||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
|
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
|
|
||||||
|
|
||||||
LOCAL_CFLAGS := \
|
|
||||||
-DLOG_TAG=\"ReactNative\"
|
|
||||||
|
|
||||||
LOCAL_CFLAGS += -fexceptions -frtti
|
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -1,24 +0,0 @@
|
|||||||
load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob")
|
|
||||||
load("//tools/build_defs/oss:rn_defs.bzl", "rn_xplat_cxx_library")
|
|
||||||
|
|
||||||
rn_xplat_cxx_library(
|
|
||||||
name = "privatedata",
|
|
||||||
srcs = glob(["**/*.cpp"]),
|
|
||||||
header_namespace = "",
|
|
||||||
exported_headers = subdir_glob(
|
|
||||||
[
|
|
||||||
("", "**/*.h"),
|
|
||||||
],
|
|
||||||
prefix = "privatedata",
|
|
||||||
),
|
|
||||||
compiler_flags = [
|
|
||||||
"-Wall",
|
|
||||||
"-fexceptions",
|
|
||||||
"-frtti",
|
|
||||||
"-fvisibility=hidden",
|
|
||||||
"-std=c++1y",
|
|
||||||
],
|
|
||||||
visibility = [
|
|
||||||
"PUBLIC",
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#include "PrivateDataBase.h"
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
PrivateDataBase::~PrivateDataBase() {}
|
|
||||||
|
|
||||||
} }
|
|
@ -1,45 +0,0 @@
|
|||||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
|
|
||||||
// This source code is licensed under the MIT license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#ifndef RN_EXPORT
|
|
||||||
#define RN_EXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace facebook {
|
|
||||||
namespace react {
|
|
||||||
|
|
||||||
// Base class for private data used to implement hybrid JS-native objects. A common root class,
|
|
||||||
// rtti and dynamic_cast allow us to do some runtime type checking that makes it possible
|
|
||||||
// for multiple hybrid object implementations to co-exist.
|
|
||||||
class RN_EXPORT PrivateDataBase {
|
|
||||||
public:
|
|
||||||
virtual ~PrivateDataBase();
|
|
||||||
|
|
||||||
// Casts given void* to PrivateDataBase and performs dynamic_cast to desired type. Returns null on
|
|
||||||
// failure.
|
|
||||||
template <typename T>
|
|
||||||
static typename std::enable_if<std::is_base_of<PrivateDataBase, T>::value, T>::type* tryCast(void* ptr) {
|
|
||||||
return dynamic_cast<T*>(reinterpret_cast<PrivateDataBase*>(ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like tryCast, but aborts on failure.
|
|
||||||
template <typename T>
|
|
||||||
static typename std::enable_if<std::is_base_of<PrivateDataBase, T>::value, T>::type* cast(void* ptr) {
|
|
||||||
auto result = tryCast<T>(ptr);
|
|
||||||
if (!result) {
|
|
||||||
assert(false && "could not cast to desired type");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} }
|
|
Loading…
x
Reference in New Issue
Block a user