/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** 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 The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QV4SCOPEDVALUE_P_H #define QV4SCOPEDVALUE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qv4engine_p.h" #include "qv4value_p.h" #include "qv4property_p.h" #include "qv4propertykey_p.h" #ifdef V4_USE_VALGRIND #include #endif 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; #define CHECK_EXCEPTION() \ do { \ if (scope.hasException() || scope.engine->isInterrupted.loadAcquire()) { \ return QV4::Encode::undefined(); \ } \ } while (false) #define RETURN_UNDEFINED() \ return QV4::Encode::undefined() #define RETURN_RESULT(r) \ return QV4::Encode(r) #define THROW_TYPE_ERROR() \ return scope.engine->throwTypeError() #define THROW_GENERIC_ERROR(str) \ return scope.engine->throwError(QString::fromUtf8(str)) struct Scope { explicit Scope(ExecutionContext *ctx) : engine(ctx->engine()) , mark(engine->jsStackTop) { } explicit Scope(ExecutionEngine *e) : engine(e) , mark(engine->jsStackTop) { } explicit Scope(const Managed *m) : engine(m->engine()) , mark(engine->jsStackTop) { } ~Scope() { #ifndef QT_NO_DEBUG Q_ASSERT(engine->jsStackTop >= mark); // Q_ASSERT(engine->currentContext < mark); memset(mark, 0, (engine->jsStackTop - mark)*sizeof(Value)); #endif #ifdef V4_USE_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED(mark, (engine->jsStackLimit - mark) * sizeof(Value)); #endif engine->jsStackTop = mark; } enum AllocMode { Undefined, Empty, /* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */ Uninitialized }; template QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const { Value *ptr = engine->jsAlloca(nValues); switch (mode) { case Undefined: for (int i = 0; i < nValues; ++i) ptr[i] = Value::undefinedValue(); break; case Empty: for (int i = 0; i < nValues; ++i) ptr[i] = Value::emptyValue(); break; case Uninitialized: break; } return ptr; } template QML_NEARLY_ALWAYS_INLINE Value *alloc() const { Value *ptr = engine->jsAlloca(1); switch (mode) { case Undefined: *ptr = Value::undefinedValue(); break; case Empty: *ptr = Value::emptyValue(); break; case Uninitialized: break; } return ptr; } bool hasException() const { return engine->hasException; } ExecutionEngine *engine; Value *mark; private: Q_DISABLE_COPY(Scope) }; struct ScopedValue { ScopedValue(const ScopedValue &) = default; ScopedValue(ScopedValue &&) = default; ScopedValue(const Scope &scope) { ptr = scope.alloc(); ptr->setRawValue(0); } ScopedValue(const Scope &scope, const Value &v) { ptr = scope.alloc(); *ptr = v; } ScopedValue(const Scope &scope, Heap::Base *o) { ptr = scope.alloc(); ptr->setM(o); } ScopedValue(const Scope &scope, Managed *m) { ptr = scope.alloc(); ptr->setRawValue(m->asReturnedValue()); } ScopedValue(const Scope &scope, const ReturnedValue &v) { ptr = scope.alloc(); ptr->setRawValue(v); } ScopedValue &operator=(const Value &v) { *ptr = v; return *this; } ScopedValue &operator=(Heap::Base *o) { ptr->setM(o); return *this; } ScopedValue &operator=(Managed *m) { *ptr = *m; return *this; } ScopedValue &operator=(const ReturnedValue &v) { ptr->setRawValue(v); return *this; } ScopedValue &operator=(const ScopedValue &other) { *ptr = *other.ptr; return *this; } Value *operator->() { return ptr; } const Value *operator->() const { return ptr; } operator Value *() { return ptr; } operator const Value &() const { return *ptr; } Value *ptr; }; struct ScopedPropertyKey { ScopedPropertyKey(const Scope &scope) { ptr = reinterpret_cast(scope.alloc()); *ptr = PropertyKey::invalid(); } ScopedPropertyKey(const Scope &scope, const PropertyKey &v) { ptr = reinterpret_cast(scope.alloc()); *ptr = v; } ScopedPropertyKey &operator=(const PropertyKey &other) { *ptr = other; return *this; } PropertyKey *operator->() { return ptr; } operator PropertyKey() const { return *ptr; } bool operator==(const PropertyKey &other) const { return *ptr == other; } bool operator==(const ScopedPropertyKey &other) const { return *ptr == *other.ptr; } bool operator!=(const PropertyKey &other) const { return *ptr != other; } bool operator!=(const ScopedPropertyKey &other) const { return *ptr != *other.ptr; } PropertyKey *ptr; }; template struct Scoped { enum ConvertType { Convert }; QML_NEARLY_ALWAYS_INLINE void setPointer(const Managed *p) { ptr->setM(p ? p->m() : nullptr); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope) { ptr = scope.alloc(); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v) { ptr = scope.alloc(); setPointer(v.as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, Heap::Base *o) { Value v; v = o; ptr = scope.alloc(); setPointer(v.as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.alloc(); setPointer(v.ptr->as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value &v, ConvertType) { ptr = scope.alloc(); ptr->setRawValue(value_convert(scope.engine, v)); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const Value *v) { ptr = scope.alloc(); setPointer(v ? v->as() : nullptr); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, T *t) { ptr = scope.alloc(); setPointer(t); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const T *t) { ptr = scope.alloc(); setPointer(t); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, typename T::Data *t) { ptr = scope.alloc(); *ptr = t; } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v) { ptr = scope.alloc(); setPointer(QV4::Value::fromReturnedValue(v).as()); } QML_NEARLY_ALWAYS_INLINE Scoped(const Scope &scope, const ReturnedValue &v, ConvertType) { ptr = scope.alloc(); ptr->setRawValue(value_convert(scope.engine, QV4::Value::fromReturnedValue(v))); } Scoped &operator=(Heap::Base *o) { setPointer(Value::fromHeapObject(o).as()); return *this; } Scoped &operator=(typename T::Data *t) { *ptr = t; return *this; } Scoped &operator=(const Value &v) { setPointer(v.as()); return *this; } Scoped &operator=(Value *v) { setPointer(v ? v->as() : nullptr); return *this; } Scoped &operator=(const ReturnedValue &v) { setPointer(QV4::Value::fromReturnedValue(v).as()); return *this; } Scoped &operator=(T *t) { setPointer(t); return *this; } operator T *() { return static_cast(ptr->managed()); } operator const Value &() const { return *ptr; } T *operator->() { return getPointer(); } const T *operator->() const { return getPointer(); } explicit operator bool() const { return ptr->m(); } T *getPointer() { return reinterpret_cast(ptr); } const T *getPointer() const { return reinterpret_cast(ptr); } Value *getRef() { return ptr; } QML_NEARLY_ALWAYS_INLINE ReturnedValue asReturnedValue() const { return ptr->rawValue(); } Value *ptr; }; inline Value &Value::operator =(const ScopedValue &v) { _val = v.ptr->rawValue(); return *this; } template inline Value &Value::operator=(const Scoped &t) { _val = t.ptr->rawValue(); return *this; } struct ScopedProperty { ScopedProperty(Scope &scope) { property = reinterpret_cast(scope.alloc(sizeof(Property) / sizeof(Value))); } Property *operator->() { return property; } operator const Property *() const { return property; } operator Property *() { return property; } Property *property; }; } QT_END_NAMESPACE #endif