diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/script/qscriptcontext_p.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/script/qscriptcontext_p.cpp')
-rw-r--r-- | src/script/qscriptcontext_p.cpp | 2598 |
1 files changed, 2598 insertions, 0 deletions
diff --git a/src/script/qscriptcontext_p.cpp b/src/script/qscriptcontext_p.cpp new file mode 100644 index 0000000..199c9d4 --- /dev/null +++ b/src/script/qscriptcontext_p.cpp @@ -0,0 +1,2598 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include <QtCore/QtDebug> + +#ifndef QT_NO_SCRIPT + +#include "qscriptcontext_p.h" +#include "qscriptengine_p.h" +#include "qscriptvalueimpl_p.h" +#include "qscriptmember_p.h" +#include "qscriptobject_p.h" +#include "qscriptprettypretty_p.h" +#include "qscriptast_p.h" +#include "qscriptnodepool_p.h" +#include "qscriptcompiler_p.h" +#include "qscriptextenumeration_p.h" + +#include <math.h> // floor & friends... + +QT_BEGIN_NAMESPACE + +#define Q_SCRIPT_NO_PRINT_GENERATED_CODE + +#define Q_SCRIPT_NO_JOINED_FUNCTION + +#define CHECK_TEMPSTACK(needed) do { \ + if (stackPtr + needed >= eng->tempStackEnd) { \ + throwError(QLatin1String("out of memory")); \ + HandleException(); \ + } \ +} while (0) + +#ifndef Q_SCRIPT_NO_PRINT_GENERATED_CODE +static QTextStream qout(stderr, QIODevice::WriteOnly); +#endif + +static inline void qscript_uint_to_string_helper(uint i, QString &s) +{ + switch (i) { + case 0: case 1: case 2: case 3: case 4: + case 5: case 6: case 7: case 8: case 9: + s += QLatin1Char('0' + i); + break; + + default: + qscript_uint_to_string_helper(i / 10, s); + s += QLatin1Char('0' + (i % 10)); + } +} + +static inline void qscript_uint_to_string(qsreal i, QString &s) +{ + if ((i < 0) || (i > 0xFFFFFFFF)) + return; // nothing to do + + qsreal x = ::fmod(i, 10); + + if (x != 0.0 && x != 1.0 + && x != 2.0 && x != 3.0 + && x != 4.0 && x != 5.0 + && x != 6.0 && x != 7.0 + && x != 8.0 && x != 9.0) + return; // nothing to do + + qscript_uint_to_string_helper(uint(i), s); +} + +static inline quint32 toArrayIndex(const QScriptValueImpl &v) +{ + if (v.isNumber()) { + quint32 ui = v.toUInt32(); + if (qsreal(ui) == v.m_number_value) + return ui; + } else if (v.isString()) { + QByteArray bytes = v.m_string_value->s.toUtf8(); + char *eptr; + quint32 pos = strtoul(bytes.constData(), &eptr, 10); + if ((eptr == bytes.constData() + bytes.size()) + && (QByteArray::number(pos) == bytes)) { + return pos; + } + } + return 0xFFFFFFFF; +} + +#define CREATE_MEMBER(__obj__, __name__, __member__, __flags__) do { \ + (__obj__).createMember(__name__, __member__, __flags__); \ + eng->adjustBytesAllocated(sizeof(QScript::Member) + sizeof(QScriptValueImpl)); \ +} while (0) + +#define BEGIN_PREFIX_OPERATOR \ + QScriptValue::ResolveFlags mode; \ + mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) \ + | QScriptValue::ResolvePrototype; \ + --stackPtr; \ + QScriptValueImpl object = eng->toObject(stackPtr[-1]); \ + if (!object.isObject()) { \ + stackPtr -= 2; \ + throwTypeError(QLatin1String("not an object")); \ + HandleException(); \ + } \ + QScriptNameIdImpl *memberName = 0; \ + if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) \ + memberName = stackPtr[0].m_string_value; \ + else \ + memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); \ + QScript::Member member; \ + QScriptValueImpl base; \ + QScriptValueImpl value; \ + QScriptValueImpl getter; \ + QScriptValueImpl setter; \ + const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); \ + if (object.resolve(memberName, &member, &base, mode, QScript::ReadWrite)) { \ + base.get(member, &value); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + HandleException(); \ + } else if (member.isGetterOrSetter()) { \ + if (member.isGetter()) { \ + getter = value; \ + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { \ + stackPtr -= 2; \ + throwError(QLatin1String("No setter defined")); \ + HandleException(); \ + } \ + base.get(member, &setter); \ + } else { \ + setter = value; \ + QScript::Member tmp = member; \ + if (!base.m_object_value->findGetter(&member)) { \ + stackPtr -= 2; \ + throwError(QLatin1String("No getter defined")); \ + HandleException(); \ + } \ + base.get(member, &getter); \ + member = tmp; \ + } \ + value = getter.call(object); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + Done(); \ + } \ + } \ + } else if (!isMemberAssignment) { \ + stackPtr -= 2; \ + throwNotDefined(memberName); \ + HandleException(); \ + } else { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + value = undefined; \ + } + +#define END_PREFIX_OPERATOR \ + if (member.isSetter()) { \ + setter.call(object, QScriptValueImplList() << value); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + Done(); \ + } \ + } else { \ + if (member.isWritable()) { \ + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + } \ + base.put(member, value); \ + if (hasUncaughtException()) { \ + stackPtr -= 2; \ + HandleException(); \ + } \ + } \ + } \ + *--stackPtr = value; \ + ++iPtr; + +#define BEGIN_INPLACE_OPERATOR \ + if (! stackPtr[-1].isReference()) { \ + stackPtr -= 2; \ + throwSyntaxError(QLatin1String("invalid assignment lvalue")); \ + HandleException(); \ + } \ + QScriptValue::ResolveFlags mode; \ + mode = QScriptValue::ResolveFlags(stackPtr[-1].m_int_value) \ + | QScriptValue::ResolvePrototype; \ + QScriptValueImpl object = eng->toObject(stackPtr[-3]); \ + if (! object.isValid()) { \ + stackPtr -= 4; \ + throwTypeError(QLatin1String("not an object")); \ + HandleException(); \ + } \ + QScriptNameIdImpl *memberName = 0; \ + if (stackPtr[-2].isString() && stackPtr[-2].m_string_value->unique) \ + memberName = stackPtr[-2].m_string_value; \ + else \ + memberName = eng->nameId(stackPtr[-2].toString(), /*persistent=*/false); \ + QScriptValueImpl lhs; \ + QScriptValueImpl base; \ + QScript::Member member; \ + QScriptValueImpl getter; \ + QScriptValueImpl setter; \ + const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); \ + if (object.resolve(memberName, &member, &base, mode, QScript::ReadWrite)) { \ + base.get(member, &lhs); \ + if (hasUncaughtException()) { \ + stackPtr -= 4; \ + HandleException(); \ + } else if (member.isGetterOrSetter()) { \ + if (member.isGetter()) { \ + getter = lhs; \ + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { \ + stackPtr -= 4; \ + throwError(QLatin1String("No setter defined")); \ + HandleException(); \ + } \ + base.get(member, &setter); \ + } else { \ + setter = lhs; \ + QScript::Member tmp = member; \ + if (!base.m_object_value->findGetter(&member)) { \ + stackPtr -= 4; \ + throwError(QLatin1String("No getter defined")); \ + HandleException(); \ + } \ + base.get(member, &getter); \ + member = tmp; \ + } \ + lhs = getter.call(object); \ + if (hasUncaughtException()) { \ + stackPtr -= 4; \ + Done(); \ + } \ + } \ + } else if (!isMemberAssignment) { \ + stackPtr -= 4; \ + throwNotDefined(memberName); \ + HandleException(); \ + } else { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + lhs = undefined; \ + } \ + QScriptValueImpl rhs = stackPtr[0]; + +#define END_INPLACE_OPERATOR \ + if (member.isSetter()) { \ + setter.call(object, QScriptValueImplList() << *stackPtr); \ + if (hasUncaughtException()) { \ + stackPtr -= 1; \ + Done(); \ + } \ + } else { \ + if (member.isWritable()) { \ + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { \ + base = object; \ + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \ + } \ + base.put(member, *stackPtr); \ + if (hasUncaughtException()) { \ + stackPtr -= 1; \ + HandleException(); \ + } \ + } \ + } \ + ++iPtr; + +namespace QScript { + +void ScriptFunction::execute(QScriptContextPrivate *context) +{ + if (! m_compiledCode) { + QScriptEnginePrivate *eng = context->engine(); + Compiler compiler(eng); + + CompilationUnit unit = compiler.compile(m_definition->body, formals); + if (! unit.isValid()) { + context->throwError(unit.errorMessage()); + return; + } + + m_compiledCode = m_astPool->createCompiledCode(m_definition->body, unit); + } + + context->execute(m_compiledCode); +} + +QString ScriptFunction::toString(QScriptContextPrivate *) const +{ + QString str; + QTextStream out(&str, QIODevice::WriteOnly); + PrettyPretty pp(out); + pp(m_definition, /*indent=*/ 0); + return str; +} + +QString ScriptFunction::fileName() const +{ + return m_astPool->fileName(); +} + +QString ScriptFunction::functionName() const +{ + if (!m_definition->name) + return QString(); + return m_definition->name->s; +} + +int ScriptFunction::startLineNumber() const +{ + return m_definition->startLine; +} + +int ScriptFunction::endLineNumber() const +{ + return m_definition->endLine; +} + +} // namespace QScript + +/*! + \internal + + Resolves and gets the value specified by \a stackPtr. + stackPtr[0] contains the member specifier, stackPtr[-1] contains the object. + If the member can be resolved, sets \a value to the value of that member, + otherwise returns false. +*/ +bool QScriptContextPrivate::resolveField(QScriptEnginePrivate *eng, + QScriptValueImpl *stackPtr, + QScriptValueImpl *value) +{ + const QScriptValueImpl &m = stackPtr[0]; + QScriptValueImpl &object = stackPtr[-1]; + + if (! object.isObject()) + object = eng->toObject(object); + + if (! object.isValid()) + return false; + + if (QScript::Ecma::Array::Instance *arrayInstance = eng->arrayConstructor->get(object)) { + quint32 pos = toArrayIndex(m); + if (pos != 0xFFFFFFFF) { + *value = arrayInstance->value.at(pos); + + if (! value->isValid()) + *value = eng->undefinedValue(); + + return true; + } + } + + QScriptNameIdImpl *nameId = m.isString() ? m.m_string_value : 0; + + if (! nameId || ! nameId->unique) + nameId = eng->nameId(QScriptEnginePrivate::convertToNativeString(m), /*persistent=*/false); // ### slow! + + QScript::Member member; + QScriptValueImpl base; + + if (! object.resolve(nameId, &member, &base, QScriptValue::ResolveFull, QScript::Read)) // ### ... + return false; + + if (QScriptEnginePrivate::strictlyEquals(base, eng->m_globalObject)) + stackPtr[-1] = base; + else if (object.classInfo() == eng->m_class_with) + stackPtr[-1] = object.prototype(); + + base.get(member, value); + + if (member.isGetterOrSetter()) { + // call the getter function + QScriptValueImpl getter; + if (member.isGetter()) { + getter = *value; + } else { + if (!base.m_object_value->findGetter(&member)) { + *value = eng->undefinedValue(); + return true; + } + base.get(member, &getter); + } + *value = getter.call(object); + } + + return true; +} + +void QScriptContextPrivate::execute(QScript::Code *code) +{ + int oldCurrentLine = currentLine; + int oldCurrentColumn = currentColumn; + QScript::Code *oldCode = m_code; + m_code = code; + +#ifndef Q_SCRIPT_NO_PRINT_GENERATED_CODE + qout << QLatin1String("function:") << endl; + for (QScriptInstruction *current = code->firstInstruction; current != code->lastInstruction; ++current) { + qout << int(current - code->firstInstruction) << QLatin1String(":\t"); + current->print(qout); + qout << endl; + } + qout << endl; +#endif + + QScriptEnginePrivate *eng = engine(); + + bool wasEvaluating = eng->m_evaluating; + if (!wasEvaluating) { + eng->setupProcessEvents(); + eng->resetAbortFlag(); + } + eng->m_evaluating = true; + + // set up the temp stack + if (! tempStack) + stackPtr = tempStack = eng->tempStackBegin; + + QScriptValueImpl undefined(eng->undefinedValue()); + + catching = false; + m_state = QScriptContext::NormalState; + m_result = undefined; + firstInstruction = code->firstInstruction; + lastInstruction = code->lastInstruction; + iPtr = code->firstInstruction; + + if (!m_scopeChain.isValid()) + m_scopeChain = m_activation; + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyFunctionEntry(this); +#endif + +#ifndef Q_SCRIPT_DIRECT_CODE + +# define I(opc) case QScriptInstruction::OP_##opc +# define Next() goto Lfetch +# define Done() goto Ldone +# define HandleException() goto Lhandle_exception +# define Abort() goto Labort + +Lfetch: + + +#else + +# define I(opc) qscript_execute_##opc +# define Next() goto *iPtr->code +# define Done() goto Ldone +# define HandleException() goto Lhandle_exception +# define Abort() goto Labort + + static void * const jump_table[] = { + +# define Q_SCRIPT_DEFINE_OPERATOR(op) &&I(op), +# include "instruction.table" +# undef Q_SCRIPT_DEFINE_OPERATOR + }; // jump_table + + + if (!code->optimized) { + for (QScriptInstruction *current = code->firstInstruction; current != code->lastInstruction; ++current) { + current->code = jump_table[current->op]; + } + + code->optimized = true; + } + +#endif +Ltop: + +#ifndef Q_SCRIPT_DIRECT_CODE + switch (iPtr->op) { +#else + goto *iPtr->code; +#endif + + I(Nop): + { + ++iPtr; + } Next(); + + I(LoadUndefined): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = undefined; + ++iPtr; + } Next(); + + I(LoadTrue): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = QScriptValueImpl(true); + ++iPtr; + } Next(); + + I(LoadFalse): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = QScriptValueImpl(false); + ++iPtr; + } Next(); + + I(LoadThis): + { + CHECK_TEMPSTACK(1); + Q_ASSERT(m_thisObject.isObject()); + *++stackPtr = m_thisObject; + ++iPtr; + } Next(); + + I(LoadActivation): + { + CHECK_TEMPSTACK(1); + *++stackPtr = m_activation; + ++iPtr; + } Next(); + + I(LoadNull): + { + CHECK_TEMPSTACK(1); + *(++stackPtr) = eng->nullValue(); + ++iPtr; + } Next(); + + I(LoadNumber): + { + CHECK_TEMPSTACK(1); + *++stackPtr = iPtr->operand[0]; + ++iPtr; + } Next(); + + + I(LoadString): + { + CHECK_TEMPSTACK(1); + *++stackPtr = iPtr->operand[0]; + ++iPtr; + } Next(); + + I(NewString): + { + CHECK_TEMPSTACK(1); + eng->newNameId(++stackPtr, iPtr->operand[0].m_string_value); + ++iPtr; + } Next(); + + I(Duplicate): + { + CHECK_TEMPSTACK(1); + ++stackPtr; + *stackPtr = stackPtr[-1]; + ++iPtr; + } Next(); + + I(Swap): + { + QScriptValueImpl tmp = stackPtr[0]; + *stackPtr = stackPtr[-1]; + stackPtr[-1] = tmp; + ++iPtr; + } Next(); + + + I(Receive): + { + int n = iPtr->operand[0].m_int_value; + + if (n >= argc) { + throwError(QLatin1String("invalid argument")); + HandleException(); + } + + CHECK_TEMPSTACK(1); + *++stackPtr = argument(n); + ++iPtr; + } Next(); + + I(Fetch): + { + CHECK_TEMPSTACK(1); + + QScriptNameIdImpl *memberName = iPtr->operand[0].m_string_value; + + QScriptValueImpl base; + QScript::Member member; + + QScriptObject *instance = m_scopeChain.m_object_value; + if (instance->findMember(memberName, &member)) { + instance->get(member, ++stackPtr); + base = m_scopeChain; + } else { + if (m_scopeChain.resolve_helper(memberName, &member, &base, QScriptValue::ResolveFull, QScript::Read)) { + base.get(member, ++stackPtr); + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } + } else { + throwNotDefined(memberName); + HandleException(); + } + } + if (member.isGetterOrSetter()) { + // locate the getter function + QScriptValueImpl getter; + if (member.isGetter()) { + getter = *stackPtr; + } else { + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 1; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + } + // decide the this-object. This is the object that actually + // has the getter (in its prototype chain). + QScriptValueImpl object = m_scopeChain; + while (!object.resolve(memberName, &member, &base, QScriptValue::ResolvePrototype, QScript::Read)) + object = object.scope(); + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + + *stackPtr = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 1; + Done(); + } + } + ++iPtr; + } Next(); + + I(Resolve): + { + Q_ASSERT(iPtr->operand[0].isString()); + + CHECK_TEMPSTACK(2); + *++stackPtr = m_scopeChain; + *++stackPtr = iPtr->operand[0]; + eng->newReference(++stackPtr, QScriptValue::ResolveScope); + ++iPtr; + } Next(); + + I(PutField): + { + Q_ASSERT(stackPtr[-1].isReference()); + + const QScriptValueImpl &object = stackPtr[-3]; + QScriptNameIdImpl *memberName = stackPtr[-2].m_string_value; + const QScriptValueImpl &value = stackPtr[0]; + + QScript::Member member; + QScriptValueImpl base; + + if (! object.resolve(memberName, &member, &base, QScriptValue::ResolveLocal, QScript::Write)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + + base.put(member, value); + stackPtr -= 4; + if (hasUncaughtException()) + HandleException(); + ++iPtr; + } Next(); + + I(Call): + { + int argc = iPtr->operand[0].m_int_value; + QScriptValueImpl *argp = stackPtr - argc; + + QScriptValueImpl base; + QScriptValueImpl callee; + + bool isReference = argp[0].isReference(); + + if (! isReference) { // we have a value + base = eng->m_globalObject; + callee = argp[0]; + } else if (resolveField(eng, &argp[-1], &callee)) { + if (hasUncaughtException()) { + stackPtr = argp - 3; + HandleException(); + } + base = argp[-2]; + } else { + QScriptValueImpl member = argp[-1]; + stackPtr = argp - 1; + Q_ASSERT(isReference); + stackPtr -= 2; + + if (member.isString()) + throwNotDefined(member.toString()); + else + throwNotDefined(QLatin1String("function")); + HandleException(); + } + + Q_ASSERT(base.isValid()); + Q_ASSERT(callee.isValid()); + + QScriptFunction *function = QScriptEnginePrivate::convertToNativeFunction(callee); + if (! function) { + QScriptValueImpl member = argp[-1]; + QString message; + if (member.isString()) { + message = QString::fromLatin1("%0 is not a function") + .arg(member.toString()); + } else { + message = QLatin1String("not a function"); + } + throwTypeError(message); + HandleException(); + } + + if (++eng->m_callDepth == eng->m_maxCallDepth) { + throwError(QLatin1String("call stack overflow")); + HandleException(); + } + + QScriptContextPrivate *nested_data = eng->pushContext(); + nested_data->m_thisObject = base; + nested_data->m_callee = callee; + + // create the activation + eng->newActivation(&nested_data->m_activation); + QScriptObject *activation_data = nested_data->m_activation.m_object_value; + + int formalCount = function->formals.count(); + int mx = qMax(formalCount, argc); + activation_data->m_members.resize(mx); + activation_data->m_values.resize(mx); + for (int i = 0; i < mx; ++i) { + QScriptNameIdImpl *nameId = 0; + if (i < formalCount) + nameId = function->formals.at(i); + + activation_data->m_members[i].object(nameId, i, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + activation_data->m_values[i] = (i < argc) ? argp[i + 1] : undefined; + } + + nested_data->argc = argc; + if (callee.m_object_value->m_scope.isValid()) + activation_data->m_scope = callee.m_object_value->m_scope; + else + activation_data->m_scope = eng->m_globalObject; + nested_data->tempStack = stackPtr; + nested_data->args = &argp[1]; + + function->execute(nested_data); + + --eng->m_callDepth; + + stackPtr = argp - 1; + if (isReference) + stackPtr -= 2; + + if (nested_data->m_state == QScriptContext::ExceptionState) { + eng->popContext(); + if (eng->shouldAbort()) + Abort(); + else + Done(); + } + + CHECK_TEMPSTACK(1); + *++stackPtr = nested_data->m_result; + + eng->popContext(); + + if (eng->shouldAbort()) + Abort(); + + if (eng->m_processEventsInterval > 0) + eng->processEvents(); + + ++iPtr; + } Next(); + + + I(NewArray): + { + CHECK_TEMPSTACK(1); + eng->arrayConstructor->newArray(++stackPtr, QScript::Array(eng)); + ++iPtr; + } Next(); + + I(NewRegExp): + { + CHECK_TEMPSTACK(1); + + QString pattern = eng->toString(iPtr->operand[0].m_string_value); +#ifndef QT_NO_REGEXP + QString literal = pattern; +#endif + int flags = 0; + if (iPtr->operand[1].isValid()) { + flags = iPtr->operand[1].m_int_value; +#ifndef QT_NO_REGEXP + if (flags != 0) { + literal += QLatin1String("/"); + literal += QString::number(flags); + } +#endif + } + +#ifndef QT_NO_REGEXP + QRegExp rx; + // lazy compilation of regexp literals + QHash<QString, QRegExp>::const_iterator it; + it = eng->m_regExpLiterals.constFind(literal); + if (it == eng->m_regExpLiterals.constEnd()) { + rx = QScript::Ecma::RegExp::toRegExp(pattern, flags); + eng->m_regExpLiterals.insert(literal, rx); + } else { + rx = *it; + } + eng->regexpConstructor->newRegExp(++stackPtr, rx, flags); +#else + eng->regexpConstructor->newRegExp(++stackPtr, pattern, flags); +#endif + ++iPtr; + } Next(); + + I(NewObject): + { + CHECK_TEMPSTACK(1); + eng->objectConstructor->newObject(++stackPtr); + ++iPtr; + } Next(); + + I(New): + { + int argc = iPtr->operand[0].m_int_value; + QScriptValueImpl *argp = stackPtr - argc; + + // QScriptValueImpl base; + QScriptValueImpl callee; + + bool isReference = argp[0].isReference(); + + if (! isReference) { // we have a value + // base = eng->globalObject; + callee = argp[0]; + } else if (resolveField(eng, &argp[-1], &callee)) { + // base = argp[-2]; + if (hasUncaughtException()) { + stackPtr = argp - 3; + HandleException(); + } + } else { + QScriptValueImpl member = argp[-1]; + stackPtr = argp - 1; + Q_ASSERT(isReference); + stackPtr -= 2; + + if (member.isString()) + throwNotDefined(member.toString()); + else + throwNotDefined(QLatin1String("constructor")); + HandleException(); + } + + // Q_ASSERT(base.isValid()); + Q_ASSERT(callee.isValid()); + + QScriptFunction *function = QScriptEnginePrivate::convertToNativeFunction(callee); + if (! function) { + QScriptValueImpl member = argp[-1]; + QString message; + if (member.isString()) { + message = QString::fromLatin1("%0 is not a constructor") + .arg(member.toString()); + } else { + message = QLatin1String("not a constructor"); + } + throwTypeError(message); + HandleException(); + } + + if (++eng->m_callDepth == eng->m_maxCallDepth) { + throwError(QLatin1String("call stack overflow")); + HandleException(); + } + + QScriptContextPrivate *nested_data = eng->pushContext(); + nested_data->m_callee = callee; + nested_data->m_calledAsConstructor = true; + + // create the activation + eng->newActivation(&nested_data->m_activation); + QScriptObject *activation_data = nested_data->m_activation.m_object_value; + + int formalCount = function->formals.count(); + int mx = qMax(formalCount, argc); + activation_data->m_members.resize(mx); + activation_data->m_values.resize(mx); + for (int i = 0; i < mx; ++i) { + QScriptNameIdImpl *nameId = 0; + if (i < formalCount) + nameId = function->formals.at(i); + + activation_data->m_members[i].object(nameId, i, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + activation_data->m_values[i] = (i < argc) ? argp[i + 1] : undefined; + } + + eng->objectConstructor->newObject(&nested_data->m_thisObject); + nested_data->argc = argc; + if (callee.m_object_value->m_scope.isValid()) + activation_data->m_scope = callee.m_object_value->m_scope; + else + activation_data->m_scope = eng->m_globalObject; + nested_data->tempStack = stackPtr; + nested_data->args = &argp[1]; + nested_data->m_result = undefined; + + QScriptObject *instance = nested_data->m_thisObject.m_object_value; + + // set [[prototype]] + QScriptValueImpl dummy; + QScript::Member proto; + if (callee.resolve(eng->idTable()->id_prototype, &proto, &dummy, QScriptValue::ResolveLocal, QScript::Read)) + callee.get(proto, &instance->m_prototype); + if (!instance->m_prototype.isObject()) + instance->m_prototype = eng->objectConstructor->publicPrototype; + + function->execute(nested_data); + + --eng->m_callDepth; + + stackPtr = argp - 1; + if (isReference) + stackPtr -= 2; + + if (! nested_data->m_result.isValid()) + nested_data->m_result = undefined; + else if (! nested_data->m_result.isObject()) + nested_data->m_result = nested_data->m_thisObject; + + if (nested_data->m_state == QScriptContext::ExceptionState) { + eng->popContext(); + if (eng->shouldAbort()) + Abort(); + else + Done(); + } + + CHECK_TEMPSTACK(1); + + *++stackPtr = nested_data->m_result; + + eng->popContext(); + + if (eng->shouldAbort()) + Abort(); + + if (eng->m_processEventsInterval > 0) + eng->processEvents(); + + ++iPtr; + } Next(); + + I(FetchField): + { + QScriptValueImpl object = eng->toObject(stackPtr[-1]); + if (! object.isValid()) { + stackPtr -= 2; + throwTypeError(QLatin1String("not an object")); + HandleException(); + } + + QScriptValueImpl m = stackPtr[0]; + + QScript::Ecma::Array::Instance *arrayInstance = 0; + if (object.classInfo() == eng->arrayConstructor->classInfo()) + arrayInstance = static_cast<QScript::Ecma::Array::Instance *> (object.m_object_value->m_data); + + if (arrayInstance) { + quint32 pos = toArrayIndex(m); + if (pos != 0xFFFFFFFF) { + QScriptValueImpl val = arrayInstance->value.at(pos); + if (val.isValid()) { + *--stackPtr = val; + ++iPtr; + Next(); + } + } + } + + QScriptNameIdImpl *nameId = m.isString() ? m.m_string_value : 0; + + if (! nameId || ! nameId->unique) { + QString str; + + if (m.isNumber()) + qscript_uint_to_string(m.m_number_value, str); + + if (str.isEmpty()) + str = QScriptEnginePrivate::convertToNativeString(m); + + nameId = eng->nameId(str, /*persistent=*/false); + } + + QScript::Member member; + QScriptValueImpl base; + + if (object.resolve(nameId, &member, &base, QScriptValue::ResolvePrototype, QScript::Read)) { + base.get(member, --stackPtr); + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } else if (member.isGetterOrSetter()) { + // call the getter function + QScriptValueImpl getter; + if (member.isGetter()) { + getter = *stackPtr; + } else { + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 1; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + } + *stackPtr = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 1; + Done(); + } + } + } else { + *(--stackPtr) = undefined; + } + + ++iPtr; + } Next(); + + I(LazyArguments): + { + QScript::Member member; + QScriptValueImpl base; + QScriptNameIdImpl *arguments = eng->idTable()->id_arguments; + if (!m_activation.resolve(arguments, &member, &base, QScriptValue::ResolveLocal, QScript::Read)) { + CREATE_MEMBER(m_activation, arguments, &member, QScriptValue::Undeletable); + if (!m_arguments.isValid()) { + if (eng->strictlyEquals(m_activation, eng->globalObject())) + m_arguments = undefined; + else + eng->newArguments(&m_arguments, m_activation, argc, m_callee); + } + m_activation.put(member, m_arguments); + } + ++iPtr; + } Next(); + + I(DeclareLocal): + { + QScriptValueImpl &act = m_activation; + + QScriptNameIdImpl *memberName = iPtr->operand[0].m_string_value; + bool readOnly = iPtr->operand[1].m_int_value != 0; + QScript::Member member; + QScriptValueImpl object; + + if (! act.resolve(memberName, &member, &object, QScriptValue::ResolveLocal, QScript::ReadWrite)) { + uint flags = QScriptValue::Undeletable; + if (readOnly) + flags |= QScript::Member::UninitializedConst | QScriptValue::ReadOnly; + CREATE_MEMBER(act, memberName, &member, flags); + act.put(member, undefined); + } + ++iPtr; + } Next(); + + I(Assign): + { + if (! stackPtr[-1].isReference()) { + stackPtr -= 2; + throwSyntaxError(QLatin1String("invalid assignment lvalue")); + HandleException(); + } + + QScriptValue::ResolveFlags mode; + mode = QScriptValue::ResolveFlags(stackPtr[-1].m_int_value) + | QScriptValue::ResolvePrototype; + + QScriptValueImpl object = eng->toObject(stackPtr[-3]); + if (! object.isValid()) { + stackPtr -= 4; + throwTypeError(QLatin1String("invalid assignment lvalue")); + HandleException(); + } + + QScriptValueImpl m = stackPtr[-2]; + QScriptValueImpl value = stackPtr[0]; + + quint32 pos = 0xFFFFFFFF; + + QScript::Ecma::Array::Instance *arrayInstance = eng->arrayConstructor->get(object); + if (arrayInstance) + pos = toArrayIndex(m); + + stackPtr -= 3; + + if (pos != 0xFFFFFFFF) + arrayInstance->value.assign(pos, value); + + else { + QScriptNameIdImpl *memberName; + + if (m.isString() && m.m_string_value->unique) + memberName = m.m_string_value; + else + memberName = eng->nameId(QScriptEnginePrivate::convertToNativeString(m), /*persistent=*/false); + + QScriptValueImpl base; + QScript::Member member; + + const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); + if (! object.resolve(memberName, &member, &base, mode, QScript::Write)) { + if (isMemberAssignment) + base = object; + else + base = eng->m_globalObject; + + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + + if (value.isString() && ! value.m_string_value->unique) + eng->newNameId(&value, value.m_string_value->s); + + if (member.isGetterOrSetter()) { + // find and call setter(value) + QScriptValueImpl setter; + if (!member.isSetter()) { + if (!base.m_object_value->findSetter(&member)) { + stackPtr -= 1; + throwError(QLatin1String("no setter defined")); + HandleException(); + } + } + base.get(member, &setter); + + if (!isMemberAssignment) { + // decide the this-object. This is the object that actually + // has the setter (in its prototype chain). + while (!object.resolve(memberName, &member, &base, QScriptValue::ResolvePrototype, QScript::Write)) + object = object.scope(); + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + } + + value = setter.call(object, QScriptValueImplList() << value); + if (hasUncaughtException()) { + stackPtr -= 1; + Done(); + } + } else { + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + + if (member.isWritable()) { + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + base.put(member, value); + } else if (member.isUninitializedConst()) { + base.put(member, value); + if (member.isObjectProperty()) { + base.m_object_value->m_members[member.id()] + .unsetFlags(QScript::Member::UninitializedConst); + } + } + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } + } + } + + *stackPtr = value; + ++iPtr; + } Next(); + + I(BitAnd): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 & v2); + ++iPtr; + } Next(); + + I(BitOr): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 | v2); + ++iPtr; + } Next(); + + I(BitXor): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 ^ v2); + ++iPtr; + } Next(); + + I(BitNot): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]); + *stackPtr = QScriptValueImpl(~v1); + ++iPtr; + } Next(); + + I(Not): + { + bool v1 = QScriptEnginePrivate::convertToNativeBoolean(stackPtr[0]); + *stackPtr = QScriptValueImpl(!v1); + ++iPtr; + } Next(); + + I(LeftShift): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]) & 0x1f; + *(--stackPtr) = QScriptValueImpl(v1 << v2); + ++iPtr; + } Next(); + + I(Mod): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + + *(--stackPtr) = QScriptValueImpl(::fmod(v1, v2)); + ++iPtr; + } Next(); + + I(RightShift): + { + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]); + quint32 v2 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(stackPtr[0])) & 0x1f; + *(--stackPtr) = QScriptValueImpl(v1 >> v2); + ++iPtr; + } Next(); + + I(URightShift): + { + quint32 v1 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(stackPtr[-1])); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]) & 0x1f; + *(--stackPtr) = QScriptValueImpl(v1 >> v2); + ++iPtr; + } Next(); + + I(InstanceOf): + { + QScriptValueImpl object = stackPtr[-1]; + QScriptValueImpl ctor = stackPtr[0]; + + if (!ctor.isObject() || !ctor.implementsHasInstance()) { + stackPtr -= 2; + throwTypeError(QLatin1String("invalid 'instanceof' operand")); + HandleException(); + } + + bool result = ctor.hasInstance(object); + if (eng->hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } + + *(--stackPtr) = QScriptValueImpl(result); + ++iPtr; + } Next(); + + I(In): + { + QScriptValueImpl object = stackPtr[0]; + if (!object.isObject()) { + stackPtr -= 2; + throwTypeError(QLatin1String("invalid 'in' operand")); + HandleException(); + } + QString propertyName = QScriptEnginePrivate::convertToNativeString(stackPtr[-1]); + bool result = object.property(propertyName, QScriptValue::ResolvePrototype).isValid(); // ### hasProperty() + *(--stackPtr) = QScriptValueImpl(result); + ++iPtr; + } Next(); + + I(Add): + { + QScriptValueImpl lhs = eng->toPrimitive(stackPtr[-1], QScriptValueImpl::NoTypeHint); + QScriptValueImpl rhs = eng->toPrimitive(stackPtr[0], QScriptValueImpl::NoTypeHint); + + if (lhs.isString() || rhs.isString()) { + QString tmp = QScriptEnginePrivate::convertToNativeString(lhs); + tmp += QScriptEnginePrivate::convertToNativeString(rhs); + eng->newString(--stackPtr, tmp); + } else { + qsreal tmp = QScriptEnginePrivate::convertToNativeDouble(lhs); + tmp += QScriptEnginePrivate::convertToNativeDouble(rhs); + *(--stackPtr) = QScriptValueImpl(tmp); + } + + ++iPtr; + } Next(); + + I(Div): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 / v2); + ++iPtr; + } Next(); + + I(Equal): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(eq_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(GreatOrEqual): + { + QScriptValueImpl v1 = stackPtr[0]; + QScriptValueImpl v2 = stackPtr[-1]; + *(--stackPtr) = QScriptValueImpl(le_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(GreatThan): + { + QScriptValueImpl v1 = stackPtr[0]; + QScriptValueImpl v2 = stackPtr[-1]; + *(--stackPtr) = QScriptValueImpl(lt_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(LessOrEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(le_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(LessThan): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(lt_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(NotEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = QScriptValueImpl(!eq_cmp(v1, v2)); + ++iPtr; + } Next(); + + I(Mul): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 * v2); + ++iPtr; + } Next(); + + I(StrictEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = strict_eq_cmp(v1, v2); + ++iPtr; + } Next(); + + I(StrictNotEqual): + { + QScriptValueImpl v1 = stackPtr[-1]; + QScriptValueImpl v2 = stackPtr[0]; + *(--stackPtr) = ! strict_eq_cmp(v1, v2); + ++iPtr; + } Next(); + + I(Sub): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]); + *(--stackPtr) = QScriptValueImpl(v1 - v2); + ++iPtr; + } Next(); + + I(UnaryMinus): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(*stackPtr); + *stackPtr = QScriptValueImpl(-v1); + ++iPtr; + } Next(); + + I(UnaryPlus): + { + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(*stackPtr); + *stackPtr = QScriptValueImpl(+v1); + ++iPtr; + } Next(); + + I(Branch): + { + eng->maybeProcessEvents(); + if (hasUncaughtException()) + HandleException(); + if (eng->shouldAbort()) + Abort(); + iPtr += iPtr->operand[0].m_int_value; + } Next(); + + I(BranchFalse): + { + if (! QScriptEnginePrivate::convertToNativeBoolean(*stackPtr--)) + iPtr += iPtr->operand[0].m_int_value; + else + ++iPtr; + } Next(); + + I(BranchTrue): + { + if (eng->convertToNativeBoolean(*stackPtr--)) + iPtr += iPtr->operand[0].m_int_value; + else + ++iPtr; + } Next(); + + I(NewClosure): + { + CHECK_TEMPSTACK(1); + + QScript::AST::FunctionExpression *expr = static_cast<QScript::AST::FunctionExpression *> (iPtr->operand[0].m_ptr_value); + +#ifndef Q_SCRIPT_NO_JOINED_FUNCTION + if (QScript::Code *code = eng->findCode(functionBody)) { + QScriptValueImpl value = code->value; + + if (isValid(value)) { + QScriptObject *instance = value.m_object_value; + Q_ASSERT(instance != 0); + + if (instance->m_scope.m_object_value == m_scopeChain.m_object_value) + { + *++stackPtr = value; + ++iPtr; + Next(); + } + } + } +#endif + + QScript::ScriptFunction *function = new QScript::ScriptFunction(expr, code->astPool); + + // update the formals + for (QScript::AST::FormalParameterList *it = expr->formals; it != 0; it = it->next) { + function->formals.append(it->name); + } + function->length = function->formals.count(); + + eng->functionConstructor->newFunction(++stackPtr, function); + + QScriptObject *instance = stackPtr->m_object_value; + // initialize [[scope]] + instance->m_scope = m_scopeChain; + + // create and initialize `prototype' + QScriptValueImpl proto; + eng->objectConstructor->newObject(&proto); + + QScript::Member member; + CREATE_MEMBER(proto, eng->idTable()->id_constructor, &member, + QScriptValue::Undeletable + | QScriptValue::SkipInEnumeration); + proto.put(member, *stackPtr); + + stackPtr->createMember(eng->idTable()->id_prototype, &member, + QScriptValue::Undeletable); + stackPtr->put(member, proto); + + ++iPtr; + } Next(); + + I(Incr): + { + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid increment operand")); + HandleException(); + } + + BEGIN_PREFIX_OPERATOR + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + value = QScriptValueImpl(x + 1); + + END_PREFIX_OPERATOR + } Next(); + + I(Decr): + { + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid decrement operand")); + HandleException(); + } + + BEGIN_PREFIX_OPERATOR + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + value = QScriptValueImpl(x - 1); + + END_PREFIX_OPERATOR + } Next(); + + I(PostIncr): + { + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid increment operand")); + HandleException(); + } + + QScriptValue::ResolveFlags mode; + mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) + | QScriptValue::ResolvePrototype; + + --stackPtr; + + QScriptValueImpl object = eng->toObject(stackPtr[-1]); + if (!object.isObject()) { + stackPtr -= 2; + throwTypeError(QLatin1String("not an object")); + HandleException(); + } + + QScriptNameIdImpl *memberName = 0; + if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) + memberName = stackPtr[0].m_string_value; + else + memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); + + QScript::Member member; + QScriptValueImpl base; + QScriptValueImpl value; + QScriptObject *instance = object.m_object_value; + const bool isMemberAssignment = (instance != m_scopeChain.m_object_value); + if (instance->findMember(memberName, &member)) { + if (!member.isGetterOrSetter()) { + QScriptValueImpl &r = instance->reference(member); + if (r.isNumber()) { + *(--stackPtr) = QScriptValueImpl(r.m_number_value); + r.incr(); + ++iPtr; + Next(); + } + } + base = object; + } else if (!object.resolve_helper(memberName, &member, &base, mode, QScript::ReadWrite)) { + if (!isMemberAssignment) { + stackPtr -= 2; + throwNotDefined(memberName); + HandleException(); + } + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + base.put(member, undefined); + } + + QScriptValueImpl getter; + QScriptValueImpl setter; + base.get(member, &value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } else if (member.isGetterOrSetter()) { + if (member.isGetter()) { + getter = value; + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No setter defined")); + HandleException(); + } + base.get(member, &setter); + } else { + setter = value; + QScript::Member tmp = member; + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + member = tmp; + } + value = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + + value = QScriptValueImpl(x + 1); + + if (member.isSetter()) { + setter.call(object, QScriptValueImplList() << value); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } else { + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + if (member.isWritable()) { + base.put(member, value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } + } + } + + *(--stackPtr) = QScriptValueImpl(x); + + ++iPtr; + } Next(); + + I(PostDecr): + { + // ### most of the code is duplicated from PostIncr -- try to merge + if (! stackPtr[0].isReference()) { + stackPtr -= 1; + throwSyntaxError(QLatin1String("invalid decrement operand")); + HandleException(); + } + + QScriptValue::ResolveFlags mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) + | QScriptValue::ResolvePrototype; + + --stackPtr; + + QScriptValueImpl object = eng->toObject(stackPtr[-1]); + if (!object.isObject()) { + stackPtr -= 2; + throwTypeError(QLatin1String("not an object")); + HandleException(); + } + + QScriptNameIdImpl *memberName = 0; + if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) + memberName = stackPtr[0].m_string_value; + else + memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); + + QScript::Member member; + QScriptValueImpl base; + QScriptValueImpl value; + QScriptObject *instance = object.m_object_value; + const bool isMemberAssignment = (instance != m_scopeChain.m_object_value); + if (instance->findMember(memberName, &member)) { + if (!member.isGetterOrSetter()) { + QScriptValueImpl &r = instance->reference(member); + if (r.isNumber()) { + *(--stackPtr) = QScriptValueImpl(r.m_number_value); + r.decr(); + ++iPtr; + Next(); + } + } + base = object; + } else if (! object.resolve_helper(memberName, &member, &base, mode, QScript::ReadWrite)) { + if (!isMemberAssignment) { + stackPtr -= 2; + throwNotDefined(memberName); + HandleException(); + } + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + base.put(member, undefined); + } + + QScriptValueImpl getter; + QScriptValueImpl setter; + base.get(member, &value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } else if (member.isGetterOrSetter()) { + if (member.isGetter()) { + getter = value; + if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No setter defined")); + HandleException(); + } + base.get(member, &setter); + } else { + setter = value; + QScript::Member tmp = member; + if (!base.m_object_value->findGetter(&member)) { + stackPtr -= 2; + throwError(QLatin1String("No getter defined")); + HandleException(); + } + base.get(member, &getter); + member = tmp; + } + value = getter.call(object); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } + + qsreal x = QScriptEnginePrivate::convertToNativeDouble(value); + + value = QScriptValueImpl(x - 1); + + if (member.isSetter()) { + setter.call(object, QScriptValueImplList() << value); + if (hasUncaughtException()) { + stackPtr -= 2; + Done(); + } + } else { + if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { + base = object; + CREATE_MEMBER(base, memberName, &member, /*flags=*/0); + } + if (member.isWritable()) { + base.put(member, value); + if (hasUncaughtException()) { + stackPtr -= 2; + HandleException(); + } + } + } + + *(--stackPtr) = QScriptValueImpl(x); + + ++iPtr; + } Next(); + + I(InplaceAdd): + { + BEGIN_INPLACE_OPERATOR + + lhs = eng->toPrimitive(lhs); + rhs = eng->toPrimitive(rhs); + if (lhs.isString() || rhs.isString()) { + if (lhs.isString() && !lhs.m_string_value->unique) { + lhs.m_string_value->s += QScriptEnginePrivate::convertToNativeString(rhs); + stackPtr -= 3; + *stackPtr = lhs; + } else { + QString tmp = QScriptEnginePrivate::convertToNativeString(lhs); + tmp += QScriptEnginePrivate::convertToNativeString(rhs); + stackPtr -= 3; + eng->newString(stackPtr, tmp); + } + } else { + qsreal tmp = QScriptEnginePrivate::convertToNativeDouble(lhs); + tmp += QScriptEnginePrivate::convertToNativeDouble(rhs); + stackPtr -= 3; + *stackPtr = QScriptValueImpl(tmp); + } + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceSub): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 - v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceAnd): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 & v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceDiv): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 / v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceLeftShift): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 << v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceMod): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(::fmod (v1, v2)); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceMul): + { + BEGIN_INPLACE_OPERATOR + + qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 * v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceOr): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 | v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceRightShift): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 >> v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceURightShift): + { + BEGIN_INPLACE_OPERATOR + + quint32 v1 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(lhs)); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 >> v2); + + END_INPLACE_OPERATOR + } Next(); + + I(InplaceXor): + { + BEGIN_INPLACE_OPERATOR + + qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs); + qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs); + + stackPtr -= 3; + *stackPtr = QScriptValueImpl(v1 ^ v2); + + END_INPLACE_OPERATOR + } Next(); + + I(MakeReference): + { + CHECK_TEMPSTACK(1); + eng->newReference(++stackPtr, QScriptValue::ResolveLocal); + ++iPtr; + } Next(); + + I(TypeOf): + { + QScriptValueImpl value; + + bool isReference = stackPtr[0].isReference(); + + if (! isReference) { // we have a value + value = stackPtr[0]; + } else if (resolveField(eng, &stackPtr[-1], &value)) { + stackPtr -= 2; + if (hasUncaughtException()) { + stackPtr -= 1; + HandleException(); + } + } else { + value = undefined; + stackPtr -= 2; + } + + QString typeName; + + switch (value.type()) { + case QScript::InvalidType: + typeName = QLatin1String("invalid"); + break; + + case QScript::UndefinedType: + typeName = QLatin1String("undefined"); + break; + + case QScript::NullType: + typeName = QLatin1String("object"); + break; + + case QScript::BooleanType: + typeName = QLatin1String("boolean"); + break; + + case QScript::IntegerType: + case QScript::NumberType: + typeName = QLatin1String("number"); + break; + + case QScript::StringType: + case QScript::LazyStringType: + typeName = QLatin1String("string"); + break; + + case QScript::ReferenceType: + typeName = QLatin1String("reference"); + break; + + case QScript::PointerType: + typeName = QLatin1String("pointer"); + break; + + case QScript::ObjectType: + if (value.isFunction()) + typeName = QLatin1String("function"); + else + typeName = QLatin1String("object"); + break; + } + + eng->newString(stackPtr, typeName); + ++iPtr; + } Next(); + + I(Line): + { + eng->maybeGC(); + eng->maybeProcessEvents(); + if (hasUncaughtException()) + HandleException(); + if (eng->shouldAbort()) + Abort(); + currentLine = iPtr->operand[0].m_int_value; + currentColumn = iPtr->operand[1].m_int_value; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + if (eng->shouldNotify()) { + eng->notifyPositionChange(this); + if (hasUncaughtException()) + HandleException(); + if (eng->shouldAbort()) + Abort(); + } +#endif + ++iPtr; + } Next(); + + I(Delete): + { + bool result; + if (! stackPtr[0].isReference()) + result = true; + + else { + QScriptValueImpl object = stackPtr[-2]; + if (!object.isObject()) + object = eng->toObject(object); + + QScriptNameIdImpl *nameId = 0; + if (stackPtr[-1].isString() && stackPtr[-1].m_string_value->unique) { + nameId = stackPtr[-1].m_string_value; + } else { + nameId = eng->nameId(QScriptEnginePrivate::convertToNativeString(stackPtr[-1]), + /*persistent=*/false); + } + if (object.classInfo() == eng->m_class_with) + object = object.prototype(); + result = object.deleteProperty(nameId, QScriptValue::ResolveScope); + stackPtr -= 2; + } + + *stackPtr = QScriptValueImpl(result); + + ++iPtr; + } Next(); + + + I(NewEnumeration): { + QScriptValueImpl e; + QScriptValueImpl object = eng->toObject(stackPtr[0]); + eng->enumerationConstructor->newEnumeration(&e, object); + *stackPtr = e; + ++iPtr; + } Next(); + + + I(ToFirstElement): { + QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[0]); + Q_ASSERT(e != 0); + e->toFront(); + --stackPtr; + ++iPtr; + } Next(); + + + I(HasNextElement): { + QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[0]); + Q_ASSERT(e != 0); + e->hasNext(this, stackPtr); + ++iPtr; + } Next(); + + + I(NextElement): { + // the Enumeration should be located below the result of I(Resolve) + if (! stackPtr[0].isReference()) { + throwTypeError(QLatin1String("QScript.VM.NextElement")); + HandleException(); + } + + QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[-3]); + if (! e) { + throwTypeError(QLatin1String("QScript.VM.NextElement")); + HandleException(); + } + e->next(this, ++stackPtr); + ++iPtr; + } Next(); + + + I(Pop): + { + --stackPtr; + ++iPtr; + } Next(); + + I(Sync): + { + m_result = *stackPtr; + --stackPtr; + ++iPtr; + } Next(); + + I(Throw): + { + Q_ASSERT(stackPtr->isValid()); + m_result = *stackPtr--; + if (!m_result.isError() && !exceptionHandlerContext()) + eng->m_exceptionBacktrace = backtrace(); + m_state = QScriptContext::ExceptionState; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyException(this); +#endif + } HandleException(); + + I(Ret): + { + Q_ASSERT(stackPtr->isValid()); + m_result = *stackPtr--; + ++iPtr; + } Done(); + + I(Halt): + { + ++iPtr; + } Done(); + + I(EnterWith): + { + QScriptValueImpl object = eng->toObject(*stackPtr--); + if (! object.isValid()) { + throwTypeError(QLatin1String("value has no properties")); + HandleException(); + } + QScriptValueImpl withObject; + eng->newObject(&withObject, object, eng->m_class_with); + withObject.m_object_value->m_scope = m_scopeChain; + m_scopeChain = withObject; + ++iPtr; + } Next(); + + I(LeaveWith): + { + QScriptValueImpl withObject = m_scopeChain; + m_scopeChain = withObject.m_object_value->m_scope; + ++iPtr; + } Next(); + + I(BeginCatch): + { + // result contains the thrown object + QScriptValueImpl object; + eng->newObject(&object, undefined); // ### prototype + QScript::Member member; + CREATE_MEMBER(object, iPtr->operand[0].m_string_value, &member, /*flags=*/0); + object.put(member, m_result); + // make catch-object head of scopechain + object.m_object_value->m_scope = m_scopeChain; + m_scopeChain = object; + + catching = true; + ++iPtr; + } Next(); + + I(EndCatch): + { + // remove catch-object from scopechain + QScriptValueImpl object = m_scopeChain; + m_scopeChain = object.m_object_value->m_scope; + + catching = false; + ++iPtr; + } Next(); + + I(Debugger): + { +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyDebugger(this); +#endif + ++iPtr; + } Next(); + +#ifndef Q_SCRIPT_DIRECT_CODE + I(Dummy): + { ; } + + } // end switch +#endif + +Lhandle_exception: + errorLineNumber = currentLine; + +Ldone: + Q_ASSERT(m_result.isValid()); + + if (m_state == QScriptContext::ExceptionState) { + if (catching) { + // exception thrown in catch -- clean up scopechain + QScriptValueImpl object = m_scopeChain; + m_scopeChain = object.m_object_value->m_scope; + catching = false; + } + + // see if we have an exception handler in this context + const QScriptInstruction *exPtr = findExceptionHandler(iPtr); + if (exPtr) { + if (m_scopeChain.classInfo() == eng->m_class_with) { + // clean up effects of with-statements if necessary + int withLevel = 0; + for (++iPtr; iPtr != exPtr; ++iPtr) { + if (iPtr->op == QScriptInstruction::OP_EnterWith) { + ++withLevel; + } else if (iPtr->op == QScriptInstruction::OP_LeaveWith) { + --withLevel; + if (withLevel < 0) { + QScriptValueImpl withObject = m_scopeChain; + m_scopeChain = withObject.m_object_value->m_scope; + } + } + } + } else { + iPtr = exPtr; + } + // go to the handler + recover(); +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyExceptionCatch(this); +#endif + goto Ltop; + } else { + if (!parentContext()) { + // pop all the top-level with-objects + while ((m_scopeChain.classInfo() == eng->m_class_with) + && !m_scopeChain.internalValue().isValid()) { + QScriptValueImpl withObject = m_scopeChain; + m_scopeChain = withObject.m_object_value->m_scope; + } + } + } + } + +Labort: +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng->notifyFunctionExit(this); +#endif + + eng->maybeGC(); + + currentLine = oldCurrentLine; + currentColumn = oldCurrentColumn; + m_code = oldCode; + + eng->m_evaluating = wasEvaluating; +} + +QScriptValueImpl QScriptContextPrivate::throwError(QScriptContext::Error error, const QString &text) +{ + QScriptEnginePrivate *eng_p = engine(); + QScript::Ecma::Error *ctor = eng_p->errorConstructor; + m_result.invalidate(); + switch (error) { + case QScriptContext::ReferenceError: + ctor->newReferenceError(&m_result, text); + break; + case QScriptContext::SyntaxError: + ctor->newSyntaxError(&m_result, text); + break; + case QScriptContext::TypeError: + ctor->newTypeError(&m_result, text); + break; + case QScriptContext::RangeError: + ctor->newRangeError(&m_result, text); + break; + case QScriptContext::URIError: + ctor->newURIError(&m_result, text); + break; + case QScriptContext::UnknownError: + default: + ctor->newError(&m_result, text); + } + setDebugInformation(&m_result); + m_state = QScriptContext::ExceptionState; +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY + eng_p->notifyException(this); +#endif + return m_result; +} + +#ifndef Q_SCRIPT_NO_EVENT_NOTIFY +qint64 QScriptContextPrivate::scriptId() const +{ + if (!m_code) + return -1; + return m_code->astPool->id(); +} +#endif + +QString QScriptContextPrivate::fileName() const +{ + if (!m_code) + return QString(); + return m_code->astPool->fileName(); +} + +QString QScriptContextPrivate::functionName() const +{ + if (!m_callee.isValid()) + return QString(); + QScriptFunction *fun = m_callee.toFunction(); + if (fun) + return fun->functionName(); + return QString(); +} + +void QScriptContextPrivate::setDebugInformation(QScriptValueImpl *error) const +{ + QScriptEnginePrivate *eng_p = engine(); + error->setProperty(QLatin1String("lineNumber"), QScriptValueImpl(currentLine)); + if (!fileName().isEmpty()) + error->setProperty(QLatin1String("fileName"), QScriptValueImpl(eng_p, fileName())); + + const QScriptContextPrivate *ctx = this; + QScriptValueImpl stackArray = eng_p->newArray(); + int i = 0; + while (ctx) { + QScriptValueImpl obj = eng_p->newObject(); + obj.setProperty(QLatin1String("frame"), ctx->activationObject()); + obj.setProperty(QLatin1String("lineNumber"), QScriptValueImpl(ctx->currentLine)); + if (!ctx->fileName().isEmpty()) + obj.setProperty(QLatin1String("fileName"), QScriptValueImpl(eng_p, ctx->fileName())); + if (!ctx->functionName().isEmpty()) + obj.setProperty(QLatin1String("functionName"), QScriptValueImpl(eng_p, ctx->functionName())); + stackArray.setProperty(i, obj); + ctx = ctx->parentContext(); + ++i; + } + error->setProperty(QLatin1String("stack"), stackArray); +} + +QStringList QScriptContextPrivate::backtrace() const +{ + QStringList result; + const QScriptContextPrivate *ctx = this; + while (ctx) { + QString s; + QString functionName = ctx->functionName(); + if (!functionName.isEmpty()) + s += functionName; + else { + if (ctx->parentContext()) { + if (ctx->callee().isFunction() + && ctx->callee().toFunction()->type() != QScriptFunction::Script) { + s += QLatin1String("<native>"); + } else { + s += QLatin1String("<anonymous>"); + } + } else { + s += QLatin1String("<global>"); + } + } + s += QLatin1String("("); + for (int i = 0; i < ctx->argc; ++i) { + if (i > 0) + s += QLatin1String(","); + QScriptValueImpl arg = ctx->args[i]; + if (arg.isObject()) + s += QLatin1String("[object Object]"); // don't do a function call + else + s += arg.toString(); + } + s += QLatin1String(")@"); + s += ctx->fileName(); + s += QString::fromLatin1(":%0").arg(ctx->currentLine); + result.append(s); + ctx = ctx->parentContext(); + } + return result; +} + +QScriptValueImpl QScriptContextPrivate::throwError(const QString &text) +{ + return throwError(QScriptContext::UnknownError, text); +} + +QScriptValueImpl QScriptContextPrivate::throwNotImplemented(const QString &name) +{ + return throwTypeError(QString::fromUtf8("%1 is not implemented").arg(name)); +} + +QScriptValueImpl QScriptContextPrivate::throwNotDefined(const QString &name) +{ + return throwError(QScriptContext::ReferenceError, + QString::fromUtf8("%1 is not defined").arg(name)); +} + +QScriptValueImpl QScriptContextPrivate::throwNotDefined(QScriptNameIdImpl *nameId) +{ + return throwNotDefined(QScriptEnginePrivate::toString(nameId)); +} + +bool QScriptContextPrivate::eq_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ + if (lhs.isNull() && rhs.isUndefined()) + return true; + + else if (lhs.isUndefined() && rhs.isNull()) + return true; + + else if (isNumerical(lhs) && rhs.isString()) + return QScriptEnginePrivate::convertToNativeDouble(lhs) == QScriptEnginePrivate::convertToNativeDouble(rhs); + + else if (lhs.isString() && isNumerical(rhs)) + return QScriptEnginePrivate::convertToNativeDouble(lhs) == QScriptEnginePrivate::convertToNativeDouble(rhs); + + else if (lhs.isBoolean()) + return eq_cmp(QScriptValueImpl(QScriptEnginePrivate::convertToNativeDouble(lhs)), rhs); + + else if (rhs.isBoolean()) + return eq_cmp(lhs, QScriptValueImpl(QScriptEnginePrivate::convertToNativeDouble(rhs))); + + else if (lhs.isObject() && ! rhs.isNull()) { + lhs = lhs.engine()->toPrimitive(lhs); + + if (lhs.isValid() && ! lhs.isObject()) + return eq_cmp(lhs, rhs); + } + + else if (rhs.isObject() && ! lhs.isNull()) { + rhs = rhs.engine()->toPrimitive(rhs); + + if (rhs.isValid() && ! rhs.isObject()) + return eq_cmp(lhs, rhs); + } + + return false; +} + +#if defined(Q_CC_GNU) && __GNUC__ <= 3 +bool QScriptContextPrivate::lt_cmp(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ + if (lhs.type() == rhs.type()) { + switch (lhs.type()) { + case QScript::InvalidType: + case QScript::UndefinedType: + case QScript::NullType: + return false; + + case QScript::NumberType: + return lhs.m_number_value < rhs.m_number_value; + + case QScript::IntegerType: + return lhs.m_int_value < rhs.m_int_value; + + case QScript::BooleanType: + return lhs.m_bool_value < rhs.m_bool_value; + + default: + break; + } // switch + } +#else +bool QScriptContextPrivate::lt_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ +#endif + if ((lhs.type() == rhs.type()) && (lhs.type() == QScript::StringType)) + return lhs.m_string_value->s < rhs.m_string_value->s; + + if (lhs.isObject()) + lhs = lhs.engine()->toPrimitive(lhs, QScriptValueImpl::NumberTypeHint); + + if (rhs.isObject()) + rhs = rhs.engine()->toPrimitive(rhs, QScriptValueImpl::NumberTypeHint); + + if (lhs.isString() && rhs.isString()) + return QScriptEnginePrivate::convertToNativeString(lhs) < QScriptEnginePrivate::convertToNativeString(rhs); + + qsreal n1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal n2 = QScriptEnginePrivate::convertToNativeDouble(rhs); +#if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET + if (qIsNaN(n1) || qIsNaN(n2)) + return false; +#endif + return n1 < n2; +} + +bool QScriptContextPrivate::le_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs) +{ + if ((lhs.type() == rhs.type()) && (lhs.type() == QScript::StringType)) + return lhs.m_string_value->s <= rhs.m_string_value->s; + + if (lhs.isObject()) + lhs = lhs.engine()->toPrimitive(lhs, QScriptValueImpl::NumberTypeHint); + + if (rhs.isObject()) + rhs = rhs.engine()->toPrimitive(rhs, QScriptValueImpl::NumberTypeHint); + + if (lhs.isString() && rhs.isString()) + return QScriptEnginePrivate::convertToNativeString(lhs) <= QScriptEnginePrivate::convertToNativeString(rhs); + + qsreal n1 = QScriptEnginePrivate::convertToNativeDouble(lhs); + qsreal n2 = QScriptEnginePrivate::convertToNativeDouble(rhs); + return n1 <= n2; +} + +const QScriptInstruction *QScriptContextPrivate::findExceptionHandler( + const QScriptInstruction *ip) const +{ + Q_ASSERT(m_code); + int offset = ip - m_code->firstInstruction; + for (int i = 0; i < m_code->exceptionHandlers.count(); ++i) { + QScript::ExceptionHandlerDescriptor e = m_code->exceptionHandlers.at(i); + if (offset >= e.startInstruction() && offset <= e.endInstruction()) { + return m_code->firstInstruction + e.handlerInstruction(); + } + } + return 0; +} + +const QScriptInstruction *QScriptContextPrivate::findExceptionHandlerRecursive( + const QScriptInstruction *ip, QScriptContextPrivate **handlerContext) const +{ + const QScriptContextPrivate *ctx = this; + const QScriptInstruction *iip = ip; + while (ctx) { + if (ctx->m_code) { + const QScriptInstruction *ep = ctx->findExceptionHandler(iip); + if (ep) { + Q_ASSERT(handlerContext); + *handlerContext = const_cast<QScriptContextPrivate*>(ctx); + return ep; + } + } + ctx = ctx->parentContext(); + if (ctx) + iip = ctx->iPtr; + } + return 0; +} + +/*! + Requires that iPtr in current context is in sync +*/ +QScriptContextPrivate *QScriptContextPrivate::exceptionHandlerContext() const +{ + QScriptContextPrivate *handlerContext; + if (findExceptionHandlerRecursive(iPtr, &handlerContext)) + return handlerContext; + return 0; +} + +QScriptContext *QScriptContextPrivate::get(QScriptContextPrivate *d) +{ + if (d) + return d->q_func(); + return 0; +} + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT |