Introduce prepareJavaScript jsi API

Summary:
This adds a new jsi API prepareJavaScript. This accepts the same
parameters as evaluateJavaScript() but does not evaluate anything; instead
it returns a new object PreparedJavaScript which can itself be evaluated,
via the new API evaluatePreparedJavaScript().

There is a new empty class PreparedJavaScript which may be subclassed by
each Runtime variant to store its particular prepared form.

Reviewed By: mhorowitz

Differential Revision: D10491585

fbshipit-source-id: 702b9e23f2ff03d71a8ab17efb7e154b16dd8e87
This commit is contained in:
Peter Ammon
2019-02-15 01:48:58 -08:00
committed by Facebook Github Bot
parent 7a8957c0be
commit 0d7faf6f73
6 changed files with 127 additions and 9 deletions

View File

@@ -794,6 +794,9 @@
3DFE0D1B1DF8575800459392 /* YGMacros.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; };
3DFE0D1C1DF8575800459392 /* Yoga.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; };
3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; };
4F56C93822167A4800DB9F3F /* jsilib.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsilib.h */; };
4F56C93922167A4D00DB9F3F /* jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsilib.h */; };
4F56C93A2216A3B700DB9F3F /* jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsilib.h */; };
50E98FEA21460B0D00CD9289 /* RCTWKWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E98FE621460B0D00CD9289 /* RCTWKWebViewManager.m */; };
50E98FEB21460B0D00CD9289 /* RCTWKWebView.h in Headers */ = {isa = PBXBuildFile; fileRef = 50E98FE721460B0D00CD9289 /* RCTWKWebView.h */; };
50E98FEC21460B0D00CD9289 /* RCTWKWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 50E98FE821460B0D00CD9289 /* RCTWKWebView.m */; };
@@ -1753,6 +1756,7 @@
ED296FC7214C9B4B00B7C4FE /* instrumentation.h in Copy Headers */,
ED296FC6214C9B4400B7C4FE /* JSIDynamic.h in Copy Headers */,
ED296FC5214C9B3E00B7C4FE /* jsi-inl.h in Copy Headers */,
4F56C93A2216A3B700DB9F3F /* jsilib.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
@@ -1780,6 +1784,7 @@
EDEBC71D214B40F900DD5AC8 /* JSIDynamic.h in Copy Headers */,
EDEBC71E214B40F900DD5AC8 /* JSCRuntime.h in Copy Headers */,
EDEBC71F214B40F900DD5AC8 /* jsi.h in Copy Headers */,
4F56C93922167A4D00DB9F3F /* jsilib.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
@@ -2058,6 +2063,7 @@
3EDCA8A21D3591E700450C31 /* RCTErrorCustomizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorCustomizer.h; sourceTree = "<group>"; };
3EDCA8A31D3591E700450C31 /* RCTErrorInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTErrorInfo.h; sourceTree = "<group>"; };
3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTErrorInfo.m; sourceTree = "<group>"; };
4F56C93722167A4800DB9F3F /* jsilib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsilib.h; sourceTree = "<group>"; };
50E98FE621460B0D00CD9289 /* RCTWKWebViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWKWebViewManager.m; sourceTree = "<group>"; };
50E98FE721460B0D00CD9289 /* RCTWKWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWKWebView.h; sourceTree = "<group>"; };
50E98FE821460B0D00CD9289 /* RCTWKWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWKWebView.m; sourceTree = "<group>"; };
@@ -3040,6 +3046,7 @@
EDEBC6DF214B3F6800DD5AC8 /* BUCK */,
EDEBC6E0214B3F6800DD5AC8 /* instrumentation.h */,
EDEBC6E1214B3F6800DD5AC8 /* jsi.h */,
4F56C93722167A4800DB9F3F /* jsilib.h */,
);
path = jsi;
sourceTree = "<group>";
@@ -3590,6 +3597,7 @@
buildActionMask = 2147483647;
files = (
EDEBC6E9214B3F6800DD5AC8 /* jsi.h in Headers */,
4F56C93822167A4800DB9F3F /* jsilib.h in Headers */,
EDEBC6E7214B3F6800DD5AC8 /* JSCRuntime.h in Headers */,
EDEBC6E5214B3F6800DD5AC8 /* JSIDynamic.h in Headers */,
EDEBC6E2214B3F6800DD5AC8 /* jsi-inl.h in Headers */,

View File

@@ -12,6 +12,7 @@ rn_xplat_cxx_library(
"instrumentation.h",
"jsi.h",
"jsi-inl.h",
"jsilib.h",
],
compiler_flags = [
"-O3",

View File

@@ -9,6 +9,7 @@
#include <atomic>
#include <condition_variable>
#include <cstdlib>
#include <jsi/jsilib.h>
#include <mutex>
#include <queue>
#include <sstream>
@@ -36,6 +37,13 @@ class JSCRuntime : public jsi::Runtime {
JSCRuntime(JSGlobalContextRef ctx);
~JSCRuntime();
std::shared_ptr<const jsi::PreparedJavaScript> prepareJavaScript(
const std::shared_ptr<const jsi::Buffer> &buffer,
std::string sourceURL) override;
void evaluatePreparedJavaScript(
const std::shared_ptr<const jsi::PreparedJavaScript>& js) override;
void evaluateJavaScript(
const std::shared_ptr<const jsi::Buffer> &buffer,
const std::string& sourceURL) override;
@@ -318,6 +326,23 @@ JSCRuntime::~JSCRuntime() {
#endif
}
std::shared_ptr<const jsi::PreparedJavaScript> JSCRuntime::prepareJavaScript(
const std::shared_ptr<const jsi::Buffer> &buffer,
std::string sourceURL) {
return std::make_shared<jsi::SourceJavaScriptPreparation>(
buffer, std::move(sourceURL));
}
void JSCRuntime::evaluatePreparedJavaScript(
const std::shared_ptr<const jsi::PreparedJavaScript>& js) {
assert(
dynamic_cast<const jsi::SourceJavaScriptPreparation*>(js.get()) &&
"preparedJavaScript must be a SourceJavaScriptPreparation");
auto sourceJs =
std::static_pointer_cast<const jsi::SourceJavaScriptPreparation>(js);
evaluateJavaScript(sourceJs, sourceJs->sourceURL());
}
void JSCRuntime::evaluateJavaScript(
const std::shared_ptr<const jsi::Buffer> &buffer,
const std::string& sourceURL) {

View File

@@ -24,6 +24,8 @@ void throwJSError(Runtime& rt, const char* msg) {
Buffer::~Buffer() {}
PreparedJavaScript::~PreparedJavaScript() = default;
Value HostObject::get(Runtime&, const PropNameID&) {
return Value();
}

View File

@@ -52,6 +52,18 @@ class StringBuffer : public Buffer {
std::string s_;
};
/// PreparedJavaScript is a base class repesenting JavaScript which is in a form
/// optimized for execution, in a runtime-specific way. Construct one via
/// jsi::Runtime::prepareJavaScript().
/// ** This is an experimental API that is subject to change. **
class PreparedJavaScript {
protected:
PreparedJavaScript() = default;
public:
virtual ~PreparedJavaScript() = 0;
};
class Runtime;
class Pointer;
class PropNameID;
@@ -145,6 +157,25 @@ class Runtime {
virtual void evaluateJavaScript(
const std::shared_ptr<const Buffer>& buffer,
const std::string& sourceURL) = 0;
/// Prepares to evaluate the given JavaScript \c buffer by processing it into
/// a form optimized for execution. This may include pre-parsing, compiling,
/// etc. If the input is invalid (for example, cannot be parsed), a
/// JSIException will be thrown. The resulting object is tied to the
/// particular concrete type of Runtime from which it was created. It may be
/// used (via evaluatePreparedJavaScript) in any Runtime of the same concrete
/// type.
/// The PreparedJavaScript object may be passed to multiple VM instances, so
/// they can all share and benefit from the prepared script.
virtual std::shared_ptr<const PreparedJavaScript> prepareJavaScript(
const std::shared_ptr<const Buffer>& buffer,
std::string sourceURL) = 0;
/// Evaluates a PreparedJavaScript. If evaluation causes an error, a
/// JSIException will be thrown.
virtual void evaluatePreparedJavaScript(
const std::shared_ptr<const PreparedJavaScript>& js) = 0;
/// \return the global object
virtual Object global() = 0;
@@ -304,8 +335,8 @@ class PropNameID : public Pointer {
public:
using Pointer::Pointer;
PropNameID(Runtime &runtime, const PropNameID &other)
: Pointer(runtime.clonePropNameID(other.ptr_)) {}
PropNameID(Runtime& runtime, const PropNameID& other)
: PropNameID(runtime.clonePropNameID(other.ptr_)) {}
PropNameID(PropNameID&& other) = default;
PropNameID& operator=(PropNameID&& other) = default;
@@ -1031,13 +1062,7 @@ class Value {
ValueKind kind_;
Data data_;
// In the future: Value becomes NaN-boxed. In the Hermes impl, if
// the object contains a PinnedHermesValue, we need to be able to
// get a pointer to it; this can be casted from 'this'. In the JSC
// impl, we need to be able to convert the boxed value into a JSC
// ref. This can be done by casting this, deferencing it to get a
// number, doing some bit masks, and then casting again into the
// desired JSC ref type.
// In the future: Value becomes NaN-boxed. See T40538354.
};
/// Not movable and not copyable RAII marker advising the underlying

57
ReactCommon/jsi/jsilib.h Normal file
View File

@@ -0,0 +1,57 @@
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
#pragma once
#include <jsi/jsi.h>
namespace facebook {
namespace jsi {
class FileBuffer : public Buffer {
public:
FileBuffer(const std::string& path);
~FileBuffer();
size_t size() const override {
return size_;
}
const uint8_t* data() const override {
return data_;
}
private:
size_t size_;
uint8_t* data_;
};
// A trivial implementation of PreparedJavaScript that simply stores the source
// buffer and URL.
class SourceJavaScriptPreparation final : public jsi::PreparedJavaScript,
public jsi::Buffer {
std::shared_ptr<const jsi::Buffer> buf_;
std::string sourceURL_;
public:
SourceJavaScriptPreparation(
std::shared_ptr<const jsi::Buffer> buf,
std::string sourceURL)
: buf_(std::move(buf)), sourceURL_(std::move(sourceURL)) {}
const std::string& sourceURL() const {
return sourceURL_;
}
size_t size() const override {
return buf_->size();
}
const uint8_t* data() const override {
return buf_->data();
}
};
} // namespace jsi
} // namespace facebook