diff options
author | Jedrzej Nowacki <jedrzej.nowacki@nokia.com> | 2011-05-19 16:34:32 +0200 |
---|---|---|
committer | Jedrzej Nowacki <jedrzej.nowacki@nokia.com> | 2011-05-25 10:56:26 +0200 |
commit | 8a84d56c572b163b6f4e50f3f66d6bb3cc057a03 (patch) | |
tree | c1c5ca7374cd137f8ce5ff9beecaf73dad333942 | |
parent | 41668e40943f596dc3f64b2ec827ed40d9e25408 (diff) |
Introduce optimized Handle class for QScriptContextPrivate usage.
New class depending on parameter behaves as v8::Local or as
v8::Persistent.
According to benchmarks, The QSCP::Handle class together with
QSCP::Stack and QSCP::Heap classes gives us QObject bindings
speedup from 2-12% (it reduce significantly v8::Persistent
usage).
-rw-r--r-- | src/script/api/qscriptclass.cpp | 2 | ||||
-rw-r--r-- | src/script/api/qscriptcontext_impl_p.h | 66 | ||||
-rw-r--r-- | src/script/api/qscriptcontext_p.h | 142 | ||||
-rw-r--r-- | src/script/api/qscriptcontextinfo.cpp | 2 |
4 files changed, 185 insertions, 27 deletions
diff --git a/src/script/api/qscriptclass.cpp b/src/script/api/qscriptclass.cpp index ad6d8ac..0e5aac6 100644 --- a/src/script/api/qscriptclass.cpp +++ b/src/script/api/qscriptclass.cpp @@ -249,7 +249,7 @@ v8::Handle<v8::Value> QScriptClassObject::call(const v8::Arguments& args) if (!userCallback->supportsExtension(QScriptClass::Callable)) return handleScope.Close(v8::ThrowException(v8::Exception::TypeError(v8::String::New("QScriptClass for object doesn't support Callable extension")))); - v8::Handle<v8::Object> thisObject; + v8::Local<v8::Object> thisObject; // v8 doesn't create a new Object to put in This() when the constructor call came from // a callback registered with SetCallAsFunctionHandler(). diff --git a/src/script/api/qscriptcontext_impl_p.h b/src/script/api/qscriptcontext_impl_p.h index 266f2d0..b2305e0 100644 --- a/src/script/api/qscriptcontext_impl_p.h +++ b/src/script/api/qscriptcontext_impl_p.h @@ -51,10 +51,10 @@ inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, Q inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Handle<v8::Value> callee, v8::Handle<v8::Object> customThisObject) : m_allocation(type), q_ptr(this), engine(engine), arguments(args), accessorInfo(0), - context(v8::Persistent<v8::Context>::New(v8::Context::NewFunctionContext())), - inheritedScope(v8::Persistent<v8::Context>::New(v8::Context::GetCallerContext())), - parent(engine->setCurrentQSContext(this)), previous(0), m_thisObject(v8::Persistent<v8::Object>::New(customThisObject)), - m_callee(v8::Persistent<v8::Value>::New(callee)), hasArgumentGetter(false) + context(type, v8::Context::NewFunctionContext()), + inheritedScope(type, v8::Context::GetCallerContext()), + parent(engine->setCurrentQSContext(this)), previous(0), m_thisObject(type, customThisObject), + m_callee(type, callee), hasArgumentGetter(false) { Q_ASSERT(engine); Q_ASSERT(parent); @@ -63,8 +63,8 @@ inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, Q inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, const v8::AccessorInfo *accessor) : m_allocation(type), q_ptr(this), engine(engine), arguments(0), accessorInfo(accessor), - context(v8::Persistent<v8::Context>::New(v8::Context::NewFunctionContext())), - inheritedScope(v8::Persistent<v8::Context>::New(v8::Context::GetCallerContext())), + context(type, v8::Context::NewFunctionContext()), + inheritedScope(type, v8::Context::GetCallerContext()), parent(engine->setCurrentQSContext(this)), previous(0), hasArgumentGetter(false) { Q_ASSERT(engine); @@ -74,7 +74,8 @@ inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, Q inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, v8::Handle<v8::Context> context) : m_allocation(type), q_ptr(this), engine(engine), arguments(0), accessorInfo(0), - context(v8::Persistent<v8::Context>::New(context)), parent(engine->setCurrentQSContext(this)), + context(type, context), + parent(engine->setCurrentQSContext(this)), previous(0), hasArgumentGetter(false) { Q_ASSERT(engine); @@ -84,7 +85,39 @@ inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, Q inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptContextPrivate *parent, v8::Handle<v8::StackFrame> frame) : m_allocation(type), q_ptr(this), engine(parent->engine), arguments(0), accessorInfo(0), - parent(parent), previous(0), frame(v8::Persistent<v8::StackFrame>::New(frame)), hasArgumentGetter(false) + parent(parent), previous(0), frame(type, frame), hasArgumentGetter(false) +{ + Q_ASSERT(engine); + Q_ASSERT(parent); +} + +inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Local<v8::Value> callee, v8::Local<v8::Object> customThisObject) + : m_allocation(type), q_ptr(this), engine(engine), arguments(args), accessorInfo(0), + context(type, v8::Context::NewFunctionContext()), + inheritedScope(type, v8::Context::GetCallerContext()), + parent(engine->setCurrentQSContext(this)), previous(0), m_thisObject(type, customThisObject), + m_callee(type, callee), hasArgumentGetter(false) +{ + Q_ASSERT(engine); + Q_ASSERT(parent); + context->Enter(); +} + + +inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, v8::Local<v8::Context> context) + : m_allocation(type), q_ptr(this), engine(engine), arguments(0), accessorInfo(0), + context(type, context), + parent(engine->setCurrentQSContext(this)), + previous(0), hasArgumentGetter(false) +{ + Q_ASSERT(engine); + Q_ASSERT(parent); + context->Enter(); +} + +inline QScriptContextPrivate::QScriptContextPrivate(const AllocationType type, QScriptContextPrivate *parent, v8::Local<v8::StackFrame> frame) + : m_allocation(type), q_ptr(this), engine(parent->engine), arguments(0), accessorInfo(0), + parent(parent), previous(0), frame(type, frame), hasArgumentGetter(false) { Q_ASSERT(engine); Q_ASSERT(parent); @@ -166,7 +199,7 @@ inline v8::Handle<v8::Object> QScriptContextPrivate::thisObject() const // setThisObject() doesn't work for native functions, but the constructor for native function // can set m_thisObject, so we give it higher precedence. if (!m_thisObject.IsEmpty()) { - return m_thisObject; + return m_thisObject.v8Handle(); } else if (isNativeFunction()) { return arguments->This(); } else if (isNativeAccessor()) { @@ -197,8 +230,7 @@ inline void QScriptContextPrivate::setThisObject(QScriptValuePrivate *newThis) return; } - m_thisObject.Dispose(); - m_thisObject = v8::Persistent<v8::Object>::New(*newThis); + m_thisObject = static_cast<v8::Handle<v8::Object> >(*newThis); } @@ -206,7 +238,7 @@ inline QScriptPassPointer<QScriptValuePrivate> QScriptContextPrivate::callee() c { if (isNativeFunction()) { if (!m_callee.IsEmpty()) - return new QScriptValuePrivate(engine, m_callee); + return new QScriptValuePrivate(engine, m_callee.v8Handle()); return new QScriptValuePrivate(engine, arguments->Callee()); } @@ -271,7 +303,7 @@ inline QScriptValueList QScriptContextPrivate::scopeChain() const list.append(QScriptValuePrivate::get(activationObject())); if (!inheritedScope.IsEmpty()) { - v8::Handle<v8::Context> current = inheritedScope; + v8::Handle<v8::Context> current = inheritedScope.v8Handle(); do { v8::Handle<v8::Object> object = current->GetExtensionObject(); list.append(QScriptValuePrivate::get(new QScriptValuePrivate(engine, object))); @@ -290,8 +322,8 @@ inline QScriptValueList QScriptContextPrivate::scopeChain() const inline void QScriptContextPrivate::pushScope(QScriptValuePrivate *object) { v8::Handle<v8::Object> objectHandle(v8::Object::Cast(*object->asV8Value(engine))); - v8::Handle<v8::Context> scopeContext = v8::Context::NewScopeContext(objectHandle); - scopes.append(v8::Persistent<v8::Context>::New(scopeContext)); + Handle<v8::Context> scopeContext(m_allocation, v8::Context::NewScopeContext(objectHandle)); + scopes.append(scopeContext); scopeContext->Enter(); } @@ -303,7 +335,7 @@ inline QScriptPassPointer<QScriptValuePrivate> QScriptContextPrivate::popScope() Q_UNIMPLEMENTED(); return InvalidValue(); } - v8::Persistent<v8::Context> scopeContext = scopes.takeLast(); + Handle<v8::Context> scopeContext = scopes.takeLast(); v8::Handle<v8::Object> object = scopeContext->GetExtensionObject(); scopeContext->Exit(); scopeContext.Dispose(); @@ -384,7 +416,7 @@ inline QScriptContextPrivate::Stack::Stack(QScriptEnginePrivate *engine) // the : QScriptContextPrivate(StackAllocation, engine) {} -inline QScriptContextPrivate::Stack::Stack(QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Handle<v8::Value> callee, v8::Handle<v8::Object> customThisObject) // native function context (on the stack) +inline QScriptContextPrivate::Stack::Stack(QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Local<v8::Value> callee, v8::Local<v8::Object> customThisObject) // native function context (on the stack) : QScriptContextPrivate(StackAllocation, engine, args, callee, customThisObject) {} diff --git a/src/script/api/qscriptcontext_p.h b/src/script/api/qscriptcontext_p.h index daac674..d9bd218 100644 --- a/src/script/api/qscriptcontext_p.h +++ b/src/script/api/qscriptcontext_p.h @@ -59,9 +59,136 @@ protected: inline QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, v8::Handle<v8::Context> context); // from QScriptEngine::pushContext inline QScriptContextPrivate(const AllocationType type, QScriptContextPrivate *parent, v8::Handle<v8::StackFrame> frame); // internal, for js frame (allocated in parentContext()) + inline QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Local<v8::Value> callee = v8::Local<v8::Value>(), v8::Local<v8::Object> customThisObject = v8::Local<v8::Object>()); // native function context (on the stack) + inline QScriptContextPrivate(const AllocationType type, QScriptEnginePrivate *engine, v8::Local<v8::Context> context); // from QScriptEngine::pushContext + inline QScriptContextPrivate(const AllocationType type, QScriptContextPrivate *parent, v8::Local<v8::StackFrame> frame); // internal, for js frame (allocated in parentContext()) public: class Stack; class Heap; + template<class T> + class Handle : protected v8::Handle<T> + { + public: + typedef QScriptContextPrivate::AllocationType Type; + + Handle() + : m_type(HeapAllocation) // lazy fall-back to Persistent + {} + + Handle(Type type) + : m_type(type) + {} + + Handle(Type type, v8::Handle<T> handle) + : m_type(type) + { + switch (m_type){ + case Local: *asLocal() = v8::Local<T>::New(handle); break; + case Persistent: *asPersistent() = v8::Persistent<T>::New(handle); break; + } + } + + Handle(Type type, v8::Local<T> handle) + : m_type(type) + { + switch (m_type){ + case Local: + // We do not need to call Local::New because this local is already protected by + // a higher HandleScope that would survive longer than this QScriptContextPrivate + *asLocal() = handle; + break; + case Persistent: *asPersistent() = v8::Persistent<T>::New(handle); break; + } + } + + + Handle(const Handle<T>& handle) + : v8::Handle<T>(*handle) + , m_type(handle.m_type) + { + switch (m_type){ + case Local: + // The other handle is already protected, its live time would the same or a bit longer + // so we do not need Local::New here. + break; + case Persistent: *asPersistent() = v8::Persistent<T>::New(handle); break; + } + } + + void operator =(v8::Handle<T> handle) + { + switch (m_type){ + case Local: *asLocal() = v8::Local<T>::New(handle); break; + case Persistent: + asPersistent()->Dispose(); + *asPersistent() = v8::Persistent<T>::New(handle); + break; + } + } + + void operator =(v8::Local<T> handle) + { + switch (m_type){ + case Local: + // The other handle is already protected, its live time would the same or a bit longer + // so we do not need Local::New here. + *asLocal() = handle; + break; + case Persistent: + asPersistent()->Dispose(); + *asPersistent() = v8::Persistent<T>::New(handle); + break; + } + } + + void operator =(Handle<T> handle) + { + Q_ASSERT(handle.m_type == m_type); + switch (m_type) { + case Local: + // The other handle is already protected, its live time would the same or a bit longer + // so we do not need Local::New here. + *asLocal() = *handle.asLocal(); + break; + case Persistent: + asPersistent()->Dispose(); + *asPersistent() = v8::Persistent<T>::New(handle); + break; + } + } + + void Dispose() + { + if (m_type == Persistent) { + asPersistent()->Dispose(); + // FIXME: maybe it is not needed ? + asPersistent()->Clear(); + } + } + + inline T* operator->() const { return v8::Handle<T>::operator ->(); } + inline T* operator*() const { return v8::Handle<T>::operator *(); } + inline bool IsEmpty() const { return v8::Handle<T>::IsEmpty(); } + inline v8::Handle<T> v8Handle() const { return v8::Handle<T>(*this); } + + private: + static const int Persistent = QScriptContextPrivate::HeapAllocation; + static const int Local = QScriptContextPrivate::StackAllocation; + const Type m_type; + + inline v8::Persistent<T> *asPersistent() + { + Q_ASSERT(m_type == Persistent); + return reinterpret_cast<v8::Persistent<T> *>(this); + } + + inline v8::Local<T> *asLocal() + { + Q_ASSERT(m_type == Local); + return reinterpret_cast<v8::Local<T> *>(this); + } + }; + static QScriptContextPrivate *get(const QScriptContext *q) { Q_ASSERT(q->d_ptr); return q->d_ptr; } static QScriptContext *get(QScriptContextPrivate *d) { return d->q_func(); } @@ -96,15 +223,15 @@ public: QScriptEnginePrivate *engine; const v8::Arguments *arguments; const v8::AccessorInfo *accessorInfo; - v8::Persistent<v8::Context> context; - QList<v8::Persistent<v8::Context> > scopes; - v8::Persistent<v8::Context> inheritedScope; + Handle<v8::Context> context; + QList<Handle<v8::Context> > scopes; + Handle<v8::Context> inheritedScope; QScriptContextPrivate *parent; //the parent native frame as seen by the engine mutable QScriptContextPrivate *previous; //the previous js frame (lazily build) - v8::Persistent<v8::StackFrame> frame; //only for js frames + Handle<v8::StackFrame> frame; //only for js frames QScriptSharedDataPointer<QScriptValuePrivate> argsObject; - v8::Persistent<v8::Object> m_thisObject; - v8::Persistent<v8::Value> m_callee; + Handle<v8::Object> m_thisObject; + Handle<v8::Value> m_callee; bool hasArgumentGetter; static const int stackTraceLimit = 100; @@ -123,7 +250,7 @@ class QScriptContextPrivate::Stack : public QScriptContextPrivate { public: inline Stack(QScriptEnginePrivate *engine); // the global context (member of QScriptEnginePrivate) - inline Stack(QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Handle<v8::Value> callee = v8::Handle<v8::Value>(), v8::Handle<v8::Object> customThisObject = v8::Handle<v8::Object>()); // native function context (on the stack) + inline Stack(QScriptEnginePrivate *engine, const v8::Arguments *args, v8::Local<v8::Value> callee = v8::Local<v8::Value>(), v8::Local<v8::Object> customThisObject = v8::Local<v8::Object>()); // native function context (on the stack) inline Stack(QScriptEnginePrivate *engine, const v8::AccessorInfo *accessor); // native acessors (on the stack) // Only base class is used so destructor here is pointless private: @@ -145,7 +272,6 @@ public: // Only base class is used so a destructor here is pointless }; - QT_END_NAMESPACE #endif diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp index ca96ecb..274fa81 100644 --- a/src/script/api/qscriptcontextinfo.cpp +++ b/src/script/api/qscriptcontextinfo.cpp @@ -128,7 +128,7 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte QScriptIsolate api(context_p->engine, QScriptIsolate::NotNullEngine); v8::HandleScope handleScope; if (context_p->isJSFrame()) { - v8::Handle<v8::StackFrame> frame = context_p->frame; + v8::Handle<v8::StackFrame> frame = context_p->frame.v8Handle(); scriptId = frame->GetScriptId()->NumberValue(); columnNumber = frame->GetColumn(); lineNumber = frame->GetLineNumber(); |