/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QV4SCOPEDVALUE_P_H #define QV4SCOPEDVALUE_P_H #include "qv4engine_p.h" #include "qv4value_def_p.h" QT_BEGIN_NAMESPACE #define SAVE_JS_STACK(ctx) Value *__jsStack = ctx->engine->jsStackTop #define CHECK_JS_STACK(ctx) Q_ASSERT(__jsStack == ctx->engine->jsStackTop) namespace QV4 { struct ScopedValue; struct Scope { explicit Scope(ExecutionContext *ctx) : engine(ctx->engine) #ifndef QT_NO_DEBUG , size(0) #endif { mark = engine->jsStackTop; } explicit Scope(ExecutionEngine *e) : engine(e) { mark = engine->jsStackTop; } ~Scope() { #ifndef QT_NO_DEBUG Q_ASSERT(engine->jsStackTop >= mark); memset(mark, 0, (engine->jsStackTop - mark)*sizeof(SafeValue)); #endif engine->jsStackTop = mark; } SafeValue *alloc(int nValues) { SafeValue *ptr = engine->jsStackTop; engine->jsStackTop += nValues; #ifndef QT_NO_DEBUG size += nValues; #endif return ptr; } ExecutionEngine *engine; SafeValue *mark; #ifndef QT_NO_DEBUG mutable int size; #endif }; struct ScopedValue; struct ValueRef; struct ScopedValue { ScopedValue(const Scope &scope) { ptr = scope.engine->jsStackTop++; #ifndef QT_NO_DEBUG ++scope.size; #endif } ScopedValue(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; *ptr = v; #ifndef QT_NO_DEBUG ++scope.size; #endif } ScopedValue(const Scope &scope, Managed *m) { ptr = scope.engine->jsStackTop++; ptr->val = m->asReturnedValue(); #ifndef QT_NO_DEBUG ++scope.size; #endif } ScopedValue(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; ptr->val = v; #ifndef QT_NO_DEBUG ++scope.size; #endif } template ScopedValue(const Scope &scope, Returned *t) { ptr = scope.engine->jsStackTop++; *ptr = t->getPointer() ? Value::fromManaged(t->getPointer()) : Primitive::undefinedValue(); #ifndef QT_NO_DEBUG ++scope.size; #endif } ScopedValue &operator=(const Value &v) { *ptr = v; return *this; } ScopedValue &operator=(Managed *m) { ptr->val = m->asReturnedValue(); return *this; } ScopedValue &operator=(const ReturnedValue &v) { ptr->val = v; return *this; } template ScopedValue &operator=(Returned *t) { *ptr = t->getPointer() ? Value::fromManaged(t->getPointer()) : Primitive::undefinedValue(); return *this; } ScopedValue &operator=(const ScopedValue &other) { *ptr = *other.ptr; return *this; } SafeValue *operator->() { return ptr; } const SafeValue *operator->() const { return ptr; } ReturnedValue asReturnedValue() const { return ptr->val; } SafeValue *ptr; }; template struct Scoped { enum _Convert { Convert }; enum _Cast { Cast }; inline void setPointer(Managed *p) { #if QT_POINTER_SIZE == 8 ptr->val = (quint64)p; #else *ptr = p ? QV4::Value::fromManaged(p) : QV4::Primitive::undefinedValue(); #endif } Scoped(const Scope &scope) { ptr = scope.engine->jsStackTop++; #ifndef QT_NO_DEBUG ++scope.size; #endif } // ### GC FIX casting below to be safe Scoped(const Scope &scope, const Value &v) { ptr = scope.engine->jsStackTop++; setPointer(value_cast(v)); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; setPointer(value_cast(*v.ptr)); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped(const Scope &scope, const Value &v, _Convert) { ptr = scope.engine->jsStackTop++; ptr->val = value_convert(scope.engine->current, v); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped(const Scope &scope, const ValueRef &v); Scoped(const Scope &scope, T *t) { ptr = scope.engine->jsStackTop++; setPointer(t); #ifndef QT_NO_DEBUG ++scope.size; #endif } template Scoped(const Scope &scope, X *t, _Cast) { ptr = scope.engine->jsStackTop++; setPointer(managed_cast(t)); #ifndef QT_NO_DEBUG ++scope.size; #endif } template Scoped(const Scope &scope, Returned *x) { ptr = scope.engine->jsStackTop++; setPointer(Returned::getPointer(x)); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.engine->jsStackTop++; setPointer(value_cast(QV4::Value::fromReturnedValue(v))); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped(const Scope &scope, const ReturnedValue &v, _Convert) { ptr = scope.engine->jsStackTop++; ptr->val = value_convert(scope.engine->current, QV4::Value::fromReturnedValue(v)); #ifndef QT_NO_DEBUG ++scope.size; #endif } Scoped &operator=(const Value &v) { setPointer(value_cast(v)); return *this; } Scoped &operator=(const ValueRef &v); Scoped &operator=(const ReturnedValue &v) { setPointer(value_cast(QV4::Value::fromReturnedValue(v))); return *this; } Scoped &operator=(const Scoped &other) { *ptr = *other.ptr; return *this; } Scoped &operator=(T *t) { setPointer(t); return *this; } template Scoped &operator=(Returned *x) { setPointer(Returned::getPointer(x)); return *this; } T *operator->() { return static_cast(ptr->managed()); } bool operator!() const { return !ptr->managed(); } operator void *() const { return ptr->managed(); } T *getPointer() { return static_cast(ptr->managed()); } ReturnedValue asReturnedValue() const { #if QT_POINTER_SIZE == 8 return ptr->val ? ptr->val : Primitive::undefinedValue().asReturnedValue(); #else return ptr->val; #endif } SafeValue *ptr; }; struct CallData { // below is to be compatible with Value. Initialize tag to 0 #if Q_BYTE_ORDER != Q_LITTLE_ENDIAN uint tag; #endif int argc; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN uint tag; #endif inline ReturnedValue argument(int i) { return i < argc ? args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } SafeValue thisObject; SafeValue args[1]; }; struct ScopedCallData { ScopedCallData(Scope &scope, int argc) { int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue); ptr = reinterpret_cast(scope.engine->stackPush(size)); ptr->tag = QV4::Value::Integer_Type; ptr->argc = argc; #ifndef QT_NO_DEBUG scope.size += size; for (int ii = 0; ii < qMax(argc, (int)QV4::Global::ReservedArgumentCount); ++ii) ptr->args[ii] = QV4::Primitive::undefinedValue(); #endif } CallData *operator->() { return ptr; } operator CallData *() const { return ptr; } CallData *ptr; }; struct ValueRef { ValueRef(const ScopedValue &v) : ptr(v.ptr) {} template ValueRef(const Scoped &v) : ptr(v.ptr) {} ValueRef(const PersistentValue &v) : ptr(&v.d->value) {} ValueRef(PersistentValuePrivate *p) : ptr(&p->value) {} ValueRef(SafeValue &v) { ptr = &v; } // Important: Do NOT add a copy constructor to this class // adding a copy constructor actually changes the calling convention, ie. // is not even binary compatible. Adding it would break assumptions made // in the jit'ed code. ValueRef &operator=(const ScopedValue &o) { *ptr = *o.ptr; return *this; } ValueRef &operator=(const ValueRef &o) { *ptr = *o.ptr; return *this; } ValueRef &operator=(const Value &v) { *ptr = v; return *this; } ValueRef &operator=(const ReturnedValue &v) { ptr->val = v; return *this; } template ValueRef &operator=(Returned *v) { ptr->val = v->asReturnedValue(); return *this; } operator const Value *() const { return ptr; } const Value *operator->() const { return ptr; } operator Value *() { return ptr; } SafeValue *operator->() { return ptr; } static ValueRef fromRawValue(Value *v) { return ValueRef(v); } static const ValueRef fromRawValue(const Value *v) { return ValueRef(const_cast(v)); } ReturnedValue asReturnedValue() const { return ptr->val; } // ### get rid of this one! ValueRef(Value *v) { ptr = reinterpret_cast(v); } private: SafeValue *ptr; }; template struct Referenced { // Important: Do NOT add a copy constructor to this class // adding a copy constructor actually changes the calling convention, ie. // is not even binary compatible. Adding it would break assumptions made // in the jit'ed code. Referenced(const Scoped &v) : ptr(v.ptr) {} Referenced(Safe &v) { ptr = &v; } Referenced(SafeValue &v) { ptr = value_cast(v) ? &v : 0; } Referenced &operator=(const Referenced &o) { *ptr = *o.ptr; return *this; } Referenced &operator=(T *t) { #if QT_POINTER_SIZE == 4 ptr->tag = Value::Managed_Type; #endif ptr->m = t; return *this; } Referenced &operator=(Returned *t) { #if QT_POINTER_SIZE == 4 ptr->tag = Value::Managed_Type; #endif ptr->m = t->getPointer(); return *this; } operator const T *() const { return ptr ? static_cast(ptr->managed()) : 0; } const T *operator->() const { return static_cast(ptr->managed()); } operator T *() { return ptr ? static_cast(ptr->managed()) : 0; } T *operator->() { return static_cast(ptr->managed()); } T *getPointer() const { return static_cast(ptr->managed()); } ReturnedValue asReturnedValue() const { return ptr ? ptr->val : Primitive::undefinedValue().asReturnedValue(); } operator Returned *() const { return ptr ? Returned::create(getPointer()) : 0; } bool operator==(const Referenced &other) { if (ptr == other.ptr) return true; return ptr && other.ptr && ptr->m == other.ptr->m; } bool operator!=(const Referenced &other) { if (ptr == other.ptr) return false; return !ptr || ptr->m != other.ptr->m; } bool operator!() const { return !ptr || !ptr->managed(); } static Referenced null() { return Referenced(Null); } bool isNull() const { return !ptr; } private: enum _Null { Null }; Referenced(_Null) { ptr = 0; } SafeValue *ptr; }; typedef Referenced StringRef; typedef Referenced ObjectRef; typedef Referenced FunctionObjectRef; template inline Scoped::Scoped(const Scope &scope, const ValueRef &v) { ptr = scope.engine->jsStackTop++; setPointer(value_cast(*v.operator ->())); #ifndef QT_NO_DEBUG ++scope.size; #endif } template inline Scoped &Scoped::operator=(const ValueRef &v) { setPointer(value_cast(*v.operator ->())); return *this; } struct CallDataRef { CallDataRef(const ScopedCallData &c) : ptr(c.ptr) {} CallDataRef(CallData *v) { ptr = v; } // Important: Do NOT add a copy constructor to this class // adding a copy constructor actually changes the calling convention, ie. // is not even binary compatible. Adding it would break assumptions made // in the jit'ed code. CallDataRef &operator=(const ScopedCallData &c) { *ptr = *c.ptr; return *this; } CallDataRef &operator=(const CallDataRef &o) { *ptr = *o.ptr; return *this; } operator const CallData *() const { return ptr; } const CallData *operator->() const { return ptr; } operator CallData *() { return ptr; } CallData *operator->() { return ptr; } private: CallData *ptr; }; struct Encode { static ReturnedValue undefined() { return quint64(Value::Undefined_Type) << Value::Tag_Shift; } static ReturnedValue null() { return quint64(Value::_Null_Type) << Value::Tag_Shift; } Encode(bool b) { val = (quint64(Value::_Boolean_Type) << Value::Tag_Shift) | (uint)b; } Encode(double d) { Value v; v.setDouble(d); val = v.val; } Encode(int i) { val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | (uint)i; } Encode(uint i) { if (i <= INT_MAX) { val = (quint64(Value::_Integer_Type) << Value::Tag_Shift) | i; } else { Value v; v.setDouble(i); val = v.val; } } Encode(ReturnedValue v) { val = v; } template Encode(Returned *t) { val = t->getPointer()->asReturnedValue(); } operator ReturnedValue() const { return val; } quint64 val; private: Encode(void *); }; template inline Value &Value::operator=(Returned *t) { val = t->getPointer()->asReturnedValue(); return *this; } inline SafeValue &SafeValue::operator =(const ScopedValue &v) { val = v.ptr->val; return *this; } template inline SafeValue &SafeValue::operator=(Returned *t) { val = t->getPointer()->asReturnedValue(); return *this; } template inline SafeValue &SafeValue::operator=(const Scoped &t) { val = t.ptr->val; return *this; } inline SafeValue &SafeValue::operator=(const ValueRef v) { val = v.asReturnedValue(); return *this; } template inline Returned *SafeValue::as() { return Returned::create(value_cast(*this)); } template inline Referenced SafeValue::asRef() { return Referenced(*this); } template inline Safe &Safe::operator =(T *t) { val = t->asReturnedValue(); return *this; } template inline Safe &Safe::operator =(const Scoped &v) { val = v.ptr->val; return *this; } template inline Safe &Safe::operator=(Returned *t) { val = t->getPointer()->asReturnedValue(); return *this; } template inline Safe &Safe::operator =(const Referenced &v) { val = v.asReturnedValue(); return *this; } template inline Safe &Safe::operator=(const Safe &t) { val = t.val; return *this; } template inline Returned * Safe::ret() const { return Returned::create(static_cast(managed())); } inline Primitive::operator ValueRef() { return ValueRef(this); } template PersistentValue::PersistentValue(Returned *obj) : d(new PersistentValuePrivate(QV4::Value::fromManaged(obj->getPointer()))) { } template inline PersistentValue::PersistentValue(const Referenced obj) : d(new PersistentValuePrivate(*obj.ptr)) { } template inline PersistentValue &PersistentValue::operator=(Returned *obj) { return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue()); } template inline PersistentValue &PersistentValue::operator=(const Referenced obj) { return operator=(*obj.ptr); } template inline WeakValue::WeakValue(Returned *obj) : d(new PersistentValuePrivate(QV4::Value::fromManaged(obj->getPointer()), /*engine*/0, /*weak*/true)) { } template inline WeakValue &WeakValue::operator=(Returned *obj) { return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue()); } inline ReturnedValue SimpleCallContext::argument(int i) { return i < callData->argc ? callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } } QT_END_NAMESPACE #endif