-
Notifications
You must be signed in to change notification settings - Fork 2
refactor: remove eval #22
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #include <worklets/SharedItems/Shareables.h> | ||
| #include "WorkletStore.h" | ||
|
|
||
| using namespace facebook; | ||
|
|
||
|
|
@@ -57,9 +58,11 @@ jsi::Value makeShareableClone( | |
| auto object = value.asObject(rt); | ||
|
|
||
| jsi::PropNameID prop = workletCodePropName(rt); | ||
| if (object.hasProperty(rt, prop)) { | ||
| jsi::Value code = object.getProperty(rt, prop); | ||
| shareable = std::make_shared<ShareableString>(code.asString(rt).utf8(rt)); | ||
| if (object.hasProperty(rt, prop)) { // Worklet function | ||
| auto code = object.getProperty(rt, prop).asString(rt).utf8(rt); | ||
| double hash = object.getProperty(rt,jsi::String::createFromUtf8(rt,"hash")).asNumber(); | ||
| WorkletStore::getInstance().set(hash, code); | ||
| shareable = std::make_shared<ShareableString>(""); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to return anything |
||
| } else if (!object.getProperty(rt, "__workletHash").isUndefined()) { | ||
| shareable = std::make_shared<ShareableWorklet>(rt, object); | ||
| } else if (!object.getProperty(rt, "__init").isUndefined()) { | ||
|
|
||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gemini's work |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| // | ||
| // WorkletStore.cpp | ||
| // Pods | ||
| // | ||
| // Created by Alexander Pataridze on 29.03.25. | ||
| // | ||
|
|
||
| #include "WorkletStore.h" // Include the header definition | ||
| #include <utility> // For potential use of std::move if needed | ||
|
|
||
| // --- Singleton Implementation --- | ||
| // Provides the actual instance storage and retrieval logic. | ||
| // Meyers' Singleton pattern guarantees thread-safe initialization since C++11. | ||
| WorkletStore& WorkletStore::getInstance() { | ||
| // The 'static' variable is initialized only once, the first time this function is called. | ||
| static WorkletStore instance; | ||
| return instance; | ||
| } | ||
|
|
||
| // --- Method Implementations --- | ||
|
|
||
| void WorkletStore::set(double key, const std::string& value) { | ||
| // Acquire an exclusive lock that automatically releases when 'lock' goes out of scope. | ||
| std::lock_guard<std::mutex> lock(storeMutex_); | ||
| // Insert or update the key-value pair in the map. | ||
| store_[key] = value; | ||
| } | ||
|
|
||
| std::string WorkletStore::get(double key) const { | ||
| // Acquire a lock (needed even for reading to prevent data races with writes). | ||
| std::lock_guard<std::mutex> lock(storeMutex_); | ||
| // Find the key in the map. | ||
| auto it = store_.find(key); | ||
| if (it != store_.end()) { | ||
| // Key found, return the value wrapped in std::optional. | ||
| return it->second; | ||
| } | ||
| // Key not found, return an empty std::optional. | ||
| return ""; | ||
| } | ||
|
|
||
| bool WorkletStore::remove(double key) { | ||
| // Acquire an exclusive lock. | ||
| std::lock_guard<std::mutex> lock(storeMutex_); | ||
| // Attempt to erase the key. std::unordered_map::erase returns the number | ||
| // of elements removed (0 or 1 for maps with unique keys). | ||
| return store_.erase(key) > 0; | ||
| } | ||
|
|
||
| bool WorkletStore::contains(double key) const { | ||
| // Acquire a lock. | ||
| std::lock_guard<std::mutex> lock(storeMutex_); | ||
| // Check if the key exists. map::count returns 1 if the key exists, 0 otherwise. | ||
| return store_.count(key) > 0; | ||
| // Alternative: return store_.find(key) != store_.end(); | ||
| } | ||
|
|
||
| void WorkletStore::clear() { | ||
| // Acquire an exclusive lock. | ||
| std::lock_guard<std::mutex> lock(storeMutex_); | ||
| // Remove all elements from the map. | ||
| store_.clear(); | ||
| } | ||
|
|
||
| size_t WorkletStore::size() const { | ||
| // Acquire a lock. | ||
| std::lock_guard<std::mutex> lock(storeMutex_); | ||
| // Return the current number of elements in the map. | ||
| return store_.size(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| // | ||
| // WorkletMap.h | ||
| // Pods | ||
| // | ||
| // Created by Alexander Pataridze on 29.03.25. | ||
| // | ||
|
|
||
| #pragma once // Prevents multiple inclusions of the header | ||
|
|
||
| #include <string> | ||
| #include <unordered_map> // Efficient hash-based map | ||
| #include <mutex> // For thread safety | ||
| #include <optional> // To safely return values that might not exist | ||
| #include <shared_mutex> // For potential read-write optimization (optional) | ||
|
|
||
| // A thread-safe singleton class for storing key-value pairs (string -> string). | ||
| class WorkletStore { | ||
| public: | ||
| // --- Singleton Access --- | ||
|
|
||
| /** | ||
| * @brief Gets the single instance of the WorkletStore. Thread-safe initialization. | ||
| * @return Reference to the WorkletStore instance. | ||
| */ | ||
| static WorkletStore& getInstance(); | ||
|
|
||
| // --- Deleted Constructors/Assignments (Singleton Pattern) --- | ||
| // Prevent copying and moving to enforce single instance | ||
| WorkletStore(const WorkletStore&) = delete; | ||
| WorkletStore& operator=(const WorkletStore&) = delete; | ||
| WorkletStore(WorkletStore&&) = delete; | ||
| WorkletStore& operator=(WorkletStore&&) = delete; | ||
|
|
||
| // --- Public Interface --- | ||
|
|
||
| /** | ||
| * @brief Sets (inserts or updates) the value for a given key. Thread-safe. | ||
| * @param key The key to set. | ||
| * @param value The value to associate with the key. | ||
| */ | ||
| void set(double key, const std::string& value); | ||
|
|
||
| /** | ||
| * @brief Gets the value associated with a given key. Thread-safe. | ||
| * @param key The key to look up. | ||
| * @return An std::optional<std::string> containing the value if the key exists, | ||
| * otherwise std::nullopt. | ||
| */ | ||
| std::string get(double key) const; // const because it reads | ||
|
|
||
| /** | ||
| * @brief Removes a key-value pair from the store. Thread-safe. | ||
| * @param key The key to remove. | ||
| * @return true if an element was removed, false otherwise. | ||
| */ | ||
| bool remove(double key); | ||
|
|
||
| /** | ||
| * @brief Checks if the store contains a specific key. Thread-safe. | ||
| * @param key The key to check for. | ||
| * @return true if the key exists, false otherwise. | ||
| */ | ||
| bool contains(double key) const; // const because it reads | ||
|
|
||
| /** | ||
| * @brief Removes all key-value pairs from the store. Thread-safe. | ||
| */ | ||
| void clear(); | ||
|
|
||
| /** | ||
| * @brief Gets the number of key-value pairs currently in the store. Thread-safe. | ||
| * @return The number of elements. | ||
| */ | ||
| size_t size() const; // const because it reads | ||
|
|
||
| private: | ||
| // --- Private Members --- | ||
|
|
||
| // Private constructor: enforce singleton access via getInstance() | ||
| WorkletStore() = default; | ||
|
|
||
| // Private destructor (can be defaulted if no special cleanup needed) | ||
| ~WorkletStore() = default; | ||
|
|
||
| // The underlying map storing the data | ||
| std::unordered_map<double, std::string> store_; | ||
|
|
||
| // Mutex to protect access to the store_ map from concurrent threads. | ||
| // 'mutable' allows locking even in 'const' methods like get() and contains(). | ||
| mutable std::mutex storeMutex_; | ||
|
|
||
| // --- Optional Optimization (Advanced) --- | ||
| // For high-contention scenarios with many more reads than writes, | ||
| // a std::shared_mutex can sometimes offer better performance. | ||
| // mutable std::shared_mutex storeSharedMutex_; | ||
| // Use std::lock_guard<std::shared_mutex> for writes (exclusive lock). | ||
| // Use std::shared_lock<std::shared_mutex> for reads (shared lock). | ||
| // For simplicity, we'll stick with the standard std::mutex here. | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #include <worklets/WorkletRuntime/ReanimatedHermesRuntime.h> | ||
| #include <worklets/SharedItems/WorkletStore.h> | ||
|
|
||
| // Only include this file in Hermes-enabled builds as some platforms (like tvOS) | ||
| // don't support hermes and it causes the compilation to fail. | ||
|
|
@@ -80,34 +81,33 @@ ReanimatedHermesRuntime::ReanimatedHermesRuntime( | |
| jsQueue->quitSynchronous(); | ||
| #endif // HERMES_ENABLE_DEBUGGER | ||
|
|
||
| #ifndef NDEBUG | ||
| facebook::hermes::HermesRuntime *wrappedRuntime = runtime_.get(); | ||
| jsi::Value evalWithSourceMap = jsi::Function::createFromHostFunction( | ||
| *runtime_, | ||
| jsi::PropNameID::forAscii(*runtime_, "evalWithSourceMap"), | ||
| 3, | ||
| [wrappedRuntime]( | ||
| jsi::Runtime &rt, | ||
| const jsi::Value &thisValue, | ||
| const jsi::Value *args, | ||
| size_t count) -> jsi::Value { | ||
| auto code = std::make_shared<const jsi::StringBuffer>( | ||
| args[0].asString(rt).utf8(rt)); | ||
| std::string sourceURL; | ||
| if (count > 1 && args[1].isString()) { | ||
| sourceURL = args[1].asString(rt).utf8(rt); | ||
| } | ||
| std::shared_ptr<const jsi::Buffer> sourceMap; | ||
| if (count > 2 && args[2].isString()) { | ||
| sourceMap = std::make_shared<const jsi::StringBuffer>( | ||
| args[2].asString(rt).utf8(rt)); | ||
| } | ||
| return wrappedRuntime->evaluateJavaScriptWithSourceMap( | ||
| code, sourceMap, sourceURL); | ||
| }); | ||
| runtime_->global().setProperty( | ||
| *runtime_, "evalWithSourceMap", evalWithSourceMap); | ||
| #endif // NDEBUG | ||
|
|
||
| facebook::hermes::HermesRuntime *wrappedRuntime = runtime_.get(); | ||
| jsi::Value evalFromHashValue = jsi::Function::createFromHostFunction( | ||
| *runtime_, | ||
| jsi::PropNameID::forAscii(*runtime_, "evalFromHashValue"), | ||
| 3, | ||
| [wrappedRuntime]( | ||
| jsi::Runtime &rt, | ||
| const jsi::Value &thisValue, | ||
| const jsi::Value *args, | ||
| size_t count) -> jsi::Value { | ||
| auto code = std::make_shared<const jsi::StringBuffer>("("+WorkletStore::getInstance().get(args[0].asNumber())+"\n)"); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. grab the function from the store |
||
|
|
||
| std::string sourceURL; | ||
| if (count > 1 && args[1].isString()) { | ||
| sourceURL = args[1].asString(rt).utf8(rt); | ||
| } | ||
| std::shared_ptr<const jsi::Buffer> sourceMap; | ||
| if (count > 2 && args[2].isString()) { | ||
| sourceMap = std::make_shared<const jsi::StringBuffer>( | ||
| args[2].asString(rt).utf8(rt)); | ||
| } | ||
| return wrappedRuntime->evaluateJavaScriptWithSourceMap( | ||
| code, sourceMap, sourceURL); | ||
| }); | ||
| runtime_->global().setProperty( | ||
| *runtime_, "evalFromHashValue", evalFromHashValue); | ||
| } | ||
|
|
||
| ReanimatedHermesRuntime::~ReanimatedHermesRuntime() { | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,13 +153,18 @@ export function makeWorkletFactory( | |
| true | ||
| ); | ||
|
|
||
| const reanimatedSecretCodeProperty = objectProperty( | ||
| const workletHashProperty = objectProperty( | ||
| stringLiteral('hash'), | ||
| numericLiteral(workletHash) | ||
| ); | ||
|
|
||
| const reanimatedWorkletCodeProperty = objectProperty( | ||
| identifier('__reanimated_workletCodeWrapper'), | ||
| objectExpression([workletCodeProperty]) | ||
| objectExpression([workletCodeProperty, workletHashProperty]) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add hash to our wrapper for easy access in Shareables.CPP |
||
| ); | ||
|
|
||
| const initDataObjectExpression = objectExpression([ | ||
| reanimatedSecretCodeProperty, | ||
| reanimatedWorkletCodeProperty, | ||
| ]); | ||
|
|
||
| // When testing with jest I noticed that environment variables are set later | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to return anything