Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Enable support for C++ TurboModules #6804

Merged
10 commits merged into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Enable support for C++ TurboModules",
"packageName": "react-native-windows",
"email": "vmorozov@microsoft.com",
"dependentChangeType": "patch"
}
6 changes: 6 additions & 0 deletions vnext/Desktop/React.Windows.Desktop.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@
<ClCompile Include="..\Microsoft.ReactNative\IReactPropertyBag.cpp">
<DependentUpon>..\Microsoft.ReactNative\IReactPropertyBag.idl</DependentUpon>
</ClCompile>
<ClCompile Include="..\Microsoft.ReactNative\JsiApi.cpp">
<DependentUpon>..\Microsoft.ReactNative\JsiApi.idl</DependentUpon>
</ClCompile>
<ClCompile Include="..\Microsoft.ReactNative\JsiReader.cpp">
<DependentUpon>..\Microsoft.ReactNative\IJSValueReader.idl</DependentUpon>
</ClCompile>
Expand Down Expand Up @@ -289,6 +292,9 @@
<DependentUpon>..\Microsoft.ReactNative\IReactPropertyBag.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="..\Microsoft.ReactNative\JsiApi.h">
<DependentUpon>..\Microsoft.ReactNative\JsiApi.idl</DependentUpon>
</ClInclude>
<ClInclude Include="..\Microsoft.ReactNative\RedBoxErrorFrameInfo.h" />
<ClInclude Include="..\Microsoft.ReactNative\RedBoxErrorInfo.h" />
<ClInclude Include="JSBigStringResourceDll.h" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,14 @@
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactNonAbiValue.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactNotificationService.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactPackageBuilder.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactPackageProvider.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactPropertyBag.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IViewManager.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IViewManagerCore.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\JsiApi.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\ReactInstanceSettings.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\ReactNativeHost.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\RedBoxHandler.idl" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,23 @@ void ReactContextMock::EmitJSEvent(
m_builderMock->EmitJSEvent(eventEmitterName, eventName, paramsArgWriter);
}

Microsoft::ReactNative::IReactPropertyNamespace ReactPropertyBagHelper::GlobalNamespace() {
VerifyElseCrashSz(false, "Not implemented");
}

Microsoft::ReactNative::IReactPropertyNamespace ReactPropertyBagHelper::GetNamespace(
param::hstring const & /*namespaceName*/) {
VerifyElseCrashSz(false, "Not implemented");
}

Microsoft::ReactNative::IReactPropertyName ReactPropertyBagHelper::GetName(
Microsoft::ReactNative::IReactPropertyNamespace const & /*ns*/,
param::hstring const & /*localName*/) {
VerifyElseCrashSz(false, "Not implemented");
}

Microsoft::ReactNative::IReactPropertyBag ReactPropertyBagHelper::CreatePropertyBag() {
VerifyElseCrashSz(false, "Not implemented");
}

} // namespace winrt::Microsoft::ReactNative
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once
#ifndef MICROSOFT_REACTNATIVE_JSI_JSIAPI
#define MICROSOFT_REACTNATIVE_JSI_JSIAPI
#include "../ReactContext.h"
#include "JsiAbiApi.h"
#include "pch.h"
#include "JsiApiContext.h"

// Use __ImageBase to get current DLL handle.
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
Expand Down Expand Up @@ -58,21 +55,4 @@ facebook::jsi::Runtime &GetOrCreateContextRuntime(ReactContext const &context) n
return *runtime;
}

// Call provided lambda with the facebook::jsi::Runtime& parameter.
// For example: ExecuteJsi(context, [](facebook::jsi::Runtime& runtime){...})
// The code is executed synchronously if it is already in JSDispatcher, or asynchronously otherwise.
template <class TCodeWithRuntime>
void ExecuteJsi(ReactContext const &context, TCodeWithRuntime const &code) {
ReactDispatcher jsDispatcher = context.JSDispatcher();
if (jsDispatcher.HasThreadAccess()) {
// Execute immediately if we are in JS thread.
code(GetOrCreateContextRuntime(context));
} else {
// Otherwise, schedule work in JS thread.
jsDispatcher.Post([ context, code ]() noexcept { code(GetOrCreateContextRuntime(context)); });
}
}

} // namespace winrt::Microsoft::ReactNative

