Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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 @@ -230,55 +230,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,3 +1,4 @@
#include <worklets/Tools/ScriptBuffer.h>
#include <worklets/WorkletRuntime/WorkletHermesRuntime.h>

#include <jsi/jsi.h>
Expand Down Expand Up @@ -30,6 +31,20 @@ WorkletHermesRuntime::WorkletHermesRuntime(std::unique_ptr<facebook::hermes::Her
return wrappedRuntime->evaluateJavaScriptWithSourceMap(code, sourceMap, sourceURL);
});
runtime_->global().setProperty(*runtime_, "evalWithSourceMap", evalWithSourceMap);
#else
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));
#endif // NDEBUG
}

Expand Down
Loading
Loading