diff --git a/doric-Qt/doric/doric.pro b/doric-Qt/doric/doric.pro index baff2f7b..abb41e6d 100644 --- a/doric-Qt/doric/doric.pro +++ b/doric-Qt/doric/doric.pro @@ -30,6 +30,9 @@ SOURCES += \ engine/DoricNativeLog.cpp \ engine/DoricNativeRequire.cpp \ engine/DoricTimerExtension.cpp \ + engine/native/NativeExecutor.cpp \ + engine/v8/JSValueHelper.cpp \ + engine/v8/V8Executor.cpp \ main.cpp \ plugin/DoricShaderPlugin.cpp \ shader/DoricGroupNode.cpp \ @@ -92,6 +95,9 @@ HEADERS += \ engine/DoricNativeLog.h \ engine/DoricNativeRequire.h \ engine/DoricTimerExtension.h \ + engine/native/NativeExecutor.h \ + engine/v8/JSValueHelper.h \ + engine/v8/V8Executor.h \ plugin/DoricNativePlugin.h \ plugin/DoricShaderPlugin.h \ shader/DoricGroupNode.h \ diff --git a/doric-Qt/doric/doric.pro.user b/doric-Qt/doric/doric.pro.user index 885b0eab..3f716abb 100644 --- a/doric-Qt/doric/doric.pro.user +++ b/doric-Qt/doric/doric.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -86,6 +86,228 @@ ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 6.0.2 MSVC2019 64bit + Desktop Qt 6.0.2 MSVC2019 64bit + qt.qt6.602.win64_msvc2019_64_kit + 0 + 0 + 0 + + 0 + C:\Users\maverick\Workspace\Doric\doric-Qt\build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Debug + C:/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Debug + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 0 + + + C:\Users\maverick\Workspace\Doric\doric-Qt\build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Release + C:/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Release + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + + 0 + C:\Users\maverick\Workspace\Doric\doric-Qt\build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Profile + C:/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Profile + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/maverick/Workspace/Doric/doric-Qt/doric/doric.pro + C:/Users/maverick/Workspace/Doric/doric-Qt/doric/doric.pro + false + true + true + false + true + C:/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_6_0_2_MSVC2019_64bit-Debug + + 1 + + + + ProjectExplorer.Project.Target.1 Desktop Desktop Qt 6.0.1 MinGW 64-bit @@ -301,14 +523,13 @@ true false true - C:/Users/maverick/Workspace/Doric/doric-Qt/build-doric-Desktop_Qt_6_0_1_MinGW_64_bit-Debug 1 ProjectExplorer.Project.TargetCount - 1 + 2 ProjectExplorer.Project.Updater.FileVersion diff --git a/doric-Qt/doric/engine/DoricJSEngine.cpp b/doric-Qt/doric/engine/DoricJSEngine.cpp index ca442155..fe1aae56 100644 --- a/doric-Qt/doric/engine/DoricJSEngine.cpp +++ b/doric-Qt/doric/engine/DoricJSEngine.cpp @@ -17,8 +17,12 @@ DoricJSEngine::DoricJSEngine(QObject *parent) : QObject(parent) { mJSThreadPool.setMaxThreadCount(1); + mJSThreadPool.setStackSize(3000000000); - QtConcurrent::run(&mJSThreadPool, [this] { mJSE = new DoricNativeJSE(); }); + QtConcurrent::run(&mJSThreadPool, [this] { + qDebug() << QThread::currentThread()->stackSize(); + mJSE = new DoricNativeJSE(); + }); QtConcurrent::run(&mJSThreadPool, [this] { // inject env QScreen *screen = QGuiApplication::primaryScreen(); diff --git a/doric-Qt/doric/engine/DoricNativeJSE.cpp b/doric-Qt/doric/engine/DoricNativeJSE.cpp index 5751d923..d4459bf6 100644 --- a/doric-Qt/doric/engine/DoricNativeJSE.cpp +++ b/doric-Qt/doric/engine/DoricNativeJSE.cpp @@ -5,159 +5,29 @@ #include "DoricNativeJSE.h" DoricNativeJSE::DoricNativeJSE() { - mJSEngine.installExtensions(QJSEngine::AllExtensions); - - std::unique_ptr platform = v8::platform::NewDefaultPlatform(); - v8::V8::InitializePlatform(platform.get()); - v8::V8::Initialize(); - - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = - v8::ArrayBuffer::Allocator::NewDefaultAllocator(); - v8::Isolate *isolate = v8::Isolate::New(create_params); - - { - v8::Isolate::Scope isolate_scope(isolate); - - // Create a stack-allocated handle scope. - v8::HandleScope handle_scope(isolate); - - // Create a new context. - v8::Local context = v8::Context::New(isolate); - - // Enter the context for compiling and running the hello world script. - v8::Context::Scope context_scope(context); - - { - // Create a string containing the JavaScript source code. - v8::Local source = - v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'"); - - // Compile the source code. - v8::Local script = - v8::Script::Compile(context, source).ToLocalChecked(); - - // Run the script to get the result. - v8::Local result = script->Run(context).ToLocalChecked(); - - // Convert the result to an UTF8 string and print it. - v8::String::Utf8Value utf8(isolate, result); - printf("%s\n", *utf8); - } - - { - // Use the JavaScript API to generate a WebAssembly module. - // - // |bytes| contains the binary format for the following module: - // - // (func (export "add") (param i32 i32) (result i32) - // get_local 0 - // get_local 1 - // i32.add) - // - const char csource[] = R"( - let bytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, - 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, - 0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01, - 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b - ]); - let module = new WebAssembly.Module(bytes); - let instance = new WebAssembly.Instance(module); - instance.exports.add(3, 4); - )"; - - // Create a string containing the JavaScript source code. - v8::Local source = - v8::String::NewFromUtf8Literal(isolate, csource); - - // Compile the source code. - v8::Local script = - v8::Script::Compile(context, source).ToLocalChecked(); - - // Run the script to get the result. - v8::Local result = script->Run(context).ToLocalChecked(); - - // Convert the result to a uint32 and print it. - uint32_t number = result->Uint32Value(context).ToChecked(); - printf("3 + 4 = %u\n", number); - } - } - - // Dispose the isolate and tear down V8. - isolate->Dispose(); - v8::V8::Dispose(); - v8::V8::ShutdownPlatform(); - delete create_params.array_buffer_allocator; + v8Executor = new V8Executor(); +// nativeExecutor = new NativeExecutor(); } QString DoricNativeJSE::loadJS(QString script, QString source) { - return mJSEngine.evaluate(script, source).toString(); +// return nativeExecutor->loadJS(script, source); + return v8Executor->loadJS(script, source); } void DoricNativeJSE::injectGlobalJSObject(QString name, QObject *object) { - QJSValue jsObject = mJSEngine.newQObject(object); - - QList propertyNames = object->dynamicPropertyNames(); - foreach (QByteArray propertyName, propertyNames) { - QString key = QString::fromStdString(propertyName.toStdString()); - if (key == "undefined") { - - } else { - jsObject.setProperty( - key, mJSEngine.toScriptValue(object->property(propertyName))); - } - } - - mJSEngine.globalObject().setProperty(name, jsObject); +// nativeExecutor->injectGlobalJSObject(name, object); + v8Executor->injectGlobalJSObject(name, object); } void DoricNativeJSE::injectGlobalJSFunction(QString name, QObject *function, QString property) { - QJSValue functionObject = mJSEngine.newQObject(function); - mJSEngine.globalObject().setProperty(name, functionObject.property(property)); +// nativeExecutor->injectGlobalJSFunction(name, function, property); + // v8Executor->injectGlobalJSFunction(name, function, property); } QJSValue DoricNativeJSE::invokeObject(QString objectName, QString functionName, QVariantList arguments) { - QJSValue object = mJSEngine.evaluate(objectName); - QJSValue function = object.property(functionName); - - QJSValueList args; - foreach (QVariant variant, arguments) { - if (variant.type() == QVariant::String) { - args.push_back(QJSValue(variant.toString())); - } else if (variant.type() == QVariant::Map) { - QJSValue arg = mJSEngine.newObject(); - QMap map = variant.toMap(); - foreach (QString key, map.keys()) { - QVariant value = map.value(key); - if (value.type() == QVariant::String) { - arg.setProperty(key, value.toString()); - } else if (value.type() == QVariant::Int) { - arg.setProperty(key, value.toInt()); - } - } - args.push_back(arg); - } else if (variant.type() == QVariant::StringList) { - QStringList array = variant.toStringList(); - QJSValue arg = mJSEngine.newArray(array.size()); - - for (int i = 0; i != array.size(); i++) { - arg.setProperty(i, array.at(i)); - } - args.push_back(arg); - } - } - - QJSValue result = function.call(args); - if (result.isError()) { - qCritical() << "++++++++++++++++++++++++++++++++++++++++++++++++"; - qCritical() << result.toString(); - QStringList stacktraces = result.property("stack").toString().split("\n"); - foreach (QString stacktrace, stacktraces) { qDebug() << stacktrace; } - qCritical() << "------------------------------------------------"; - } - - return result; + return QJSValue::UndefinedValue; +// return nativeExecutor->invokeObject(objectName, functionName, arguments); + // return v8Executor->invokeObject(objectName, functionName, arguments); } diff --git a/doric-Qt/doric/engine/DoricNativeJSE.h b/doric-Qt/doric/engine/DoricNativeJSE.h index a06defd5..f09734ae 100644 --- a/doric-Qt/doric/engine/DoricNativeJSE.h +++ b/doric-Qt/doric/engine/DoricNativeJSE.h @@ -2,15 +2,13 @@ #define NATIVE_JSE_H #include "DoricInterfaceJSE.h" -#include -#include - -#include "libplatform/libplatform.h" -#include "v8.h" +#include "native/NativeExecutor.h" +#include "v8/V8Executor.h" class DoricNativeJSE : public DoricInterfaceJSE { private: - QJSEngine mJSEngine; + V8Executor *v8Executor; + NativeExecutor *nativeExecutor; public: DoricNativeJSE(); diff --git a/doric-Qt/doric/engine/native/NativeExecutor.cpp b/doric-Qt/doric/engine/native/NativeExecutor.cpp new file mode 100644 index 00000000..aa345322 --- /dev/null +++ b/doric-Qt/doric/engine/native/NativeExecutor.cpp @@ -0,0 +1,80 @@ +#include "NativeExecutor.h" + +NativeExecutor::NativeExecutor() { + mJSEngine = new QJSEngine(); + mJSEngine->installExtensions(QJSEngine::AllExtensions); +} + +NativeExecutor::~NativeExecutor() { delete mJSEngine; } + +QString NativeExecutor::loadJS(QString script, QString source) { + return mJSEngine->evaluate(script, source).toString(); +} + +void NativeExecutor::injectGlobalJSObject(QString name, QObject *object) { + QJSValue jsObject = mJSEngine->newQObject(object); + + QList propertyNames = object->dynamicPropertyNames(); + foreach (QByteArray propertyName, propertyNames) { + QString key = QString::fromStdString(propertyName.toStdString()); + if (key == "undefined") { + + } else { + jsObject.setProperty( + key, mJSEngine->toScriptValue(object->property(propertyName))); + } + } + + mJSEngine->globalObject().setProperty(name, jsObject); +} + +void NativeExecutor::injectGlobalJSFunction(QString name, QObject *function, + QString property) { + QJSValue functionObject = mJSEngine->newQObject(function); + mJSEngine->globalObject().setProperty(name, + functionObject.property(property)); +} + +QJSValue NativeExecutor::invokeObject(QString objectName, QString functionName, + QVariantList arguments) { + QJSValue object = mJSEngine->evaluate(objectName); + QJSValue function = object.property(functionName); + + QJSValueList args; + foreach (QVariant variant, arguments) { + if (variant.type() == QVariant::String) { + args.push_back(QJSValue(variant.toString())); + } else if (variant.type() == QVariant::Map) { + QJSValue arg = mJSEngine->newObject(); + QMap map = variant.toMap(); + foreach (QString key, map.keys()) { + QVariant value = map.value(key); + if (value.type() == QVariant::String) { + arg.setProperty(key, value.toString()); + } else if (value.type() == QVariant::Int) { + arg.setProperty(key, value.toInt()); + } + } + args.push_back(arg); + } else if (variant.type() == QVariant::StringList) { + QStringList array = variant.toStringList(); + QJSValue arg = mJSEngine->newArray(array.size()); + + for (int i = 0; i != array.size(); i++) { + arg.setProperty(i, array.at(i)); + } + args.push_back(arg); + } + } + + QJSValue result = function.call(args); + if (result.isError()) { + qCritical() << "++++++++++++++++++++++++++++++++++++++++++++++++"; + qCritical() << result.toString(); + QStringList stacktraces = result.property("stack").toString().split("\n"); + foreach (QString stacktrace, stacktraces) { qDebug() << stacktrace; } + qCritical() << "------------------------------------------------"; + } + + return result; +} diff --git a/doric-Qt/doric/engine/native/NativeExecutor.h b/doric-Qt/doric/engine/native/NativeExecutor.h new file mode 100644 index 00000000..171db46f --- /dev/null +++ b/doric-Qt/doric/engine/native/NativeExecutor.h @@ -0,0 +1,27 @@ +#ifndef NATIVEEXECUTOR_H +#define NATIVEEXECUTOR_H + +#include + +class NativeExecutor { + +private: + QJSEngine *mJSEngine; + +public: + NativeExecutor(); + + ~NativeExecutor(); + + QString loadJS(QString script, QString source); + + void injectGlobalJSObject(QString name, QObject *object); + + void injectGlobalJSFunction(QString name, QObject *function, + QString property); + + QJSValue invokeObject(QString objectName, QString functionName, + QVariantList arguments); +}; + +#endif // NATIVEEXECUTOR_H diff --git a/doric-Qt/doric/engine/v8/JSValueHelper.cpp b/doric-Qt/doric/engine/v8/JSValueHelper.cpp new file mode 100644 index 00000000..02def4f3 --- /dev/null +++ b/doric-Qt/doric/engine/v8/JSValueHelper.cpp @@ -0,0 +1,63 @@ +#include "JSValueHelper.h" + +#include +#include + +std::string ToString(v8::Local object) { + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handleScope(isolate); + v8::Local context = isolate->GetEnteredOrMicrotaskContext(); + if (object->IsString() || object->IsRegExp() || object->IsFunction()) { + v8::String::Utf8Value utf8(isolate, object); + return std::string(*utf8); + } + if (object->IsObject()) { + v8::MaybeLocal str = v8::JSON::Stringify( + context, object->ToObject(context).ToLocalChecked()); + if (str.IsEmpty()) { + return ""; + } + v8::Local s = str.ToLocalChecked(); + v8::String::Utf8Value str2(isolate, s); + return std::string(*str2 ? *str2 : ""); + } + + v8::Local global = context->Global(); + v8::Local JSON = global->Get(context, NewV8String("JSON")) + .ToLocalChecked() + ->ToObject(context) + .ToLocalChecked(); + v8::Local argv[] = {object}; + v8::Local JSON_stringify = v8::Local::Cast( + JSON->Get(context, NewV8String("stringify")).ToLocalChecked()); + v8::String::Utf8Value str( + isolate, JSON_stringify->Call(context, JSON, 1, argv).ToLocalChecked()); + return std::string(*str ? *str : ""); +} + +v8::Local ObjectToJS(QObject *object) { + QJsonObject jsonObject; + + QList propertyNames = object->dynamicPropertyNames(); + foreach (QByteArray propertyName, propertyNames) { + QString key = QString::fromStdString(propertyName.toStdString()); + object->property(propertyName).toString(); + if (key == "undefined" || key.isEmpty()) { + + } else { + jsonObject[key] = QJsonValue::fromVariant(object->property(propertyName)); + } + } + + QJsonDocument doc(jsonObject); + QString strJson(doc.toJson(QJsonDocument::Compact)); + + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handleScope(isolate); + v8::Local context = isolate->GetEnteredOrMicrotaskContext(); + v8::Local jsString = NewV8String(strJson.toUtf8().constData()); + + v8::Local ret = v8::JSON::Parse(context, jsString).ToLocalChecked(); + + return handleScope.Escape(ret); +} diff --git a/doric-Qt/doric/engine/v8/JSValueHelper.h b/doric-Qt/doric/engine/v8/JSValueHelper.h new file mode 100644 index 00000000..b353f006 --- /dev/null +++ b/doric-Qt/doric/engine/v8/JSValueHelper.h @@ -0,0 +1,18 @@ +#ifndef JSVALUEHELPER_H +#define JSVALUEHELPER_H + +#include +#include + +#include "v8/v8.h" + +#define NewV8String(name) \ + v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), name, \ + v8::NewStringType::kNormal) \ + .ToLocalChecked() + +std::string ToString(v8::Local object); + +v8::Local ObjectToJS(QObject *object); + +#endif // JSVALUEHELPER_H diff --git a/doric-Qt/doric/engine/v8/V8Executor.cpp b/doric-Qt/doric/engine/v8/V8Executor.cpp new file mode 100644 index 00000000..abf6e9eb --- /dev/null +++ b/doric-Qt/doric/engine/v8/V8Executor.cpp @@ -0,0 +1,101 @@ +#include "V8Executor.h" +#include "JSValueHelper.h" + +#include + +V8Executor::V8Executor() { + std::unique_ptr platform = v8::platform::NewDefaultPlatform(); + v8::V8::InitializePlatform(platform.get()); + v8::V8::Initialize(); + + create_params.array_buffer_allocator = + v8::ArrayBuffer::Allocator::NewDefaultAllocator(); + m_isolate = v8::Isolate::New(create_params); + m_isolate_scope = new v8::Isolate::Scope(m_isolate); + + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + + v8::Local global = v8::ObjectTemplate::New(isolate); + v8::Local context = v8::Context::New(isolate, nullptr, global); + context->Enter(); + m_global_context = new v8::Global(isolate, context); +} + +V8Executor::~V8Executor() { + { + v8::HandleScope scope(m_isolate); + v8::Local context = m_global_context->Get(m_isolate); + context->Exit(); + } + m_global_context->Reset(); + delete m_global_context; + delete m_isolate_scope; + m_isolate->Dispose(); + v8::V8::Dispose(); + v8::V8::ShutdownPlatform(); + delete create_params.array_buffer_allocator; +} + +QString V8Executor::loadJS(QString script, QString source) { + std::string exception; + v8::HandleScope scope(m_isolate); + v8::Local ret = innerExec(script.toUtf8().constData(), + source.toUtf8().constData(), &exception); + std::string result = ToString(ret); + + return QString::fromUtf8(result.c_str()); +} + +void V8Executor::injectGlobalJSObject(QString name, QObject *target) { + v8::HandleScope handleScope(v8::Isolate::GetCurrent()); + v8::Local local = ObjectToJS(target); + + v8::Isolate *isolate = m_isolate; + v8::HandleScope handle_scope(isolate); + v8::Local context = isolate->GetEnteredOrMicrotaskContext(); + v8::Local object = context->Global(); + v8::Maybe result = + object->Set(context, NewV8String(name.toUtf8().constData()), local); + result.ToChecked(); +} + +v8::Local V8Executor::innerExec(const char *script, + const char *source, + std::string *exception_str) { + v8::Isolate *isolate = m_isolate; + v8::EscapableHandleScope handle_scope(isolate); + v8::Local result = Undefined(isolate); + v8::Local context = isolate->GetEnteredOrMicrotaskContext(); + v8::Context::Scope context_scope(context); + v8::ScriptOrigin origin(NewV8String(source)); + if (script) { + v8::Local jsSource = NewV8String(script); + v8::TryCatch try_catch(isolate); + try_catch.SetVerbose(true); + + v8::MaybeLocal maybeScript = + v8::Script::Compile(context, jsSource, &origin); + + if (!maybeScript.IsEmpty()) { + v8::Local js_script = maybeScript.ToLocalChecked(); + v8::MaybeLocal res = js_script->Run(context); + if (!res.IsEmpty()) { + result = res.ToLocalChecked(); + } + } + + v8::Local exception = try_catch.Exception(); + if (!exception.IsEmpty()) { + if (exception->IsObject()) { + v8::Local exc = v8::Local::Cast(exception); + v8::Local stack = + exc->Get(context, NewV8String("stack")).FromMaybe(exception); + *exception_str = ToString(stack); + } else { + *exception_str = ToString(exception); + } + } + } + return handle_scope.Escape(result); +} diff --git a/doric-Qt/doric/engine/v8/V8Executor.h b/doric-Qt/doric/engine/v8/V8Executor.h new file mode 100644 index 00000000..18a32e22 --- /dev/null +++ b/doric-Qt/doric/engine/v8/V8Executor.h @@ -0,0 +1,31 @@ +#ifndef V8EXECUTOR_H +#define V8EXECUTOR_H + +#include "libplatform/libplatform.h" +#include "v8/v8.h" + +#include +#include + +class V8Executor { + +private: + v8::Isolate::CreateParams create_params; + v8::Isolate *m_isolate; + v8::Isolate::Scope *m_isolate_scope; + v8::Global *m_global_context; + + v8::Local innerExec(const char *script, const char *source, + std::string *exception_str); + +public: + V8Executor(); + + ~V8Executor(); + + QString loadJS(QString script, QString source); + + void injectGlobalJSObject(QString name, QObject *object); +}; + +#endif // V8EXECUTOR_H