#endif // MICROSOFT_REACTNATIVE_JSI_JSIAPI
35 changes: 35 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once
#ifndef MICROSOFT_REACTNATIVE_JSI_JSIAPI
#define MICROSOFT_REACTNATIVE_JSI_JSIAPI

#include "../ReactContext.h"
#include "JsiAbiApi.h"

namespace winrt::Microsoft::ReactNative {

// Get JSI Runtime from the current JS dispatcher thread.
// If it is not found, then create it and store it in the context.Properties().
// Make sure that the JSI runtime holder is removed when the instance is unloaded.
facebook::jsi::Runtime &GetOrCreateContextRuntime(ReactContext const &context) noexcept;

// Call provided lambda with the facebook::jsi::Runtime& parameter.
// For example: ExecuteJsi(context, [](facebook::jsi::Runtime& runtime){...})
// The code is executed synchronously if it is already in JSDispatcher, or asynchronously otherwise.
template <class TCodeWithRuntime>
void ExecuteJsi(ReactContext const &context, TCodeWithRuntime const &code) {
ReactDispatcher jsDispatcher = context.JSDispatcher();
if (jsDispatcher.HasThreadAccess()) {
// Execute immediately if we are in JS thread.
code(GetOrCreateContextRuntime(context));
} else {
// Otherwise, schedule work in JS thread.
jsDispatcher.Post([ context, code ]() noexcept { code(GetOrCreateContextRuntime(context)); });
}
}

} // namespace winrt::Microsoft::ReactNative

