Skip to content

Commit

Permalink
Implement Runtime.compileScript
Browse files Browse the repository at this point in the history
Summary:
Implement Runtime.compileScript, which is a dev tools request to compile a given script, optionally persisting the compiled result.

There are 3 main cases:
- Unsuccessful compilation, populates the exception details output. (We could retrieve the line and column number from the exception message, but it felt a bit too hacky.)
- Successful unpersisted output, returns an empty result, indicating success
- Successful persisted output, returns a result with a unique scriptID that identifies the prepared script.

The script IDs end with an index that can be used to infer the location in the vector storing persisted scripts.

Changelog: [Internal]

Reviewed By: jpporto

Differential Revision: D38761119

fbshipit-source-id: 504faad0149d1637682fa11d285f71736c3133e5
  • Loading branch information
mattbfb authored and facebook-github-bot committed Aug 29, 2022
1 parent a45eeea commit 2b4390e
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 2 deletions.
42 changes: 42 additions & 0 deletions ReactCommon/hermes/inspector/chrome/Connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace m = ::facebook::hermes::inspector::chrome::message;
static const char *const kVirtualBreakpointPrefix = "virtualbreakpoint-";
static const char *const kBeforeScriptWithSourceMapExecution =
"beforeScriptWithSourceMapExecution";
static const char *const kUserEnteredScriptPrefix = "userScript";

