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
9 changes: 9 additions & 0 deletions apps/common-app/src/apps/reanimated/examples/AboutExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ function getBundle() {
return __DEV__ ? 'dev' : 'production';
}

function usesLegacyEvalBytecode() {
return !!(() => {
'worklet';
// @ts-expect-error It's fine
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
})?.__initData?.bytecode;
}

function getRuntime() {
if ('HermesInternal' in globalThis) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
Expand Down Expand Up @@ -129,6 +137,7 @@ export default function AboutExample() {
<Item label="JS runtime" value={getRuntime()} />
<Item label="RN version" value={getReactNativeVersion()} />
<Item label="Bundle mode" value={isBundleModeEnabled()} />
<Item label="Legacy eval bytecode" value={usesLegacyEvalBytecode()} />
<Text style={styles.sectionHeader}>Reanimated static flags</Text>
{staticFlagsReanimated.map((name) => (
<Item
Expand Down
19 changes: 19 additions & 0 deletions apps/fabric-example/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
const workletsPluginOptions = {
strictGlobal: true,
bundleMode: true,
hermesBytecode: false,
getHBCBinary,
};

/** @type {import('@babel/core').TransformOptions} */
Expand All @@ -20,3 +22,20 @@ module.exports = {
],
],
};

const path = require('path');

function getHBCBinary() {
const hermescDir = path.join(
path.dirname(require.resolve('hermes-compiler/package.json')),
'hermesc'
);
const binDir =
process.platform === 'darwin'
? 'osx-bin'
: process.platform === 'win32'
? 'win64-bin'
: 'linux64-bin';
const binName = process.platform === 'win32' ? 'hermesc.exe' : 'hermesc';
return path.join(hermescDir, binDir, binName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,55 +215,37 @@ jsi::Object JSIWorkletsModuleProxy::toOptimizedObject(jsi::Runtime &rt) const {
jsi_utils::addMethod<18>(
rt,
obj,
"loadUnpackers",
"loadUnpackersWithCode",
[unpackerLoader = unpackerLoader_](jsi::Runtime &rt, const jsi::Value &, const jsi::Value(&args)[18]) {
const auto valueUnpackerCode = at<0>(args).asString(rt).utf8(rt);
const auto valueUnpackerLocation = at<1>(args).asString(rt).utf8(rt);
const auto valueUnpackerSourceMap = at<2>(args).asString(rt).utf8(rt);

const auto synchronizableUnpackerCode = at<3>(args).asString(rt).utf8(rt);
const auto synchronizableUnpackerLocation = at<4>(args).asString(rt).utf8(rt);
const auto synchronizableUnpackerSourceMap = at<5>(args).asString(rt).utf8(rt);

const auto customSerializableUnpackerCode = at<6>(args).asString(rt).utf8(rt);
const auto customSerializableUnpackerLocation = at<7>(args).asString(rt).utf8(rt);
const auto customSerializableUnpackerSourceMap = at<8>(args).asString(rt).utf8(rt);

const auto shareableHostUnpackerCode = at<9>(args).asString(rt).utf8(rt);
const auto shareableHostUnpackerLocation = at<10>(args).asString(rt).utf8(rt);
const auto shareableHostUnpackerSourceMap = at<11>(args).asString(rt).utf8(rt);

const auto shareableGuestUnpackerCode = at<12>(args).asString(rt).utf8(rt);
const auto shareableGuestUnpackerLocation = at<13>(args).asString(rt).utf8(rt);
const auto shareableGuestUnpackerSourceMap = at<14>(args).asString(rt).utf8(rt);

const auto remoteFunctionUnpackerCode = args[15].asString(rt).utf8(rt);
const auto remoteFunctionUnpackerLocation = args[16].asString(rt).utf8(rt);
const auto remoteFunctionUnpackerSourceMap = args[17].asString(rt).utf8(rt);

unpackerLoader->loadUnpackers(ShareableUnpackers{
.valueUnpacker =
{.code = valueUnpackerCode, .location = valueUnpackerLocation, .sourceMap = valueUnpackerSourceMap},
.synchronizableUnpacker =
{.code = synchronizableUnpackerCode,
.location = synchronizableUnpackerLocation,
.sourceMap = synchronizableUnpackerSourceMap},
.customSerializableUnpacker =
{.code = customSerializableUnpackerCode,
.location = customSerializableUnpackerLocation,
.sourceMap = customSerializableUnpackerSourceMap},
.shareableHostUnpacker =
{.code = shareableHostUnpackerCode,
.location = shareableHostUnpackerLocation,
.sourceMap = shareableHostUnpackerSourceMap},
.shareableGuestUnpacker =
{.code = shareableGuestUnpackerCode,
.location = shareableGuestUnpackerLocation,
.sourceMap = shareableGuestUnpackerSourceMap},
.remoteFunctionUnpacker =
{.code = remoteFunctionUnpackerCode,
.location = remoteFunctionUnpackerLocation,
.sourceMap = remoteFunctionUnpackerSourceMap},
const auto str = [&](size_t i) {
return args[i].getString(rt).utf8(rt);
};
unpackerLoader->loadCodeUnpackers({
CodeUnpacker{.code = str(0), .location = str(1), .sourceMap = str(2)},
CodeUnpacker{.code = str(3), .location = str(4), .sourceMap = str(5)},
CodeUnpacker{.code = str(6), .location = str(7), .sourceMap = str(8)},
CodeUnpacker{.code = str(9), .location = str(10), .sourceMap = str(11)},
CodeUnpacker{.code = str(12), .location = str(13), .sourceMap = str(14)},
CodeUnpacker{.code = str(15), .location = str(16), .sourceMap = str(17)},
});
});

jsi_utils::addMethod<6>(
rt,
obj,
"loadUnpackersWithBytecode",
[unpackerLoader = unpackerLoader_](jsi::Runtime &rt, const jsi::Value &, const jsi::Value(&args)[6]) {
const auto bytecode = [&](size_t i) {
const auto buffer = args[i].getObject(rt).getArrayBuffer(rt);
return std::vector<uint8_t>(buffer.data(rt), buffer.data(rt) + buffer.size(rt));
};
unpackerLoader->loadBytecodeUnpackers({
BytecodeUnpacker{.bytecode = bytecode(0)},
BytecodeUnpacker{.bytecode = bytecode(1)},
BytecodeUnpacker{.bytecode = bytecode(2)},
BytecodeUnpacker{.bytecode = bytecode(3)},
BytecodeUnpacker{.bytecode = bytecode(4)},
BytecodeUnpacker{.bytecode = bytecode(5)},
});
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,114 +1,78 @@
#pragma once

#include <jsi/jsi.h>
#include <worklets/Tools/ScriptBuffer.h>

#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <vector>

namespace worklets {

struct Unpacker {
struct CodeUnpacker {
std::string code;
std::string location;
std::string sourceMap;
};

struct ShareableUnpackers {
Unpacker valueUnpacker;
Unpacker synchronizableUnpacker;
Unpacker customSerializableUnpacker;
Unpacker shareableHostUnpacker;
Unpacker shareableGuestUnpacker;
Unpacker remoteFunctionUnpacker;
struct BytecodeUnpacker {
std::vector<uint8_t> bytecode;
};

class UnpackerLoader {
public:
void loadUnpackers(const ShareableUnpackers &unpackers) {
valueUnpacker_ = {
"(" + unpackers.valueUnpacker.code + ")();",
unpackers.valueUnpacker.location,
unpackers.valueUnpacker.sourceMap};
synchronizableUnpacker_ = {
"(" + unpackers.synchronizableUnpacker.code + ")();",
unpackers.synchronizableUnpacker.location,
unpackers.synchronizableUnpacker.sourceMap};
customSerializableUnpacker_ = {
"(" + unpackers.customSerializableUnpacker.code + ")();",
unpackers.customSerializableUnpacker.location,
unpackers.customSerializableUnpacker.sourceMap};
shareableHostUnpacker_ = {
"(" + unpackers.shareableHostUnpacker.code + ")();",
unpackers.shareableHostUnpacker.location,
unpackers.shareableHostUnpacker.sourceMap};
shareableGuestUnpacker_ = {
"(" + unpackers.shareableGuestUnpacker.code + ")();",
unpackers.shareableGuestUnpacker.location,
unpackers.shareableGuestUnpacker.sourceMap};
remoteFunctionUnpacker_ = {
"(" + unpackers.remoteFunctionUnpacker.code + ")();",
unpackers.remoteFunctionUnpacker.location,
unpackers.remoteFunctionUnpacker.sourceMap};
void loadCodeUnpackers(std::array<CodeUnpacker, 6> unpackers) {
codeUnpackers_ = std::move(unpackers);
}

void loadBytecodeUnpackers(std::array<BytecodeUnpacker, 6> unpackers) {
bytecodeUnpackers_ = std::move(unpackers);
}

void installUnpackers(facebook::jsi::Runtime &rt) const {
if (valueUnpacker_.code.empty() || synchronizableUnpacker_.code.empty() ||
customSerializableUnpacker_.code.empty() || shareableHostUnpacker_.code.empty() ||
shareableGuestUnpacker_.code.empty() || remoteFunctionUnpacker_.code.empty()) [[unlikely]] {
throw std::runtime_error(
"[Worklets] UnpackerLoader tried to install unpackers but the code for unpackers was not loaded.");
if (codeUnpackers_) {
for (const auto &unpacker : *codeUnpackers_) {
installUnpacker(rt, unpacker);
}
} else if (bytecodeUnpackers_) {
for (const auto &unpacker : *bytecodeUnpackers_) {
installUnpacker(rt, unpacker);
}
} else {
throw std::runtime_error("[Worklets] UnpackerLoader tried to install unpackers but they were not loaded.");
}
}

const auto useSourceMaps =
private:
static void installUnpacker(facebook::jsi::Runtime &rt, const CodeUnpacker &unpacker) {
#ifndef NDEBUG
!valueUnpacker_.sourceMap.empty();
#else
false;
if (!unpacker.sourceMap.empty()) {
rt.global()
.getPropertyAsFunction(rt, "evalWithSourceMap")
.call(rt, unpacker.code, unpacker.location, unpacker.sourceMap)
.getObject(rt)
.getFunction(rt)
.call(rt);
return;
}
#endif // NDEBUG
rt.evaluateJavaScript(std::make_shared<facebook::jsi::StringBuffer>(unpacker.code), unpacker.location)
.getObject(rt)
.getFunction(rt)
.call(rt);
}

if (useSourceMaps) {
const auto evalWithSourceMap = rt.global().getPropertyAsFunction(rt, "evalWithSourceMap");
evalWithSourceMap.call(rt, valueUnpacker_.code, valueUnpacker_.location, valueUnpacker_.sourceMap);
evalWithSourceMap.call(
rt, synchronizableUnpacker_.code, synchronizableUnpacker_.location, synchronizableUnpacker_.sourceMap);
evalWithSourceMap.call(
rt,
customSerializableUnpacker_.code,
customSerializableUnpacker_.location,
customSerializableUnpacker_.sourceMap);
evalWithSourceMap.call(
rt, shareableHostUnpacker_.code, shareableHostUnpacker_.location, shareableHostUnpacker_.sourceMap);
evalWithSourceMap.call(
rt, shareableGuestUnpacker_.code, shareableGuestUnpacker_.location, shareableGuestUnpacker_.sourceMap);
evalWithSourceMap.call(
rt, remoteFunctionUnpacker_.code, remoteFunctionUnpacker_.location, remoteFunctionUnpacker_.sourceMap);
} else {
rt.evaluateJavaScript(
std::make_shared<facebook::jsi::StringBuffer>(valueUnpacker_.code), valueUnpacker_.location);
rt.evaluateJavaScript(
std::make_shared<facebook::jsi::StringBuffer>(synchronizableUnpacker_.code),
synchronizableUnpacker_.location);
rt.evaluateJavaScript(
std::make_shared<facebook::jsi::StringBuffer>(customSerializableUnpacker_.code),
customSerializableUnpacker_.location);
rt.evaluateJavaScript(
std::make_shared<facebook::jsi::StringBuffer>(shareableHostUnpacker_.code), shareableHostUnpacker_.location);
rt.evaluateJavaScript(
std::make_shared<facebook::jsi::StringBuffer>(shareableGuestUnpacker_.code),
shareableGuestUnpacker_.location);
rt.evaluateJavaScript(
std::make_shared<facebook::jsi::StringBuffer>(remoteFunctionUnpacker_.code),
remoteFunctionUnpacker_.location);
}
static void installUnpacker(facebook::jsi::Runtime &rt, const BytecodeUnpacker &unpacker) {
auto buffer = std::make_shared<BytecodeBuffer>(unpacker.bytecode);
rt.evaluateJavaScript(buffer, "").getObject(rt).getFunction(rt).call(rt);
}

private:
Unpacker valueUnpacker_;
Unpacker synchronizableUnpacker_;
Unpacker customSerializableUnpacker_;
Unpacker shareableHostUnpacker_;
Unpacker shareableGuestUnpacker_;
Unpacker remoteFunctionUnpacker_;
std::optional<std::array<CodeUnpacker, 6>> codeUnpackers_;
std::optional<std::array<BytecodeUnpacker, 6>> bytecodeUnpackers_;
};

} // namespace worklets
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,20 @@ class ScriptBuffer : public jsi::Buffer {
std::shared_ptr<const JSBigString> script_;
};

class BytecodeBuffer : public jsi::Buffer {
public:
explicit BytecodeBuffer(const std::vector<uint8_t> &bytecode) : bytecode_(bytecode) {}

size_t size() const override {
return bytecode_.size();
}

const uint8_t *data() const override {
return bytecode_.data();
}

private:
std::vector<uint8_t> bytecode_;
};

} // namespace worklets
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
#include <worklets/Tools/ScriptBuffer.h>
#include <worklets/WorkletRuntime/WorkletHermesRuntime.h>

#include <jsi/jsi.h>

#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>

namespace worklets {

WorkletHermesRuntime::WorkletHermesRuntime(std::unique_ptr<facebook::hermes::HermesRuntime> runtime)
: jsi::WithRuntimeDecorator<WorkletsReentrancyCheck>(*runtime, reentrancyCheck_), runtime_(std::move(runtime)) {
auto evalBytecode = [](facebook::jsi::Runtime &rt,
const facebook::jsi::Value &,
const facebook::jsi::Value *args,
size_t) -> facebook::jsi::Value {
const auto buffer = args[0].getObject(rt).getArrayBuffer(rt);
auto data = std::vector<uint8_t>(buffer.data(rt), buffer.data(rt) + buffer.size(rt));
return rt.evaluateJavaScript(std::make_shared<BytecodeBuffer>(data), "");
};
runtime_->global().setProperty(
*runtime_,
"evalBytecode",
facebook::jsi::Function::createFromHostFunction(
*runtime_, facebook::jsi::PropNameID::forAscii(*runtime_, "evalBytecode"), 1, evalBytecode));

#ifndef NDEBUG
facebook::hermes::HermesRuntime *wrappedRuntime = runtime_.get();
jsi::Value evalWithSourceMap = jsi::Function::createFromHostFunction(
Expand Down
Loading
Loading