Files
react-native/ReactCommon/hermes/inspector/chrome/tests/AsyncHermesRuntime.cpp
T
John Porto fefa7b6ac8 Add support for devtools' profiler
Summary:
Add support for analyzing sampling profiler data in devtools' JavaScript Profiler tab.

Changelog: [Added]

Reviewed By: neildhar

Differential Revision: D34114709

fbshipit-source-id: 1bf02ce02a250f68af1189c6516fb79795a8e887
2022-04-01 23:03:55 -07:00

167 lines
4.5 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "AsyncHermesRuntime.h"
#include <functional>
#include <stdexcept>
#include <thread>
#include <glog/logging.h>
namespace facebook {
namespace hermes {
namespace inspector {
namespace chrome {
namespace detail = facebook::hermes::inspector::detail;
AsyncHermesRuntime::AsyncHermesRuntime(bool veryLazy)
: executor_(
std::make_unique<detail::SerialExecutor>("async-hermes-runtime")) {
using namespace std::placeholders;
auto builder = ::hermes::vm::RuntimeConfig::Builder();
if (veryLazy) {
builder.withCompilationMode(::hermes::vm::ForceLazyCompilation);
}
runtime_ = facebook::hermes::makeHermesRuntime(builder.build());
runtime_->global().setProperty(
*runtime_,
"shouldStop",
jsi::Function::createFromHostFunction(
*runtime_,
jsi::PropNameID::forAscii(*runtime_, "shouldStop"),
0,
std::bind(&AsyncHermesRuntime::shouldStop, this, _1, _2, _3, _4)));
runtime_->global().setProperty(
*runtime_,
"storeValue",
jsi::Function::createFromHostFunction(
*runtime_,
jsi::PropNameID::forAscii(*runtime_, "storeValue"),
0,
std::bind(&AsyncHermesRuntime::storeValue, this, _1, _2, _3, _4)));
}
AsyncHermesRuntime::~AsyncHermesRuntime() {
stop();
wait();
}
void AsyncHermesRuntime::executeScriptAsync(
const std::string &script,
const std::string &url,
HermesRuntime::DebugFlags flags) {
int scriptId = rand();
LOG(INFO) << "AsyncHermesRuntime will execute script with id: " << scriptId
<< ", contents: " << script;
executor_->add([this, script, url, flags, scriptId] {
LOG(INFO) << "AsyncHermesRuntime executing script id " << scriptId
<< " in background";
try {
runtime_->debugJavaScript(script, url, flags);
} catch (jsi::JSError &error) {
LOG(INFO) << "AsyncHermesRuntime JSError " << error.getMessage();
thrownExceptions_.push_back(error.getMessage());
}
LOG(INFO) << "AsyncHermesRuntime finished executing script id " << scriptId;
});
}
void AsyncHermesRuntime::start() {
LOG(INFO) << "AsyncHermesRuntime: set stop flag false";
stopFlag_.store(false);
}
void AsyncHermesRuntime::stop() {
LOG(INFO) << "AsyncHermesRuntime: set stop flag true";
stopFlag_.store(true);
}
folly::Future<jsi::Value> AsyncHermesRuntime::getStoredValue() {
return storedValue_.getFuture();
}
bool AsyncHermesRuntime::hasStoredValue() {
return storedValue_.isFulfilled();
}
jsi::Value AsyncHermesRuntime::awaitStoredValue(
std::chrono::milliseconds timeout) {
return getStoredValue().get(timeout);
}
void AsyncHermesRuntime::wait(std::chrono::milliseconds timeout) {
LOG(INFO) << "AsyncHermesRuntime wait requested";
auto promise = std::make_shared<folly::Promise<bool>>();
auto future = promise->getFuture();
executor_->add([promise] {
LOG(INFO) << "AsyncHermesRuntime wait resolved";
promise->setValue(true);
});
std::move(future).get(timeout);
}
jsi::Value AsyncHermesRuntime::shouldStop(
jsi::Runtime &runtime,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
return stopFlag_.load() ? jsi::Value(true) : jsi::Value(false);
}
jsi::Value AsyncHermesRuntime::storeValue(
jsi::Runtime &runtime,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
if (count > 0) {
storedValue_.setValue(jsi::Value(runtime, args[0]));
}
return jsi::Value();
}
size_t AsyncHermesRuntime::getNumberOfExceptions() {
return thrownExceptions_.size();
}
std::string AsyncHermesRuntime::getLastThrownExceptionMessage() {
return thrownExceptions_.back();
}
void AsyncHermesRuntime::registerForProfilingInExecutor() {
// Sampling profiler registration needs to happen in the thread where JS runs.
folly::via(executor_.get(), [runtime = runtime_]() {
runtime->registerForProfiling();
});
// Wait until the executor is registered for profiling.
wait();
}
void AsyncHermesRuntime::unregisterForProfilingInExecutor() {
// Sampling profiler deregistration needs to happen in the thread where JS
// runs.
folly::via(executor_.get(), [runtime = runtime_]() {
runtime->unregisterForProfiling();
});
// Wait until the executor is unregistered for profiling.
wait();
}
} // namespace chrome
} // namespace inspector
} // namespace hermes
} // namespace facebook