/*
* Connection::Impl
Expand Down Expand Up @@ -104,6 +105,7 @@ class Connection::Impl : public inspector::InspectorObserver,
void handle(const m::profiler::StartRequest &req) override;
void handle(const m::profiler::StopRequest &req) override;
void handle(const m::runtime::CallFunctionOnRequest &req) override;
void handle(const m::runtime::CompileScriptRequest &req) override;
void handle(const m::runtime::EvaluateRequest &req) override;
void handle(const m::runtime::GetHeapUsageRequest &req) override;
void handle(const m::runtime::GetPropertiesRequest &req) override;
Expand Down Expand Up @@ -160,6 +162,10 @@ class Connection::Impl : public inspector::InspectorObserver,
std::mutex parsedScriptsMutex_;
std::vector<std::string> parsedScripts_;

// preparedScripts_ stores user-entered scripts that have been prepared for
// execution, and may be invoked by a later command.
std::vector<std::shared_ptr<const jsi::PreparedJavaScript>> preparedScripts_;

// Some events are represented as a mode in Hermes but a breakpoint in CDP,
// e.g. "beforeScriptExecution" and "beforeScriptWithSourceMapExecution".
// Keep track of these separately. The caller should lock the
Expand Down Expand Up @@ -1092,6 +1098,42 @@ void Connection::Impl::handle(const m::runtime::CallFunctionOnRequest &req) {
.thenError<std::exception>(sendErrorToClient(req.id));
}

void Connection::Impl::handle(const m::runtime::CompileScriptRequest &req) {
auto resp = std::make_shared<m::runtime::CompileScriptResponse>();
resp->id = req.id;

inspector_
->executeIfEnabled(
"Runtime.compileScriptRequest",
[this, req, resp](const debugger::ProgramState &state) {
if (req.executionContextId.hasValue() &&
req.executionContextId.value() != kHermesExecutionContextId) {
throw std::invalid_argument("Invalid execution context");
}

auto source = std::make_shared<jsi::StringBuffer>(req.expression);
std::shared_ptr<const jsi::PreparedJavaScript> preparedScript;
try {
preparedScript =
getRuntime().prepareJavaScript(source, req.sourceURL);
} catch (const facebook::jsi::JSIException &err) {
resp->exceptionDetails = m::runtime::ExceptionDetails();
resp->exceptionDetails->text = err.what();
return;
}

if (req.persistScript) {
auto scriptId = folly::to<std::string>(
kUserEnteredScriptPrefix, preparedScripts_.size());
preparedScripts_.push_back(std::move(preparedScript));
resp->scriptId = scriptId;
}
})
.via(executor_.get())
.thenValue([this, resp](auto &&) { sendResponseToClient(*resp); })
.thenError<std::exception>(sendErrorToClient(req.id));
}

void Connection::Impl::handle(const m::runtime::EvaluateRequest &req) {
auto remoteObjPtr = std::make_shared<m::runtime::RemoteObject>();

Expand Down
55 changes: 54 additions & 1 deletion ReactCommon/hermes/inspector/chrome/MessageTypes.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.
// @generated SignedSource<<d10e11c5f88b40149af7ace19008d0fc>>
// @generated SignedSource<<8397f2428e68a26e014f91fdb77c1eb3>>

#include "MessageTypes.h"

Expand Down Expand Up @@ -63,6 +63,7 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
{"Profiler.start", makeUnique<profiler::StartRequest>},
{"Profiler.stop", makeUnique<profiler::StopRequest>},
{"Runtime.callFunctionOn", makeUnique<runtime::CallFunctionOnRequest>},
{"Runtime.compileScript", makeUnique<runtime::CompileScriptRequest>},
{"Runtime.evaluate", makeUnique<runtime::EvaluateRequest>},
{"Runtime.getHeapUsage", makeUnique<runtime::GetHeapUsageRequest>},
{"Runtime.getProperties", makeUnique<runtime::GetPropertiesRequest>},
Expand Down Expand Up @@ -1112,6 +1113,39 @@ void runtime::CallFunctionOnRequest::accept(RequestHandler &handler) const {
handler.handle(*this);
}

runtime::CompileScriptRequest::CompileScriptRequest()
: Request("Runtime.compileScript") {}

runtime::CompileScriptRequest::CompileScriptRequest(const dynamic &obj)
: Request("Runtime.compileScript") {
assign(id, obj, "id");
assign(method, obj, "method");

dynamic params = obj.at("params");
assign(expression, params, "expression");
assign(sourceURL, params, "sourceURL");
assign(persistScript, params, "persistScript");
assign(executionContextId, params, "executionContextId");
}

dynamic runtime::CompileScriptRequest::toDynamic() const {
dynamic params = dynamic::object;
put(params, "expression", expression);
put(params, "sourceURL", sourceURL);
put(params, "persistScript", persistScript);
put(params, "executionContextId", executionContextId);

dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "method", method);
put(obj, "params", std::move(params));
return obj;
}

void runtime::CompileScriptRequest::accept(RequestHandler &handler) const {
handler.handle(*this);
}

runtime::EvaluateRequest::EvaluateRequest() : Request("Runtime.evaluate") {}

runtime::EvaluateRequest::EvaluateRequest(const dynamic &obj)
Expand Down Expand Up @@ -1456,6 +1490,25 @@ dynamic runtime::CallFunctionOnResponse::toDynamic() const {
return obj;
}

runtime::CompileScriptResponse::CompileScriptResponse(const dynamic &obj) {
assign(id, obj, "id");

dynamic res = obj.at("result");
assign(scriptId, res, "scriptId");
assign(exceptionDetails, res, "exceptionDetails");
}

dynamic runtime::CompileScriptResponse::toDynamic() const {
dynamic res = dynamic::object;
put(res, "scriptId", scriptId);
put(res, "exceptionDetails", exceptionDetails);

dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "result", std::move(res));
return obj;
}

runtime::EvaluateResponse::EvaluateResponse(const dynamic &obj) {
assign(id, obj, "id");

Expand Down
28 changes: 27 additions & 1 deletion ReactCommon/hermes/inspector/chrome/MessageTypes.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved.
// @generated SignedSource<<dafd583635231e17c0264beb38610499>>
// @generated SignedSource<<2bada3d9c303c840ddcc292c7ba52604>>

#pragma once

Expand Down Expand Up @@ -52,6 +52,8 @@ struct CallArgument;
struct CallFrame;
struct CallFunctionOnRequest;
struct CallFunctionOnResponse;
struct CompileScriptRequest;
struct CompileScriptResponse;
struct ConsoleAPICalledNotification;
struct EvaluateRequest;
struct EvaluateResponse;
Expand Down Expand Up @@ -141,6 +143,7 @@ struct RequestHandler {
virtual void handle(const profiler::StartRequest &req) = 0;
virtual void handle(const profiler::StopRequest &req) = 0;
virtual void handle(const runtime::CallFunctionOnRequest &req) = 0;
virtual void handle(const runtime::CompileScriptRequest &req) = 0;
virtual void handle(const runtime::EvaluateRequest &req) = 0;
virtual void handle(const runtime::GetHeapUsageRequest &req) = 0;
virtual void handle(const runtime::GetPropertiesRequest &req) = 0;
Expand Down Expand Up @@ -180,6 +183,7 @@ struct NoopRequestHandler : public RequestHandler {
void handle(const profiler::StartRequest &req) override {}
void handle(const profiler::StopRequest &req) override {}
void handle(const runtime::CallFunctionOnRequest &req) override {}
void handle(const runtime::CompileScriptRequest &req) override {}
void handle(const runtime::EvaluateRequest &req) override {}
void handle(const runtime::GetHeapUsageRequest &req) override {}
void handle(const runtime::GetPropertiesRequest &req) override {}
Expand Down Expand Up @@ -654,6 +658,19 @@ struct runtime::CallFunctionOnRequest : public Request {
folly::Optional<std::string> objectGroup;
};

struct runtime::CompileScriptRequest : public Request {
CompileScriptRequest();
explicit CompileScriptRequest(const folly::dynamic &obj);

folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override;

std::string expression;
std::string sourceURL;
bool persistScript{};
folly::Optional<runtime::ExecutionContextId> executionContextId;
};

struct runtime::EvaluateRequest : public Request {
EvaluateRequest();
explicit EvaluateRequest(const folly::dynamic &obj);
Expand Down Expand Up @@ -801,6 +818,15 @@ struct runtime::CallFunctionOnResponse : public Response {
folly::Optional<runtime::ExceptionDetails> exceptionDetails;
};

struct runtime::CompileScriptResponse : public Response {
CompileScriptResponse() = default;
explicit CompileScriptResponse(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;

folly::Optional<runtime::ScriptId> scriptId;
folly::Optional<runtime::ExceptionDetails> exceptionDetails;
};

struct runtime::EvaluateResponse : public Response {
EvaluateResponse() = default;
explicit EvaluateResponse(const folly::dynamic &obj);
Expand Down
1 change: 1 addition & 0 deletions ReactCommon/hermes/inspector/tools/message_types.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ Runtime.getHeapUsage
Runtime.getProperties
Runtime.runIfWaitingForDebugger
Runtime.globalLexicalScopeNames
Runtime.compileScript

0 comments on commit 2b4390e

Please sign in to comment.