#endif // MICROSOFT_REACTNATIVE_JSI_JSIAPI
45 changes: 39 additions & 6 deletions vnext/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{da8b35b3-da00-4b02-bde6-6a397b3fd46b}</ItemsProjectGuid>
<ReactNativeDir Condition="'$(ReactNativeDir)' == '' AND Exists('$(MSBuildThisFileDirectory)\..\..\node_modules\react-native\package.json')">$(MSBuildThisFileDirectory)\..\..\node_modules\react-native</ReactNativeDir>
<ReactNativeDir Condition="'$(ReactNativeDir)' == '' AND Exists('$(MSBuildThisFileDirectory)\..\..\..\node_modules\react-native\package.json')">$(MSBuildThisFileDirectory)\..\..\..\node_modules\react-native</ReactNativeDir>
<ReactNativeDir Condition="'$(ReactNativeDir)' == '' AND Exists('$(MSBuildThisFileDirectory)..\..\node_modules\react-native\package.json')">$(MSBuildThisFileDirectory)..\..\node_modules\react-native</ReactNativeDir>
<ReactNativeDir Condition="'$(ReactNativeDir)' == '' AND Exists('$(MSBuildThisFileDirectory)..\..\..\node_modules\react-native\package.json')">$(MSBuildThisFileDirectory)..\..\..\node_modules\react-native</ReactNativeDir>
<JSI_SourcePath Condition="'$(JSI_SourcePath)' == '' AND '$(ReactNativeDir)' != ''">$(ReactNativeDir)\ReactCommon\jsi</JSI_SourcePath>
<JSI_SourcePath Condition="'$(JSI_SourcePath)' == '' AND Exists('$(MSBuildThisFileDirectory)\jsi\jsi.h')">$(MSBuildThisFileDirectory)</JSI_SourcePath>
<JSI_SourcePath Condition="'$(JSI_SourcePath)' == '' AND Exists('$(MSBuildThisFileDirectory)jsi\jsi.h')">$(MSBuildThisFileDirectory)</JSI_SourcePath>
<CallInvoker_SourcePath Condition="'$(CallInvoker_SourcePath)' == '' AND '$(ReactNativeDir)' != ''">$(ReactNativeDir)\ReactCommon\callinvoker</CallInvoker_SourcePath>
<CallInvoker_SourcePath Condition="'$(CallInvoker_SourcePath)' == '' AND Exists('$(MSBuildThisFileDirectory)ReactCommon\CallInvoker.h')">$(MSBuildThisFileDirectory)</CallInvoker_SourcePath>
<TurboModule_SourcePath Condition="'$(TurboModule_SourcePath)' == '' AND '$(ReactNativeDir)' != ''">$(ReactNativeDir)\ReactCommon\react\nativemodule\core</TurboModule_SourcePath>
<TurboModule_SourcePath Condition="'$(TurboModule_SourcePath)' == '' AND Exists('$(MSBuildThisFileDirectory)ReactCommon\TurboModule.h')">$(MSBuildThisFileDirectory)</TurboModule_SourcePath>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);$(JSI_SourcePath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>
$(MSBuildThisFileDirectory);
$(JSI_SourcePath);
$(CallInvoker_SourcePath);
$(TurboModule_SourcePath);
%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
</ClCompile>
<Midl>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
Expand All @@ -24,10 +34,16 @@
<ClInclude Include="$(JSI_SourcePath)\jsi\instrumentation.h" />
<ClInclude Include="$(JSI_SourcePath)\jsi\jsi-inl.h" />
<ClInclude Include="$(JSI_SourcePath)\jsi\jsi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)TurboModuleProvider.h" />
<ClInclude Include="$(CallInvoker_SourcePath)\ReactCommon\CallInvoker.h" />
<ClInclude Include="$(TurboModule_SourcePath)\ReactCommon\LongLivedObject.h" />
<ClInclude Include="$(TurboModule_SourcePath)\ReactCommon\TurboModule.h" />
<!-- TODO: change TurboModuleUtils.h to use the $(TurboModule_SourcePath) after we fix and 'de-fork' it. -->
<ClInclude Include="$(MSBuildThisFileDirectory)ReactCommon\TurboModuleUtils.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)CppWinRTIncludes.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)Crash.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSI\JsiAbiApi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSI\JsiApi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSI\JsiApiContext.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactHandleHelper.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSValue.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSValueReader.h" />
Expand Down Expand Up @@ -71,11 +87,28 @@
<ClCompile Include="$(JSI_SourcePath)\jsi\jsi.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)JSI\JsiAbiApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)JSI\JsiApiContext.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)JSValue.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)JSValueTreeReader.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)JSValueTreeWriter.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)ModuleRegistration.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)ReactPromise.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)JSI\JsiAbiApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)TurboModuleProvider.cpp" />
<ClCompile Include="$(TurboModule_SourcePath)\ReactCommon\LongLivedObject.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(TurboModule_SourcePath)\ReactCommon\TurboModule.cpp">
<DisableSpecificWarnings>4100;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<!-- TODO: change TurboModuleUtils.cpp to use the $(TurboModule_SourcePath) after we fix and 'de-fork' TurboModuleUtils.h. -->
<ClCompile Include="$(MSBuildThisFileDirectory)ReactCommon\TurboModuleUtils.cpp">
<DisableSpecificWarnings>4100;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)README.md" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@
<ClCompile Include="$(MSBuildThisFileDirectory)JSI\JsiAbiApi.cpp">
<Filter>JSI</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)ReactCommon\TurboModuleUtils.cpp">
<Filter>TurboModule</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)TurboModuleProvider.cpp">
<Filter>TurboModule</Filter>
</ClCompile>
<ClCompile Include="$(TurboModule_SourcePath)\ReactCommon\TurboModule.cpp">
<Filter>TurboModule</Filter>
</ClCompile>
<ClCompile Include="$(TurboModule_SourcePath)\ReactCommon\LongLivedObject.cpp">
<Filter>TurboModule</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)JSI\JsiApiContext.cpp">
<Filter>JSI</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)Crash.h" />
Expand Down Expand Up @@ -112,9 +127,22 @@
<ClInclude Include="$(JSI_SourcePath)\jsi\instrumentation.h">
<Filter>JSI</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)JSI\JsiApi.h">
<ClInclude Include="$(MSBuildThisFileDirectory)TurboModuleProvider.h">
<Filter>TurboModule</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ReactCommon\TurboModuleUtils.h">
<Filter>TurboModule</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)JSI\JsiApiContext.h">
<Filter>JSI</Filter>
</ClInclude>
<ClInclude Include="$(CallInvoker_SourcePath)\ReactCommon\CallInvoker.h" />
<ClInclude Include="$(TurboModule_SourcePath)\ReactCommon\TurboModule.h">
<Filter>TurboModule</Filter>
</ClInclude>
<ClInclude Include="$(TurboModule_SourcePath)\ReactCommon\LongLivedObject.h">
<Filter>TurboModule</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="JSI">
Expand All @@ -123,5 +151,11 @@
<Filter Include="UI">
<UniqueIdentifier>{acac5f8a-4b6a-4139-9b74-6e3c36aceb20}</UniqueIdentifier>
</Filter>
<Filter Include="TurboModule">
<UniqueIdentifier>{b5c0294c-d72f-44fa-8509-369f7d3e4a56}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)README.md" />
</ItemGroup>
</Project>
100 changes: 100 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/ReactCommon/TurboModuleUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// This file is a copy from react-native NPM package to avoid dependency on folly.
// It must be removed after the TurboModuleUtils.h file is fixed in react-native repo:
// https://github.com/facebook/react-native/pull/30672

