Skip to content
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
20 changes: 19 additions & 1 deletion vnext/ReactUWP/Base/UwpReactInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
#include <cxxreact/CxxNativeModule.h>
#include <cxxreact/Instance.h>

#if !defined(OSS_RN)
#include<UwpScriptStore.h>
#include<UwpPreparedScriptStore.h>
#endif

#if !defined(OSS_RN)
#include "ChakraJSIRuntimeHolder.h"
#endif
Expand Down Expand Up @@ -273,7 +278,20 @@ void UwpReactInstance::Start(const std::shared_ptr<IReactInstance>& spThis, cons

#if !defined(OSS_RN)
if (settings.UseJsi)
devSettings->jsiRuntimeHolder = std::make_shared<ChakraJSIRuntimeHolder>(devSettings, jsQueue, nullptr, nullptr);
{
std::unique_ptr<facebook::jsi::ScriptStore> scriptStore = nullptr;
std::unique_ptr<facebook::jsi::PreparedScriptStore> preparedScriptStore = nullptr;

if (settings.EnableByteCodeCacheing || !settings.ByteCodeFileUri.empty()) {
scriptStore = std::make_unique<UwpScriptStore>();
preparedScriptStore = std::make_unique<UwpPreparedScriptStore>(winrt::to_hstring(settings.ByteCodeFileUri));
}
devSettings->jsiRuntimeHolder = std::make_shared<ChakraJSIRuntimeHolder>(
devSettings,
jsQueue,
std::move(scriptStore),
std::move(preparedScriptStore));
}
#endif

try
Expand Down
4 changes: 4 additions & 0 deletions vnext/ReactUWP/ReactUWP.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@
<ClInclude Include="ABI\ReactControl_rt.h" />
<ClInclude Include="Base\ChakraJSIRuntimeHolder.h" />
<ClInclude Include="Base\UwpReactInstance.h" />
<ClInclude Include="UwpPreparedScriptStore.h" Condition="'$(OSS_RN)' != 'true'" />
<ClInclude Include="UwpScriptStore.h" Condition="'$(OSS_RN)' != 'true'" />
<ClInclude Include="Executors\WebSocketJSExecutorUwp.h" />
<ClInclude Include="Modules\AppStateModuleUwp.h" />
<ClInclude Include="Modules\ClipboardModule.h" />
Expand Down Expand Up @@ -250,6 +252,8 @@
<ClCompile Include="Base\ChakraJSIRuntimeHolder.cpp" Condition="'$(OSS_RN)' != 'true'" />
<ClCompile Include="Base\InstanceFactory.cpp" />
<ClCompile Include="Base\UwpReactInstance.cpp" />
<ClCompile Include="UwpPreparedScriptStore.cpp" Condition="'$(OSS_RN)' != 'true'" />
<ClCompile Include="UwpScriptStore.cpp" Condition="'$(OSS_RN)' != 'true'" />
<ClCompile Include="CxxReactUWP\JSBigString.cpp" />
<ClCompile Include="EndPoints\dll\dllmain.cpp" />
<ClCompile Include="EndPoints\dll\JSCGlue.cpp" />
Expand Down
11 changes: 11 additions & 0 deletions vnext/ReactUWP/ReactUWP.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@
<ClCompile Include="Views\ScrollContentViewManager.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="UwpPreparedScriptStore.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="UwpScriptStore.cpp">
<Filter>Utils</Filter>
<ClCompile Include="Views\Image\ImageViewManager.cpp">
<Filter>Views\Image</Filter>
</ClCompile>
Expand Down Expand Up @@ -483,6 +488,12 @@
<ClInclude Include="Views\Image\BorderEffect.h">
<Filter>Views\Image</Filter>
</ClInclude>
<ClInclude Include="UwpPreparedScriptStore.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="UwpScriptStore.h">
<Filter>Utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="EndPoints\dll\react-native-uwp.arm.def">
Expand Down
108 changes: 108 additions & 0 deletions vnext/ReactUWP/UwpPreparedScriptStore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "pch.h"
#include "UwpPreparedScriptStore.h"
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Storage.FileProperties.h>
#include "unicode.h"
#include "jsi/jsi.h"

#if _MSC_VER <= 1913
// VC 19 (2015-2017.6) cannot optimize co_await/cppwinrt usage
#pragma optimize( "", off )
#endif

namespace winrt {
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Storage;
};

namespace react { namespace uwp {
UwpPreparedScriptStore::UwpPreparedScriptStore(winrt::hstring uri)
{
if (!uri.empty())
{
m_byteCodeFileAsync = winrt::StorageFile::GetFileFromApplicationUriAsync(winrt::Uri(uri));
}
}

std::unique_ptr<const facebook::jsi::Buffer> UwpPreparedScriptStore::tryGetPreparedScript(
const facebook::jsi::ScriptSignature& scriptSignature,
const facebook::jsi::JSRuntimeSignature& runtimeSignature,
const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache.
) noexcept
{
try {

// check if app bundle version is older than or equal to the prepared script version
// if true then just read the buffer from the prepared script and return
auto byteCodeFile = TryGetByteCodeFileSync(scriptSignature);
if (byteCodeFile == nullptr) {
return nullptr;
}

auto buffer = winrt::FileIO::ReadBufferAsync(byteCodeFile).get();
auto bytecodeBuffer(std::make_unique<ByteCodeBuffer>(buffer.Length()));
auto dataReader{ winrt::Streams::DataReader::FromBuffer(buffer) };
dataReader.ReadBytes(winrt::array_view<uint8_t> { &bytecodeBuffer->data()[0], &bytecodeBuffer->data()[bytecodeBuffer->size()] });
dataReader.Close();

return bytecodeBuffer;
}
catch (...) {
return nullptr;
}
}

void UwpPreparedScriptStore::persistPreparedScript(
std::shared_ptr<const facebook::jsi::Buffer> preparedScript,
const facebook::jsi::ScriptSignature& scriptMetadata,
const facebook::jsi::JSRuntimeSignature& runtimeMetadata,
const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache.
) noexcept
{
persistPreparedScriptAsync(preparedScript, scriptMetadata, runtimeMetadata, prepareTag);
}

winrt::fire_and_forget UwpPreparedScriptStore::persistPreparedScriptAsync(
std::shared_ptr<const facebook::jsi::Buffer> preparedScript,
const facebook::jsi::ScriptSignature& scriptMetadata,
const facebook::jsi::JSRuntimeSignature& runtimeMetadata,
const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache.
)
{
try {
co_await winrt::resume_background();
auto folder = winrt::ApplicationData::Current().LocalCacheFolder();
auto fileName = winrt::to_hstring(scriptMetadata.url + ".bytecode");
auto file = co_await folder.CreateFileAsync(fileName, winrt::CreationCollisionOption::ReplaceExisting);
winrt::FileIO::WriteBytesAsync(file, winrt::array_view<const uint8_t>{ &preparedScript->data()[0], &preparedScript->data()[preparedScript->size()] });
}
catch (...) {
}
}

winrt::StorageFile UwpPreparedScriptStore::TryGetByteCodeFileSync(const facebook::jsi::ScriptSignature& scriptSignature)
{
try {
if (m_byteCodeFileAsync != nullptr) {
auto file = m_byteCodeFileAsync.get();
auto fileprops = file.GetBasicPropertiesAsync().get();
facebook::jsi::ScriptVersion_t byteCodeVersion = fileprops.DateModified().time_since_epoch().count();
if (byteCodeVersion >= scriptSignature.version) {
return file;
}
}
}
catch (...) {
// Eat this exception. If we can't get the file from the uri. Still try looking in the cache.
}

// Getting here means one of two things. No bytecode file uri was specified, or the file uri was specified but it is outdated.
// Try looking in LocalCache folder for bytecode file and use that.
auto fileName = winrt::to_hstring(scriptSignature.url + ".bytecode");
auto file = winrt::ApplicationData::Current().LocalCacheFolder().GetFileAsync(fileName).get();
auto fileprops = file.GetBasicPropertiesAsync().get();
facebook::jsi::ScriptVersion_t byteCodeVersion = fileprops.DateModified().time_since_epoch().count();

return byteCodeVersion > scriptSignature.version ? file : nullptr;
}
}}
64 changes: 64 additions & 0 deletions vnext/ReactUWP/UwpPreparedScriptStore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once
#include <jsi/ScriptStore.h>
#include <winrt/Windows.Foundation.h>
#include <cxxreact/JSBigString.h>
#include <string>
#include <future>
#include <winrt/Windows.Storage.h>
#include "jsi/jsi.h"

namespace react { namespace uwp {
class UwpPreparedScriptStore : public facebook::jsi::PreparedScriptStore
{
public:
UwpPreparedScriptStore(winrt::hstring uri);
std::unique_ptr<const facebook::jsi::Buffer> tryGetPreparedScript(
const facebook::jsi::ScriptSignature& scriptSignature,
const facebook::jsi::JSRuntimeSignature& runtimeSignature,
const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache.
) noexcept override;

void persistPreparedScript(
std::shared_ptr<const facebook::jsi::Buffer> preparedScript,
const facebook::jsi::ScriptSignature& scriptMetadata,
const facebook::jsi::JSRuntimeSignature& runtimeMetadata,
const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache.
) noexcept override;

UwpPreparedScriptStore(const UwpPreparedScriptStore&) = delete;
void operator=(const UwpPreparedScriptStore&) = delete;
private:
winrt::fire_and_forget persistPreparedScriptAsync(
std::shared_ptr<const facebook::jsi::Buffer> preparedScript,
const facebook::jsi::ScriptSignature& scriptMetadata,
const facebook::jsi::JSRuntimeSignature& runtimeMetadata,
const char* prepareTag // Optional tag. For e.g. eagerly evaluated vs lazy cache.
);
winrt::Windows::Storage::StorageFile TryGetByteCodeFileSync(const facebook::jsi::ScriptSignature& scriptSignature);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> m_byteCodeFileAsync;
};

// This is very similiar to ByteArrayBuffer in ChakraJsiRuntime.h.
// Defining this to avoid referencing types in chakra headers
class ByteCodeBuffer final : public facebook::jsi::Buffer {
public:
size_t size() const override {
return size_;
}
const uint8_t* data() const {
return byteArray_.get();
}

uint8_t* data() {
return byteArray_.get();
}

ByteCodeBuffer(int size) : size_(size), byteArray_(std::make_unique<uint8_t[]>(size)) {}
ByteCodeBuffer(const ByteCodeBuffer&) = delete;
void operator=(const ByteCodeBuffer&) = delete;

private:
int size_;
std::unique_ptr<uint8_t[]> byteArray_;
};
}}
54 changes: 54 additions & 0 deletions vnext/ReactUWP/UwpScriptStore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "pch.h"
#include "UwpScriptStore.h"
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.FileProperties.h>
#include <winrt/Windows.Foundation.h>
#include <future>
#include "unicode.h"

namespace winrt {
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Storage;
}

namespace react { namespace uwp {

UwpScriptStore::UwpScriptStore() {}

facebook::jsi::VersionedBuffer UwpScriptStore::getVersionedScript(const std::string& url) noexcept
{
facebook::jsi::VersionedBuffer versionedBuffer_;
versionedBuffer_.buffer = nullptr;
versionedBuffer_.version = 0;

return versionedBuffer_;
}

// Script version = timestamp of bundle file last created
facebook::jsi::ScriptVersion_t UwpScriptStore::getScriptVersion(const std::string& url) noexcept
{
const std::string bundleUrl = "ms-appx:///Bundle/" + url + ".bundle";
const winrt::DateTime bundleModifiedTime = getBundleModifiedDate(bundleUrl).get();
const std::uint64_t timestamp = bundleModifiedTime.time_since_epoch().count();
return timestamp;
}

std::future<winrt::DateTime> UwpScriptStore::getBundleModifiedDate(const std::string& bundleUri)
{
winrt::hstring str(facebook::react::unicode::utf8ToUtf16(bundleUri));
winrt::Windows::Foundation::Uri uri(str);

try
{
auto file = co_await winrt::StorageFile::GetFileFromApplicationUriAsync(uri);
auto props = file.GetBasicPropertiesAsync().get();
return props.DateModified();
}
catch (winrt::hresult_error const& ex)
{
winrt::DateTime date;
return date;
}
}

}}
19 changes: 19 additions & 0 deletions vnext/ReactUWP/UwpScriptStore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once
#include <jsi/ScriptStore.h>
#include <future>

namespace react { namespace uwp {

class UwpScriptStore : public facebook::jsi::ScriptStore
{
public:
facebook::jsi::VersionedBuffer getVersionedScript(const std::string& url) noexcept override;
facebook::jsi::ScriptVersion_t getScriptVersion(const std::string& url) noexcept override;
UwpScriptStore();
UwpScriptStore(const UwpScriptStore&) = delete;
void operator=(const UwpScriptStore&) = delete;
private:
std::future<winrt::Windows::Foundation::DateTime> getBundleModifiedDate(const std::string& bundlePath);
};

}}
3 changes: 3 additions & 0 deletions vnext/include/ReactUWP/IReactInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ struct ReactInstanceSettings
bool UseDirectDebugger{ false };
bool UseJsi { true };
bool EnableJITCompilation { true };
bool EnableByteCodeCacheing { false };

std::string ByteCodeFileUri;
std::string DebugHost;
std::string DebugBundlePath;
facebook::react::NativeLoggingHook LoggingCallback;
Expand Down
2 changes: 1 addition & 1 deletion vnext/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@
"react": "16.8.3",
"react-native": "^0.59.0 || 0.59.0-microsoft.5 || https://github.com/microsoft/react-native/archive/v0.59.0-microsoft.5.tar.gz"
}
}
}