-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implemented Uwp ScriptStore and PreparedScriptStore to allow caching scripts as bytecdoes #2653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
dce7987
added basic script store
c6577a7
add basic prepared script store
cd9871a
added code for script store and tryGetPreparedScript
d3cb7aa
added ability to read and write buffer from/to local file
1e275ec
changed code style to match other files in Utils folder
40b0fd8
made writing bytecode generate appropriately sized file, removed wrap…
9174f33
made reading and writing work, removed unneeded wrapper
eb540ce
set default bytecode caching to false
506c40b
address comments
stecrain 20a23a1
merge master
stecrain 49aae2f
use modified date not created
stecrain 43ffb07
excluded stores from OSS_RN, hide copy constructors/assignments, used…
cee3723
excluded OSS_RN from uwpreactinstance
72fc234
fix OSS_RN exclude placement for uwpreactinstance
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | ||
| } | ||
| }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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_; | ||
| }; | ||
| }} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | ||
| } | ||
| } | ||
|
|
||
| }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | ||
| }; | ||
|
|
||
| }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.