/*
* 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 "TurboModuleUtils.h"

namespace facebook {
namespace react {

static jsi::Value deepCopyJSIValue(jsi::Runtime &rt, const jsi::Value &value) {
if (value.isNull()) {
return jsi::Value::null();
}

if (value.isBool()) {
return jsi::Value(value.getBool());
}

if (value.isNumber()) {
return jsi::Value(value.getNumber());
}

if (value.isString()) {
return value.getString(rt);
}

if (value.isObject()) {
jsi::Object o = value.getObject(rt);
if (o.isArray(rt)) {
return deepCopyJSIArray(rt, o.getArray(rt));
}
if (o.isFunction(rt)) {
return o.getFunction(rt);
}
return deepCopyJSIObject(rt, o);
}

return jsi::Value::undefined();
}

jsi::Object deepCopyJSIObject(jsi::Runtime &rt, const jsi::Object &obj) {
jsi::Object copy(rt);
jsi::Array propertyNames = obj.getPropertyNames(rt);
size_t size = propertyNames.size(rt);
for (size_t i = 0; i < size; i++) {
jsi::String name = propertyNames.getValueAtIndex(rt, i).getString(rt);
jsi::Value value = obj.getProperty(rt, name);
copy.setProperty(rt, name, deepCopyJSIValue(rt, value));
}
return copy;
}

jsi::Array deepCopyJSIArray(jsi::Runtime &rt, const jsi::Array &arr) {
size_t size = arr.size(rt);
jsi::Array copy(rt, size);
for (size_t i = 0; i < size; i++) {
copy.setValueAtIndex(rt, i, deepCopyJSIValue(rt, arr.getValueAtIndex(rt, i)));
}
return copy;
}

Promise::Promise(jsi::Runtime &rt, jsi::Function resolve, jsi::Function reject)
: runtime_(rt), resolve_(std::move(resolve)), reject_(std::move(reject)) {}

void Promise::resolve(const jsi::Value &result) {
resolve_.call(runtime_, result);
}

void Promise::reject(const std::string &message) {
jsi::Object error(runtime_);
error.setProperty(runtime_, "message", jsi::String::createFromUtf8(runtime_, message));
reject_.call(runtime_, error);
}

jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, const PromiseSetupFunctionType func) {
jsi::Function JSPromise = rt.global().getPropertyAsFunction(rt, "Promise");
jsi::Function fn = jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forAscii(rt, "fn"),
2,
[func](jsi::Runtime &rt2, const jsi::Value &thisVal, const jsi::Value *args, size_t count) {
jsi::Function resolve = args[0].getObject(rt2).getFunction(rt2);
jsi::Function reject = args[1].getObject(rt2).getFunction(rt2);
auto wrapper = std::make_shared<Promise>(rt2, std::move(resolve), std::move(reject));
func(rt2, wrapper);
return jsi::Value::undefined();
});

return JSPromise.callAsConstructor(rt, fn);
}

} // namespace react
} // namespace facebook
Loading