From d61bc7f667b3e637f8cbb870c40958885625a850 Mon Sep 17 00:00:00 2001 From: Alexey Kuts Date: Sat, 16 Jun 2018 01:46:46 +0300 Subject: [PATCH 01/26] added stub v8 script implementation --- CMakeLists.txt | 5 +- src/CMakeLists.txt | 6 + src/rtScript.cpp | 6 + src/rtScriptV8/jsCallback.cpp | 156 +++++++++ src/rtScriptV8/jsCallback.h | 79 +++++ src/rtScriptV8/rtFunctionWrapper.cpp | 426 ++++++++++++++++++++++++ src/rtScriptV8/rtFunctionWrapper.h | 175 ++++++++++ src/rtScriptV8/rtObjectWrapper.cpp | 473 +++++++++++++++++++++++++++ src/rtScriptV8/rtObjectWrapper.h | 147 +++++++++ src/rtScriptV8/rtScriptV8.cpp | 238 ++++++++++++++ src/rtScriptV8/rtScriptV8.h | 29 ++ src/rtScriptV8/rtWrapperUtils.cpp | 355 ++++++++++++++++++++ src/rtScriptV8/rtWrapperUtils.h | 323 ++++++++++++++++++ src/rtScriptV8/v8_headers.h | 29 ++ 14 files changed, 2445 insertions(+), 2 deletions(-) create mode 100755 src/rtScriptV8/jsCallback.cpp create mode 100755 src/rtScriptV8/jsCallback.h create mode 100755 src/rtScriptV8/rtFunctionWrapper.cpp create mode 100755 src/rtScriptV8/rtFunctionWrapper.h create mode 100755 src/rtScriptV8/rtObjectWrapper.cpp create mode 100755 src/rtScriptV8/rtObjectWrapper.h create mode 100755 src/rtScriptV8/rtScriptV8.cpp create mode 100755 src/rtScriptV8/rtScriptV8.h create mode 100755 src/rtScriptV8/rtWrapperUtils.cpp create mode 100755 src/rtScriptV8/rtWrapperUtils.h create mode 100755 src/rtScriptV8/v8_headers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d11b7d0206..924c3c247a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,9 @@ option(PREFER_SYSTEM_LIBRARIES "Prefer to use system libraries over bundled." "O option(DISABLE_DEBUG_MODE "Disable debugging mode." "OFF") # OFF for backward compatibility -option(SUPPORT_DUKTAPE "SUPPORT_DUKTAPE" ON) -option(SUPPORT_NODE "SUPPORT_NODE" ON) +option(SUPPORT_DUKTAPE "SUPPORT_DUKTAPE" OFF) +option(SUPPORT_NODE "SUPPORT_NODE" OFF) +option(SUPPORT_V8 "SUPPORT_V8" ON) option(ENABLE_THREAD_SANITIZER "ENABLE_THREAD_SANITIZER" OFF) option(ENABLE_ADDRESS_SANITIZER "ENABLE_ADDRESS_SANITIZER" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfdf2a83fd..99ebdf04d6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -216,6 +216,12 @@ if (SUPPORT_NODE) rtScriptNode/rtObjectWrapper.cpp rtScriptNode/rtWrapperUtils.cpp) endif() +if (SUPPORT_V8) + message("Adding V8 scripting support") + add_definitions(-DRTSCRIPT_SUPPORT_V8) + set(PXCORE_FILES ${PXCORE_FILES} rtScriptV8/rtScriptV8.cpp rtScriptV8/jsCallback.cpp rtScriptV8/rtFunctionWrapper.cpp + rtScriptV8/rtObjectWrapper.cpp rtScriptV8/rtWrapperUtils.cpp) +endif() if (PXCORE_MATRIX_HELPERS) set(PXCORE_FILES ${PXCORE_FILES} pxMatrix4T.cpp) diff --git a/src/rtScript.cpp b/src/rtScript.cpp index 539418110a..7b2554ec50 100644 --- a/src/rtScript.cpp +++ b/src/rtScript.cpp @@ -30,6 +30,10 @@ #include "rtScriptNode/rtScriptNode.h" #endif +#ifdef RTSCRIPT_SUPPORT_V8 +#include "rtScriptV8/rtScriptV8.h" +#endif + #ifdef RTSCRIPT_SUPPORT_DUKTAPE #include "rtScriptDuk/rtScriptDuk.h" #endif @@ -192,6 +196,8 @@ rtError rtScript::init() createScriptDuk(mScript); else createScriptNode(mScript); + #elif defined(RTSCRIPT_SUPPORT_V8) + createScriptV8(mScript); #elif defined(RTSCRIPT_SUPPORT_DUKTAPE) createScriptDuk(mScript); #elif defined(RTSCRIPT_SUPPORT_NODE) diff --git a/src/rtScriptV8/jsCallback.cpp b/src/rtScriptV8/jsCallback.cpp new file mode 100755 index 0000000000..20b4621d40 --- /dev/null +++ b/src/rtScriptV8/jsCallback.cpp @@ -0,0 +1,156 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#include "jsCallback.h" +#include "rtWrapperUtils.h" + + +using namespace v8; + +namespace rtScriptV8Utils +{ + +jsCallback::jsCallback(v8::Local& ctx) + : mReq() + , mFunctionLookup(NULL) + , mIsolate(ctx->GetIsolate()) + , mCompletionFunc(NULL) + , mCompletionContext(NULL) +{ + mReq.data = this; + + mContext.Reset(mIsolate, ctx); +} + +jsCallback::~jsCallback() +{ + mContext.Reset(); + delete mFunctionLookup; +} + +void jsCallback::enqueue() +{ + uv_queue_work(uv_default_loop(), &mReq, &work, &doCallback); +} + +void jsCallback::registerForCompletion(jsCallbackCompletionFunc callback, void* argp) +{ + mCompletionFunc = callback; + mCompletionContext = argp; +} + +void jsCallback::work(uv_work_t* /* req */) +{ +} + +jsCallback* jsCallback::create(v8::Local& ctx) +{ + return new jsCallback(ctx); +} + +jsCallback* jsCallback::addArg(const rtValue& val) +{ + mArgs.push_back(val); + return this; +} + +Handle* jsCallback::makeArgs(Local& ctx) +{ + Handle* args = new Handle[mArgs.size()]; + + for (size_t i = 0; i < mArgs.size(); ++i) + { + args[i] = rt2js(ctx, mArgs[i]); + } + + return args; +} + +jsCallback* jsCallback::setFunctionLookup(jsIFunctionLookup* functionLookup) +{ + mFunctionLookup = functionLookup; + return this; +} + +void jsCallback::doCallback(uv_work_t* req, int /* status */) +{ + jsCallback* ctx = reinterpret_cast(req->data); + + assert(ctx != NULL); + assert(ctx->mFunctionLookup != NULL); + + rtValue ret = ctx->run(); + + if (ctx->mCompletionFunc) + { + ctx->mCompletionFunc(ctx->mCompletionContext, ret); + } + + delete ctx; +} + +rtValue jsCallback::run() +{ + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); + + Local ctx = PersistentToLocal(mIsolate, mContext); + Handle* args = this->makeArgs(ctx); + Local func = this->mFunctionLookup->lookup(ctx); + + assert(!func.IsEmpty()); + assert(!func->IsUndefined()); + + // This is really nice debugging + #if 0 + Local s = func->ToString(); + String::Utf8Value v(s); + rtLogInfo("FUNC: %s", *v); + #endif + + Local context = func->CreationContext(); + Context::Scope contextScope(context); + + Local val; + + TryCatch tryCatch(mIsolate); + if (!func.IsEmpty()) + { + // TODO: check that first arg. Is that 'this' why are we using context->Global()? + val = func->Call(context->Global(), static_cast(this->mArgs.size()), args); + } + + delete [] args; + + rtValue returnValue; + if (tryCatch.HasCaught()) + { + String::Utf8Value trace(tryCatch.StackTrace()); + rtLogWarn("%s", *trace); + } + else + { + rtWrapperError error; + returnValue = js2rt(context, val, &error); + } + + return returnValue; +} + +} // namespace diff --git a/src/rtScriptV8/jsCallback.h b/src/rtScriptV8/jsCallback.h new file mode 100755 index 0000000000..ee6a656790 --- /dev/null +++ b/src/rtScriptV8/jsCallback.h @@ -0,0 +1,79 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#ifndef RT_JAVASCRIPT_CALLBACK_H +#define RT_JAVASCRIPT_CALLBACK_H + + +#include "v8_headers.h" +#include +#include + +namespace rtScriptV8Utils +{ + +typedef void (*jsCallbackCompletionFunc)(void* argp, rtValue const& result); + +struct jsIFunctionLookup +{ + virtual ~jsIFunctionLookup() { } + virtual v8::Local lookup(v8::Local& ctx) = 0; +}; + +struct jsCallback +{ + virtual void enqueue(); + void registerForCompletion(jsCallbackCompletionFunc callback, void* argp); + rtValue run(); + + + static jsCallback* create(v8::Local& ctx); + + jsCallback* addArg(const rtValue& val); + + jsCallback* setFunctionLookup(jsIFunctionLookup* functionLookup); + + static void work(uv_work_t* req); + static void doCallback(uv_work_t* req, int status); + + // made this public for the direct call (rtIsMain) path + virtual ~jsCallback(); + +protected: + virtual v8::Handle* makeArgs(v8::Local& ctx); + +private: + + std::vector mArgs; + uv_work_t mReq; + jsIFunctionLookup* mFunctionLookup; + + // TODO: Is it ok to hold this pointer here? + v8::Persistent mContext; + v8::Isolate* mIsolate; + + jsCallbackCompletionFunc mCompletionFunc; + void* mCompletionContext; + + jsCallback(v8::Local& ctx); +}; + +} // namespace + +#endif + diff --git a/src/rtScriptV8/rtFunctionWrapper.cpp b/src/rtScriptV8/rtFunctionWrapper.cpp new file mode 100755 index 0000000000..55857a3bc5 --- /dev/null +++ b/src/rtScriptV8/rtFunctionWrapper.cpp @@ -0,0 +1,426 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#include "rtFunctionWrapper.h" +#include "rtWrapperUtils.h" +#include "jsCallback.h" + +#include +using namespace v8; + +namespace rtScriptV8Utils +{ + +static const char* kClassName = "Function"; +static Persistent ctor; +std::hash hashFn; + +static void jsFunctionCompletionHandler(void* argp, rtValue const& result) +{ + jsFunctionWrapper* wrapper = reinterpret_cast(argp); + wrapper->signal(result); +} + +rtResolverFunction::rtResolverFunction(Disposition disp, v8::Local& ctx, Local& resolver) + : rtAbstractFunction() + , mDisposition(disp) + , mResolver(ctx->GetIsolate(), resolver) + , mContext(ctx->GetIsolate(), ctx) + , mIsolate(ctx->GetIsolate()) + , mReq() +{ +} + +rtResolverFunction::~rtResolverFunction() +{ + rtLogDebug("~rtResolverFunction"); + mResolver.Reset(); +} + +rtError rtResolverFunction::Send(int numArgs, const rtValue* args, rtValue* /*result*/) +{ + AsyncContext* ctx = new AsyncContext(); + + // keep current object alive while we enqueue this request + ctx->resolverFunc = rtFunctionRef(this); + + for (int i = 0; i < numArgs; ++i) + { + ctx->args.push_back(args[i]); + } + + mReq.data = ctx; + uv_queue_work(uv_default_loop(), &mReq, &workCallback, &afterWorkCallback); + return RT_OK; +} + +void rtResolverFunction::workCallback(uv_work_t* /*req */) +{ + // empty +} + +void rtResolverFunction::afterWorkCallback(uv_work_t* req, int /* status */) +{ + AsyncContext* ctx = reinterpret_cast(req->data); + rtResolverFunction* resolverFunc = static_cast(ctx->resolverFunc.getPtr()); + + assert(ctx->args.size() < 2); +// assert(Isolate::GetCurrent() == resolverFunc->mIsolate); + + Locker locker(resolverFunc->mIsolate); + Isolate::Scope isolate_scope(resolverFunc->mIsolate); + HandleScope handle_scope(resolverFunc->mIsolate); + + Local creationContext = PersistentToLocal(resolverFunc->mIsolate, resolverFunc->mContext); + Context::Scope contextScope(creationContext); + + Handle value; + if (ctx->args.size() > 0) + { + value = rt2js(creationContext, ctx->args[0]); + } + + Local resolver = PersistentToLocal(resolverFunc->mIsolate, resolverFunc->mResolver); + Local local_context = resolver->CreationContext(); + Context::Scope context_scope(local_context); + + TryCatch tryCatch(resolverFunc->mIsolate); + if (resolverFunc->mDisposition == DispositionResolve) + { + resolver->Resolve(value); + } + else + { + resolver->Reject(value); + } + + if (tryCatch.HasCaught()) + { + String::Utf8Value trace(tryCatch.StackTrace()); + rtLogWarn("Error resolving promise"); + rtLogWarn("%s", *trace); + } + resolverFunc->mIsolate->RunMicrotasks(); + delete ctx; +} + +rtFunctionWrapper::rtFunctionWrapper(const rtFunctionRef& ref) + : rtWrapper(ref) +{ +} + +rtFunctionWrapper::~rtFunctionWrapper() +{ +} + +void rtFunctionWrapper::destroyPrototype() +{ + if( !ctor.IsEmpty() ) + { + // TODO: THIS LEAKS... need to free obj within persistent + + // rtFunctionWrapper *obj = V8::Utils::OpenPersistent(ctor); + + ctor.ClearWeak(); + ctor.Reset(); + } +} + +void rtFunctionWrapper::exportPrototype(Isolate* isolate, Handle exports) +{ + Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); // Create a stack-allocated handle scope. + + Local tmpl = FunctionTemplate::New(isolate, create); + tmpl->SetClassName(String::NewFromUtf8(isolate, kClassName)); + + Local inst = tmpl->InstanceTemplate(); + inst->SetInternalFieldCount(1); + inst->SetCallAsFunctionHandler(call); + + ctor.Reset(isolate, tmpl->GetFunction()); + exports->Set(String::NewFromUtf8(isolate, kClassName), tmpl->GetFunction()); +} + +void rtFunctionWrapper::create(const FunctionCallbackInfo& args) +{ + assert(args.IsConstructCall()); + + HandleScope scope(args.GetIsolate()); + + // Local c1 = args.GetIsolate()->GetCurrentContext(); + // Local c2 = args.GetIsolate()->GetCallingContext(); + // Local c3 = args.GetIsolate()->GetEnteredContext(); + // rtLogInfo("current:%u calling:%u entered:%u", GetContextId(c1), GetContextId(c2), + // GetContextId(c3)); + + rtIFunction* func = static_cast(args[0].As()->Value()); + rtFunctionWrapper* wrapper = new rtFunctionWrapper(func); + wrapper->Wrap(args.This()); +} + + +Handle rtFunctionWrapper::createFromFunctionReference(v8::Local& ctx, Isolate* isolate, const rtFunctionRef& func) +{ + Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + EscapableHandleScope scope(isolate); + + Local argv[1] = + { + External::New(isolate, func.getPtr()) + }; + + Local c = PersistentToLocal(isolate, ctor); + return scope.Escape((c->NewInstance(ctx, 1, argv)).FromMaybe(Local())); +} + +void rtFunctionWrapper::call(const FunctionCallbackInfo& args) +{ + Isolate* isolate = args.GetIsolate(); + + Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); // Create a stack-allocated handle scope. + + // Local curr = isolate->GetCurrentContext(); + + rtWrapperError error; + + #if 0 + Local s = args.This()->ToString(); + String::Utf8Value v(s); + rtLogInfo("call:%s", *v); + #endif + + Local ctx = args.This()->CreationContext(); + // rtLogInfo("id: %u", GetContextId(ctx)); + Context::Scope contextScope(ctx); + + std::vector argList; + for (int i = 0; i < args.Length(); ++i) + { + argList.push_back(js2rt(ctx, args[i], &error)); + if (error.hasError()) + isolate->ThrowException(error.toTypeError(isolate)); + } + + rtValue result; + rtError err = unwrap(args)->Send(args.Length(), &argList[0], &result); + + if (err != RT_OK) + { + return throwRtError(isolate, err, "failed to invoke function"); + } + + if (rtIsPromise(result)) + { + Local resolver = Promise::Resolver::New(isolate); + + rtFunctionRef resolve(new rtResolverFunction(rtResolverFunction::DispositionResolve, ctx, resolver)); + rtFunctionRef reject(new rtResolverFunction(rtResolverFunction::DispositionReject, ctx, resolver)); + + rtObjectRef newPromise; + rtObjectRef promise = result.toObject(); + + Local jsPromise = resolver->GetPromise(); + HandleMap::addWeakReference(isolate, promise, jsPromise); + + rtError err = promise.send("then", resolve, reject, newPromise); + + if (err != RT_OK) + return throwRtError(isolate, err, "failed to register for promise callback"); + else + args.GetReturnValue().Set(jsPromise); + } + else + { + args.GetReturnValue().Set(rt2js(ctx, result)); + } +} + +jsFunctionWrapper::jsFunctionWrapper(Local& ctx, const Handle& val) + : mRefCount(0) + , mFunction(ctx->GetIsolate(), Handle::Cast(val)) + , mComplete(false) + , mTeardownThreadingPrimitives(false) + , mHash(-1) +{ + v8::String::Utf8Value fn(Handle::Cast(val)->ToString()); + if (NULL != *fn) { + mHash = hashFn(*fn); + } + mIsolate = ctx->GetIsolate(); + mContext.Reset(ctx->GetIsolate(), ctx); + assert(val->IsFunction()); +} + +jsFunctionWrapper::~jsFunctionWrapper() +{ + mFunction.Reset(); + mContext.Reset(); + + if (mTeardownThreadingPrimitives) + { +#ifndef USE_STD_THREADS + pthread_mutex_destroy(&mMutex); + pthread_cond_destroy(&mCond); +#endif + } + mHash = -1; +} + +void jsFunctionWrapper::setupSynchronousWait() +{ + mTeardownThreadingPrimitives = true; +#ifndef USE_STD_THREADS + pthread_mutex_init(&mMutex, NULL); + pthread_cond_init(&mCond, NULL); +#endif +#ifdef USE_STD_THREADS + std::unique_lock lock(mMutex); + mComplete = false; +#else + pthread_mutex_lock(&mMutex); + mComplete = false; + pthread_mutex_unlock(&mMutex); +#endif +} + +void jsFunctionWrapper::signal(rtValue const& returnValue) +{ +#ifdef USE_STD_THREADS + std::unique_lock lock(mMutex); +#else + pthread_mutex_lock(&mMutex); +#endif + + mComplete = true; + mReturnValue = returnValue; + +#ifdef USE_STD_THREADS + mCond.notify_one(); +#else + pthread_mutex_unlock(&mMutex); + pthread_cond_signal(&mCond); +#endif +} + +rtValue jsFunctionWrapper::wait() +{ +#ifdef USE_STD_THREADS + std::unique_lock lock(mMutex); + mCond.wait(lock, [&] { return mComplete; }); +#else + pthread_mutex_lock(&mMutex); + while (!mComplete) + pthread_cond_wait(&mCond, &mMutex); + pthread_mutex_unlock(&mMutex); +#endif + return mReturnValue; +} + +unsigned long jsFunctionWrapper::AddRef() +{ + return rtAtomicInc(&mRefCount); +} + +unsigned long jsFunctionWrapper::Release() +{ + unsigned long l = rtAtomicDec(&mRefCount); + if (l == 0) delete this; + return l; +} + +rtError jsFunctionWrapper::Send(int numArgs, const rtValue* args, rtValue* result) +{ + // + // TODO: Return values are not supported. This class is an rtFunction that wraps + // a javascript function. If everything is behaving normally, we're running in the + // context of a native/non-js thread. This is almost certainly the "render" thread. + // The function is "packed" up and sent off to a javascript thread via the + // enqueue() on the jsCallback. That means the called is queued with nodejs' event + // queue. This is required to prevent multiple threads from + // entering the JS engine. The problem is that the caller can't expect anything in + // return in the result (last parameter to this function. + // If you have the current thread wait and then return the result, you'd block this + // thread until the completion of the javascript function call. + // + // Here's an example of how you'd get into this situation. This is a contrived example. + // No known case exists right now. + // + // The closure function below will be wrapped and registered with the rt object layer. + // If the 'someEvent' is fired, excecution wll arrive here (this code). You'll never see + // the "return true" because this call returns and the function is run in another + // thread. + // + // This won't work! + // + // var foo = ... + // foo.on('someEvent', function(msg) { + // console.log("I'm running in a javascript thread"); + // return true; // <-- Can't do this + // }); + // + + Locker locker(mIsolate); + HandleScope handleScope(mIsolate); + Local ctx = PersistentToLocal(mIsolate, mContext); + Context::Scope contextScope(ctx); + + jsCallback* callback = jsCallback::create(ctx); + for (int i = 0; i < numArgs; ++i) + callback->addArg(args[i]); + + callback->setFunctionLookup(new FunctionLookup(this)); + + if (result) // wants result run synchronously + { + //if (rtIsMainThreadNode()) // main thread run now + { + *result = callback->run(); + delete callback; + } + //else // queue and wait + //{ + // setupSynchronousWait(); + // callback->registerForCompletion(jsFunctionCompletionHandler, this); + // callback->enqueue(); + + // // !CLF: When/why was this wait() introduced? Need fix for multi-thread solution + // // *result = wait(); + //} + } + else // just queue + { + callback->enqueue(); + } + + return RT_OK; +} + +Local jsFunctionWrapper::FunctionLookup::lookup(v8::Local& ctx) +{ + EscapableHandleScope handleScope(mParent->mIsolate); + Context::Scope contextScope(ctx); + Local func = PersistentToLocal(mParent->mIsolate, mParent->mFunction); + return handleScope.Escape(func); +} + +} // namespace diff --git a/src/rtScriptV8/rtFunctionWrapper.h b/src/rtScriptV8/rtFunctionWrapper.h new file mode 100755 index 0000000000..b5419e1498 --- /dev/null +++ b/src/rtScriptV8/rtFunctionWrapper.h @@ -0,0 +1,175 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#ifndef RT_FUNCTION_WRAPPER_H +#define RT_FUNCTION_WRAPPER_H + +#include "rtWrapperUtils.h" +#include "jsCallback.h" + +#ifdef USE_STD_THREADS +# include +# include +#endif + +namespace rtScriptV8Utils +{ + +class rtAbstractFunction : public rtIFunction +{ +public: + virtual unsigned long AddRef() + { + return rtAtomicInc(&mRefCount); + } + + virtual unsigned long Release() + { + unsigned long l = rtAtomicDec(&mRefCount); + if (l == 0) delete this; + return l; + } + + virtual unsigned long getRefCount() const + { + return mRefCount; + } +protected: + virtual ~rtAbstractFunction() {} + unsigned long mRefCount; +}; + +class rtFunctionWrapper : public rtWrapper +{ +public: + rtFunctionWrapper(const rtFunctionRef& ref); + virtual ~rtFunctionWrapper(); + +public: + static void exportPrototype(v8::Isolate* isolate, v8::Handle exports); + static void destroyPrototype(); + static v8::Handle createFromFunctionReference(v8::Local& ctx, v8::Isolate* isolate, const rtFunctionRef& func); + +private: + static void create(const v8::FunctionCallbackInfo& args); + static void call(const v8::FunctionCallbackInfo& args); +}; + +class jsFunctionWrapper : public rtIFunction +{ +public: + jsFunctionWrapper(v8::Local& ctx, const v8::Handle& val); + virtual ~jsFunctionWrapper(); + + virtual unsigned long AddRef(); + virtual unsigned long Release(); + virtual unsigned long getRefCount() const { + return mRefCount; + } + virtual size_t hash() { + return mHash; + } + + virtual void setHash(size_t hash) { + UNUSED_PARAM(hash); + } + + void signal(rtValue const& returnValue); + +private: + virtual rtError Send(int numArgs, const rtValue* args, rtValue* result); + + rtValue wait(); + void setupSynchronousWait(); + + class FunctionLookup : public jsIFunctionLookup + { + public: + FunctionLookup(jsFunctionWrapper* parent) : mParent(parent) { } + virtual v8::Local lookup(v8::Local& ctx); + private: + jsFunctionWrapper* mParent; + }; + + friend class FunctionLookup; + +private: + unsigned long mRefCount; + v8::Persistent mFunction; + v8::Persistent mContext; + v8::Isolate* mIsolate; + std::vector mArgs; + + bool mComplete; + bool mTeardownThreadingPrimitives; + +#ifdef USE_STD_THREADS + std::mutex mMutex; + std::condition_variable mCond; +#else + pthread_mutex_t mMutex; + pthread_cond_t mCond; +#endif + size_t mHash; + rtValue mReturnValue; +}; + +class rtResolverFunction : public rtAbstractFunction +{ +public: + enum Disposition + { + DispositionResolve, + DispositionReject + }; + + rtResolverFunction(Disposition d, v8::Local& ctx, v8::Local& resolver); + virtual ~rtResolverFunction(); + virtual rtError Send(int numArgs, const rtValue* args, rtValue* result); + virtual size_t hash() + { + return -1; + } + + virtual void setHash(size_t hash) { + UNUSED_PARAM(hash); + } + + +private: + struct AsyncContext + { + rtFunctionRef resolverFunc; + std::vector args; + }; + +private: + static void workCallback(uv_work_t* req); + static void afterWorkCallback(uv_work_t* req, int status); + +private: + Disposition mDisposition; + v8::Persistent mResolver; + v8::Persistent mContext; + v8::Isolate* mIsolate; + uv_work_t mReq; +}; + +} // namespace + +#endif diff --git a/src/rtScriptV8/rtObjectWrapper.cpp b/src/rtScriptV8/rtObjectWrapper.cpp new file mode 100755 index 0000000000..f14050b8f5 --- /dev/null +++ b/src/rtScriptV8/rtObjectWrapper.cpp @@ -0,0 +1,473 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#include "rtObjectWrapper.h" +#include "rtFunctionWrapper.h" +#include "rtWrapperUtils.h" + +#include + +using namespace v8; + +namespace rtScriptV8Utils +{ + +static const char* kClassName = "rtObject"; +static const char* kFuncAllKeys = "allKeys"; +static const char* kPropLength = "length"; + +const char* jsObjectWrapper::kIsJavaScriptObjectWrapper = "8907a0a6-ef86-4c3d-aea1-c40c0aa2f6f0"; + +bool jsObjectWrapper::isJavaScriptObjectWrapper(const rtObjectRef& obj) +{ + rtValue value; + return obj && obj->Get(jsObjectWrapper::kIsJavaScriptObjectWrapper, &value) == RT_OK; +} + +static Handle makeStringFromKey(Isolate* isolate, rtObjectRef& keys, uint32_t index) +{ + return String::NewFromUtf8(isolate, keys.get(index).cString()); +} + +static Handle makeIntegerFromKey(Isolate* isolate, rtObjectRef& , uint32_t index) +{ + return Number::New(isolate, index); +} + +static Persistent ctor; + +rtObjectWrapper::rtObjectWrapper(const rtObjectRef& ref) + : rtWrapper(ref) +{ +} + +rtObjectWrapper::~rtObjectWrapper() +{ +} + +void rtObjectWrapper::destroyPrototype() +{ + if( !ctor.IsEmpty() ) + { + // TODO: THIS LEAKS... need to free obj within persistent + + ctor.ClearWeak(); + ctor.Reset(); + } +} + +void rtObjectWrapper::exportPrototype(Isolate* isolate, Handle exports) +{ + Local tmpl = FunctionTemplate::New(isolate, create); + tmpl->SetClassName(String::NewFromUtf8(isolate, kClassName)); + + Local inst = tmpl->InstanceTemplate(); + inst->SetInternalFieldCount(1); + inst->SetNamedPropertyHandler( + &getPropertyByName, + &setPropertyByName, + NULL, + NULL, + &getEnumerablePropertyNames); + + inst->SetIndexedPropertyHandler( + &getPropertyByIndex, + &setPropertyByIndex, + NULL, + NULL, + &getEnumerablePropertyIndecies); + ctor.Reset(isolate, tmpl->GetFunction()); + exports->Set(String::NewFromUtf8(isolate, kClassName), tmpl->GetFunction()); +} + +Handle rtObjectWrapper::createFromObjectReference(v8::Local& ctx, const rtObjectRef& ref) +{ + Isolate* isolate(ctx->GetIsolate()); + + EscapableHandleScope scope(isolate); + Context::Scope contextScope(ctx); + + // rtLogInfo("lookup:%u addr:%p", GetContextId(ctx), ref.getPtr()); + Local obj = HandleMap::lookupSurrogate(ctx, ref); + + if (!obj.IsEmpty()) + return scope.Escape(obj); + + // introspect for rtArrayValue + // TODO: not sure this is good. Any object can have a 'length' property + { + rtValue length; + if (ref && ref->Get("length", &length) != RT_PROP_NOT_FOUND) + { + const int n = length.toInt32(); + Local arr = Array::New(isolate, n); + for (int i = 0; i < n; ++i) + { + rtValue item; + rtError err = ref->Get(i, &item); + if (err == RT_OK) + arr->Set(Number::New(isolate, i), rt2js(ctx, item)); + } + return scope.Escape(arr); + } + } + + { + rtString desc; + if (ref) + { + rtError err = const_cast(ref).sendReturns("description", desc); + if (err == RT_OK && strcmp(desc.cString(), "rtPromise") == 0) + { + Local resolver = Promise::Resolver::New(isolate); + + rtFunctionRef resolve(new rtResolverFunction(rtResolverFunction::DispositionResolve, ctx, resolver)); + rtFunctionRef reject(new rtResolverFunction(rtResolverFunction::DispositionReject, ctx, resolver)); + + rtObjectRef newPromise; + rtObjectRef promise = ref; + + Local jsPromise = resolver->GetPromise(); + + // rtLogInfo("addp id:%u addr:%p", GetContextId(creationContext), ref.getPtr()); + HandleMap::addWeakReference(isolate, ref, jsPromise); + + err = promise.send("then", resolve, reject, newPromise); + if (err == RT_OK) + return scope.Escape(jsPromise); + else + rtLogError("failed to setup promise"); + + return scope.Escape(Local()); + } + } + } + + Local argv[1] = + { + External::New(isolate, ref.getPtr()) + }; + + Local func = PersistentToLocal(isolate, ctor); + obj = (func->NewInstance(ctx, 1, argv)).FromMaybe(Local()); + + // Local creationContext = obj->CreationContext(); + // rtLogInfo("add id:%u addr:%p", GetContextId(creationContext), ref.getPtr()); + // assert(GetContextId(creationContext) == GetContextId(ctx)); + + HandleMap::addWeakReference(isolate, ref, obj); + return scope.Escape(obj); +} + +rtValue rtObjectWrapper::unwrapObject(const Local& obj) +{ + return rtValue(unwrap(obj)); +} + +template +void rtObjectWrapper::getProperty(const T& prop, const PropertyCallbackInfo& info) +{ + HandleScope handle_scope(info.GetIsolate()); + Local ctx = info.This()->CreationContext(); + + rtObjectWrapper* wrapper = V8ObjectWrap::Unwrap(info.This()); + if (!wrapper) + return; + + rtObjectRef ref = wrapper->mWrappedObject; + if (!ref) + return; + + rtValue value; + rtError err = ref->Get(prop, &value); + + if (err != RT_OK) + { + if (err == RT_PROP_NOT_FOUND) + return; + else + info.GetIsolate()->ThrowException(Exception::Error(String::NewFromUtf8(info.GetIsolate(), + rtStrError(err)))); + } + else + { + Local v; + EscapableHandleScope scope(info.GetIsolate()); + v = rt2js(ctx, value); +// info.GetReturnValue().Set(rt2js(info.GetIsolate(), value)); + scope.Escape(v); + info.GetReturnValue().Set(v); + } +} + +template +void rtObjectWrapper::setProperty(const T& prop, Local val, const PropertyCallbackInfo& info) +{ + Locker locker(info.GetIsolate()); + Isolate::Scope isolateScope(info.GetIsolate()); + HandleScope handleScope(info.GetIsolate()); + Local creationContext = info.This()->CreationContext(); + + rtWrapperError error; + rtValue value = js2rt(creationContext, val, &error); + if (error.hasError()) + info.GetIsolate()->ThrowException(error.toTypeError(info.GetIsolate())); + + rtError err = unwrap(info)->Set(prop, &value); + if (err == RT_OK) + info.GetReturnValue().Set(val); +} + +void rtObjectWrapper::getEnumerable(const PropertyCallbackInfo& info, enumerable_item_creator_t create) +{ + rtObjectWrapper* wrapper = V8ObjectWrap::Unwrap(info.This()); + if (!wrapper) + return; + + rtObjectRef ref = wrapper->mWrappedObject; + if (!ref) + return; + + rtObjectRef keys = ref.get(kFuncAllKeys); + if (!keys) + return; + + uint32_t length = keys.get(kPropLength); + Local props = Array::New(info.GetIsolate(), length); + + for (uint32_t i = 0; i < length; ++i) + props->Set(Number::New(info.GetIsolate(), i), create(info.GetIsolate(), keys, i)); + + info.GetReturnValue().Set(props); +} + +void rtObjectWrapper::getEnumerablePropertyNames(const PropertyCallbackInfo& info) +{ + getEnumerable(info, makeStringFromKey); +} + +void rtObjectWrapper::getEnumerablePropertyIndecies(const PropertyCallbackInfo& info) +{ + getEnumerable(info, makeIntegerFromKey); +} + +void rtObjectWrapper::getPropertyByName(Local prop, const PropertyCallbackInfo& info) +{ + rtString name = toString(prop); + getProperty(name.cString(), info); +} + +void rtObjectWrapper::getPropertyByIndex(uint32_t index, const PropertyCallbackInfo& info) +{ + getProperty(index, info); +} + +void rtObjectWrapper::setPropertyByName(Local prop, Local val, const PropertyCallbackInfo& info) +{ + rtString name = toString(prop); + setProperty(name.cString(), val, info); +} + +void rtObjectWrapper::setPropertyByIndex(uint32_t index, Local val, const PropertyCallbackInfo& info) +{ + setProperty(index, val, info); +} + +void rtObjectWrapper::create(const FunctionCallbackInfo& args) +{ + assert(args.IsConstructCall()); + + HandleScope scope(args.GetIsolate()); + rtObject* obj = static_cast(args[0].As()->Value()); + rtObjectWrapper* wrapper = new rtObjectWrapper(obj); + wrapper->Wrap(args.This()); +} + +jsObjectWrapper::jsObjectWrapper(Isolate* isolate, const Handle& obj, bool isArray) + : mRefCount(0) + , mObject(isolate, Handle::Cast(obj)) + , mIsolate(isolate) + , mIsArray(isArray) +{ +} + +jsObjectWrapper::~jsObjectWrapper() +{ + mObject.Reset(); +} + +unsigned long jsObjectWrapper::AddRef() +{ + return rtAtomicInc(&mRefCount); +} + +unsigned long jsObjectWrapper::Release() +{ + unsigned long l = rtAtomicDec(&mRefCount); + if (l == 0) delete this; + return l; +} + +rtError jsObjectWrapper::getAllKeys(Isolate* isolate, rtValue* value) const +{ + HandleScope handleScope(isolate); + Local self = PersistentToLocal(isolate, mObject); + Local names = self->GetPropertyNames(); + Local ctx = self->CreationContext(); + + rtRefT result(new rtArrayObject); + for (int i = 0, n = names->Length(); i < n; ++i) + { + rtWrapperError error; + rtValue val = js2rt(ctx, names->Get(i), &error); + if (error.hasError()) + return RT_FAIL; + else + result->pushBack(val); + } + + *value = rtValue(result); + return RT_OK; +} + +rtError jsObjectWrapper::Get(const char* name, rtValue* value) const +{ + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); + + if (!name) + return RT_ERROR_INVALID_ARG; + if (!value) + return RT_ERROR_INVALID_ARG; + + if (strcmp(name, jsObjectWrapper::kIsJavaScriptObjectWrapper) == 0) + return RT_OK; + + // TODO: does array support this? + if (strcmp(name, kFuncAllKeys) == 0) + return getAllKeys(mIsolate, value); + + rtError err = RT_OK; + + Local self = PersistentToLocal(mIsolate, mObject); + Local s = String::NewFromUtf8(mIsolate, name); + Local ctx = self->CreationContext(); + + if (mIsArray) + { + if (!strcmp(name, "length")) + *value = rtValue(Array::Cast(*self)->Length()); + else + err = Get((s->ToArrayIndex(ctx)).FromMaybe(Local())->Value(), value); + } + else + { + if (!self->Has(s)) + { + err = RT_PROPERTY_NOT_FOUND; + } + else + { + rtWrapperError error; + *value = js2rt(ctx, self->Get(s), &error); + if (error.hasError()) + err = RT_ERROR_INVALID_ARG; + } + } + return err; +} + +rtError jsObjectWrapper::Get(uint32_t i, rtValue* value) const +{ + if (!value) + return RT_ERROR_INVALID_ARG; + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handleScope(mIsolate); + + Local self = PersistentToLocal(mIsolate, mObject); + Local ctx = self->CreationContext(); + + if (!(self->Has(ctx,i).FromMaybe(false))) + return RT_PROPERTY_NOT_FOUND; + rtWrapperError error; + *value = js2rt(ctx, self->Get(i), &error); + if (error.hasError()) + return RT_ERROR_INVALID_ARG; + + return RT_OK; +} + +rtError jsObjectWrapper::Set(const char* name, const rtValue* value) +{ + if (!name) + return RT_ERROR_INVALID_ARG; + if (!value) + return RT_ERROR_INVALID_ARG; + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handleScope(mIsolate); + Local s = String::NewFromUtf8(mIsolate, name); + Local self = PersistentToLocal(mIsolate, mObject); + Local ctx = self->CreationContext(); + + rtError err = RT_OK; + + if (mIsArray) + { + Local idx = (s->ToArrayIndex(ctx)).FromMaybe(Local()); + if (idx.IsEmpty()) + err = RT_ERROR_INVALID_ARG; + else + err = Set(idx->Value(), value); + } + else + { + err = self->Set(s, rt2js(ctx, *value)); + } + + return err; +} + +rtError jsObjectWrapper::Set(uint32_t i, const rtValue* value) +{ + if (!value) + return RT_ERROR_INVALID_ARG; + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handleScope(mIsolate); + Local self = PersistentToLocal(mIsolate, mObject); + Local ctx = self->CreationContext(); + + if (!self->Set(i, rt2js(ctx, *value))) + return RT_FAIL; + + return RT_OK; +} + +Local jsObjectWrapper::getWrappedObject() +{ + EscapableHandleScope scope(mIsolate); + return scope.Escape(PersistentToLocal(mIsolate, mObject)); +} + +} diff --git a/src/rtScriptV8/rtObjectWrapper.h b/src/rtScriptV8/rtObjectWrapper.h new file mode 100755 index 0000000000..6213b20daf --- /dev/null +++ b/src/rtScriptV8/rtObjectWrapper.h @@ -0,0 +1,147 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#ifndef RT_OBJECT_WRAPPER_H +#define RT_OBJECT_WRAPPER_H + +#include "rtWrapperUtils.h" + +using namespace v8; + +namespace rtScriptV8Utils +{ + +class rtObjectWrapper : public rtWrapper +{ +public: + rtObjectWrapper(const rtObjectRef& ref); + virtual ~rtObjectWrapper(); + + void dispose() + { + } + +public: + static void exportPrototype(Isolate* isolate, Handle exports); + static void destroyPrototype(); + + static Handle createFromObjectReference(v8::Local& ctx, const rtObjectRef& ref); + + static rtValue unwrapObject(const Local& val); + +private: + static void create(const FunctionCallbackInfo& args); + + static void getPropertyByName(Local prop, const PropertyCallbackInfo& info); + static void setPropertyByName(Local prop, Local val, const PropertyCallbackInfo& info); + static void getEnumerablePropertyNames(const PropertyCallbackInfo& info); + static void getPropertyByIndex(uint32_t index, const PropertyCallbackInfo& info); + static void setPropertyByIndex(uint32_t index, Local val, const PropertyCallbackInfo& info); + static void getEnumerablePropertyIndecies(const PropertyCallbackInfo& info); + + template + static void getProperty(const T& prop, const PropertyCallbackInfo& info); + + template + static void setProperty(const T& prop, Local val, const PropertyCallbackInfo& info); + + typedef Handle (*enumerable_item_creator_t)(v8::Isolate* isolate, rtObjectRef& keys, uint32_t index); + static void getEnumerable(const PropertyCallbackInfo& info, enumerable_item_creator_t create); +}; + +class jsObjectWrapper : public rtIObject +{ +public: + jsObjectWrapper(v8::Isolate* isolate, const Handle& val, bool isArray); + virtual ~jsObjectWrapper(); + + static const char* kIsJavaScriptObjectWrapper; + static bool isJavaScriptObjectWrapper(const rtObjectRef& obj); + + virtual unsigned long AddRef(); + virtual unsigned long Release(); + virtual unsigned long getRefCount() const + { return mRefCount; } + + virtual rtError Get(const char* name, rtValue* value) const; + virtual rtError Get(uint32_t i, rtValue* value) const; + virtual rtError Set(const char* name, const rtValue* value); + virtual rtError Set(uint32_t i, const rtValue* value); + virtual rtMethodMap* getMap() const { return NULL; } + Local getWrappedObject(); + +private: + rtError getAllKeys(Isolate* isolate, rtValue* value) const; + +private: + unsigned long mRefCount; + Persistent mObject; + Isolate* mIsolate; + bool mIsArray; +}; + +} // namespace + +#endif + +#ifndef RT_WRAPPER_UTILS +#define RT_WRAPPER_UTILS + +#include + +#include +#include +#include + +namespace rtScriptV8Utils +{ + +inline rtString toString(const v8::Handle& obj) +{ + v8::String::Utf8Value utf(obj->ToString()); + return rtString(*utf); +} + +inline rtString toString(const v8::Handle& val) +{ + v8::String::Utf8Value utf(val->ToString()); + return rtString(*utf); +} + +inline rtString toString(const v8::Local& s) +{ + v8::String::Utf8Value utf(s); + return rtString(*utf); +} + +inline int toInt32(const v8::FunctionCallbackInfo& args, int which, int defaultValue = 0) +{ + int i = defaultValue; + if (!args[which]->IsUndefined()) + i = args[which]->IntegerValue(); + return i; +} + +rtValue js2rt(const v8::Handle& val); + +v8::Handle rt2js(const rtValue& val); + +} // namespace + +#endif + diff --git a/src/rtScriptV8/rtScriptV8.cpp b/src/rtScriptV8/rtScriptV8.cpp new file mode 100755 index 0000000000..44a043cafa --- /dev/null +++ b/src/rtScriptV8/rtScriptV8.cpp @@ -0,0 +1,238 @@ +/* + + pxCore Copyright 2005-2018 John Robinson + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +// rtNode.cpp + +#if defined WIN32 +#include +#include +#define __PRETTY_FUNCTION__ __FUNCTION__ +#else +#include +#endif + +#include +#include + +#include +#include + +#include +#include + +#ifndef WIN32 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +#include "rtWrapperUtils.h" + +#ifndef WIN32 +#pragma GCC diagnostic pop +#endif + +#include "rtScriptV8.h" + + +#include "rtCore.h" +#include "rtObject.h" +#include "rtValue.h" +#include "rtAtomic.h" +#include "rtScript.h" + + +#include +#include + +#if !defined(WIN32) && !defined(ENABLE_DFB) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#pragma GCC diagnostic ignored "-Wall" +#endif + +#include "uv.h" +#include "v8.h" +#include "libplatform/libplatform.h" + +#include "rtObjectWrapper.h" +#include "rtFunctionWrapper.h" + +#if !defined(WIN32) & !defined(ENABLE_DFB) +#pragma GCC diagnostic pop +#endif + +class rtV8Context; + +typedef rtRef rtV8ContextRef; + +class rtV8Context: rtIScriptContext // V8 +{ +public: + rtV8Context(v8::Isolate *isolate, v8::Platform* platform); + + virtual ~rtV8Context(); + + virtual rtError add(const char *name, const rtValue& val) + { + return RT_OK; + } + virtual rtValue get(const char *name) + { + return rtValue(); + } + + virtual bool has(const char *name) + { + return true; + } + + virtual rtError runScript(const char *script, rtValue* retVal = NULL, const char *args = NULL) + { + return RT_OK; + } + virtual rtError runFile (const char *file, rtValue* retVal = NULL, const char *args = NULL) + { + return RT_OK; + } + + unsigned long AddRef() + { + return rtAtomicInc(&mRefCount); + } + + unsigned long Release(); + +private: + v8::Isolate *mIsolate; + v8::Platform *mPlatform; + int mRefCount; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef std::map rtV8Contexts; +typedef std::map::const_iterator rtV8Contexts_iterator; + +class rtScriptV8: public rtIScript +{ +public: + rtScriptV8(); + virtual ~rtScriptV8(); + + unsigned long AddRef() + { + return rtAtomicInc(&mRefCount); + } + + unsigned long Release(); + + rtError init() + { + return RT_OK; + } + rtError term() + { + return RT_OK; + } + + rtString engine() { return "v8"; } + + rtError createContext(const char *lang, rtScriptContextRef& ctx) + { + return RT_OK; + } + + rtError pump() + { + return RT_OK; + } + + v8::Isolate *getIsolate() + { + return mIsolate; + } + v8::Platform *getPlatform() + { + return mPlatform; + } + + rtError collectGarbage() + { + return RT_OK; + } + void* getParameter(rtString param) + { + return NULL; + } + +private: + v8::Isolate *mIsolate; + v8::Platform *mPlatform; + + int mRefCount; +}; + + +using namespace v8; + +rtV8Context::rtV8Context(Isolate *isolate, Platform *platform) : + mIsolate(isolate), mRefCount(0), mPlatform(platform) +{ +} + +rtV8Context::~rtV8Context() +{ +} + +rtScriptV8::rtScriptV8():mRefCount(0) +{ + mIsolate = NULL; + mPlatform = NULL; + init(); +} + +rtScriptV8::~rtScriptV8() +{ +} + +unsigned long rtScriptV8::Release() +{ + long l = rtAtomicDec(&mRefCount); + if (l == 0) + { + delete this; + } + return l; +} + +unsigned long rtV8Context::Release() +{ + long l = rtAtomicDec(&mRefCount); + if (l == 0) + { + delete this; + } + return l; +} + +rtError createScriptV8(rtScriptRef& script) +{ + script = new rtScriptV8(); + return RT_OK; +} diff --git a/src/rtScriptV8/rtScriptV8.h b/src/rtScriptV8/rtScriptV8.h new file mode 100755 index 0000000000..7295cc9ffb --- /dev/null +++ b/src/rtScriptV8/rtScriptV8.h @@ -0,0 +1,29 @@ +/* + + pxCore Copyright 2005-2018 John Robinson + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +// rtScriptNode.h + +#ifndef RTSCRIPTV8_H +#define RTSCRIPTV8_H + + +rtError createScriptV8(rtScriptRef& script); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // RTSCRIPTV8_H diff --git a/src/rtScriptV8/rtWrapperUtils.cpp b/src/rtScriptV8/rtWrapperUtils.cpp new file mode 100755 index 0000000000..915daeffdd --- /dev/null +++ b/src/rtScriptV8/rtWrapperUtils.cpp @@ -0,0 +1,355 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#include "rtWrapperUtils.h" +#include "rtObjectWrapper.h" +#include "rtFunctionWrapper.h" +#include + +#if defined(USE_STD_THREADS) +#include +#include +#endif + +using namespace std; + +//----------------------------------- + +namespace rtScriptV8Utils +{ + +const int HandleMap::kContextIdIndex = 2; + +struct ObjectReference +{ + rtObjectRef RTObject; + Persistent PersistentObject; + uint32_t CreationContextId; +}; + +typedef std::map< rtIObject*, ObjectReference* > ObjectReferenceMap; +static ObjectReferenceMap objectMap; + +uint32_t +GetContextId(Local& ctx) +{ + if (ctx.IsEmpty()) return 0; + + HandleScope handleScope(ctx->GetIsolate()); + Local val = ctx->GetEmbedderData(HandleMap::kContextIdIndex); + assert(!val.IsEmpty()); + return val->Uint32Value(); +} + +static void WeakCallback(const WeakCallbackInfo& data) { + Locker locker(data.GetIsolate()); + Isolate::Scope isolateScope(data.GetIsolate()); + HandleScope handleScope(data.GetIsolate()); + rtObjectRef temp; + ObjectReferenceMap::iterator j = objectMap.find(data.GetParameter()); + if (j != objectMap.end()) + { + // TODO: Removing this temporarily until we understand how this callback works. I + // would have assumed that this is a weak persistent since we called SetWeak() on it + // before inserting it into the objectMap_rt2v8 map. + // assert(p->IsWeak()); + // + j->second->PersistentObject.ClearWeak(); + j->second->PersistentObject.Reset(); + temp = j->second->RTObject; + delete j->second; + objectMap.erase(j); + } + else + { + rtLogWarn("failed to find:%p in map", data.GetParameter()); + } + if (NULL != temp.getPtr()) + { + rtObjectRef parentRef; + rtError err = temp.get("parent",parentRef); + if (err == RT_OK) + { + if (NULL == parentRef) + { + temp.send("dispose"); + } + } + } +} + +void +HandleMap::clearAllForContext(uint32_t contextId) +{ + typedef ObjectReferenceMap::iterator iterator; + + int n = 0; + rtLogInfo("clearing all persistent handles for: %u size:%u", contextId, + static_cast(objectMap.size())); + vector refs; + for (iterator begin = objectMap.begin(), end = objectMap.end(); begin != end;) + { + ObjectReference* ref = begin->second; + //rtLogInfo("looking at:%d == %d", ref->CreationContextId, contextId); + + if (ref->CreationContextId == contextId) + { + refs.push_back(begin); + ref->PersistentObject.ClearWeak(); + ref->PersistentObject.Reset(); + delete ref; + ref = NULL; + begin++; + n++; + } + else + { + //rtLogInfo("looping :%d == %d", ref->CreationContextId, contextId); + ++begin; + } + } + + for(unsigned int i=0; i(objectMap.size())); +} + +void HandleMap::addWeakReference(v8::Isolate* isolate, const rtObjectRef& from, Local& to) +{ + HandleScope handleScope(isolate); + Local creationContext = to->CreationContext(); + + uint32_t const contextIdCreation = GetContextId(creationContext); + assert(contextIdCreation != 0); + ObjectReferenceMap::iterator i = objectMap.find(from.getPtr()); + if (i != objectMap.end()) + { + if (!(i->second->PersistentObject.IsNearDeath())) + { + rtLogError("About to add weak reference which is already present"); + } + } + //assert(i == objectMap.end()); + + if (i == objectMap.end()) + { + // rtLogInfo("add id:%u addr:%p", contextIdCreation, from.getPtr()); + ObjectReference* entry(new ObjectReference()); + entry->PersistentObject.Reset(isolate, to); + entry->PersistentObject.SetWeak(from.getPtr(), WeakCallback, v8::WeakCallbackType::kParameter); + entry->RTObject = from; + entry->CreationContextId = contextIdCreation; + objectMap.insert(std::make_pair(from.getPtr(), entry)); + } +rtWrapperSceneUpdateExit(); + + #if 0 + static FILE* f = NULL; + if (!f) + f = fopen("/tmp/handles.txt", "w+"); + if (f) + { + rtString desc; + const_cast(from).sendReturns("description", desc); + fprintf(f, "%p (%s) => %p\n", from.getPtr(), desc.cString(), h); + } + #endif + +} + +Local HandleMap::lookupSurrogate(v8::Local& ctx, const rtObjectRef& from) +{ + Isolate* isolate = ctx->GetIsolate(); + EscapableHandleScope scope(isolate); + Local obj; + ObjectReferenceMap::iterator i = objectMap.find(from.getPtr()); + if (i == objectMap.end()) + { + return scope.Escape(obj); + } + obj = PersistentToLocal(isolate, i->second->PersistentObject); + + if (!obj.IsEmpty()) + { + // JR sanity check + if ((from.getPtr() != NULL) && (from.get("animateTo") != NULL) && + (!obj->Has(v8::String::NewFromUtf8(isolate,"animateTo")))) + { + // TODO change description to a property + rtString desc; + const_cast(from).sendReturns("description", desc); + rtLogError("type mismatch in handle map %p (%s)", from.getPtr(), desc.cString()); + assert(false); + } + } + + return scope.Escape(obj); +} + +bool rtIsPromise(const rtValue& v) +{ + if (v.getType() != RT_rtObjectRefType) + return false; + + rtObjectRef ref = v.toObject(); + if (!ref) + return false; + + rtString desc; + rtError err = ref.sendReturns("description", desc); + if (err != RT_OK) + return false; + + return strcmp(desc.cString(), "rtPromise") == 0; +} + + + +using namespace v8; + +Handle rt2js(Local& ctx, const rtValue& v) +{ + Context::Scope contextScope(ctx); + + Isolate* isolate = ctx->GetIsolate(); + + switch (v.getType()) + { + case RT_int32_tType: + { + int32_t i = v.toInt32(); + return Integer::New(isolate, i); + } + break; + case RT_uint32_tType: + { + uint32_t u = v.toUInt32(); + return Integer::NewFromUnsigned(isolate, u); + } + break; + case RT_int64_tType: + { + double d = v.toDouble(); + return Number::New(isolate, d); + } + break; + case RT_floatType: + { + float f = v.toFloat(); + return Number::New(isolate, f); + } + break; + case RT_doubleType: + { + double d = v.toDouble(); + return Number::New(isolate, d); + } + break; + case RT_uint64_tType: + { + double d = v.toDouble(); + return Number::New(isolate, d); + } + break; + case RT_functionType: + { + rtFunctionRef func = v.toFunction(); + if (!func) + return v8::Null(isolate); + return rtFunctionWrapper::createFromFunctionReference(ctx, isolate, func); + } + break; + case RT_rtObjectRefType: + { + rtObjectRef obj = v.toObject(); + if (!obj) + return v8::Null(isolate); + + return jsObjectWrapper::isJavaScriptObjectWrapper(obj) + ? static_cast(obj.getPtr())->getWrappedObject() + : rtObjectWrapper::createFromObjectReference(ctx, obj); + } + break; + case RT_boolType: + return Boolean::New(isolate, v.toBool()); + break; + case RT_rtStringType: + { + rtString s = v.toString(); + return String::NewFromUtf8(isolate, s.cString()); + } + break; + case RT_voidPtrType: + rtLogWarn("attempt to convert from void* to JS object"); + return Handle(); // TODO + break; + case 0: // This is really a value rtValue() will set mType to zero + return Handle(); + break; + default: + rtLogFatal("unsupported rtValue [(char value(%c) int value(%d)] to javascript conversion", + v.getType(), v.getType()); + break; + } + + return Undefined(isolate); +} + +rtValue js2rt(v8::Local& ctx, const Handle& val, rtWrapperError* ) +{ + v8::Isolate* isolate = ctx->GetIsolate(); + + if (val->IsUndefined()) { return rtValue((void *)0); } + if (val->IsNull()) { return rtValue((char *)0); } + if (val->IsString()) { return toString(val); } + if (val->IsFunction()) { return rtValue(rtFunctionRef(new jsFunctionWrapper(ctx, val))); } + if (val->IsArray() || val->IsObject()) + { + // This is mostly a heuristic. We should probably set a second internal + // field and use a uuid as a magic number to ensure this is one of our + // wrapped objects. + // It's very possible that someone is trying to use another wrapped object + // from some other native addon. Maybe that would actuall work and fail + // at a lower level? + Local obj = val->ToObject(); + if (obj->InternalFieldCount() > 0) + { + return rtObjectWrapper::unwrapObject(obj); + } + else + { + // this is a regular JS object. i.e. one that does not wrap an rtObject. + // in this case, we'll provide the necessary adapter. + return rtValue(new jsObjectWrapper(isolate, obj->ToObject(), val->IsArray())); + } + } + + if (val->IsBoolean()) { return rtValue(val->BooleanValue()); } + if (val->IsNumber()) { return rtValue(val->NumberValue()); } + if (val->IsInt32()) { return rtValue(val->Int32Value()); } + if (val->IsUint32()) { return rtValue(val->Uint32Value()); } + + rtLogFatal("unsupported javascript -> rtValue type conversion"); + return rtValue(0); +} + +} // namespace diff --git a/src/rtScriptV8/rtWrapperUtils.h b/src/rtScriptV8/rtWrapperUtils.h new file mode 100755 index 0000000000..39f31b770c --- /dev/null +++ b/src/rtScriptV8/rtWrapperUtils.h @@ -0,0 +1,323 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#ifndef RT_WRAPPER_UTILS +#define RT_WRAPPER_UTILS + +#include "v8_headers.h" + +#include +#include +#include +#include + +#include "rtScript.h" + +#include +#include +#include +#include + +#include + +namespace rtScriptV8Utils +{ + +//bool rtIsRenderThread(); +bool rtIsPromise(const rtValue& v); + +template +inline std::string jsToString(T const& val) +{ + v8::String::Utf8Value v(val->ToString()); + return std::string(*v); +} + +template +inline v8::Local _StrongPersistentToLocal(const v8::Persistent& persistent) +{ + return *reinterpret_cast*>( + const_cast*>(&persistent)); +} + +template +inline v8::Local _WeakPersistentToLocal(v8::Isolate* isolate, const v8::Persistent& persistent) +{ + return v8::Local::New(isolate, persistent); +} + +template +inline v8::Local PersistentToLocal(v8::Isolate* isolate, const v8::Persistent& persistent) +{ + if (persistent.IsWeak()) + return _WeakPersistentToLocal(isolate, persistent); + else if (persistent.IsNearDeath()) + return v8::Local(); + else + return _StrongPersistentToLocal(persistent); +} + +uint32_t GetContextId(v8::Local& ctx); + +// I don't think node/v8 addons support c++ exceptions. In cases where +// a pending error might be set on a call stack, you can use this object +// to pass around. If there's a pending error, simply use: +// rtWrapperError error; +// someFunction(arg1, arg2, &error); +// if (error.hasError()) +// v8::ThrowException(error.toTypeError()); +// use the correct flavor of javascript exception. +class rtWrapperError +{ +public: + rtWrapperError() { } + rtWrapperError(const char* errorMessage) + : mMessage(errorMessage) { } + + inline bool hasError() const + { return !mMessage.empty(); } + + v8::Local toTypeError(v8::Isolate* isolate) + { + return v8::Exception::TypeError(v8::String::NewFromUtf8(isolate, mMessage.c_str())); + } + + v8::Local toRangeError(v8::Isolate* isolate) + { + return v8::Exception::RangeError(v8::String::NewFromUtf8(isolate, mMessage.c_str())); + } + + v8::Local toReferenceError(v8::Isolate* isolate) + { + return v8::Exception::ReferenceError(v8::String::NewFromUtf8(isolate, mMessage.c_str())); + } + + v8::Local toSyntaxError(v8::Isolate* isolate) + { + return v8::Exception::SyntaxError(v8::String::NewFromUtf8(isolate, mMessage.c_str())); + } + + v8::Local toGenericError(v8::Isolate* isolate) + { + return v8::Exception::Error(v8::String::NewFromUtf8(isolate, mMessage.c_str())); + } + + void setMessage(const char* errorMessage) + { mMessage = errorMessage; } + +private: + std::string mMessage; +}; + +inline rtString toString(const v8::Handle& obj) +{ + v8::String::Utf8Value utf(obj->ToString()); + return rtString(*utf); +} + +inline rtString toString(const v8::Handle& val) +{ + v8::String::Utf8Value utf(val->ToString()); + return rtString(*utf); +} + +inline rtString toString(const v8::Local& s) +{ + v8::String::Utf8Value utf(s); + return rtString(*utf); +} + +inline int toInt32(const v8::FunctionCallbackInfo& args, int which, int defaultValue = 0) +{ + int i = defaultValue; + if (!args[which]->IsUndefined()) + i = (int)args[which]->IntegerValue(); + return i; +} + +class V8ObjectWrap { + public: + V8ObjectWrap() { + refs_ = 0; + } + + + virtual ~V8ObjectWrap() { + if (persistent().IsEmpty()) + return; + assert(persistent().IsNearDeath()); + persistent().ClearWeak(); + persistent().Reset(); + } + + + template + static inline T* Unwrap(v8::Local handle) { + assert(!handle.IsEmpty()); + assert(handle->InternalFieldCount() > 0); + // Cast to V8ObjectWrap before casting to T. A direct cast from void + // to T won't work right when T has more than one base class. + void* ptr = handle->GetAlignedPointerFromInternalField(0); + V8ObjectWrap* wrap = static_cast(ptr); + return static_cast(wrap); + } + + + inline v8::Local handle() { + return handle(v8::Isolate::GetCurrent()); + } + + + inline v8::Local handle(v8::Isolate* isolate) { + return v8::Local::New(isolate, persistent()); + } + + + inline v8::Persistent& persistent() { + return handle_; + } + + + protected: + inline void Wrap(v8::Local handle) { + assert(persistent().IsEmpty()); + assert(handle->InternalFieldCount() > 0); + handle->SetAlignedPointerInInternalField(0, this); + persistent().Reset(v8::Isolate::GetCurrent(), handle); + MakeWeak(); + } + + + inline void MakeWeak(void) { + persistent().SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); + persistent().MarkIndependent(); + } + + /* Ref() marks the object as being attached to an event loop. + * Refed objects will not be garbage collected, even if + * all references are lost. + */ + virtual void Ref() { + assert(!persistent().IsEmpty()); + persistent().ClearWeak(); + refs_++; + } + + /* Unref() marks an object as detached from the event loop. This is its + * default state. When an object with a "weak" reference changes from + * attached to detached state it will be freed. Be careful not to access + * the object after making this call as it might be gone! + * (A "weak reference" means an object that only has a + * persistent handle.) + * + * DO NOT CALL THIS FROM DESTRUCTOR + */ + virtual void Unref() { + assert(!persistent().IsEmpty()); + assert(!persistent().IsWeak()); + assert(refs_ > 0); + if (--refs_ == 0) + MakeWeak(); + } + + int refs_; // ro + + private: + static void WeakCallback( + const v8::WeakCallbackInfo& data) { + V8ObjectWrap* wrap = data.GetParameter(); + assert(wrap->refs_ == 0); + wrap->handle_.Reset(); + delete wrap; + } + + v8::Persistent handle_; +}; + +template +class rtWrapper : public V8ObjectWrap +{ +protected: + rtWrapper(const TRef& ref) : mWrappedObject(ref) + { + } + + virtual ~rtWrapper(){ } + + static TRef unwrap(const v8::FunctionCallbackInfo& args) + { + return V8ObjectWrap::Unwrap(args.This())->mWrappedObject; + } + + static TRef unwrap(const v8::PropertyCallbackInfo& args) + { + return V8ObjectWrap::Unwrap(args.This())->mWrappedObject; + } + + static TRef unwrap(const v8::Local& obj) + { + return V8ObjectWrap::Unwrap(obj)->mWrappedObject; + } + + static void throwRtError(v8::Isolate* isolate, rtError err, const char* format, ...) + RT_PRINTF_FORMAT(3, 4) + { + const int kBuffSize = 256; + char buff[kBuffSize]; + + va_list ptr; + va_start(ptr, format); + int n = vsnprintf(buff, sizeof(buff), format, ptr); + if (n >= kBuffSize) + { + buff[kBuffSize - 1] = '\0'; + } + else + { + strcat(buff, ": "); + strncat(buff, rtStrError(err), kBuffSize - strlen(buff) - 1); + } + va_end(ptr); + + isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, buff))); + } + +protected: + TRef mWrappedObject; +}; + +rtValue js2rt(v8::Local& ctx, const v8::Handle& val, rtWrapperError* error); + +v8::Handle rt2js(v8::Local& ctx, const rtValue& val); + + +class HandleMap +{ +public: + static int const kContextIdIndex; + + static void addWeakReference(v8::Isolate* isolate, const rtObjectRef& from, v8::Local& to); + static v8::Local lookupSurrogate(v8::Local& ctx, const rtObjectRef& from); + static void clearAllForContext(uint32_t contextId); +}; + + +} // namespace + +#endif + diff --git a/src/rtScriptV8/v8_headers.h b/src/rtScriptV8/v8_headers.h new file mode 100755 index 0000000000..86540e4a79 --- /dev/null +++ b/src/rtScriptV8/v8_headers.h @@ -0,0 +1,29 @@ +/* + +pxCore Copyright 2005-2018 John Robinson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*/ + +#ifndef V8_HEADERS_H +#define V8_HEADERS_H + +#include + +#include +#include +#include + +#endif + From 6756bd3fe79360d832cacb460445036d082954cf Mon Sep 17 00:00:00 2001 From: Kuts Alexey Date: Wed, 20 Jun 2018 21:14:47 +0100 Subject: [PATCH 02/26] v8 driver and binding test code --- cmake/V8Deps.cmake | 57 +++ examples/pxScene2d/src/CMakeLists.txt | 19 +- examples/pxScene2d/src/pxScene.cpp | 5 + examples/pxScene2d/src/pxScene2d.cpp | 31 ++ examples/pxScene2d/src/pxScene2d.h | 9 + examples/pxScene2d/src/test_binding.js | 43 ++ src/CMakeLists.txt | 534 +++++++++++++------------ src/rtScriptV8/jsCallback.cpp | 4 +- src/rtScriptV8/rtFunctionWrapper.cpp | 6 +- src/rtScriptV8/rtObjectWrapper.cpp | 18 +- src/rtScriptV8/rtScriptV8.cpp | 534 ++++++++++++++++++++++--- src/rtScriptV8/rtWrapperUtils.cpp | 4 +- src/rtScriptV8/rtWrapperUtils.h | 4 +- 13 files changed, 928 insertions(+), 340 deletions(-) create mode 100644 cmake/V8Deps.cmake create mode 100644 examples/pxScene2d/src/test_binding.js diff --git a/cmake/V8Deps.cmake b/cmake/V8Deps.cmake new file mode 100644 index 0000000000..55a75b0bdd --- /dev/null +++ b/cmake/V8Deps.cmake @@ -0,0 +1,57 @@ + +set(NODEDIR "${EXTDIR}/libnode-v6.9.0/") +set(V8_INCLUDE_DIRS ${NODEDIR}/src ${NODEDIR}/deps/uv/include ${NODEDIR}/deps/v8/include ${NODEDIR}/deps/cares/include) + +if (WIN32) + set(V8_INCLUDE_DIRS ${V8_INCLUDE_DIRS} + ${NODEDIR}/deps/openssl/openssl/include ${NODEDIR}/deps/http_parser + ${NODEDIR}/deps/v8_inspector/third_party/v8_inspector/ + ${NODEDIR}/deps/icu-small/source/common/unicode + ${NODEDIR}/Release/obj/global_intermediate/blink + ${NODEDIR}/Release/obj/global_intermediate + ${NODEDIR}/Release/obj/gen/blink + ${NODEDIR}/deps/icu-small/source/common + ${NODEDIR}/tools/msvs/genfiles + ) + set(V8_LIBRARY_DIRS ${NODEDIR}build/Release/lib ${NODEDIR}Release/lib ${NODEDIR}Release) + set(V8_LIBRARIES + v8_libplatform.lib v8_libbase.lib v8_nosnapshot.lib v8_snapshot.lib v8_base_0.lib + v8_base_1.lib v8_base_2.lib v8_base_3.lib + gtest.lib cares.lib http_parser.lib + icutools.lib icustubdata.lib icudata.lib icuucx.lib icui18n.lib + libuv.lib openssl.lib v8_inspector_stl.lib cctest.lib + ) +else (WIN32) + set(V8_LIBRARY_DIRS + ${NODEDIR}/out/Release/obj.target + ${NODEDIR}/out/Release/obj.target/deps/v8_inspector/third_party/v8_inspector/platform/v8_inspector + ${NODEDIR}/out/Release/obj.target/deps/uv + ${NODEDIR}/out/Release/obj.target/deps/v8/tools/gyp + ${NODEDIR}/out/Release/obj.target/deps/cares + ${NODEDIR}/out/Release/obj.target/deps/zlib + ${NODEDIR}/out/Release/obj.target/deps/http_parser + ${NODEDIR}out/Release/obj.target/tools/icu + ) + set(V8_LIBRARIES + v8_inspector_stl + uv + v8_snapshot + v8_base + v8_nosnapshot + v8_libplatform + v8_libbase + cares + zlib + http_parser + icustubdata + icui18n + icuucx + icudata + ) +endif (WIN32) + +if (NOT SUPPORT_V8) + unset(V8_INCLUDE_DIRS) + unset(V8_LIBRARY_DIRS) + unset(V8_LIBRARIES) +endif (NOT SUPPORT_V8) diff --git a/examples/pxScene2d/src/CMakeLists.txt b/examples/pxScene2d/src/CMakeLists.txt index 088a91e802..9c43aac5a4 100644 --- a/examples/pxScene2d/src/CMakeLists.txt +++ b/examples/pxScene2d/src/CMakeLists.txt @@ -14,6 +14,7 @@ include(${PXCOREDIR}/cmake/CommDeps.cmake) include(${PXCOREDIR}/cmake/NodeDeps.cmake) include(${PXCOREDIR}/cmake/DukeDeps.cmake) include(${PXCOREDIR}/cmake/SManDeps.cmake) +include(${PXCOREDIR}/cmake/V8Deps.cmake) set(WESTEROSINC ${EXTDIR}/westeros/external/install/include) set(WESTEROSSTUBINC ${EXTDIR}/westeros-stub) @@ -91,9 +92,9 @@ if (APPLE) set(PXSCENE_LINKER_OPTIONS "${PXSCENE_LINKER_OPTIONS} -fsanitize=address") endif (ENABLE_ADDRESS_SANITIZER) set(PXSCENE_LINK_LIBRARIES) - set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${NODE_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS} ${COMM_DEPS_LIBRARY_DIRS}) - set(PLATFORM_LIBRARIES pxCore rtCore_s pthread ${NODE_LIBRARIES} ${DUKE_LIBRARIES} ${COMM_DEPS_LIBRARIES}) - include_directories(AFTER ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS} ${COMM_DEPS_INCLUDE_DIRS}) + set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${NODE_LIBRARY_DIRS} ${V8_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS} ${COMM_DEPS_LIBRARY_DIRS}) + set(PLATFORM_LIBRARIES pxCore rtCore_s pthread ${NODE_LIBRARIES} ${V8_LIBRARIES} ${DUKE_LIBRARIES} ${COMM_DEPS_LIBRARIES}) + include_directories(AFTER ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS} ${COMM_DEPS_INCLUDE_DIRS}) if (DEFINED ENV{CODE_COVERAGE}) message("enabling code coverage support") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") @@ -116,17 +117,20 @@ elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") include_directories(AFTER ${NODE_INCLUDE_DIRS} + ${V8_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS} ${COMM_DEPS_INCLUDE_DIRS} ) set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${NODE_LIBRARY_DIRS} + ${V8_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS} ${COMM_DEPS_LIBRARY_DIRS} ) set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${NODE_LIBRARIES} + ${V8_LIBRARIES} ${DUKE_LIBRARIES} ${COMM_DEPS_LIBRARIES} pthread rt dl m) @@ -272,13 +276,14 @@ elseif (WIN32) -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 -DUCONFIG_NO_CONVERSION=1 -DHTTP_PARSER_STRICT=0 -DUSE_RENDER_STATS -D_HAS_EXCEPTIONS=0) add_definitions(${COMM_DEPS_DEFINITIONS}) - include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS} ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) + include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS} ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) include_directories(AFTER "${EXTDIR}/pthread-2.9" ${WINSPARKLEINC} ${EXTDIR}/breakpad-chrome_55/src/) - set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${COMM_DEPS_LIBRARY_DIRS} ${NODE_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS}) + set(PXSCENE_LINK_DIRECTORIES ${PXSCENE_LINK_DIRECTORIES} ${COMM_DEPS_LIBRARY_DIRS} ${NODE_LIBRARY_DIRS} + ${V8_LIBRARY_DIRS} ${DUKE_LIBRARY_DIRS}) set(PLATFORM_LIBRARIES pxCore.lib) - set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${COMM_DEPS_LIBRARIES} ${NODE_LIBRARIES} ${DUKE_LIBRARIES}) + set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} ${COMM_DEPS_LIBRARIES} ${NODE_LIBRARIES} ${V8_LIBRARIES} ${DUKE_LIBRARIES}) set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} pthreadVC2.lib opengl32.lib Winmm.lib Ws2_32.lib Wldap32.lib msvcrt.lib psapi.lib @@ -319,7 +324,7 @@ set(PXSCENE_DEFINITIONS ${PXSCENE_DEFINITIONS} -D${PX_PLATFORM} -DENABLE_RT_NODE #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") #set(PXSCENE_LINKER_OPTIONS "${PXSCENE_LINKER_OPTIONS} -lgcov") -include_directories(AFTER ${NODE_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) +include_directories(AFTER ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} ${DUKE_INCLUDE_DIRS}) include_directories(AFTER ${WESTEROSINC} ${WESTEROSSTUBINC} ${TURBO_JPEG_INCLUDE_DIRS} ${BREAKPADINC} ${RTREMOTEINC} ${PXCOREDIR}/src) include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}/rasterizer) diff --git a/examples/pxScene2d/src/pxScene.cpp b/examples/pxScene2d/src/pxScene.cpp index b9eee3831a..4d8d66bf36 100644 --- a/examples/pxScene2d/src/pxScene.cpp +++ b/examples/pxScene2d/src/pxScene.cpp @@ -171,12 +171,17 @@ class sceneWindow : public pxWindow, public pxIViewContainer char buffer[MAX_URL_SIZE + 50]; memset (buffer, 0, sizeof(buffer)); +#ifdef PXSCENE_V8_TEST + snprintf(buffer, sizeof(buffer), "%s", escapedUrl.c_str()); +#else if (std::string::npos != escapedUrl.find("http")) { snprintf(buffer,sizeof(buffer),"shell.js?url=%s",rtUrlEncodeParameters(escapedUrl.c_str()).cString()); } else { snprintf(buffer,sizeof(buffer),"shell.js?url=%s",escapedUrl.c_str()); } +#endif + #ifdef RUNINMAIN setView( new pxScriptView(buffer,"javascript/node/v8")); #else diff --git a/examples/pxScene2d/src/pxScene2d.cpp b/examples/pxScene2d/src/pxScene2d.cpp index f8f21f906c..cf0ac1070d 100644 --- a/examples/pxScene2d/src/pxScene2d.cpp +++ b/examples/pxScene2d/src/pxScene2d.cpp @@ -3804,10 +3804,16 @@ void pxScriptView::runScript() if (mCtx) { +#ifdef PXSCENE_V8_TEST + mPrintFunc = new rtFunctionCallback(printFunc, this); +#endif mGetScene = new rtFunctionCallback(getScene, this); mMakeReady = new rtFunctionCallback(makeReady, this); mGetContextID = new rtFunctionCallback(getContextID, this); +#ifdef PXSCENE_V8_TEST + mCtx->add("print", mPrintFunc.getPtr()); +#endif mCtx->add("getScene", mGetScene.getPtr()); mCtx->add("makeReady", mMakeReady.getPtr()); mCtx->add("getContextID", mGetContextID.getPtr()); @@ -3815,6 +3821,10 @@ void pxScriptView::runScript() #ifdef RUNINMAIN mReady = new rtPromise(); #endif + +#ifdef PXSCENE_V8_TEST + mCtx->runFile(mUrl); +#else mCtx->runFile("init.js"); char buffer[MAX_URL_SIZE + 50]; @@ -3842,10 +3852,31 @@ void pxScriptView::runScript() #endif mCtx->runScript(buffer); rtLogInfo("pxScriptView::runScript() ending\n"); +#endif } #endif //ENABLE_RT_NODE } +#ifdef PXSCENE_V8_TEST +rtError pxScriptView::printFunc(int numArgs, const rtValue* args, rtValue* result, void* ctx) +{ + rtLogInfo(__FUNCTION__); + + if (ctx) + { + pxScriptView* v = (pxScriptView*)ctx; + + if (numArgs > 0 && !args[0].isEmpty()) + { + rtString toPrint = args[0].toString(); + rtLogWarn("%s", toPrint.cString()); + } + } + + return RT_OK; +} +#endif + rtError pxScriptView::getScene(int numArgs, const rtValue* args, rtValue* result, void* ctx) { rtLogInfo(__FUNCTION__); diff --git a/examples/pxScene2d/src/pxScene2d.h b/examples/pxScene2d/src/pxScene2d.h index a4df2e7b2e..65fbf9a223 100644 --- a/examples/pxScene2d/src/pxScene2d.h +++ b/examples/pxScene2d/src/pxScene2d.h @@ -44,6 +44,8 @@ #include "rtPromise.h" #include "rtThreadQueue.h" +#define PXSCENE_V8_TEST // TODO: remove + #define ANIMATION_ROTATE_XYZ #include "pxResource.h" @@ -1154,6 +1156,10 @@ class pxScriptView: public pxIView protected: +#ifdef PXSCENE_V8_TEST + static rtError printFunc(int /*numArgs*/, const rtValue* /*args*/, rtValue* result, void* ctx); +#endif + static rtError getScene(int /*numArgs*/, const rtValue* /*args*/, rtValue* result, void* ctx); static rtError makeReady(int /*numArgs*/, const rtValue* /*args*/, rtValue* result, void* ctx); @@ -1270,6 +1276,9 @@ class pxScriptView: public pxIView rtObjectRef mReady; rtObjectRef mScene; rtRef mView; +#ifdef PXSCENE_V8_TEST + rtRef mPrintFunc; +#endif rtRef mGetScene; rtRef mMakeReady; rtRef mGetContextID; diff --git a/examples/pxScene2d/src/test_binding.js b/examples/pxScene2d/src/test_binding.js new file mode 100644 index 0000000000..8d6eb93b5e --- /dev/null +++ b/examples/pxScene2d/src/test_binding.js @@ -0,0 +1,43 @@ +{ + var vArr = _testArrayReturnFunc(); + print('length=' + vArr.length); + for (i = 0; i < vArr.length; ++i ){ + print('idx[' + i + '] ' +vArr[i]); + } + + vArr[3] = 4; + + print('length=' + vArr.length); + for (i = 0; i < vArr.length; ++i ){ + print('idx[' + i + '] ' +vArr[i]); + } +} + +{ + var vMap = _testMapReturnFunc(); + print("a1: " + vMap["a1"]); + print("a2: " + vMap["a2"]); + print("a3: " + vMap.a3); + vMap["a4"] = 4; + print("a4: " + vMap.a4); +} + +{ + var vObj = _testObjectReturnFunc(); + print("propA: " + vObj.propA); + print("propB: " + vObj.propB); + vObj.propA = 3; + print("propA: " + vObj.propA); + vObj.propC = function () { print("propC()"); return 1; }; + print("propC: " + vObj.propC); + var func = vObj.propC; + func(); + vObj.propC(); + vObj.methodA(); + print('methodB: ' + vObj.methodB()); + print('methodC: ' + vObj.methodC("hi")); +} + +var vObj = _testObjectReturnFunc(); +vObj.methodD = function() {}; +print('methodD: ' + vObj.methodD); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 99ebdf04d6..86c26006d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,271 +1,273 @@ -cmake_minimum_required(VERSION 2.8) -project(pxcore) -find_package(PkgConfig) - -set(CMAKE_CXX_STANDARD 11) - -option(WINDOWLESS_EGL "WINDOWLESS_EGL" OFF) -option(PXCORE_WAYLAND_EGL "PXCORE_WAYLAND_EGL" OFF) -option(PXCORE_ESSOS "PXCORE_ESSOS" OFF) -option(PXCORE_MATRIX_HELPERS "PXCORE_MATRIX_HELPERS" ON) -option(PXCORE_ACCESS_CONTROL_CHECK "PXCORE_ACCESS_CONTROL_CHECK" ON) -option(PXCORE_PERMISSIONS_CHECK "PXCORE_PERMISSIONS_CHECK" ON) -option(BUILD_RTCORE_LIBS "BUILD_RTCORE_LIBS" ON) -option(BUILD_PXCORE_LIBS "BUILD_PXCORE_LIBS" ON) -option(OUTPUT_LIBS_LOCAL "OUTPUT_LIBS_LOCAL" OFF) -option(PXCORE_WAYLAND_DISPLAY_READ_EVENTS "PXCORE_WAYLAND_DISPLAY_READ_EVENTS" ON) -if(WIN32) - option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" OFF) -elseif (APPLE) - option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) -else() - option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) -endif(WIN32) - -set(EXTDIR "${CMAKE_CURRENT_SOURCE_DIR}/../examples/pxScene2d/external") -set(NODEDIR "${EXTDIR}/node/") -include(../cmake/CommOpts.cmake) -include(../cmake/CommDeps.cmake) -include(../cmake/NodeDeps.cmake) - -set(BUILD_RTCORE_SHARED_LIBRARY 1) - -if (APPLE) - message("Building pxcore for mac") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") - set(CMAKE_MACOSX_RPATH 1) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) - add_definitions(-DPX_PLATFORM_MAC -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) - add_definitions(-D_DARWIN_USE_64_BIT_INODE=1 -DNODE_ARCH="x64" -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS= -DNODE_SHARED_MODE - -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 - -DV8_INSPECTOR_USE_OLD_STL=1 -DHAVE_OPENSSL=1 -DHAVE_DTRACE=1 -D__POSIX__ -DNODE_PLATFORM=darwin - -DUCONFIG_NO_TRANSLITERATION=1 -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 - -DU_STATIC_IMPLEMENTATION=1 -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 - -DUCONFIG_NO_CONVERSION=1 -DHTTP_PARSER_STRICT=0 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 - -DRT_PLATFORM_LINUX -DENABLE_NODE_V_6_9) - set(PXCORE_FILES mac/pxBufferNative.mm mac/pxOffscreenNative.mm mac/pxWindowNative.mm - mac/pxEventLoopNative.mm mac/pxTimerNative.mm mac/pxTimerNative.mm - mac/pxClipboardNative.mm mac/window.mm - unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - set(PLATFORM_LINKER_FLAGS "-framework Cocoa -framework Foundation") - add_definitions(${COMM_DEPS_DEFINITIONS}) - include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) - if (DEFINED ENV{CODE_COVERAGE}) - message("enabling code coverage support") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - add_definitions(-DENABLE_CODE_COVERAGE=1) - endif () -elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") - execute_process(COMMAND "hostname" OUTPUT_VARIABLE HOSTNAME) - string(STRIP ${HOSTNAME} HOSTNAME) - - add_definitions(${COMM_DEPS_DEFINITIONS}) - - include_directories(AFTER - ${NODE_INCLUDE_DIRS} - ${COMM_DEPS_INCLUDE_DIRS} - ) - - if (HOSTNAME STREQUAL "raspberrypi") - message("Building pxcore for raspberry pi") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DPX_PLATFORM_GENERIC_EGL -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) - set(PXCORE_FILES gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp gles/pxWindowNative.cpp - gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp - gles/pxClipboardNative.cpp gles/pxEGLProviderRPi.cpp gles/LinuxInputEventDispatcher.cpp pxViewWindow.cpp - unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - set(PLATFORM_LINKER_FLAGS) - include_directories(AFTER /opt/vc/include /opt/vc/include/interface/vcos/pthreads - /opt/vc/include/interface/vmcs_host/linux /opt/vc/include) - include_directories(AFTER ${ZLIBINC} ${CURLINC} ${JPGINC} ${JPGTURBOINC} ${PNGINC}) - elseif (WINDOWLESS_EGL OR PXCORE_WAYLAND_EGL OR PXCORE_ESSOS) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING) - set(PXCORE_FILES unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - - if (PXCORE_ESSOS) - message("Building pxcore for essos windows") - add_definitions(-DPX_PLATFORM_ESSOS -DPX_PLATFORM_WAYLAND_EGL) - set(PXCORE_FILES ${PXCORE_FILES} essos/pxWindowNative.cpp essos/pxBufferNative.cpp essos/pxOffscreenNative.cpp - essos/pxEventLoopNative.cpp essos/pxTimerNative.cpp essos/pxClipboardNative.cpp) - elseif (PXCORE_WAYLAND_EGL) - message("Building pxcore for wayland windows") - add_definitions(-DPX_PLATFORM_WAYLAND_EGL) - if (PXCORE_WAYLAND_DISPLAY_READ_EVENTS) - message("Enabling wayland display read events") - add_definitions(-DPXCORE_WL_DISPLAY_READ_EVENTS) - endif(PXCORE_WAYLAND_DISPLAY_READ_EVENTS) - set(PXCORE_FILES ${PXCORE_FILES} wayland_egl/pxWindowNative.cpp wayland_egl/pxBufferNative.cpp wayland_egl/pxOffscreenNative.cpp - wayland_egl/pxEventLoopNative.cpp wayland_egl/pxTimerNative.cpp wayland_egl/pxClipboardNative.cpp) - elseif (WINDOWLESS_EGL) - message("Building pxcore for windowless egl") - add_definitions(-DPX_PLATFORM_GENERIC_EGL) - set(PXCORE_FILES ${PXCORE_FILES} gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp - gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp gles/pxClipboardNative.cpp) - endif (PXCORE_ESSOS) - set(PLATFORM_LINKER_FLAGS) - elseif (PXCORE_DFB) - message("Building pxcore for dfb ") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - set(PXCORE_INCLUDES $ENV{PXCORE_INCLUDES}) - separate_arguments(PXCORE_INCLUDES) - include_directories(BEFORE ${PXCORE_INCLUDES}) - add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING -DENABLE_DFB -DENABLE_DFB_GENERIC -DBSTD_CPU_ENDIAN=BSTD_ENDIAN_LITTLE -DPX_PLATFORM_GENERIC_DFB) - set(PXCORE_FILES x11/pxBufferNativeDfb.cpp x11/pxOffscreenNativeDfb.cpp x11/pxEventLoopNative.cpp x11/pxTimerNative.cpp x11/pxClipboardNative.cpp unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp rtFileCache.cpp rtHttpCache.cpp) - else () - message("Building pxcore for glut") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DPX_PLATFORM_GLUT -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) - set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} glut) - set(PXCORE_FILES glut/pxBufferNative.cpp glut/pxOffscreenNative.cpp glut/pxWindowNative.cpp - glut/pxEventLoopNative.cpp glut/pxTimerNative.cpp glut/pxClipboardNative.cpp pxViewWindow.cpp - unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp - rtFileCache.cpp rtHttpCache.cpp) - set(PLATFORM_LINKER_FLAGS) - if (DEFINED ENV{CODE_COVERAGE}) - message("enabling code coverage support") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") - add_definitions(-DENABLE_CODE_COVERAGE=1) - endif () - endif (HOSTNAME STREQUAL "raspberrypi") -elseif(WIN32) - message("Building pxcore for Windows") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /Zi /DEBUG") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) - add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=win32 -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) - add_definitions(-DENABLE_RT_NODE -DRUNINMAIN) - add_definitions(-DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS -DWIN32 -DWIN32_LEAN_AND_MEAN -DGLEW_STATIC -D_TIMESPEC_DEFINED -D_CONSOLE - -DCURL_STATICLIB -DRUNINMAIN -DENABLE_RT_NODE -DDISABLE_WAYLAND -DNODE_WANT_INTERNALS=1 - -DENABLE_NODE_V_6_9 -DENABLE_V8_HEAP_PARAMS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DHAVE_INSPECTOR=1 - -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1 -DENABLE_MAX_TEXTURE_SIZE - -DHAVE_OPENSSL -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_HAS_EXCEPTIONS=0 -DBUILDING_V8_SHARED=1 - -DBUILDING_UV_SHARED=1 -DNODE_ARCH="ia32" -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 - -DHAVE_OPENSSL=1 -DHAVE_ETW=1 -DHAVE_PERFCTR=1 -DFD_SETSIZE=1024 -DNODE_PLATFORM="win32" -D_UNICODE=1 -DUCONFIG_NO_TRANSLITERATION=1 - -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 -DU_STATIC_IMPLEMENTATION=1 - -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 -DUCONFIG_NO_CONVERSION=1 - -DHTTP_PARSER_STRICT=0 -DUSE_RENDER_STATS -D_HAS_EXCEPTIONS=0) - add_definitions(-DWIN32 -D_LIB -DNDEBUG -DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS) - add_definitions(${COMM_DEPS_DEFINITIONS}) - include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) - include_directories(AFTER "${EXTDIR}/pthread-2.9") - set(PXCORE_FILES win/pxBufferNative.cpp win/pxOffscreenNative.cpp win/pxWindowNative.cpp - win/pxEventLoopNative.cpp win/pxTimerNative.cpp win/pxClipboardNative.cpp pxViewWindow.cpp - win/rtMutexNative.cpp win/rtThreadPoolNative.cpp) - set_source_files_properties(utf8.c PROPERTIES LANGUAGE CXX) - set(BUILD_RTCORE_SHARED_LIBRARY 0) -else () - message(FATAL_ERROR "Cannot build pxcore. Unknown platform") -endif (APPLE) - -if (NOT PXCORE_DFB) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -std=c++11") -endif (NOT PXCORE_DFB) - -if (PXCORE_COMPILE_WARNINGS_AS_ERRORS) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") -endif (PXCORE_COMPILE_WARNINGS_AS_ERRORS) - -include_directories(AFTER ${NODE_INCLUDE_DIRS}) -include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}) - -set(PXCORE_FILES ${PXCORE_FILES} pxOffscreen.cpp pxWindowUtil.cpp - - rtFile.cpp rtLibrary.cpp rtPathUtils.cpp rtTest.cpp rtThreadPool.cpp - rtThreadQueue.cpp rtThreadTask.cpp rtUrlUtils.cpp - rtZip.cpp pxInterpolators.cpp pxUtil.cpp - rtFileDownloader.cpp unzip.c ioapi.c - rtScript.cpp rtSettings.cpp) - -if (SUPPORT_DUKTAPE) - message("Adding Duktape scripting support") - add_definitions(-DRTSCRIPT_SUPPORT_DUKTAPE) - set(PXCORE_FILES ${PXCORE_FILES} rtScriptDuk/rtScriptDuk.cpp rtScriptDuk/rtFunctionWrapperDuk.cpp rtScriptDuk/rtObjectWrapperDuk.cpp - rtScriptDuk/rtWrapperUtilsDuk.cpp rtScriptDuk/rtJsModules.cpp) -endif() - -if (SUPPORT_NODE) - message("Adding Node scripting support") - add_definitions(-DRTSCRIPT_SUPPORT_NODE) - set(PXCORE_FILES ${PXCORE_FILES} rtScriptNode/rtScriptNode.cpp rtScriptNode/jsCallback.cpp rtScriptNode/rtFunctionWrapper.cpp - rtScriptNode/rtObjectWrapper.cpp rtScriptNode/rtWrapperUtils.cpp) -endif() - +cmake_minimum_required(VERSION 2.8) +project(pxcore) +find_package(PkgConfig) + +set(CMAKE_CXX_STANDARD 11) + +option(WINDOWLESS_EGL "WINDOWLESS_EGL" OFF) +option(PXCORE_WAYLAND_EGL "PXCORE_WAYLAND_EGL" OFF) +option(PXCORE_ESSOS "PXCORE_ESSOS" OFF) +option(PXCORE_MATRIX_HELPERS "PXCORE_MATRIX_HELPERS" ON) +option(PXCORE_ACCESS_CONTROL_CHECK "PXCORE_ACCESS_CONTROL_CHECK" ON) +option(PXCORE_PERMISSIONS_CHECK "PXCORE_PERMISSIONS_CHECK" ON) +option(BUILD_RTCORE_LIBS "BUILD_RTCORE_LIBS" ON) +option(BUILD_PXCORE_LIBS "BUILD_PXCORE_LIBS" ON) +option(OUTPUT_LIBS_LOCAL "OUTPUT_LIBS_LOCAL" OFF) +option(PXCORE_WAYLAND_DISPLAY_READ_EVENTS "PXCORE_WAYLAND_DISPLAY_READ_EVENTS" ON) +if(WIN32) + option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" OFF) +elseif (APPLE) + option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) +else() + option(PXCORE_COMPILE_WARNINGS_AS_ERRORS "PXCORE_COMPILE_WARNINGS_AS_ERRORS" ON) +endif(WIN32) + +set(EXTDIR "${CMAKE_CURRENT_SOURCE_DIR}/../examples/pxScene2d/external") +set(NODEDIR "${EXTDIR}/node/") +include(../cmake/CommOpts.cmake) +include(../cmake/CommDeps.cmake) +include(../cmake/NodeDeps.cmake) +include(../cmake/V8Deps.cmake) + +set(BUILD_RTCORE_SHARED_LIBRARY 1) + +if (APPLE) + message("Building pxcore for mac") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") + set(CMAKE_MACOSX_RPATH 1) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/mac) + add_definitions(-DPX_PLATFORM_MAC -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) + add_definitions(-D_DARWIN_USE_64_BIT_INODE=1 -DNODE_ARCH="x64" -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS= -DNODE_SHARED_MODE + -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 + -DV8_INSPECTOR_USE_OLD_STL=1 -DHAVE_OPENSSL=1 -DHAVE_DTRACE=1 -D__POSIX__ -DNODE_PLATFORM=darwin + -DUCONFIG_NO_TRANSLITERATION=1 -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 + -DU_STATIC_IMPLEMENTATION=1 -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 + -DUCONFIG_NO_CONVERSION=1 -DHTTP_PARSER_STRICT=0 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 + -DRT_PLATFORM_LINUX -DENABLE_NODE_V_6_9) + set(PXCORE_FILES mac/pxBufferNative.mm mac/pxOffscreenNative.mm mac/pxWindowNative.mm + mac/pxEventLoopNative.mm mac/pxTimerNative.mm mac/pxTimerNative.mm + mac/pxClipboardNative.mm mac/window.mm + unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + set(PLATFORM_LINKER_FLAGS "-framework Cocoa -framework Foundation") + add_definitions(${COMM_DEPS_DEFINITIONS}) + include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) + if (DEFINED ENV{CODE_COVERAGE}) + message("enabling code coverage support") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + add_definitions(-DENABLE_CODE_COVERAGE=1) + endif () +elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -fPIC -g") + execute_process(COMMAND "hostname" OUTPUT_VARIABLE HOSTNAME) + string(STRIP ${HOSTNAME} HOSTNAME) + + add_definitions(${COMM_DEPS_DEFINITIONS}) + + include_directories(AFTER + ${NODE_INCLUDE_DIRS} ${V8_INCLUDE_DIRS} + ${COMM_DEPS_INCLUDE_DIRS} + ) + + if (HOSTNAME STREQUAL "raspberrypi") + message("Building pxcore for raspberry pi") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DPX_PLATFORM_GENERIC_EGL -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) + set(PXCORE_FILES gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp gles/pxWindowNative.cpp + gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp + gles/pxClipboardNative.cpp gles/pxEGLProviderRPi.cpp gles/LinuxInputEventDispatcher.cpp pxViewWindow.cpp + unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + set(PLATFORM_LINKER_FLAGS) + include_directories(AFTER /opt/vc/include /opt/vc/include/interface/vcos/pthreads + /opt/vc/include/interface/vmcs_host/linux /opt/vc/include) + include_directories(AFTER ${ZLIBINC} ${CURLINC} ${JPGINC} ${JPGTURBOINC} ${PNGINC}) + elseif (WINDOWLESS_EGL OR PXCORE_WAYLAND_EGL OR PXCORE_ESSOS) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/egl) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING) + set(PXCORE_FILES unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + + if (PXCORE_ESSOS) + message("Building pxcore for essos windows") + add_definitions(-DPX_PLATFORM_ESSOS -DPX_PLATFORM_WAYLAND_EGL) + set(PXCORE_FILES ${PXCORE_FILES} essos/pxWindowNative.cpp essos/pxBufferNative.cpp essos/pxOffscreenNative.cpp + essos/pxEventLoopNative.cpp essos/pxTimerNative.cpp essos/pxClipboardNative.cpp) + elseif (PXCORE_WAYLAND_EGL) + message("Building pxcore for wayland windows") + add_definitions(-DPX_PLATFORM_WAYLAND_EGL) + if (PXCORE_WAYLAND_DISPLAY_READ_EVENTS) + message("Enabling wayland display read events") + add_definitions(-DPXCORE_WL_DISPLAY_READ_EVENTS) + endif(PXCORE_WAYLAND_DISPLAY_READ_EVENTS) + set(PXCORE_FILES ${PXCORE_FILES} wayland_egl/pxWindowNative.cpp wayland_egl/pxBufferNative.cpp wayland_egl/pxOffscreenNative.cpp + wayland_egl/pxEventLoopNative.cpp wayland_egl/pxTimerNative.cpp wayland_egl/pxClipboardNative.cpp) + elseif (WINDOWLESS_EGL) + message("Building pxcore for windowless egl") + add_definitions(-DPX_PLATFORM_GENERIC_EGL) + set(PXCORE_FILES ${PXCORE_FILES} gles/pxBufferNative.cpp gles/pxOffscreenNative.cpp + gles/pxEventLoopNative.cpp gles/pxTimerNative.cpp gles/pxClipboardNative.cpp) + endif (PXCORE_ESSOS) + set(PLATFORM_LINKER_FLAGS) + elseif (PXCORE_DFB) + message("Building pxcore for dfb ") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/dfb) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + set(PXCORE_INCLUDES $ENV{PXCORE_INCLUDES}) + separate_arguments(PXCORE_INCLUDES) + include_directories(BEFORE ${PXCORE_INCLUDES}) + add_definitions(-DRT_PLATFORM_LINUX -DPX_NO_WINDOW -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN -DRAPIDJSON_HAS_STDSTRING -DENABLE_DFB -DENABLE_DFB_GENERIC -DBSTD_CPU_ENDIAN=BSTD_ENDIAN_LITTLE -DPX_PLATFORM_GENERIC_DFB) + set(PXCORE_FILES x11/pxBufferNativeDfb.cpp x11/pxOffscreenNativeDfb.cpp x11/pxEventLoopNative.cpp x11/pxTimerNative.cpp x11/pxClipboardNative.cpp unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp rtFileCache.cpp rtHttpCache.cpp) + else () + message("Building pxcore for glut") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/glut) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=linux -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DPX_PLATFORM_GLUT -DRT_PLATFORM_LINUX -DENABLE_RT_NODE -DENABLE_HTTP_CACHE -DRUNINMAIN) + set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} glut) + set(PXCORE_FILES glut/pxBufferNative.cpp glut/pxOffscreenNative.cpp glut/pxWindowNative.cpp + glut/pxEventLoopNative.cpp glut/pxTimerNative.cpp glut/pxClipboardNative.cpp pxViewWindow.cpp + unix/rtMutexNative.cpp unix/rtThreadPoolNative.cpp + rtFileCache.cpp rtHttpCache.cpp) + set(PLATFORM_LINKER_FLAGS) + if (DEFINED ENV{CODE_COVERAGE}) + message("enabling code coverage support") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + add_definitions(-DENABLE_CODE_COVERAGE=1) + endif () + endif (HOSTNAME STREQUAL "raspberrypi") +elseif(WIN32) + message("Building pxcore for Windows") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /Zi /DEBUG") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/win) + add_definitions(-DENABLE_NODE_V_6_9 -DNODE_PLATFORM=win32 -DNODE_WANT_INTERNALS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 -DHAVE_INSPECTOR=1 -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1) + add_definitions(-DENABLE_RT_NODE -DRUNINMAIN) + add_definitions(-DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS -DWIN32 -DWIN32_LEAN_AND_MEAN -DGLEW_STATIC -D_TIMESPEC_DEFINED -D_CONSOLE + -DCURL_STATICLIB -DRUNINMAIN -DENABLE_RT_NODE -DDISABLE_WAYLAND -DNODE_WANT_INTERNALS=1 + -DENABLE_NODE_V_6_9 -DENABLE_V8_HEAP_PARAMS=1 -DV8_DEPRECATION_WARNINGS=1 -DNODE_SHARED_MODE -DHAVE_INSPECTOR=1 + -DV8_INSPECTOR_USE_STL=1 -DV8_INSPECTOR_USE_OLD_STL=1 -DENABLE_MAX_TEXTURE_SIZE + -DHAVE_OPENSSL -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_HAS_EXCEPTIONS=0 -DBUILDING_V8_SHARED=1 + -DBUILDING_UV_SHARED=1 -DNODE_ARCH="ia32" -DNODE_USE_V8_PLATFORM=1 -DNODE_HAVE_I18N_SUPPORT=1 -DNODE_HAVE_SMALL_ICU=1 + -DHAVE_OPENSSL=1 -DHAVE_ETW=1 -DHAVE_PERFCTR=1 -DFD_SETSIZE=1024 -DNODE_PLATFORM="win32" -D_UNICODE=1 -DUCONFIG_NO_TRANSLITERATION=1 + -DUCONFIG_NO_SERVICE=1 -DUCONFIG_NO_REGULAR_EXPRESSIONS=1 -DU_ENABLE_DYLOAD=0 -DU_STATIC_IMPLEMENTATION=1 + -DU_HAVE_STD_STRING=0 -DUCONFIG_NO_BREAK_ITERATION=0 -DUCONFIG_NO_LEGACY_CONVERSION=1 -DUCONFIG_NO_CONVERSION=1 + -DHTTP_PARSER_STRICT=0 -DUSE_RENDER_STATS -D_HAS_EXCEPTIONS=0) + add_definitions(-DWIN32 -D_LIB -DNDEBUG -DPX_PLATFORM_WIN -DRT_PLATFORM_WINDOWS) + add_definitions(${COMM_DEPS_DEFINITIONS}) + include_directories(AFTER ${COMM_DEPS_INCLUDE_DIRS}) + include_directories(AFTER "${EXTDIR}/pthread-2.9") + set(PXCORE_FILES win/pxBufferNative.cpp win/pxOffscreenNative.cpp win/pxWindowNative.cpp + win/pxEventLoopNative.cpp win/pxTimerNative.cpp win/pxClipboardNative.cpp pxViewWindow.cpp + win/rtMutexNative.cpp win/rtThreadPoolNative.cpp) + set_source_files_properties(utf8.c PROPERTIES LANGUAGE CXX) + set(BUILD_RTCORE_SHARED_LIBRARY 0) +else () + message(FATAL_ERROR "Cannot build pxcore. Unknown platform") +endif (APPLE) + +if (NOT PXCORE_DFB) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -std=c++11") +endif (NOT PXCORE_DFB) + +if (PXCORE_COMPILE_WARNINGS_AS_ERRORS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") +endif (PXCORE_COMPILE_WARNINGS_AS_ERRORS) + +include_directories(AFTER ${V8_INCLUDE_DIRS}) +include_directories(AFTER ${NODE_INCLUDE_DIRS}) +include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}) + +set(PXCORE_FILES ${PXCORE_FILES} pxOffscreen.cpp pxWindowUtil.cpp + + rtFile.cpp rtLibrary.cpp rtPathUtils.cpp rtTest.cpp rtThreadPool.cpp + rtThreadQueue.cpp rtThreadTask.cpp rtUrlUtils.cpp + rtZip.cpp pxInterpolators.cpp pxUtil.cpp + rtFileDownloader.cpp unzip.c ioapi.c + rtScript.cpp rtSettings.cpp) + +if (SUPPORT_DUKTAPE) + message("Adding Duktape scripting support") + add_definitions(-DRTSCRIPT_SUPPORT_DUKTAPE) + set(PXCORE_FILES ${PXCORE_FILES} rtScriptDuk/rtScriptDuk.cpp rtScriptDuk/rtFunctionWrapperDuk.cpp rtScriptDuk/rtObjectWrapperDuk.cpp + rtScriptDuk/rtWrapperUtilsDuk.cpp rtScriptDuk/rtJsModules.cpp) +endif() + +if (SUPPORT_NODE) + message("Adding Node scripting support") + add_definitions(-DRTSCRIPT_SUPPORT_NODE) + set(PXCORE_FILES ${PXCORE_FILES} rtScriptNode/rtScriptNode.cpp rtScriptNode/jsCallback.cpp rtScriptNode/rtFunctionWrapper.cpp + rtScriptNode/rtObjectWrapper.cpp rtScriptNode/rtWrapperUtils.cpp) +endif() + if (SUPPORT_V8) message("Adding V8 scripting support") add_definitions(-DRTSCRIPT_SUPPORT_V8) set(PXCORE_FILES ${PXCORE_FILES} rtScriptV8/rtScriptV8.cpp rtScriptV8/jsCallback.cpp rtScriptV8/rtFunctionWrapper.cpp rtScriptV8/rtObjectWrapper.cpp rtScriptV8/rtWrapperUtils.cpp) -endif() - -if (PXCORE_MATRIX_HELPERS) - set(PXCORE_FILES ${PXCORE_FILES} pxMatrix4T.cpp) -endif(PXCORE_MATRIX_HELPERS) - -if (PXCORE_ACCESS_CONTROL_CHECK) - add_definitions(-DENABLE_ACCESS_CONTROL_CHECK) - set(PXCORE_FILES ${PXCORE_FILES} rtCORSUtils.cpp) -endif (PXCORE_ACCESS_CONTROL_CHECK) - -if (PXCORE_PERMISSIONS_CHECK) - add_definitions(-DENABLE_PERMISSIONS_CHECK) - set(PXCORE_FILES ${PXCORE_FILES} rtPermissions.cpp) -endif (PXCORE_PERMISSIONS_CHECK) - -set(RTCORE_FILES utf8.c rtString.cpp rtLog.cpp rtValue.cpp rtError.cpp ioapi_mem.c) - -set(RTCORE_FILES ${RTCORE_FILES} rtPromise.cpp) - -set(RTCORE_FILES ${RTCORE_FILES} rtObject.cpp) - -include_directories(AFTER ${EXTDIR}/nanosvg/src) - -if (OUTPUT_LIBS_LOCAL) - message("Output pxCore and rtCore libs locally") - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -endif (OUTPUT_LIBS_LOCAL) - -#if (USE_DUKTAPE) - include_directories(AFTER ${EXTDIR}/dukluv/lib/duktape/src) - include_directories(AFTER ${EXTDIR}/dukluv/lib/uv/include) - include_directories(AFTER ${EXTDIR}/dukluv/src) -#endif(USE_DUKTAPE) - -if (BUILD_PXCORE_LIBS) - message("Building pxcore libs") - add_library(pxCore ${PXCORE_FILES}) -endif (BUILD_PXCORE_LIBS) -if (BUILD_RTCORE_LIBS) - message("Building rtcore libs") - add_library(rtCore_s ${RTCORE_FILES}) - if (BUILD_RTCORE_SHARED_LIBRARY GREATER 0) - add_library(rtCore SHARED ${RTCORE_FILES}) - endif(BUILD_RTCORE_SHARED_LIBRARY GREATER 0) -endif (BUILD_RTCORE_LIBS) +endif() + +if (PXCORE_MATRIX_HELPERS) + set(PXCORE_FILES ${PXCORE_FILES} pxMatrix4T.cpp) +endif(PXCORE_MATRIX_HELPERS) + +if (PXCORE_ACCESS_CONTROL_CHECK) + add_definitions(-DENABLE_ACCESS_CONTROL_CHECK) + set(PXCORE_FILES ${PXCORE_FILES} rtCORSUtils.cpp) +endif (PXCORE_ACCESS_CONTROL_CHECK) + +if (PXCORE_PERMISSIONS_CHECK) + add_definitions(-DENABLE_PERMISSIONS_CHECK) + set(PXCORE_FILES ${PXCORE_FILES} rtPermissions.cpp) +endif (PXCORE_PERMISSIONS_CHECK) + +set(RTCORE_FILES utf8.c rtString.cpp rtLog.cpp rtValue.cpp rtError.cpp ioapi_mem.c) + +set(RTCORE_FILES ${RTCORE_FILES} rtPromise.cpp) + +set(RTCORE_FILES ${RTCORE_FILES} rtObject.cpp) + +include_directories(AFTER ${EXTDIR}/nanosvg/src) + +if (OUTPUT_LIBS_LOCAL) + message("Output pxCore and rtCore libs locally") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +endif (OUTPUT_LIBS_LOCAL) + +#if (USE_DUKTAPE) + include_directories(AFTER ${EXTDIR}/dukluv/lib/duktape/src) + include_directories(AFTER ${EXTDIR}/dukluv/lib/uv/include) + include_directories(AFTER ${EXTDIR}/dukluv/src) +#endif(USE_DUKTAPE) + +if (BUILD_PXCORE_LIBS) + message("Building pxcore libs") + add_library(pxCore ${PXCORE_FILES}) +endif (BUILD_PXCORE_LIBS) +if (BUILD_RTCORE_LIBS) + message("Building rtcore libs") + add_library(rtCore_s ${RTCORE_FILES}) + if (BUILD_RTCORE_SHARED_LIBRARY GREATER 0) + add_library(rtCore SHARED ${RTCORE_FILES}) + endif(BUILD_RTCORE_SHARED_LIBRARY GREATER 0) +endif (BUILD_RTCORE_LIBS) diff --git a/src/rtScriptV8/jsCallback.cpp b/src/rtScriptV8/jsCallback.cpp index 20b4621d40..8def4cd0a8 100755 --- a/src/rtScriptV8/jsCallback.cpp +++ b/src/rtScriptV8/jsCallback.cpp @@ -75,7 +75,7 @@ Handle* jsCallback::makeArgs(Local& ctx) for (size_t i = 0; i < mArgs.size(); ++i) { - args[i] = rt2js(ctx, mArgs[i]); + args[i] = rt2v8(ctx, mArgs[i]); } return args; @@ -147,7 +147,7 @@ rtValue jsCallback::run() else { rtWrapperError error; - returnValue = js2rt(context, val, &error); + returnValue = v82rt(context, val, &error); } return returnValue; diff --git a/src/rtScriptV8/rtFunctionWrapper.cpp b/src/rtScriptV8/rtFunctionWrapper.cpp index 55857a3bc5..6e91f6b5e5 100755 --- a/src/rtScriptV8/rtFunctionWrapper.cpp +++ b/src/rtScriptV8/rtFunctionWrapper.cpp @@ -92,7 +92,7 @@ void rtResolverFunction::afterWorkCallback(uv_work_t* req, int /* status */) Handle value; if (ctx->args.size() > 0) { - value = rt2js(creationContext, ctx->args[0]); + value = rt2v8(creationContext, ctx->args[0]); } Local resolver = PersistentToLocal(resolverFunc->mIsolate, resolverFunc->mResolver); @@ -216,7 +216,7 @@ void rtFunctionWrapper::call(const FunctionCallbackInfo& args) std::vector argList; for (int i = 0; i < args.Length(); ++i) { - argList.push_back(js2rt(ctx, args[i], &error)); + argList.push_back(v82rt(ctx, args[i], &error)); if (error.hasError()) isolate->ThrowException(error.toTypeError(isolate)); } @@ -251,7 +251,7 @@ void rtFunctionWrapper::call(const FunctionCallbackInfo& args) } else { - args.GetReturnValue().Set(rt2js(ctx, result)); + args.GetReturnValue().Set(rt2v8(ctx, result)); } } diff --git a/src/rtScriptV8/rtObjectWrapper.cpp b/src/rtScriptV8/rtObjectWrapper.cpp index f14050b8f5..200fa9921e 100755 --- a/src/rtScriptV8/rtObjectWrapper.cpp +++ b/src/rtScriptV8/rtObjectWrapper.cpp @@ -121,7 +121,7 @@ Handle rtObjectWrapper::createFromObjectReference(v8::Local rtValue item; rtError err = ref->Get(i, &item); if (err == RT_OK) - arr->Set(Number::New(isolate, i), rt2js(ctx, item)); + arr->Set(Number::New(isolate, i), rt2v8(ctx, item)); } return scope.Escape(arr); } @@ -208,8 +208,8 @@ void rtObjectWrapper::getProperty(const T& prop, const PropertyCallbackInfo v; EscapableHandleScope scope(info.GetIsolate()); - v = rt2js(ctx, value); -// info.GetReturnValue().Set(rt2js(info.GetIsolate(), value)); + v = rt2v8(ctx, value); +// info.GetReturnValue().Set(rt2v8(info.GetIsolate(), value)); scope.Escape(v); info.GetReturnValue().Set(v); } @@ -224,7 +224,7 @@ void rtObjectWrapper::setProperty(const T& prop, Local val, const Propert Local creationContext = info.This()->CreationContext(); rtWrapperError error; - rtValue value = js2rt(creationContext, val, &error); + rtValue value = v82rt(creationContext, val, &error); if (error.hasError()) info.GetIsolate()->ThrowException(error.toTypeError(info.GetIsolate())); @@ -334,7 +334,7 @@ rtError jsObjectWrapper::getAllKeys(Isolate* isolate, rtValue* value) const for (int i = 0, n = names->Length(); i < n; ++i) { rtWrapperError error; - rtValue val = js2rt(ctx, names->Get(i), &error); + rtValue val = v82rt(ctx, names->Get(i), &error); if (error.hasError()) return RT_FAIL; else @@ -385,7 +385,7 @@ rtError jsObjectWrapper::Get(const char* name, rtValue* value) const else { rtWrapperError error; - *value = js2rt(ctx, self->Get(s), &error); + *value = v82rt(ctx, self->Get(s), &error); if (error.hasError()) err = RT_ERROR_INVALID_ARG; } @@ -408,7 +408,7 @@ rtError jsObjectWrapper::Get(uint32_t i, rtValue* value) const if (!(self->Has(ctx,i).FromMaybe(false))) return RT_PROPERTY_NOT_FOUND; rtWrapperError error; - *value = js2rt(ctx, self->Get(i), &error); + *value = v82rt(ctx, self->Get(i), &error); if (error.hasError()) return RT_ERROR_INVALID_ARG; @@ -441,7 +441,7 @@ rtError jsObjectWrapper::Set(const char* name, const rtValue* value) } else { - err = self->Set(s, rt2js(ctx, *value)); + err = self->Set(s, rt2v8(ctx, *value)); } return err; @@ -458,7 +458,7 @@ rtError jsObjectWrapper::Set(uint32_t i, const rtValue* value) Local self = PersistentToLocal(mIsolate, mObject); Local ctx = self->CreationContext(); - if (!self->Set(i, rt2js(ctx, *value))) + if (!self->Set(i, rt2v8(ctx, *value))) return RT_FAIL; return RT_OK; diff --git a/src/rtScriptV8/rtScriptV8.cpp b/src/rtScriptV8/rtScriptV8.cpp index 44a043cafa..61676e1a8f 100755 --- a/src/rtScriptV8/rtScriptV8.cpp +++ b/src/rtScriptV8/rtScriptV8.cpp @@ -16,8 +16,6 @@ */ -// rtNode.cpp - #if defined WIN32 #include #include @@ -54,6 +52,8 @@ #include "rtValue.h" #include "rtAtomic.h" #include "rtScript.h" +#include "rtFunctionWrapper.h" +#include "rtObjectWrapper.h" #include @@ -66,17 +66,71 @@ #pragma GCC diagnostic ignored "-Wall" #endif -#include "uv.h" -#include "v8.h" +#include "v8_headers.h" #include "libplatform/libplatform.h" #include "rtObjectWrapper.h" #include "rtFunctionWrapper.h" +#include "rtWrapperUtils.h" #if !defined(WIN32) & !defined(ENABLE_DFB) #pragma GCC diagnostic pop #endif +#define USE_CONTEXTIFY_CLONES + +class V8ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { +public: + virtual void* Allocate(size_t size) + { + void *ret = AllocateUninitialized(size); + if (!ret) + { + return NULL; + } + memset(ret, 0, size); + return ret; + } + virtual void* AllocateUninitialized(size_t size) + { + return malloc(size); + } + virtual void Free(void* data, size_t) { free(data); } +}; + +V8ArrayBufferAllocator* array_buffer_allocator = NULL; + +#if 0 +template +inline v8::Local V8StrongPersistentToLocal( + const v8::Persistent& persistent) { + return *reinterpret_cast*>( + const_cast*>(&persistent)); +} + +template +inline v8::Local V8WeakPersistentToLocal( + v8::Isolate* isolate, + const v8::Persistent& persistent) { + return v8::Local::New(isolate, persistent); +} + +template +inline v8::Local V8PersistentToLocal( + v8::Isolate* isolate, + const v8::Persistent& persistent) { + if (persistent.IsWeak()) { + return V8WeakPersistentToLocal(isolate, persistent); + } + else { + return V8StrongPersistentToLocal(persistent); + } +} +#endif + +using namespace rtScriptV8Utils; + + class rtV8Context; typedef rtRef rtV8ContextRef; @@ -85,31 +139,19 @@ class rtV8Context: rtIScriptContext // V8 { public: rtV8Context(v8::Isolate *isolate, v8::Platform* platform); +#ifdef USE_CONTEXTIFY_CLONES + rtV8Context(v8::Isolate *isolate, rtV8ContextRef clone_me); +#endif virtual ~rtV8Context(); - virtual rtError add(const char *name, const rtValue& val) - { - return RT_OK; - } - virtual rtValue get(const char *name) - { - return rtValue(); - } + virtual rtError add(const char *name, const rtValue& val); + virtual rtValue get(const char *name); - virtual bool has(const char *name) - { - return true; - } + virtual bool has(const char *name); - virtual rtError runScript(const char *script, rtValue* retVal = NULL, const char *args = NULL) - { - return RT_OK; - } - virtual rtError runFile (const char *file, rtValue* retVal = NULL, const char *args = NULL) - { - return RT_OK; - } + virtual rtError runScript(const char *script, rtValue* retVal = NULL, const char *args = NULL); + virtual rtError runFile(const char *file, rtValue* retVal = NULL, const char *args = NULL); unsigned long AddRef() { @@ -121,7 +163,11 @@ class rtV8Context: rtIScriptContext // V8 private: v8::Isolate *mIsolate; v8::Platform *mPlatform; + v8::Persistent mContext; int mRefCount; + + const char *js_file; + std::string js_script; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -142,26 +188,15 @@ class rtScriptV8: public rtIScript unsigned long Release(); - rtError init() - { - return RT_OK; - } - rtError term() - { - return RT_OK; - } + rtError init(); + rtError term(); rtString engine() { return "v8"; } - rtError createContext(const char *lang, rtScriptContextRef& ctx) - { - return RT_OK; - } + rtV8ContextRef createContext(); + rtError createContext(const char *lang, rtScriptContextRef& ctx); - rtError pump() - { - return RT_OK; - } + rtError pump(); v8::Isolate *getIsolate() { @@ -172,35 +207,339 @@ class rtScriptV8: public rtIScript return mPlatform; } - rtError collectGarbage() - { - return RT_OK; - } - void* getParameter(rtString param) - { - return NULL; - } + rtError collectGarbage(); + void* getParameter(rtString param); private: v8::Isolate *mIsolate; + v8::Persistent mContext; v8::Platform *mPlatform; + bool mV8Initialized; + int mRefCount; }; using namespace v8; +#define RT_V8_TEST_BINDINGS +#ifdef RT_V8_TEST_BINDINGS + +rtError rtTestArrayReturnBinding(int numArgs, const rtValue* args, rtValue* result, void* context); +rtError rtTestMapReturnBinding(int numArgs, const rtValue* args, rtValue* result, void* context); +rtError rtTestObjectReturnBinding(int numArgs, const rtValue* args, rtValue* result, void* context); + +rtError rtTestArrayReturnBinding(int numArgs, const rtValue* args, rtValue* result, void* context) +{ + rtArrayObject* ret = new rtArrayObject(); + + ret->pushBack(rtValue(1)); + ret->pushBack(rtValue(2)); + ret->pushBack(rtValue(3)); + + *result = ret; + + return RT_OK; +} + +rtError rtTestMapReturnBinding(int numArgs, const rtValue* args, rtValue* result, void* context) +{ + rtMapObject* ret = new rtMapObject(); + + rtValue v1(1); + ret->Set("a1", &v1); + rtValue v2(2); + ret->Set("a2", &v2); + rtValue v3(3); + ret->Set("a3", &v3); + + *result = ret; + + return RT_OK; +} + +class rtTestObject : public rtObject +{ +public: + rtDeclareObject(rtTestObject, rtObject); + rtProperty(propA, propA, setPropA, int); + rtReadOnlyProperty(propB, propB, int); + rtProperty(propC, propC, setPropC, rtFunctionRef); + rtMethodNoArgAndNoReturn("methodA", methodA); + rtMethodNoArgAndReturn("methodB", methodB, int); + rtMethod1ArgAndReturn("methodC", methodC, rtString, rtString); + + rtTestObject() : mPropA(1), mPropB(2) {} + + rtError propA(int& v) const { v = mPropA; return RT_OK; } + rtError setPropA(int v) { mPropA = v; return RT_OK; } + rtError propB(int& v) const { v = mPropB; return RT_OK; } + rtError propC(rtFunctionRef& v) const { v = mPropC; return RT_OK; } + rtError setPropC(rtFunctionRef v) { mPropC = v; return RT_OK; } + + rtError methodA() { return RT_OK; } + rtError methodB(int &b) { b = 123; return RT_OK; } + rtError methodC(const rtString &in1, rtString &out1) { out1 = in1; return RT_OK; } + +private: + int mPropA; + int mPropB; + rtFunctionRef mPropC; +}; + +rtDefineObject(rtTestObject, rtObject); +rtDefineProperty(rtTestObject, propA); +rtDefineProperty(rtTestObject, propB); +rtDefineProperty(rtTestObject, propC); +rtDefineMethod(rtTestObject, methodA); +rtDefineMethod(rtTestObject, methodB); +rtDefineMethod(rtTestObject, methodC); + +rtError rtTestObjectReturnBinding(int numArgs, const rtValue* args, rtValue* result, void* context) +{ + rtTestObject* ret = new rtTestObject(); + + *result = ret; + + return RT_OK; +} + +rtRef g_testArrayReturnFunc; +rtRef g_testMapReturnFunc; +rtRef g_testObjectReturnFunc; + +#endif + rtV8Context::rtV8Context(Isolate *isolate, Platform *platform) : mIsolate(isolate), mRefCount(0), mPlatform(platform) { + rtLogInfo(__FUNCTION__); + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); + + // Create a new context. + Local localContext = Context::New(mIsolate); + + mContext.Reset(mIsolate, localContext); // local to persistent + + Context::Scope contextScope(localContext); + + Handle global = localContext->Global(); + + rtObjectWrapper::exportPrototype(mIsolate, global); + rtFunctionWrapper::exportPrototype(mIsolate, global); + + v8::platform::PumpMessageLoop(mPlatform, mIsolate); + + g_testArrayReturnFunc = new rtFunctionCallback(rtTestArrayReturnBinding); + g_testMapReturnFunc = new rtFunctionCallback(rtTestMapReturnBinding); + g_testObjectReturnFunc = new rtFunctionCallback(rtTestObjectReturnBinding); + + add("_testArrayReturnFunc", g_testArrayReturnFunc.getPtr()); + add("_testMapReturnFunc", g_testMapReturnFunc.getPtr()); + add("_testObjectReturnFunc", g_testObjectReturnFunc.getPtr()); +} + +#ifdef USE_CONTEXTIFY_CLONES +rtV8Context::rtV8Context(Isolate *isolate, rtV8ContextRef clone_me) +{ + assert(0); } +#endif rtV8Context::~rtV8Context() { } -rtScriptV8::rtScriptV8():mRefCount(0) +rtError rtV8Context::add(const char *name, const rtValue& val) +{ + if (name == NULL) + { + rtLogDebug(" rtNodeContext::add() - no symbolic name for rtValue"); + return RT_FAIL; + } + else if (this->has(name)) + { + rtLogDebug(" rtNodeContext::add() - ALREADY HAS '%s' ... over-writing.", name); + // return; // Allow for "Null"-ing erasure. + } + + if (val.isEmpty()) + { + rtLogDebug(" rtNodeContext::add() - rtValue is empty"); + return RT_FAIL; + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + + local_context->Global()->Set(String::NewFromUtf8(mIsolate, name), rt2v8(local_context, val)); + + return RT_OK; +} + +rtValue rtV8Context::get(const char *name) +{ + if (name == NULL) + { + rtLogError(" rtNodeContext::get() - no symbolic name for rtValue"); + return rtValue(); + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + + Handle global = local_context->Global(); + + // Get the object + Local object = global->Get(String::NewFromUtf8(mIsolate, name)); + + if (object->IsUndefined() || object->IsNull()) + { + rtLogError("FATAL: '%s' is Undefined ", name); + return rtValue(); + } + else + { + rtWrapperError error; // TODO - handle error + return v82rt(local_context, object, &error); + } +} + +bool rtV8Context::has(const char *name) +{ + if (name == NULL) + { + rtLogError(" rtNodeContext::has() - no symbolic name for rtValue"); + return false; + } + + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + + Handle global = local_context->Global(); + + TryCatch try_catch(mIsolate); + Handle value = global->Get(String::NewFromUtf8(mIsolate, name)); + + if (try_catch.HasCaught()) + { + rtLogError("\n ## has() - HasCaught() ... ERROR"); + return false; + } + + // No need to check if |value| is empty because it's taken care of + // by TryCatch above. + + return (!value->IsUndefined() && !value->IsNull()); +} + +rtError rtV8Context::runScript(const char *script, rtValue* retVal /*= NULL*/, const char *args /*= NULL*/) +{ + rtLogInfo(__FUNCTION__); + if (!script || strlen(script) == 0) + { + rtLogError(" %s ... no script given.", __PRETTY_FUNCTION__); + + return RT_FAIL; + } + + {//scope + Locker locker(mIsolate); + Isolate::Scope isolate_scope(mIsolate); + HandleScope handle_scope(mIsolate); // Create a stack-allocated handle scope. + + // Get a Local context... + Local local_context = PersistentToLocal(mIsolate, mContext); + Context::Scope context_scope(local_context); + // !CLF TODO: TEST FOR MT + TryCatch tryCatch(mIsolate); + Local source = String::NewFromUtf8(mIsolate, script); + + // Compile the source code. + Local