Skip to content

Commit

Permalink
Move resposibilities of V8IsolateManager to V8Engine
Browse files Browse the repository at this point in the history
  • Loading branch information
ztarem committed Nov 12, 2018
1 parent 35660eb commit d977b49
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 287 deletions.
1 change: 0 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ obj/build.h: FORCE
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h

V8_SOURCES = \
v8/v8isolatemanager.cpp \
v8/v8engine.cpp \
v8/v8filter.cpp \
v8/v8filterwatchdog.cpp \
Expand Down
46 changes: 22 additions & 24 deletions src/v8/callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@
// MultiChain code distributed under the GPLv3 license, see COPYING file.

#include "callbacks.h"
#include "rpc/rpcprotocol.h"
#include "rpc/rpcserver.h"
#include "utils/util.h"
#include "v8engine.h"
#include "v8utils.h"
#include "v8isolatemanager.h"
#include "utils/util.h"
#include "rpc/rpcserver.h"
#include "rpc/rpcprotocol.h"
#include <cassert>

namespace mc_v8
{

/**
* Call an RPC function from a V8 JS callback.
*
Expand All @@ -23,24 +21,24 @@ namespace mc_v8
* @param rpcFunction The RPC function to call.
* @param args The V8 arguments/return value.
*/
void CallRpcFunction(std::string name, rpcfn_type rpcFunction, const v8::FunctionCallbackInfo<v8::Value>& args)
void CallRpcFunction(std::string name, rpcfn_type rpcFunction, const v8::FunctionCallbackInfo<v8::Value> &args)
{
v8::Isolate* isolate = args.GetIsolate();
v8::Isolate *isolate = args.GetIsolate();
v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);
v8::HandleScope handleScope(isolate);
v8::Local<v8::Context> context(isolate->GetCurrentContext());
v8::Context::Scope contextScope(context);

IsolateData& isolateData = V8IsolateManager::Instance()->GetIsolateData(isolate);
IsolateData *isolateData = static_cast<IsolateData *>(args.Data().As<v8::External>()->Value());
json_spirit::Object callbackData;

json_spirit::Array params;
for (int i = 0; i < args.Length(); ++i)
{
params.push_back(V82Jsp(isolate, args[i]));
}
if (isolateData.withCallbackLog)
if (isolateData->withCallbackLog)
{
callbackData.push_back(json_spirit::Pair("method", name));
callbackData.push_back(json_spirit::Pair("params", params));
Expand All @@ -52,34 +50,34 @@ void CallRpcFunction(std::string name, rpcfn_type rpcFunction, const v8::Functio
{
result = rpcFunction(params, false);

if (isolateData.withCallbackLog)
if (isolateData->withCallbackLog)
{
bool success = true;
if (result.type() == json_spirit::obj_type)
{
auto obj = result.get_obj();
auto it = std::find_if(obj.begin(), obj.end(), [](const json_spirit::Pair& pair) -> bool
{
return pair.name_ == "code";
});
auto it = std::find_if(obj.begin(), obj.end(),
[](const json_spirit::Pair &pair) -> bool { return pair.name_ == "code"; });
success = (it == obj.end());
}
callbackData.push_back(json_spirit::Pair("success", success));
callbackData.push_back(json_spirit::Pair(success ? "result" : "error", result));
}
} catch (json_spirit::Object& e)
}
catch (json_spirit::Object &e)
{
args.GetReturnValue().SetUndefined();
if (isolateData.withCallbackLog)
if (isolateData->withCallbackLog)
{
callbackData.push_back(json_spirit::Pair("success", false));
callbackData.push_back(json_spirit::Pair("error", e));
}
ok = false;
} catch (std::exception& e)
}
catch (std::exception &e)
{
args.GetReturnValue().SetUndefined();
if (isolateData.withCallbackLog)
if (isolateData->withCallbackLog)
{
callbackData.push_back(json_spirit::Pair("success", false));
callbackData.push_back(json_spirit::Pair("result", e.what()));
Expand All @@ -97,14 +95,15 @@ void CallRpcFunction(std::string name, rpcfn_type rpcFunction, const v8::Functio
args.GetReturnValue().Set(Jsp2V8(isolate, result));
}

if (isolateData.withCallbackLog)
if (isolateData->withCallbackLog)
{
isolateData.callbacks.push_back(callbackData);
isolateData->callbacks.push_back(callbackData);
}
}

// clang-format off
#define FILTER_FUNCTION(name) \
void filter_##name(const v8::FunctionCallbackInfo<v8::Value>& args) \
void filter_##name(const v8::FunctionCallbackInfo<v8::Value> &args) \
{ \
CallRpcFunction(#name, name, args); \
}
Expand All @@ -123,7 +122,7 @@ FILTER_FUNCTION(verifymessage)

#define FILTER_LOOKUP(name) { #name, filter_##name }

std::map<std::string, v8::FunctionCallback> callbackLookup {
std::map<std::string, v8::FunctionCallback> callbackLookup{
FILTER_LOOKUP(getfiltertxid),
FILTER_LOOKUP(getfiltertransaction),
FILTER_LOOKUP(getfilterstreamitem),
Expand All @@ -136,6 +135,5 @@ std::map<std::string, v8::FunctionCallback> callbackLookup {
FILTER_LOOKUP(verifypermission),
FILTER_LOOKUP(verifymessage)
};

// clang-format on
} // namespace mc_v8

3 changes: 1 addition & 2 deletions src/v8/callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
#ifndef MULTICHAIN_CALLBACKS_H_
#define MULTICHAIN_CALLBACKS_H_

#include <v8.h>
#include <map>
#include <v8.h>

namespace mc_v8
{

extern std::map<std::string, v8::FunctionCallback> callbackLookup;

} // namespace mc_v8
Expand Down
67 changes: 65 additions & 2 deletions src/v8/v8engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,40 @@
#include "utils/define.h"
#include "utils/util.h"
#include "v8filter.h"
#include "v8utils.h"
#include <libplatform/libplatform.h>

extern char _binary_icudtl_dat_start;
extern char _binary_icudtl_dat_end;
extern char _binary_natives_blob_bin_start;
extern char _binary_natives_blob_bin_end;
extern char _binary_snapshot_blob_bin_start;
extern char _binary_snapshot_blob_bin_end;

namespace mc_v8
{
V8Engine::V8Engine()
{
Zero();
}

V8Engine::~V8Engine()
{
Destroy();
}

void V8Engine::Zero()
{
m_isolate = nullptr;
}

int V8Engine::Destroy()
{
if (m_isolate != nullptr)
{
m_isolate->Dispose();
delete m_createParams.array_buffer_allocator;
}
this->Zero();
return MC_ERR_NOERROR;
}
Expand All @@ -23,6 +48,12 @@ int V8Engine::Initialize(std::string &strResult)
if (fDebug)
LogPrint("v8filter", "v8filter: V8Engine::Initialize\n");
strResult.clear();
if (!m_isV8Initialized)
{
this->InitializeV8();
}
m_createParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
m_isolate = v8::Isolate::New(m_createParams);
return MC_ERR_NOERROR;
}

Expand All @@ -32,7 +63,7 @@ int V8Engine::CreateFilter(std::string script, std::string main_name, std::vecto
if (fDebug)
LogPrint("v8filter", "v8filter: V8Engine::CreateFilter\n");
strResult.clear();
return filter->Initialize(script, main_name, callback_names, strResult);
return filter->Initialize(this, script, main_name, callback_names, strResult);
}

int V8Engine::RunFilter(V8Filter *filter, std::string &strResult)
Expand Down Expand Up @@ -61,8 +92,40 @@ void V8Engine::TerminateFilter(V8Filter *filter, std::string reason)
{
if (filter != nullptr && filter->IsRunning())
{
filter->Terminate(reason);
m_reason = reason;
m_isolate->TerminateExecution();
}
}

void V8Engine::InitializeV8()
{
assert(!m_isV8Initialized);
fs::path tempDir = GetTemporaryPidDirectory();
fs::path v8TempDir = tempDir / "v8";
fs::create_directories(v8TempDir);

fs::path icudtl_blob = v8TempDir / "icudtl.dat";
fs::path natives_blob = v8TempDir / "natives_blob.bin";
fs::path snapshot_blob = v8TempDir / "snapshot_blob.bin";

WriteBinaryFile(icudtl_blob, &_binary_icudtl_dat_start, &_binary_icudtl_dat_end - &_binary_icudtl_dat_start);
WriteBinaryFile(natives_blob, &_binary_natives_blob_bin_start,
&_binary_natives_blob_bin_end - &_binary_natives_blob_bin_start);
WriteBinaryFile(snapshot_blob, &_binary_snapshot_blob_bin_start,
&_binary_snapshot_blob_bin_end - &_binary_snapshot_blob_bin_start);

v8::V8::InitializeICUDefaultLocation(icudtl_blob.string().c_str());
v8::V8::InitializeExternalStartupData(natives_blob.string().c_str());

fs::remove_all(tempDir);

m_platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(m_platform.get());
v8::V8::Initialize();
m_isV8Initialized = true;
}

std::unique_ptr<v8::Platform> V8Engine::m_platform;
v8::Isolate::CreateParams V8Engine::m_createParams;
bool V8Engine::m_isV8Initialized = false;
} // namespace mc_v8
74 changes: 62 additions & 12 deletions src/v8/v8engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,45 @@ namespace mc_v8
class V8Filter;

/**
* Interface to the Google V8 engine to create and run transaction filters.
* Auxiliary data associated with an Isolate.
*/
class V8Engine
struct IsolateData
{
public:
V8Engine()
/**
* Indicates if RPC callback data is being accumulated.
*/
bool withCallbackLog;

/**
* Detailed data about RPC callback calls.
*/
json_spirit::Array callbacks;

IsolateData() : withCallbackLog(false)
{
Zero();
}

~V8Engine()
/**
* Clear callback call data and set tracking indicator.
*
* @param withCallbackLog The value of the tracking indicator.
*/
void Reset(bool withCallbackLog = false)
{
Destroy();
this->withCallbackLog = withCallbackLog;
this->callbacks.clear();
}
};

/**
* Interface to the Google V8 engine to create and run filters.
*/
class V8Engine
{
public:
V8Engine();

~V8Engine();

void Zero();
int Destroy();
Expand All @@ -38,8 +63,18 @@ class V8Engine
*/
int Initialize(std::string &strResult);

v8::Isolate *GetIsolate()
{
return m_isolate;
}

IsolateData *GetIsolateData()
{
return &m_isolateData;
}

/**
* Create a new transaction filter.
* Create a new filter.
*
* @param script The filter JS code.
* @param main_name The expected name of the filtering function in the script.
Expand All @@ -55,8 +90,8 @@ class V8Engine
/**
* Run the filter function in the JS script.
*
* @param filter The user-defined transaction filter to use.
* @param strResult Reason for script failure or transaction rejection.
* @param filter The user-defined filter to use.
* @param strResult Reason for script failure or rejection.
* @return MC_ERR_INTERNAL_ERROR if the engine failed, MC_ERR_NOERROR otherwise.
*/
int RunFilter(V8Filter *filter, std::string &strResult);
Expand All @@ -66,8 +101,8 @@ class V8Engine
*
* This variant provides detailed data about RPC callback calls: parameters, results, success/failure and errors.
*
* @param filter The user-defined transaction filter to use.
* @param strResult Reason for script failure or transaction rejection.
* @param filter The user-defined filter to use.
* @param strResult Reason for script failure or rejection.
* @param callbacks An array of RPC callback call data.
* @return MC_ERR_INTERNAL_ERROR if the engine failed, MC_ERR_NOERROR otherwise.
*/
Expand All @@ -80,6 +115,21 @@ class V8Engine
* @param reason The reason the filter is being terminated.
*/
void TerminateFilter(V8Filter *filter, std::string reason);

std::string TerminationReason() const
{
return m_reason;
}

private:
v8::Isolate *m_isolate;
IsolateData m_isolateData;
static std::unique_ptr<v8::Platform> m_platform;
static v8::Isolate::CreateParams m_createParams;
static bool m_isV8Initialized;
std::string m_reason;

static void InitializeV8();
};

} // namespace mc_v8
Expand Down
Loading

0 comments on commit d977b49

Please sign in to comment.