diff options
Diffstat (limited to 'src/script/qscriptengine_p.h')
-rw-r--r-- | src/script/qscriptengine_p.h | 828 |
1 files changed, 828 insertions, 0 deletions
diff --git a/src/script/qscriptengine_p.h b/src/script/qscriptengine_p.h new file mode 100644 index 0000000..3d13628 --- /dev/null +++ b/src/script/qscriptengine_p.h @@ -0,0 +1,828 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTENGINE_P_H +#define QSCRIPTENGINE_P_H + +#include "qscriptenginefwd_p.h" + +#ifndef QT_NO_SCRIPT + +#include <QtCore/QDateTime> +#include <QtCore/QMutex> +#include <QtCore/QLinkedList> +#include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QHash> +#include <QtCore/qnumeric.h> + +#include "qscriptengine.h" +#include "qscriptnameid_p.h" +#include "qscriptobjectfwd_p.h" +#include "qscriptrepository_p.h" +#include "qscriptgc_p.h" +#include "qscriptecmaarray_p.h" +#include "qscriptecmadate_p.h" +#include "qscriptecmaobject_p.h" +#include "qscriptecmaboolean_p.h" +#include "qscriptecmanumber_p.h" +#include "qscriptecmastring_p.h" +#include "qscriptecmafunction_p.h" +#include "qscriptextvariant_p.h" +#include "qscriptextqobject_p.h" +#include "qscriptvalue_p.h" +#include "qscriptcontextfwd_p.h" + +#include <math.h> + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +namespace QScript { + +class ArgumentsObjectData: public QScriptObjectData +{ +public: + ArgumentsObjectData() : length(0) {} + virtual ~ArgumentsObjectData() {} + +public: // attributes + QScriptValueImpl activation; + uint length; +}; + +} // namespace QScript + +inline QScriptEnginePrivate *QScriptEnginePrivate::get(QScriptEngine *q) +{ + if (q) + return q->d_func(); + return 0; +} + +inline const QScriptEnginePrivate *QScriptEnginePrivate::get(const QScriptEngine *q) +{ + if (q) + return q->d_func(); + return 0; +} + +inline QScriptEngine *QScriptEnginePrivate::get(QScriptEnginePrivate *d) +{ + return d->q_func(); +} + +inline QString QScriptEnginePrivate::toString(QScriptNameIdImpl *id) +{ + if (! id) + return QString(); + + return id->s; +} + +inline QString QScriptEnginePrivate::memberName(const QScript::Member &member) const +{ + return toString(member.nameId()); +} + +inline void QScriptEnginePrivate::newReference(QScriptValueImpl *o, int mode) +{ + Q_ASSERT(o); + o->m_type = QScript::ReferenceType; + o->m_int_value = (mode); +} + +inline void QScriptEnginePrivate::newActivation(QScriptValueImpl *o) +{ + Q_ASSERT(o); + newObject(o, nullValue(), m_class_activation); +} + +inline void QScriptEnginePrivate::newPointer(QScriptValueImpl *o, void *ptr) +{ + Q_ASSERT(o); + o->m_type = QScript::PointerType; + o->m_ptr_value = ptr; +} + +inline void QScriptEnginePrivate::newInteger(QScriptValueImpl *o, int i) +{ + Q_ASSERT(o); + o->m_type = QScript::IntegerType; + o->m_int_value = (i); +} + +inline void QScriptEnginePrivate::newNameId(QScriptValueImpl *o, const QString &s) +{ + Q_ASSERT(o); + o->m_type = QScript::StringType; + o->m_string_value = (nameId(s, /*persistent=*/false)); +} + +inline void QScriptEnginePrivate::newString(QScriptValueImpl *o, const QString &s) +{ + Q_ASSERT(o); + o->m_type = QScript::StringType; + QScriptNameIdImpl *entry = new QScriptNameIdImpl(s); + m_tempStringRepository.append(entry); + o->m_string_value = (entry); + m_newAllocatedTempStringRepositoryChars += s.length(); +} + +inline void QScriptEnginePrivate::newNameId(QScriptValueImpl *o, QScriptNameIdImpl *id) +{ + Q_ASSERT(o); + o->m_type = QScript::StringType; + o->m_string_value = (id); +} + +inline const QScript::IdTable *QScriptEnginePrivate::idTable() const +{ + return &m_id_table; +} + +inline qsreal QScriptEnginePrivate::convertToNativeDouble(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + if (value.isNumber()) + return value.m_number_value; + + return convertToNativeDouble_helper(value); +} + +inline qint32 QScriptEnginePrivate::convertToNativeInt32(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + return toInt32 (convertToNativeDouble(value)); +} + + +inline bool QScriptEnginePrivate::convertToNativeBoolean(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + if (value.isBoolean()) + return value.m_bool_value; + + return convertToNativeBoolean_helper(value); +} + +inline QString QScriptEnginePrivate::convertToNativeString(const QScriptValueImpl &value) +{ + Q_ASSERT (value.isValid()); + + if (value.isString()) + return value.m_string_value->s; + + return convertToNativeString_helper(value); +} + +inline qsreal QScriptEnginePrivate::toInteger(qsreal n) +{ + if (qIsNaN(n)) + return 0; + + if (n == 0 || qIsInf(n)) + return n; + + int sign = n < 0 ? -1 : 1; + return sign * ::floor(::fabs(n)); +} + +inline qint32 QScriptEnginePrivate::toInt32(qsreal n) +{ + if (qIsNaN(n) || qIsInf(n) || (n == 0)) + return 0; + + double sign = (n < 0) ? -1.0 : 1.0; + qsreal abs_n = fabs(n); + + n = ::fmod(sign * ::floor(abs_n), D32); + const double D31 = D32 / 2.0; + + if (sign == -1 && n < -D31) + n += D32; + + else if (sign != -1 && n >= D31) + n -= D32; + + return qint32 (n); +} + +inline quint32 QScriptEnginePrivate::toUint32(qsreal n) +{ + if (qIsNaN(n) || qIsInf(n) || (n == 0)) + return 0; + + double sign = (n < 0) ? -1.0 : 1.0; + qsreal abs_n = fabs(n); + + n = ::fmod(sign * ::floor(abs_n), D32); + + if (n < 0) + n += D32; + + return quint32 (n); +} + +inline quint16 QScriptEnginePrivate::toUint16(qsreal n) +{ + if (qIsNaN(n) || qIsInf(n) || (n == 0)) + return 0; + + double sign = (n < 0) ? -1.0 : 1.0; + qsreal abs_n = fabs(n); + + n = ::fmod(sign * ::floor(abs_n), D16); + + if (n < 0) + n += D16; + + return quint16 (n); +} + +inline QScript::AST::Node *QScriptEnginePrivate::abstractSyntaxTree() const +{ + return m_abstractSyntaxTree; +} + +inline QScript::MemoryPool *QScriptEnginePrivate::nodePool() +{ + return m_pool; +} + +inline void QScriptEnginePrivate::setNodePool(QScript::MemoryPool *pool) +{ + m_pool = pool; +} + +inline QScript::Lexer *QScriptEnginePrivate::lexer() +{ + return m_lexer; +} + +inline void QScriptEnginePrivate::setLexer(QScript::Lexer *lexer) +{ + m_lexer = lexer; +} + +inline QScriptObject *QScriptEnginePrivate::allocObject() +{ + return objectAllocator(m_objectGeneration); +} + +inline QScriptContextPrivate *QScriptEnginePrivate::currentContext() const +{ + return m_context; +} + +inline QScriptContextPrivate *QScriptEnginePrivate::pushContext() +{ + QScriptContext *context = m_frameRepository.get(); + QScriptContextPrivate *ctx_p = QScriptContextPrivate::get(context); + ctx_p->init(m_context); + m_context = ctx_p; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + notifyContextPush(); +#endif + return m_context; +} + +inline void QScriptEnginePrivate::popContext() +{ + Q_ASSERT(m_context != 0); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + notifyContextPop(); +#endif + QScriptContextPrivate *context = m_context; + m_context = context->parentContext(); + if (m_context) { + QScriptContextPrivate *p1 = m_context; + QScriptContextPrivate *p2 = context; + if ((p1->m_state != QScriptContext::ExceptionState) + || (p2->m_state == QScriptContext::ExceptionState)) { + // propagate the state + p1->m_result = p2->m_result; + p1->m_state = p2->m_state; + // only update errorLineNumber if there actually was an exception + if (p2->m_state == QScriptContext::ExceptionState) { + if (p2->errorLineNumber != -1) + p1->errorLineNumber = p2->errorLineNumber; + else + p1->errorLineNumber = p1->currentLine; + } + } + } + m_frameRepository.release(QScriptContextPrivate::get(context)); +} + +inline void QScriptEnginePrivate::maybeGC() +{ + if (objectAllocator.blocked()) + return; + + bool do_string_gc = ((m_stringRepository.size() - m_oldStringRepositorySize) > 256) + || (m_newAllocatedStringRepositoryChars > 0x800000); + do_string_gc |= ((m_tempStringRepository.size() - m_oldTempStringRepositorySize) > 1024) + || (m_newAllocatedTempStringRepositoryChars > 0x800000); + + if (! do_string_gc && ! objectAllocator.poll()) + return; + + maybeGC_helper(do_string_gc); +} + +inline void QScriptEnginePrivate::adjustBytesAllocated(int bytes) +{ + objectAllocator.adjustBytesAllocated(bytes); +} + +inline bool QScriptEnginePrivate::blockGC(bool block) +{ + return objectAllocator.blockGC(block); +} + +inline void QScriptEnginePrivate::markString(QScriptNameIdImpl *id, int /*generation*/) +{ + id->used = true; +} + +inline QScriptValueImpl QScriptEnginePrivate::createFunction(QScriptFunction *fun) +{ + QScriptValueImpl v; + newFunction(&v, fun); + return v; +} + +inline QScriptValueImpl QScriptEnginePrivate::newArray(const QScript::Array &value) +{ + QScriptValueImpl v; + newArray(&v, value); + return v; +} + +inline QScriptValueImpl QScriptEnginePrivate::newArray(uint length) +{ + QScriptValueImpl v; + QScript::Array a(this); + a.resize(length); + newArray(&v, a); + return v; +} + +inline QScriptClassInfo *QScriptEnginePrivate::registerClass(const QString &pname, int type) +{ + if (type == -1) + type = ++m_class_prev_id; + + QScriptClassInfo *oc = new QScriptClassInfo(this, QScriptClassInfo::Type(type), pname); + m_allocated_classes.append(oc); + + return oc; +} + +inline QScriptClassInfo *QScriptEnginePrivate::registerClass(const QString &name) +{ + return registerClass(name, -1); +} + +inline QScriptValueImpl QScriptEnginePrivate::createFunction(QScriptInternalFunctionSignature fun, + int length, QScriptClassInfo *classInfo, const QString &name) +{ + return createFunction(new QScript::C2Function(fun, length, classInfo, name)); +} + +inline void QScriptEnginePrivate::newFunction(QScriptValueImpl *o, QScriptFunction *function) +{ + QScriptValueImpl proto; + if (functionConstructor) + proto = functionConstructor->publicPrototype; + else { + // creating the Function prototype object + Q_ASSERT(objectConstructor); + proto = objectConstructor->publicPrototype; + } + newObject(o, proto, m_class_function); + o->setObjectData(function); +} + +inline void QScriptEnginePrivate::newConstructor(QScriptValueImpl *ctor, + QScriptFunction *function, + QScriptValueImpl &proto) +{ + newFunction(ctor, function); + ctor->setProperty(m_id_table.id_prototype, proto, + QScriptValue::Undeletable + | QScriptValue::ReadOnly + | QScriptValue::SkipInEnumeration); + proto.setProperty(m_id_table.id_constructor, *ctor, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); +} + +inline void QScriptEnginePrivate::newArguments(QScriptValueImpl *object, + const QScriptValueImpl &activation, + uint length, + const QScriptValueImpl &callee) +{ + QScript::ArgumentsObjectData *data = new QScript::ArgumentsObjectData(); + data->activation = activation; + data->length = length; + newObject(object, m_class_arguments); + object->setObjectData(data); + object->setProperty(m_id_table.id_callee, callee, + QScriptValue::SkipInEnumeration); + object->setProperty(m_id_table.id_length, QScriptValueImpl(length), + QScriptValue::SkipInEnumeration); +} + +inline QScriptFunction *QScriptEnginePrivate::convertToNativeFunction(const QScriptValueImpl &object) +{ + if (object.isFunction()) + return static_cast<QScriptFunction*> (object.objectData()); + return 0; +} + +inline QScriptValue QScriptEnginePrivate::toPublic(const QScriptValueImpl &value) +{ + if (!value.isValid()) + return QScriptValue(); + + QScriptValuePrivate *p = registerValue(value); + QScriptValue v; + QScriptValuePrivate::init(v, p); + return v; +} + +inline QScriptValueImpl QScriptEnginePrivate::toImpl(const QScriptValue &value) +{ + QScriptValuePrivate *p = QScriptValuePrivate::get(value); + if (!p) + return QScriptValueImpl(); + if (p->value.type() == QScript::LazyStringType) + return toImpl_helper(value); + return p->value; +} + +inline QScriptValueImplList QScriptEnginePrivate::toImplList(const QScriptValueList &lst) +{ + QScriptValueImplList result; + QScriptValueList::const_iterator it; + for (it = lst.constBegin(); it != lst.constEnd(); ++it) + result.append(toImpl(*it)); + return result; +} + +inline QScriptValueImpl QScriptEnginePrivate::toObject(const QScriptValueImpl &value) +{ + if (value.isObject() || !value.isValid()) + return value; + return toObject_helper(value); +} + +inline QScriptValueImpl QScriptEnginePrivate::toPrimitive(const QScriptValueImpl &object, + QScriptValueImpl::TypeHint hint) +{ + Q_ASSERT(object.isValid()); + + if (! object.isObject()) + return object; + + return toPrimitive_helper(object, hint); +} + +inline QDateTime QScriptEnginePrivate::toDateTime(const QScriptValueImpl &value) const +{ + return dateConstructor->toDateTime(value); +} + +inline void QScriptEnginePrivate::newArray(QScriptValueImpl *object, const QScript::Array &value) +{ + arrayConstructor->newArray(object, value); +} + +inline void QScriptEnginePrivate::newObject(QScriptValueImpl *o, const QScriptValueImpl &proto, + QScriptClassInfo *oc) +{ + Q_ASSERT(o != 0); + + QScriptObject *od = allocObject(); + od->reset(); + od->m_id = ++m_next_object_id; + if (proto.isValid()) + od->m_prototype = proto; + else { + Q_ASSERT(objectConstructor); + od->m_prototype = objectConstructor->publicPrototype; + } + + o->m_type = QScript::ObjectType; + od->m_class = (oc ? oc : m_class_object); + o->m_object_value = od; +} + +inline void QScriptEnginePrivate::newObject(QScriptValueImpl *o, QScriptClassInfo *oc) +{ + newObject(o, objectConstructor->publicPrototype, oc); +} + +inline QScriptValueImpl QScriptEnginePrivate::newObject() +{ + QScriptValueImpl v; + newObject(&v); + return v; +} + +inline void QScriptEnginePrivate::newVariant(QScriptValueImpl *out, + const QVariant &value, + bool setDefaultPrototype) +{ + Q_ASSERT(variantConstructor != 0); + variantConstructor->newVariant(out, value); + if (setDefaultPrototype) { + QScriptValueImpl proto = defaultPrototype(value.userType()); + if (proto.isValid()) + out->setPrototype(proto); + } +} + +#ifndef QT_NO_QOBJECT +# ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE +inline QScriptMetaObject *QScriptEnginePrivate::cachedMetaObject(const QMetaObject *meta) +{ + QScriptMetaObject *value = m_cachedMetaObjects.value(meta); + if (!value) { + value = new QScriptMetaObject; + m_cachedMetaObjects.insert(meta, value); + } + return value; +} +# endif +#endif // !QT_NO_QOBJECT + +inline QScriptNameIdImpl *QScriptEnginePrivate::nameId(const QString &str, bool persistent) +{ + QScriptNameIdImpl *entry = toStringEntry(str); + if (! entry) + entry = insertStringEntry(str); + + Q_ASSERT(entry->unique); + + if (persistent) + entry->persistent = true; + + return entry; +} + +inline QScriptNameIdImpl *QScriptEnginePrivate::intern(const QChar *u, int s) +{ + QString tmp(u, s); + return nameId(tmp, /*persistent=*/ true); +} + +inline QScriptValueImpl QScriptEnginePrivate::valueFromVariant(const QVariant &v) +{ + QScriptValueImpl result = create(v.userType(), v.data()); + Q_ASSERT(result.isValid()); + return result; +} + +inline QScriptValueImpl QScriptEnginePrivate::undefinedValue() +{ + return m_undefinedValue; +} + +inline QScriptValueImpl QScriptEnginePrivate::nullValue() +{ + return m_nullValue; +} + +inline QScriptValueImpl QScriptEnginePrivate::defaultPrototype(int metaTypeId) const +{ + QScriptCustomTypeInfo info = m_customTypes.value(metaTypeId); + return info.prototype; +} + +inline void QScriptEnginePrivate::setDefaultPrototype(int metaTypeId, const QScriptValueImpl &prototype) +{ + QScriptCustomTypeInfo info = m_customTypes.value(metaTypeId); + info.prototype = prototype; + m_customTypes.insert(metaTypeId, info); +} + +inline uint _q_scriptHash(const QString &key) +{ + const QChar *p = key.unicode(); + int n = qMin(key.size(), 128); + uint h = key.size(); + uint g; + + while (n--) { + h = (h << 4) + (*p++).unicode(); + if ((g = (h & 0xf0000000)) != 0) + h ^= g >> 23; + h &= ~g; + } + return h; +} + +inline QScriptNameIdImpl *QScriptEnginePrivate::toStringEntry(const QString &s) +{ + uint h = _q_scriptHash(s) % m_string_hash_size; + + for (QScriptNameIdImpl *entry = m_string_hash_base[h]; entry && entry->h == h; entry = entry->next) { + if (entry->s == s) + return entry; + } + + return 0; +} + +inline bool QScriptEnginePrivate::lessThan(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + return QScriptContextPrivate::lt_cmp(lhs, rhs); +} + +inline bool QScriptEnginePrivate::equals(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + return QScriptContextPrivate::eq_cmp(lhs, rhs); +} + +inline bool QScriptEnginePrivate::strictlyEquals(const QScriptValueImpl &lhs, const QScriptValueImpl &rhs) +{ + return QScriptContextPrivate::strict_eq_cmp(lhs, rhs); +} + +inline void QScriptEnginePrivate::unregisterValue(QScriptValuePrivate *p) +{ + QScriptValueImpl &v = p->value; + Q_ASSERT(v.isValid()); + if (v.isString()) { + QScriptNameIdImpl *id = v.stringValue(); + m_stringHandles.remove(id); + } else if (v.isObject()) { + QScriptObject *instance = v.objectValue(); + m_objectHandles.remove(instance); + } else { + int i = m_otherHandles.indexOf(p); + Q_ASSERT(i != -1); + m_otherHandles.remove(i); + } + m_handleRepository.release(p); +} + +inline QScriptValueImpl QScriptEnginePrivate::globalObject() const +{ + return m_globalObject; +} + +inline bool QScriptEnginePrivate::hasUncaughtException() const +{ + return (currentContext()->state() == QScriptContext::ExceptionState); +} + +inline QScriptValueImpl QScriptEnginePrivate::uncaughtException() const +{ + if (!hasUncaughtException()) + return QScriptValueImpl(); + return currentContext()->returnValue(); +} + +inline void QScriptEnginePrivate::maybeProcessEvents() +{ + if (m_processEventsInterval > 0 && ++m_processEventIncr > 512) { + m_processEventIncr = 0; + processEvents(); + } +} + +inline bool QScriptEnginePrivate::shouldAbort() const +{ + return m_abort; +} + +inline void QScriptEnginePrivate::resetAbortFlag() +{ + m_abort = false; +} + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + +inline bool QScriptEnginePrivate::shouldNotify() const +{ + return m_agent != 0; +} + +inline void QScriptEnginePrivate::notifyScriptLoad( + qint64 id, const QString &program, + const QString &fileName, int lineNumber) +{ + if (shouldNotify()) + notifyScriptLoad_helper(id, program, fileName, lineNumber); +} + +inline void QScriptEnginePrivate::notifyScriptUnload(qint64 id) +{ + if (shouldNotify()) + notifyScriptUnload_helper(id); +} + +inline void QScriptEnginePrivate::notifyPositionChange(QScriptContextPrivate *ctx) +{ + Q_ASSERT(m_agent != 0); + notifyPositionChange_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyContextPush() +{ + if (shouldNotify()) + notifyContextPush_helper(); +} + +inline void QScriptEnginePrivate::notifyContextPop() +{ + if (shouldNotify()) + notifyContextPop_helper(); +} + +inline void QScriptEnginePrivate::notifyFunctionEntry(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyFunctionEntry_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyFunctionExit(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyFunctionExit_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyException(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyException_helper(ctx); +} + +inline void QScriptEnginePrivate::notifyExceptionCatch(QScriptContextPrivate *ctx) +{ + if (shouldNotify()) + notifyExceptionCatch_helper(ctx); +} + +#endif // Q_SCRIPT_NO_EVENT_NOTIFY + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT + +#endif |