1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Solutions component.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 **     of its contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 
42 #include <QtDebug>
43 
44 
45 #include "qscriptcontext_p.h"
46 #include "qscriptengine_p.h"
47 #include "qscriptvalueimpl_p.h"
48 #include "qscriptmember_p.h"
49 #include "qscriptobject_p.h"
50 #include "qscriptprettypretty_p.h"
51 #include "qscriptast_p.h"
52 #include "qscriptnodepool_p.h"
53 #include "qscriptcompiler_p.h"
54 #include "qscriptextenumeration_p.h"
55 
56 #include <math.h> // floor & friends...
57 
58 QT_BEGIN_NAMESPACE
59 
60 #define Q_SCRIPT_NO_PRINT_GENERATED_CODE
61 
62 #define Q_SCRIPT_NO_JOINED_FUNCTION
63 
64 #define CHECK_TEMPSTACK(needed) do { \
65     if (stackPtr + needed >= eng->tempStackEnd) { \
66         throwError(QLatin1String("out of memory")); \
67         HandleException(); \
68     } \
69 } while (0)
70 
71 #ifndef Q_SCRIPT_NO_PRINT_GENERATED_CODE
72 static QTextStream qout(stderr, QIODevice::WriteOnly);
73 #endif
74 
qscript_uint_to_string_helper(uint i,QString & s)75 static inline void qscript_uint_to_string_helper(uint i, QString &s)
76 {
77     switch (i) {
78     case 0: case 1: case 2: case 3: case 4:
79     case 5: case 6: case 7: case 8: case 9:
80         s += QLatin1Char('0' + i);
81         break;
82 
83     default:
84         qscript_uint_to_string_helper(i / 10, s);
85         s += QLatin1Char('0' + (i % 10));
86     }
87 }
88 
qscript_uint_to_string(qsreal i,QString & s)89 static inline void qscript_uint_to_string(qsreal i, QString &s)
90 {
91     if ((i < 0) || (i > 0xFFFFFFFF))
92         return; // nothing to do
93 
94     qsreal x = ::fmod(i, 10);
95 
96     if (x != 0.0 && x != 1.0
97             && x != 2.0 && x != 3.0
98             && x != 4.0 && x != 5.0
99             && x != 6.0 && x != 7.0
100             && x != 8.0 && x != 9.0)
101         return; // nothing to do
102 
103     qscript_uint_to_string_helper(uint(i), s);
104 }
105 
toArrayIndex(const QScriptValueImpl & v)106 static inline quint32 toArrayIndex(const QScriptValueImpl &v)
107 {
108     if (v.isNumber()) {
109         quint32 ui = v.toUInt32();
110         if (qsreal(ui) == v.m_number_value)
111             return ui;
112     } else if (v.isString()) {
113         QByteArray bytes = v.m_string_value->s.toUtf8();
114         char *eptr;
115         quint32 pos = strtoul(bytes.constData(), &eptr, 10);
116         if ((eptr == bytes.constData() + bytes.size())
117             && (QByteArray::number(pos) == bytes)) {
118             return pos;
119         }
120     }
121     return 0xFFFFFFFF;
122 }
123 
124 #define CREATE_MEMBER(__obj__, __name__, __member__, __flags__) do { \
125     (__obj__).createMember(__name__, __member__, __flags__); \
126     eng->adjustBytesAllocated(sizeof(QScript::Member) + sizeof(QScriptValueImpl)); \
127 } while (0)
128 
129 #define BEGIN_PREFIX_OPERATOR \
130     QScriptValue::ResolveFlags mode; \
131     mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value) \
132     | QScriptValue::ResolvePrototype; \
133     --stackPtr; \
134     QScriptValueImpl object = eng->toObject(stackPtr[-1]); \
135     if (!object.isObject()) { \
136         stackPtr -= 2;  \
137         throwTypeError(QLatin1String("not an object")); \
138         HandleException(); \
139     } \
140     QScriptNameIdImpl *memberName = 0; \
141     if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique) \
142         memberName = stackPtr[0].m_string_value; \
143     else \
144         memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false); \
145     QScript::Member member; \
146     QScriptValueImpl base; \
147     QScriptValueImpl value; \
148     QScriptValueImpl getter; \
149     QScriptValueImpl setter; \
150     const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); \
151     if (object.resolve(memberName, &member, &base, mode, QScript::ReadWrite)) {  \
152         base.get(member, &value); \
153         if (hasUncaughtException()) { \
154             stackPtr -= 2; \
155             HandleException(); \
156         } else if (member.isGetterOrSetter()) { \
157             if (member.isGetter()) { \
158                 getter = value; \
159                 if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { \
160                     stackPtr -= 2; \
161                     throwError(QLatin1String("No setter defined")); \
162                     HandleException(); \
163                 } \
164                 base.get(member, &setter); \
165             } else { \
166                 setter = value; \
167                 QScript::Member tmp = member; \
168                 if (!base.m_object_value->findGetter(&member)) { \
169                     stackPtr -= 2; \
170                     throwError(QLatin1String("No getter defined")); \
171                     HandleException(); \
172                 } \
173                 base.get(member, &getter); \
174                 member = tmp; \
175             } \
176             value = getter.call(object); \
177             if (hasUncaughtException()) { \
178                 stackPtr -= 2; \
179                 Done(); \
180             } \
181         } \
182     } else if (!isMemberAssignment) { \
183         stackPtr -= 2; \
184         throwNotDefined(memberName); \
185         HandleException(); \
186     } else { \
187         base = object; \
188         CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \
189         value = undefined; \
190     }
191 
192 #define END_PREFIX_OPERATOR \
193     if (member.isSetter()) { \
194         setter.call(object, QScriptValueImplList() << value); \
195         if (hasUncaughtException()) { \
196             stackPtr -= 2; \
197             Done(); \
198         } \
199     } else { \
200         if (member.isWritable()) { \
201             if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { \
202                 base = object; \
203                 CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \
204             } \
205             base.put(member, value); \
206             if (hasUncaughtException()) { \
207                 stackPtr -= 2; \
208                 HandleException(); \
209             } \
210         } \
211     } \
212     *--stackPtr = value; \
213     ++iPtr;
214 
215 #define BEGIN_INPLACE_OPERATOR \
216     if (! stackPtr[-1].isReference()) { \
217         stackPtr -= 2; \
218         throwSyntaxError(QLatin1String("invalid assignment lvalue")); \
219         HandleException(); \
220     } \
221     QScriptValue::ResolveFlags mode; \
222     mode = QScriptValue::ResolveFlags(stackPtr[-1].m_int_value) \
223            | QScriptValue::ResolvePrototype; \
224     QScriptValueImpl object = eng->toObject(stackPtr[-3]); \
225     if (! object.isValid()) { \
226         stackPtr -= 4; \
227         throwTypeError(QLatin1String("not an object")); \
228         HandleException(); \
229     } \
230     QScriptNameIdImpl *memberName = 0; \
231     if (stackPtr[-2].isString() && stackPtr[-2].m_string_value->unique) \
232         memberName = stackPtr[-2].m_string_value; \
233     else \
234         memberName = eng->nameId(stackPtr[-2].toString(), /*persistent=*/false); \
235     QScriptValueImpl lhs; \
236     QScriptValueImpl base; \
237     QScript::Member member; \
238     QScriptValueImpl getter; \
239     QScriptValueImpl setter; \
240     const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value); \
241     if (object.resolve(memberName, &member, &base, mode, QScript::ReadWrite)) {  \
242         base.get(member, &lhs); \
243         if (hasUncaughtException()) { \
244             stackPtr -= 4; \
245             HandleException(); \
246         } else if (member.isGetterOrSetter()) { \
247             if (member.isGetter()) { \
248                 getter = lhs; \
249                 if (!member.isSetter() && !base.m_object_value->findSetter(&member)) { \
250                     stackPtr -= 4; \
251                     throwError(QLatin1String("No setter defined")); \
252                     HandleException(); \
253                 } \
254                 base.get(member, &setter); \
255             } else { \
256                 setter = lhs; \
257                 QScript::Member tmp = member; \
258                 if (!base.m_object_value->findGetter(&member)) { \
259                     stackPtr -= 4; \
260                     throwError(QLatin1String("No getter defined")); \
261                     HandleException(); \
262                 } \
263                 base.get(member, &getter); \
264                 member = tmp; \
265             } \
266             lhs = getter.call(object); \
267             if (hasUncaughtException()) { \
268                 stackPtr -= 4; \
269                 Done(); \
270             } \
271         } \
272     } else if (!isMemberAssignment) { \
273         stackPtr -= 4; \
274         throwNotDefined(memberName); \
275         HandleException(); \
276     } else { \
277         base = object; \
278         CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \
279         lhs = undefined; \
280     } \
281     QScriptValueImpl rhs = stackPtr[0];
282 
283 #define END_INPLACE_OPERATOR \
284     if (member.isSetter()) { \
285         setter.call(object, QScriptValueImplList() << *stackPtr); \
286         if (hasUncaughtException()) { \
287             stackPtr -= 1; \
288             Done(); \
289         } \
290     } else { \
291         if (member.isWritable()) { \
292             if (isMemberAssignment && (base.m_object_value != object.m_object_value)) { \
293                 base = object; \
294                 CREATE_MEMBER(base, memberName, &member, /*flags=*/0); \
295             } \
296             base.put(member, *stackPtr); \
297             if (hasUncaughtException()) { \
298                 stackPtr -= 1; \
299                 HandleException(); \
300             } \
301         } \
302     } \
303     ++iPtr;
304 
305 namespace QScript {
306 
execute(QScriptContextPrivate * context)307 void ScriptFunction::execute(QScriptContextPrivate *context)
308 {
309     if (! m_compiledCode) {
310         QScriptEnginePrivate *eng = context->engine();
311         Compiler compiler(eng);
312 
313         CompilationUnit unit = compiler.compile(m_definition->body, formals);
314         if (! unit.isValid()) {
315             context->throwError(unit.errorMessage());
316             return;
317         }
318 
319         m_compiledCode = m_astPool->createCompiledCode(m_definition->body, unit);
320     }
321 
322     context->execute(m_compiledCode);
323 }
324 
toString(QScriptContextPrivate *) const325 QString ScriptFunction::toString(QScriptContextPrivate *) const
326 {
327     QString str;
328     QTextStream out(&str, QIODevice::WriteOnly);
329     PrettyPretty pp(out);
330     pp(m_definition, /*indent=*/ 0);
331     return str;
332 }
333 
fileName() const334 QString ScriptFunction::fileName() const
335 {
336     return m_astPool->fileName();
337 }
338 
functionName() const339 QString ScriptFunction::functionName() const
340 {
341     if (!m_definition->name)
342         return QString();
343     return m_definition->name->s;
344 }
345 
startLineNumber() const346 int ScriptFunction::startLineNumber() const
347 {
348     return m_definition->startLine;
349 }
350 
endLineNumber() const351 int ScriptFunction::endLineNumber() const
352 {
353     return m_definition->endLine;
354 }
355 
356 } // namespace QScript
357 
358 /*!
359   \internal
360 
361   Resolves and gets the value specified by \a stackPtr.
362   stackPtr[0] contains the member specifier, stackPtr[-1] contains the object.
363   If the member can be resolved, sets \a value to the value of that member,
364   otherwise returns false.
365 */
resolveField(QScriptEnginePrivate * eng,QScriptValueImpl * stackPtr,QScriptValueImpl * value)366 bool QScriptContextPrivate::resolveField(QScriptEnginePrivate *eng,
367                                          QScriptValueImpl *stackPtr,
368                                          QScriptValueImpl *value)
369 {
370     const QScriptValueImpl &m = stackPtr[0];
371     QScriptValueImpl &object = stackPtr[-1];
372 
373     if (! object.isObject())
374         object = eng->toObject(object);
375 
376     if (! object.isValid())
377         return false;
378 
379     if (QScript::Ecma::Array::Instance *arrayInstance = eng->arrayConstructor->get(object)) {
380         quint32 pos = toArrayIndex(m);
381         if (pos != 0xFFFFFFFF) {
382             *value = arrayInstance->value.at(pos);
383 
384             if (! value->isValid())
385                 *value = eng->undefinedValue();
386 
387             return true;
388         }
389     }
390 
391     QScriptNameIdImpl *nameId = m.isString() ? m.m_string_value : 0;
392 
393     if (! nameId || ! nameId->unique)
394         nameId = eng->nameId(QScriptEnginePrivate::convertToNativeString(m), /*persistent=*/false); // ### slow!
395 
396     QScript::Member member;
397     QScriptValueImpl base;
398 
399     if (! object.resolve(nameId, &member, &base, QScriptValue::ResolveFull, QScript::Read)) // ### ...
400         return false;
401 
402     if (QScriptEnginePrivate::strictlyEquals(base, eng->m_globalObject))
403         stackPtr[-1] = base;
404     else if (object.classInfo() == eng->m_class_with)
405         stackPtr[-1] = object.prototype();
406 
407     base.get(member, value);
408 
409     if (member.isGetterOrSetter()) {
410         // call the getter function
411         QScriptValueImpl getter;
412         if (member.isGetter()) {
413             getter = *value;
414         } else {
415             if (!base.m_object_value->findGetter(&member)) {
416                 *value = eng->undefinedValue();
417                 return true;
418             }
419             base.get(member, &getter);
420         }
421         *value = getter.call(object);
422     }
423 
424     return true;
425 }
426 
execute(QScript::Code * code)427 void QScriptContextPrivate::execute(QScript::Code *code)
428 {
429     int oldCurrentLine = currentLine;
430     int oldCurrentColumn = currentColumn;
431     QScript::Code *oldCode = m_code;
432     m_code = code;
433 
434 #ifndef Q_SCRIPT_NO_PRINT_GENERATED_CODE
435     qout << QLatin1String("function:") << endl;
436     for (QScriptInstruction *current = code->firstInstruction; current != code->lastInstruction; ++current) {
437         qout << int(current - code->firstInstruction) << QLatin1String(":\t");
438         current->print(qout);
439         qout << endl;
440     }
441     qout << endl;
442 #endif
443 
444     QScriptEnginePrivate *eng = engine();
445 
446     bool wasEvaluating = eng->m_evaluating;
447     if (!wasEvaluating) {
448         eng->setupProcessEvents();
449         eng->resetAbortFlag();
450     }
451     eng->m_evaluating = true;
452 
453     // set up the temp stack
454     if (! tempStack)
455         stackPtr = tempStack = eng->tempStackBegin;
456 
457     QScriptValueImpl undefined(eng->undefinedValue());
458 
459     catching = false;
460     m_state = QScriptContext::NormalState;
461     m_result = undefined;
462     firstInstruction = code->firstInstruction;
463     lastInstruction = code->lastInstruction;
464     iPtr = code->firstInstruction;
465 
466     if (!m_scopeChain.isValid())
467         m_scopeChain = m_activation;
468 
469 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
470     eng->notifyFunctionEntry(this);
471 #endif
472 
473 #ifndef Q_SCRIPT_DIRECT_CODE
474 
475 #  define I(opc) case QScriptInstruction::OP_##opc
476 #  define Next() goto Lfetch
477 #  define Done() goto Ldone
478 #  define HandleException() goto Lhandle_exception
479 #  define Abort() goto Labort
480 
481 Lfetch:
482 
483 
484 #else
485 
486 #  define I(opc) qscript_execute_##opc
487 #  define Next() goto *iPtr->code
488 #  define Done() goto Ldone
489 #  define HandleException() goto Lhandle_exception
490 #  define Abort() goto Labort
491 
492     static void * const jump_table[] = {
493 
494 #  define Q_SCRIPT_DEFINE_OPERATOR(op) &&I(op),
495 #  include "instruction.table"
496 #  undef Q_SCRIPT_DEFINE_OPERATOR
497     }; // jump_table
498 
499 
500     if (!code->optimized) {
501         for (QScriptInstruction *current = code->firstInstruction; current != code->lastInstruction; ++current) {
502             current->code = jump_table[current->op];
503         }
504 
505         code->optimized = true;
506     }
507 
508 #endif
509 Ltop:
510 
511 #ifndef Q_SCRIPT_DIRECT_CODE
512     switch (iPtr->op) {
513 #else
514     goto *iPtr->code;
515 #endif
516 
517     I(Nop):
518     {
519         ++iPtr;
520     }   Next();
521 
522     I(LoadUndefined):
523     {
524         CHECK_TEMPSTACK(1);
525         *(++stackPtr) = undefined;
526         ++iPtr;
527     }   Next();
528 
529     I(LoadTrue):
530     {
531         CHECK_TEMPSTACK(1);
532         *(++stackPtr) = QScriptValueImpl(true);
533         ++iPtr;
534     }   Next();
535 
536     I(LoadFalse):
537     {
538         CHECK_TEMPSTACK(1);
539         *(++stackPtr) = QScriptValueImpl(false);
540         ++iPtr;
541     }   Next();
542 
543     I(LoadThis):
544     {
545         CHECK_TEMPSTACK(1);
546         Q_ASSERT(m_thisObject.isObject());
547         *++stackPtr = m_thisObject;
548         ++iPtr;
549     }   Next();
550 
551     I(LoadActivation):
552     {
553         CHECK_TEMPSTACK(1);
554         *++stackPtr = m_activation;
555         ++iPtr;
556     }   Next();
557 
558     I(LoadNull):
559     {
560         CHECK_TEMPSTACK(1);
561         *(++stackPtr) = eng->nullValue();
562         ++iPtr;
563     }   Next();
564 
565     I(LoadNumber):
566     {
567         CHECK_TEMPSTACK(1);
568         *++stackPtr = iPtr->operand[0];
569         ++iPtr;
570     }   Next();
571 
572 
573     I(LoadString):
574     {
575         CHECK_TEMPSTACK(1);
576         *++stackPtr = iPtr->operand[0];
577         ++iPtr;
578     }   Next();
579 
580     I(NewString):
581     {
582         CHECK_TEMPSTACK(1);
583         eng->newNameId(++stackPtr, iPtr->operand[0].m_string_value);
584         ++iPtr;
585     }   Next();
586 
587     I(Duplicate):
588     {
589         CHECK_TEMPSTACK(1);
590         ++stackPtr;
591         *stackPtr = stackPtr[-1];
592         ++iPtr;
593     }   Next();
594 
595     I(Swap):
596     {
597         QScriptValueImpl tmp = stackPtr[0];
598         *stackPtr = stackPtr[-1];
599         stackPtr[-1] = tmp;
600         ++iPtr;
601     }   Next();
602 
603 
604     I(Receive):
605     {
606         int n = iPtr->operand[0].m_int_value;
607 
608         if (n >= argc) {
609             throwError(QLatin1String("invalid argument"));
610             HandleException();
611         }
612 
613         CHECK_TEMPSTACK(1);
614         *++stackPtr = argument(n);
615         ++iPtr;
616     }   Next();
617 
618     I(Fetch):
619     {
620         CHECK_TEMPSTACK(1);
621 
622         QScriptNameIdImpl *memberName = iPtr->operand[0].m_string_value;
623 
624         QScriptValueImpl base;
625         QScript::Member member;
626 
627         QScriptObject *instance = m_scopeChain.m_object_value;
628         if (instance->findMember(memberName, &member)) {
629             instance->get(member, ++stackPtr);
630             base = m_scopeChain;
631         } else {
632             if (m_scopeChain.resolve_helper(memberName, &member, &base, QScriptValue::ResolveFull, QScript::Read)) {
633                 base.get(member, ++stackPtr);
634                 if (hasUncaughtException()) {
635                     stackPtr -= 1;
636                     HandleException();
637                 }
638             } else {
639                 throwNotDefined(memberName);
640                 HandleException();
641             }
642         }
643         if (member.isGetterOrSetter()) {
644             // locate the getter function
645             QScriptValueImpl getter;
646             if (member.isGetter()) {
647                 getter = *stackPtr;
648             } else {
649                 if (!base.m_object_value->findGetter(&member)) {
650                     stackPtr -= 1;
651                     throwError(QLatin1String("No getter defined"));
652                     HandleException();
653                 }
654                 base.get(member, &getter);
655             }
656             // decide the this-object. This is the object that actually
657             // has the getter (in its prototype chain).
658             QScriptValueImpl object = m_scopeChain;
659             while (!object.resolve(memberName, &member, &base, QScriptValue::ResolvePrototype, QScript::Read))
660                 object = object.scope();
661             if (object.classInfo() == eng->m_class_with)
662                 object = object.prototype();
663 
664             *stackPtr = getter.call(object);
665             if (hasUncaughtException()) {
666                 stackPtr -= 1;
667                 Done();
668             }
669         }
670         ++iPtr;
671     }   Next();
672 
673     I(Resolve):
674     {
675         Q_ASSERT(iPtr->operand[0].isString());
676 
677         CHECK_TEMPSTACK(2);
678         *++stackPtr = m_scopeChain;
679         *++stackPtr = iPtr->operand[0];
680         eng->newReference(++stackPtr, QScriptValue::ResolveScope);
681         ++iPtr;
682     }   Next();
683 
684     I(PutField):
685     {
686         Q_ASSERT(stackPtr[-1].isReference());
687 
688         const QScriptValueImpl &object = stackPtr[-3];
689         QScriptNameIdImpl *memberName = stackPtr[-2].m_string_value;
690         const QScriptValueImpl &value = stackPtr[0];
691 
692         QScript::Member member;
693         QScriptValueImpl base;
694 
695         if (! object.resolve(memberName, &member, &base, QScriptValue::ResolveLocal, QScript::Write)) {
696             base = object;
697             CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
698         }
699 
700         base.put(member, value);
701         stackPtr -= 4;
702         if (hasUncaughtException())
703             HandleException();
704         ++iPtr;
705     }   Next();
706 
707     I(Call):
708     {
709         int argc = iPtr->operand[0].m_int_value;
710         QScriptValueImpl *argp = stackPtr - argc;
711 
712         QScriptValueImpl base;
713         QScriptValueImpl callee;
714 
715         bool isReference = argp[0].isReference();
716 
717         if (! isReference) { // we have a value
718             base = eng->m_globalObject;
719             callee = argp[0];
720         } else if (resolveField(eng, &argp[-1], &callee)) {
721             if (hasUncaughtException()) {
722                 stackPtr = argp - 3;
723                 HandleException();
724             }
725             base = argp[-2];
726         } else {
727             QScriptValueImpl member = argp[-1];
728             stackPtr = argp - 1;
729             Q_ASSERT(isReference);
730             stackPtr -= 2;
731 
732             if (member.isString())
733                 throwNotDefined(member.toString());
734             else
735                 throwNotDefined(QLatin1String("function"));
736             HandleException();
737         }
738 
739         Q_ASSERT(base.isValid());
740         Q_ASSERT(callee.isValid());
741 
742         QScriptFunction *function = QScriptEnginePrivate::convertToNativeFunction(callee);
743         if (! function) {
744             QScriptValueImpl member = argp[-1];
745             QString message;
746             if (member.isString()) {
747                 message = QString::fromLatin1("%0 is not a function")
748                           .arg(member.toString());
749             } else {
750                 message = QLatin1String("not a function");
751             }
752             throwTypeError(message);
753             HandleException();
754         }
755 
756         if (++eng->m_callDepth == eng->m_maxCallDepth) {
757             throwError(QLatin1String("call stack overflow"));
758             HandleException();
759         }
760 
761         QScriptContextPrivate *nested_data = eng->pushContext();
762         nested_data->m_thisObject = base;
763         nested_data->m_callee = callee;
764 
765         // create the activation
766         eng->newActivation(&nested_data->m_activation);
767         QScriptObject *activation_data = nested_data->m_activation.m_object_value;
768 
769         int formalCount = function->formals.count();
770         int mx = qMax(formalCount, argc);
771         activation_data->m_members.resize(mx);
772         activation_data->m_values.resize(mx);
773         for (int i = 0; i < mx; ++i) {
774             QScriptNameIdImpl *nameId = 0;
775             if (i < formalCount)
776                 nameId = function->formals.at(i);
777 
778             activation_data->m_members[i].object(nameId, i,
779                                                  QScriptValue::Undeletable
780                                                  | QScriptValue::SkipInEnumeration);
781             activation_data->m_values[i] = (i < argc) ? argp[i + 1] : undefined;
782         }
783 
784         nested_data->argc = argc;
785         if (callee.m_object_value->m_scope.isValid())
786             activation_data->m_scope = callee.m_object_value->m_scope;
787         else
788             activation_data->m_scope = eng->m_globalObject;
789         nested_data->tempStack = stackPtr;
790         nested_data->args = &argp[1];
791 
792         function->execute(nested_data);
793 
794         --eng->m_callDepth;
795 
796         stackPtr = argp - 1;
797         if (isReference)
798             stackPtr -= 2;
799 
800         if (nested_data->m_state == QScriptContext::ExceptionState) {
801             eng->popContext();
802             if (eng->shouldAbort())
803                 Abort();
804             else
805                 Done();
806         }
807 
808         CHECK_TEMPSTACK(1);
809         *++stackPtr = nested_data->m_result;
810 
811         eng->popContext();
812 
813         if (eng->shouldAbort())
814             Abort();
815 
816         if (eng->m_processEventsInterval > 0)
817             eng->processEvents();
818 
819         ++iPtr;
820     }   Next();
821 
822 
823     I(NewArray):
824     {
825         CHECK_TEMPSTACK(1);
826         eng->arrayConstructor->newArray(++stackPtr, QScript::Array(eng));
827         ++iPtr;
828     }   Next();
829 
830     I(NewRegExp):
831     {
832         CHECK_TEMPSTACK(1);
833 
834         QString pattern = eng->toString(iPtr->operand[0].m_string_value);
835 #ifndef QT_NO_REGEXP
836         QString literal = pattern;
837 #endif
838         int flags = 0;
839         if (iPtr->operand[1].isValid()) {
840             flags = iPtr->operand[1].m_int_value;
841 #ifndef QT_NO_REGEXP
842             if (flags != 0) {
843                 literal += QLatin1Char('/');
844                 literal += QString::number(flags);
845             }
846 #endif
847         }
848 
849 #ifndef QT_NO_REGEXP
850         QRegExp rx;
851         // lazy compilation of regexp literals
852         QHash<QString, QRegExp>::const_iterator it;
853         it = eng->m_regExpLiterals.constFind(literal);
854         if (it == eng->m_regExpLiterals.constEnd()) {
855             rx = QScript::Ecma::RegExp::toRegExp(pattern, flags);
856             eng->m_regExpLiterals.insert(literal, rx);
857         } else {
858             rx = *it;
859         }
860         eng->regexpConstructor->newRegExp(++stackPtr, rx, flags);
861 #else
862         eng->regexpConstructor->newRegExp(++stackPtr, pattern, flags);
863 #endif
864         ++iPtr;
865     }   Next();
866 
867     I(NewObject):
868     {
869         CHECK_TEMPSTACK(1);
870         eng->objectConstructor->newObject(++stackPtr);
871         ++iPtr;
872     }   Next();
873 
874     I(New):
875     {
876         int argc = iPtr->operand[0].m_int_value;
877         QScriptValueImpl *argp = stackPtr - argc;
878 
879         // QScriptValueImpl base;
880         QScriptValueImpl callee;
881 
882         bool isReference = argp[0].isReference();
883 
884         if (! isReference) { // we have a value
885             // base = eng->globalObject;
886             callee = argp[0];
887         } else if (resolveField(eng, &argp[-1], &callee)) {
888             // base = argp[-2];
889             if (hasUncaughtException()) {
890                 stackPtr = argp - 3;
891                 HandleException();
892             }
893         } else {
894             QScriptValueImpl member = argp[-1];
895             stackPtr = argp - 1;
896             Q_ASSERT(isReference);
897             stackPtr -= 2;
898 
899             if (member.isString())
900                 throwNotDefined(member.toString());
901             else
902                 throwNotDefined(QLatin1String("constructor"));
903             HandleException();
904         }
905 
906         // Q_ASSERT(base.isValid());
907         Q_ASSERT(callee.isValid());
908 
909         QScriptFunction *function = QScriptEnginePrivate::convertToNativeFunction(callee);
910         if (! function) {
911             QScriptValueImpl member = argp[-1];
912             QString message;
913             if (member.isString()) {
914                 message = QString::fromLatin1("%0 is not a constructor")
915                           .arg(member.toString());
916             } else {
917                 message = QLatin1String("not a constructor");
918             }
919             throwTypeError(message);
920             HandleException();
921         }
922 
923         if (++eng->m_callDepth == eng->m_maxCallDepth) {
924             throwError(QLatin1String("call stack overflow"));
925             HandleException();
926         }
927 
928         QScriptContextPrivate *nested_data = eng->pushContext();
929         nested_data->m_callee = callee;
930         nested_data->m_calledAsConstructor = true;
931 
932         // create the activation
933         eng->newActivation(&nested_data->m_activation);
934         QScriptObject *activation_data = nested_data->m_activation.m_object_value;
935 
936         int formalCount = function->formals.count();
937         int mx = qMax(formalCount, argc);
938         activation_data->m_members.resize(mx);
939         activation_data->m_values.resize(mx);
940         for (int i = 0; i < mx; ++i) {
941             QScriptNameIdImpl *nameId = 0;
942             if (i < formalCount)
943                 nameId = function->formals.at(i);
944 
945             activation_data->m_members[i].object(nameId, i,
946                                                  QScriptValue::Undeletable
947                                                  | QScriptValue::SkipInEnumeration);
948             activation_data->m_values[i] = (i < argc) ? argp[i + 1] : undefined;
949         }
950 
951         eng->objectConstructor->newObject(&nested_data->m_thisObject);
952         nested_data->argc = argc;
953         if (callee.m_object_value->m_scope.isValid())
954             activation_data->m_scope = callee.m_object_value->m_scope;
955         else
956             activation_data->m_scope = eng->m_globalObject;
957         nested_data->tempStack = stackPtr;
958         nested_data->args = &argp[1];
959         nested_data->m_result = undefined;
960 
961         QScriptObject *instance = nested_data->m_thisObject.m_object_value;
962 
963         // set [[prototype]]
964         QScriptValueImpl dummy;
965         QScript::Member proto;
966         if (callee.resolve(eng->idTable()->id_prototype, &proto, &dummy, QScriptValue::ResolveLocal, QScript::Read))
967             callee.get(proto, &instance->m_prototype);
968         if (!instance->m_prototype.isObject())
969             instance->m_prototype = eng->objectConstructor->publicPrototype;
970 
971         function->execute(nested_data);
972 
973         --eng->m_callDepth;
974 
975         stackPtr = argp - 1;
976         if (isReference)
977             stackPtr -= 2;
978 
979         if (! nested_data->m_result.isValid())
980             nested_data->m_result = undefined;
981         else if (! nested_data->m_result.isObject())
982             nested_data->m_result = nested_data->m_thisObject;
983 
984         if (nested_data->m_state == QScriptContext::ExceptionState) {
985             eng->popContext();
986             if (eng->shouldAbort())
987                 Abort();
988             else
989                 Done();
990         }
991 
992         CHECK_TEMPSTACK(1);
993 
994         *++stackPtr = nested_data->m_result;
995 
996         eng->popContext();
997 
998         if (eng->shouldAbort())
999             Abort();
1000 
1001         if (eng->m_processEventsInterval > 0)
1002             eng->processEvents();
1003 
1004         ++iPtr;
1005     }   Next();
1006 
1007     I(FetchField):
1008     {
1009         QScriptValueImpl object = eng->toObject(stackPtr[-1]);
1010         if (! object.isValid()) {
1011             stackPtr -= 2;
1012             throwTypeError(QLatin1String("not an object"));
1013             HandleException();
1014         }
1015 
1016         QScriptValueImpl m = stackPtr[0];
1017 
1018         QScript::Ecma::Array::Instance *arrayInstance = 0;
1019         if (object.classInfo() == eng->arrayConstructor->classInfo())
1020             arrayInstance = static_cast<QScript::Ecma::Array::Instance *> (object.m_object_value->m_data);
1021 
1022         if (arrayInstance) {
1023             quint32 pos = toArrayIndex(m);
1024             if (pos != 0xFFFFFFFF) {
1025                 QScriptValueImpl val = arrayInstance->value.at(pos);
1026                 if (val.isValid()) {
1027                     *--stackPtr = val;
1028                     ++iPtr;
1029                     Next();
1030                 }
1031             }
1032         }
1033 
1034         QScriptNameIdImpl *nameId = m.isString() ? m.m_string_value : 0;
1035 
1036         if (! nameId || ! nameId->unique) {
1037             QString str;
1038 
1039             if (m.isNumber())
1040                 qscript_uint_to_string(m.m_number_value, str);
1041 
1042             if (str.isEmpty())
1043                 str = QScriptEnginePrivate::convertToNativeString(m);
1044 
1045             nameId = eng->nameId(str, /*persistent=*/false);
1046         }
1047 
1048         QScript::Member member;
1049         QScriptValueImpl base;
1050 
1051         if (object.resolve(nameId, &member, &base, QScriptValue::ResolvePrototype, QScript::Read)) {
1052             base.get(member, --stackPtr);
1053             if (hasUncaughtException()) {
1054                 stackPtr -= 1;
1055                 HandleException();
1056             } else if (member.isGetterOrSetter()) {
1057                 // call the getter function
1058                 QScriptValueImpl getter;
1059                 if (member.isGetter()) {
1060                     getter = *stackPtr;
1061                 } else {
1062                     if (!base.m_object_value->findGetter(&member)) {
1063                         stackPtr -= 1;
1064                         throwError(QLatin1String("No getter defined"));
1065                         HandleException();
1066                     }
1067                     base.get(member, &getter);
1068                 }
1069                 *stackPtr = getter.call(object);
1070                 if (hasUncaughtException()) {
1071                     stackPtr -= 1;
1072                     Done();
1073                 }
1074             }
1075         } else {
1076             *(--stackPtr) = undefined;
1077         }
1078 
1079         ++iPtr;
1080     }   Next();
1081 
1082     I(LazyArguments):
1083     {
1084         QScript::Member member;
1085         QScriptValueImpl base;
1086         QScriptNameIdImpl *arguments = eng->idTable()->id_arguments;
1087         if (!m_activation.resolve(arguments, &member, &base, QScriptValue::ResolveLocal, QScript::Read)) {
1088             CREATE_MEMBER(m_activation, arguments, &member, QScriptValue::Undeletable);
1089             if (!m_arguments.isValid()) {
1090                 if (eng->strictlyEquals(m_activation, eng->globalObject()))
1091                     m_arguments = undefined;
1092                 else
1093                     eng->newArguments(&m_arguments, m_activation, argc, m_callee);
1094             }
1095             m_activation.put(member, m_arguments);
1096         }
1097         ++iPtr;
1098     }   Next();
1099 
1100     I(DeclareLocal):
1101     {
1102         QScriptValueImpl &act = m_activation;
1103 
1104         QScriptNameIdImpl *memberName = iPtr->operand[0].m_string_value;
1105         bool readOnly = iPtr->operand[1].m_int_value != 0;
1106         QScript::Member member;
1107         QScriptValueImpl object;
1108 
1109         if (! act.resolve(memberName, &member, &object, QScriptValue::ResolveLocal, QScript::ReadWrite)) {
1110             uint flags = QScriptValue::Undeletable;
1111             if (readOnly)
1112                 flags |= QScript::Member::UninitializedConst | QScriptValue::ReadOnly;
1113             CREATE_MEMBER(act, memberName, &member, flags);
1114             act.put(member, undefined);
1115         }
1116         ++iPtr;
1117     }   Next();
1118 
1119     I(Assign):
1120     {
1121         if (! stackPtr[-1].isReference()) {
1122             stackPtr -= 2;
1123             throwSyntaxError(QLatin1String("invalid assignment lvalue"));
1124             HandleException();
1125         }
1126 
1127         QScriptValue::ResolveFlags mode;
1128         mode = QScriptValue::ResolveFlags(stackPtr[-1].m_int_value)
1129                | QScriptValue::ResolvePrototype;
1130 
1131         QScriptValueImpl object = eng->toObject(stackPtr[-3]);
1132         if (! object.isValid()) {
1133             stackPtr -= 4;
1134             throwTypeError(QLatin1String("invalid assignment lvalue"));
1135             HandleException();
1136         }
1137 
1138         QScriptValueImpl m = stackPtr[-2];
1139         QScriptValueImpl value = stackPtr[0];
1140 
1141         quint32 pos = 0xFFFFFFFF;
1142 
1143         QScript::Ecma::Array::Instance *arrayInstance = eng->arrayConstructor->get(object);
1144         if (arrayInstance)
1145             pos = toArrayIndex(m);
1146 
1147         stackPtr -= 3;
1148 
1149         if (pos != 0xFFFFFFFF)
1150             arrayInstance->value.assign(pos, value);
1151 
1152         else {
1153             QScriptNameIdImpl *memberName;
1154 
1155             if (m.isString() && m.m_string_value->unique)
1156                 memberName = m.m_string_value;
1157             else
1158                 memberName = eng->nameId(QScriptEnginePrivate::convertToNativeString(m), /*persistent=*/false);
1159 
1160             QScriptValueImpl base;
1161             QScript::Member member;
1162 
1163             const bool isMemberAssignment = (object.m_object_value != m_scopeChain.m_object_value);
1164             if (! object.resolve(memberName, &member, &base, mode, QScript::Write)) {
1165                 if (isMemberAssignment)
1166                     base = object;
1167                 else
1168                     base = eng->m_globalObject;
1169 
1170                 CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
1171             }
1172 
1173             if (value.isString() && ! value.m_string_value->unique)
1174                 eng->newNameId(&value, value.m_string_value->s);
1175 
1176             if (member.isGetterOrSetter()) {
1177                 // find and call setter(value)
1178                 QScriptValueImpl setter;
1179                 if (!member.isSetter()) {
1180                     if (!base.m_object_value->findSetter(&member)) {
1181                         stackPtr -= 1;
1182                         throwError(QLatin1String("no setter defined"));
1183                         HandleException();
1184                     }
1185                 }
1186                 base.get(member, &setter);
1187 
1188                 if (!isMemberAssignment) {
1189                     // decide the this-object. This is the object that actually
1190                     // has the setter (in its prototype chain).
1191                     while (!object.resolve(memberName, &member, &base, QScriptValue::ResolvePrototype, QScript::Write))
1192                         object = object.scope();
1193                     if (object.classInfo() == eng->m_class_with)
1194                         object = object.prototype();
1195                 }
1196 
1197                 value = setter.call(object, QScriptValueImplList() << value);
1198                 if (hasUncaughtException()) {
1199                     stackPtr -= 1;
1200                     Done();
1201                 }
1202             } else {
1203                 if (object.classInfo() == eng->m_class_with)
1204                     object = object.prototype();
1205 
1206                 if (member.isWritable()) {
1207                     if (isMemberAssignment && (base.m_object_value != object.m_object_value)) {
1208                         base = object;
1209                         CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
1210                     }
1211                     base.put(member, value);
1212                 } else if (member.isUninitializedConst()) {
1213                     base.put(member, value);
1214                     if (member.isObjectProperty()) {
1215                         base.m_object_value->m_members[member.id()]
1216                             .unsetFlags(QScript::Member::UninitializedConst);
1217                     }
1218                 }
1219                 if (hasUncaughtException()) {
1220                     stackPtr -= 1;
1221                     HandleException();
1222                 }
1223             }
1224         }
1225 
1226         *stackPtr = value;
1227         ++iPtr;
1228     }   Next();
1229 
1230     I(BitAnd):
1231     {
1232         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]);
1233         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]);
1234         *(--stackPtr) = QScriptValueImpl(v1 & v2);
1235         ++iPtr;
1236     }   Next();
1237 
1238     I(BitOr):
1239     {
1240         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]);
1241         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]);
1242         *(--stackPtr) = QScriptValueImpl(v1 | v2);
1243         ++iPtr;
1244     }   Next();
1245 
1246     I(BitXor):
1247     {
1248         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]);
1249         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]);
1250         *(--stackPtr) = QScriptValueImpl(v1 ^ v2);
1251         ++iPtr;
1252     }   Next();
1253 
1254     I(BitNot):
1255     {
1256         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]);
1257         *stackPtr = QScriptValueImpl(~v1);
1258         ++iPtr;
1259     }   Next();
1260 
1261     I(Not):
1262     {
1263         bool v1 = QScriptEnginePrivate::convertToNativeBoolean(stackPtr[0]);
1264         *stackPtr = QScriptValueImpl(!v1);
1265         ++iPtr;
1266     }   Next();
1267 
1268     I(LeftShift):
1269     {
1270         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]);
1271         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]) & 0x1f;
1272         *(--stackPtr) = QScriptValueImpl(v1 << v2);
1273         ++iPtr;
1274     } Next();
1275 
1276     I(Mod):
1277     {
1278         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]);
1279         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]);
1280 
1281         *(--stackPtr) = QScriptValueImpl(::fmod(v1, v2));
1282         ++iPtr;
1283     }   Next();
1284 
1285     I(RightShift):
1286     {
1287         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[-1]);
1288         quint32 v2 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(stackPtr[0])) & 0x1f;
1289         *(--stackPtr) = QScriptValueImpl(v1 >> v2);
1290         ++iPtr;
1291     }   Next();
1292 
1293     I(URightShift):
1294     {
1295         quint32 v1 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(stackPtr[-1]));
1296         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(stackPtr[0]) & 0x1f;
1297         *(--stackPtr) = QScriptValueImpl(v1 >> v2);
1298         ++iPtr;
1299     }   Next();
1300 
1301     I(InstanceOf):
1302     {
1303         QScriptValueImpl object = stackPtr[-1];
1304         QScriptValueImpl ctor = stackPtr[0];
1305 
1306         if (!ctor.isObject() || !ctor.implementsHasInstance()) {
1307             stackPtr -= 2;
1308             throwTypeError(QLatin1String("invalid 'instanceof' operand"));
1309             HandleException();
1310         }
1311 
1312         bool result = ctor.hasInstance(object);
1313         if (eng->hasUncaughtException()) {
1314             stackPtr -= 2;
1315             HandleException();
1316         }
1317 
1318         *(--stackPtr) = QScriptValueImpl(result);
1319         ++iPtr;
1320     }   Next();
1321 
1322     I(In):
1323     {
1324         QScriptValueImpl object = stackPtr[0];
1325         if (!object.isObject()) {
1326             stackPtr -= 2;
1327             throwTypeError(QLatin1String("invalid 'in' operand"));
1328             HandleException();
1329         }
1330         QString propertyName = QScriptEnginePrivate::convertToNativeString(stackPtr[-1]);
1331         bool result = object.property(propertyName, QScriptValue::ResolvePrototype).isValid(); // ### hasProperty()
1332         *(--stackPtr) = QScriptValueImpl(result);
1333         ++iPtr;
1334     }   Next();
1335 
1336     I(Add):
1337     {
1338         QScriptValueImpl lhs = eng->toPrimitive(stackPtr[-1], QScriptValueImpl::NoTypeHint);
1339         QScriptValueImpl rhs = eng->toPrimitive(stackPtr[0], QScriptValueImpl::NoTypeHint);
1340 
1341         if (lhs.isString() || rhs.isString()) {
1342             QString tmp = QScriptEnginePrivate::convertToNativeString(lhs);
1343             tmp += QScriptEnginePrivate::convertToNativeString(rhs);
1344             eng->newString(--stackPtr, tmp);
1345         } else {
1346             qsreal tmp = QScriptEnginePrivate::convertToNativeDouble(lhs);
1347             tmp += QScriptEnginePrivate::convertToNativeDouble(rhs);
1348             *(--stackPtr) = QScriptValueImpl(tmp);
1349         }
1350 
1351         ++iPtr;
1352     }   Next();
1353 
1354     I(Div):
1355     {
1356         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]);
1357         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]);
1358         *(--stackPtr) = QScriptValueImpl(v1 / v2);
1359         ++iPtr;
1360     }   Next();
1361 
1362     I(Equal):
1363     {
1364         QScriptValueImpl v1 = stackPtr[-1];
1365         QScriptValueImpl v2 = stackPtr[0];
1366         *(--stackPtr) = QScriptValueImpl(eq_cmp(v1, v2));
1367         ++iPtr;
1368     }   Next();
1369 
1370     I(GreatOrEqual):
1371     {
1372         QScriptValueImpl v1 = stackPtr[0];
1373         QScriptValueImpl v2 = stackPtr[-1];
1374         *(--stackPtr) = QScriptValueImpl(le_cmp(v1, v2));
1375         ++iPtr;
1376     }   Next();
1377 
1378     I(GreatThan):
1379     {
1380         QScriptValueImpl v1 = stackPtr[0];
1381         QScriptValueImpl v2 = stackPtr[-1];
1382         *(--stackPtr) = QScriptValueImpl(lt_cmp(v1, v2));
1383         ++iPtr;
1384     }   Next();
1385 
1386     I(LessOrEqual):
1387     {
1388         QScriptValueImpl v1 = stackPtr[-1];
1389         QScriptValueImpl v2 = stackPtr[0];
1390         *(--stackPtr) = QScriptValueImpl(le_cmp(v1, v2));
1391         ++iPtr;
1392     }   Next();
1393 
1394     I(LessThan):
1395     {
1396         QScriptValueImpl v1 = stackPtr[-1];
1397         QScriptValueImpl v2 = stackPtr[0];
1398         *(--stackPtr) = QScriptValueImpl(lt_cmp(v1, v2));
1399         ++iPtr;
1400     }   Next();
1401 
1402     I(NotEqual):
1403     {
1404         QScriptValueImpl v1 = stackPtr[-1];
1405         QScriptValueImpl v2 = stackPtr[0];
1406         *(--stackPtr) = QScriptValueImpl(!eq_cmp(v1, v2));
1407         ++iPtr;
1408     }   Next();
1409 
1410     I(Mul):
1411     {
1412         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]);
1413         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]);
1414         *(--stackPtr) = QScriptValueImpl(v1 * v2);
1415         ++iPtr;
1416     }   Next();
1417 
1418     I(StrictEqual):
1419     {
1420         QScriptValueImpl v1 = stackPtr[-1];
1421         QScriptValueImpl v2 = stackPtr[0];
1422         *(--stackPtr) = strict_eq_cmp(v1, v2);
1423         ++iPtr;
1424     }   Next();
1425 
1426     I(StrictNotEqual):
1427     {
1428         QScriptValueImpl v1 = stackPtr[-1];
1429         QScriptValueImpl v2 = stackPtr[0];
1430         *(--stackPtr) = ! strict_eq_cmp(v1, v2);
1431         ++iPtr;
1432     }   Next();
1433 
1434     I(Sub):
1435     {
1436         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[-1]);
1437         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(stackPtr[0]);
1438         *(--stackPtr) = QScriptValueImpl(v1 - v2);
1439         ++iPtr;
1440     }   Next();
1441 
1442     I(UnaryMinus):
1443     {
1444         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(*stackPtr);
1445         *stackPtr = QScriptValueImpl(-v1);
1446         ++iPtr;
1447     }   Next();
1448 
1449     I(UnaryPlus):
1450     {
1451         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(*stackPtr);
1452         *stackPtr = QScriptValueImpl(+v1);
1453         ++iPtr;
1454     }   Next();
1455 
1456     I(Branch):
1457     {
1458         eng->maybeProcessEvents();
1459         if (hasUncaughtException())
1460             HandleException();
1461         if (eng->shouldAbort())
1462             Abort();
1463         iPtr += iPtr->operand[0].m_int_value;
1464     }   Next();
1465 
1466     I(BranchFalse):
1467     {
1468         if (! QScriptEnginePrivate::convertToNativeBoolean(*stackPtr--))
1469             iPtr += iPtr->operand[0].m_int_value;
1470         else
1471             ++iPtr;
1472     }   Next();
1473 
1474     I(BranchTrue):
1475     {
1476         if (eng->convertToNativeBoolean(*stackPtr--))
1477             iPtr += iPtr->operand[0].m_int_value;
1478         else
1479             ++iPtr;
1480     }   Next();
1481 
1482     I(NewClosure):
1483     {
1484         CHECK_TEMPSTACK(1);
1485 
1486         QScript::AST::FunctionExpression *expr = static_cast<QScript::AST::FunctionExpression *> (iPtr->operand[0].m_ptr_value);
1487 
1488 #ifndef Q_SCRIPT_NO_JOINED_FUNCTION
1489         if (QScript::Code *code = eng->findCode(functionBody)) {
1490             QScriptValueImpl value = code->value;
1491 
1492             if (isValid(value)) {
1493                 QScriptObject *instance = value.m_object_value;
1494                 Q_ASSERT(instance != 0);
1495 
1496                 if (instance->m_scope.m_object_value == m_scopeChain.m_object_value)
1497                 {
1498                     *++stackPtr = value;
1499                     ++iPtr;
1500                     Next();
1501                 }
1502             }
1503         }
1504 #endif
1505 
1506         QScript::ScriptFunction *function = new QScript::ScriptFunction(expr, code->astPool);
1507 
1508         // update the formals
1509         for (QScript::AST::FormalParameterList *it = expr->formals; it != 0; it = it->next) {
1510             function->formals.append(it->name);
1511         }
1512         function->length = function->formals.count();
1513 
1514         eng->functionConstructor->newFunction(++stackPtr, function);
1515 
1516         QScriptObject *instance = stackPtr->m_object_value;
1517         // initialize [[scope]]
1518         instance->m_scope = m_scopeChain;
1519 
1520         // create and initialize `prototype'
1521         QScriptValueImpl proto;
1522         eng->objectConstructor->newObject(&proto);
1523 
1524         QScript::Member member;
1525         CREATE_MEMBER(proto, eng->idTable()->id_constructor, &member,
1526                       QScriptValue::Undeletable
1527                       | QScriptValue::SkipInEnumeration);
1528         proto.put(member, *stackPtr);
1529 
1530         stackPtr->createMember(eng->idTable()->id_prototype, &member,
1531                                        QScriptValue::Undeletable);
1532         stackPtr->put(member, proto);
1533 
1534         ++iPtr;
1535     }   Next();
1536 
1537     I(Incr):
1538     {
1539         if (! stackPtr[0].isReference()) {
1540             stackPtr -= 1;
1541             throwSyntaxError(QLatin1String("invalid increment operand"));
1542             HandleException();
1543         }
1544 
1545         BEGIN_PREFIX_OPERATOR
1546 
1547         qsreal x = QScriptEnginePrivate::convertToNativeDouble(value);
1548         value = QScriptValueImpl(x + 1);
1549 
1550         END_PREFIX_OPERATOR
1551     }   Next();
1552 
1553     I(Decr):
1554     {
1555         if (! stackPtr[0].isReference()) {
1556             stackPtr -= 1;
1557             throwSyntaxError(QLatin1String("invalid decrement operand"));
1558             HandleException();
1559         }
1560 
1561         BEGIN_PREFIX_OPERATOR
1562 
1563         qsreal x = QScriptEnginePrivate::convertToNativeDouble(value);
1564         value = QScriptValueImpl(x - 1);
1565 
1566         END_PREFIX_OPERATOR
1567     }   Next();
1568 
1569     I(PostIncr):
1570     {
1571         if (! stackPtr[0].isReference()) {
1572             stackPtr -= 1;
1573             throwSyntaxError(QLatin1String("invalid increment operand"));
1574             HandleException();
1575         }
1576 
1577         QScriptValue::ResolveFlags mode;
1578         mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value)
1579                | QScriptValue::ResolvePrototype;
1580 
1581         --stackPtr;
1582 
1583         QScriptValueImpl object = eng->toObject(stackPtr[-1]);
1584         if (!object.isObject()) {
1585             stackPtr -= 2;
1586             throwTypeError(QLatin1String("not an object"));
1587             HandleException();
1588         }
1589 
1590         QScriptNameIdImpl *memberName = 0;
1591         if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique)
1592             memberName = stackPtr[0].m_string_value;
1593         else
1594             memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false);
1595 
1596         QScript::Member member;
1597         QScriptValueImpl base;
1598         QScriptValueImpl value;
1599         QScriptObject *instance = object.m_object_value;
1600         const bool isMemberAssignment = (instance != m_scopeChain.m_object_value);
1601         if (instance->findMember(memberName, &member)) {
1602             if (!member.isGetterOrSetter()) {
1603                 QScriptValueImpl &r = instance->reference(member);
1604                 if (r.isNumber()) {
1605                     *(--stackPtr) = QScriptValueImpl(r.m_number_value);
1606                     r.incr();
1607                     ++iPtr;
1608                     Next();
1609                 }
1610             }
1611             base = object;
1612         } else if (!object.resolve_helper(memberName, &member, &base, mode, QScript::ReadWrite)) {
1613             if (!isMemberAssignment) {
1614                 stackPtr -= 2;
1615                 throwNotDefined(memberName);
1616                 HandleException();
1617             }
1618             base = object;
1619             CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
1620             base.put(member, undefined);
1621         }
1622 
1623         QScriptValueImpl getter;
1624         QScriptValueImpl setter;
1625         base.get(member, &value);
1626         if (hasUncaughtException()) {
1627             stackPtr -= 2;
1628             HandleException();
1629         } else if (member.isGetterOrSetter()) {
1630             if (member.isGetter()) {
1631                 getter = value;
1632                 if (!member.isSetter() && !base.m_object_value->findSetter(&member)) {
1633                     stackPtr -= 2;
1634                     throwError(QLatin1String("No setter defined"));
1635                     HandleException();
1636                 }
1637                 base.get(member, &setter);
1638             } else {
1639                 setter = value;
1640                 QScript::Member tmp = member;
1641                 if (!base.m_object_value->findGetter(&member)) {
1642                     stackPtr -= 2;
1643                     throwError(QLatin1String("No getter defined"));
1644                     HandleException();
1645                 }
1646                 base.get(member, &getter);
1647                 member = tmp;
1648             }
1649             value = getter.call(object);
1650             if (hasUncaughtException()) {
1651                 stackPtr -= 2;
1652                 Done();
1653             }
1654         }
1655 
1656         qsreal x = QScriptEnginePrivate::convertToNativeDouble(value);
1657 
1658         value = QScriptValueImpl(x + 1);
1659 
1660         if (member.isSetter()) {
1661             setter.call(object, QScriptValueImplList() << value);
1662             if (hasUncaughtException()) {
1663                 stackPtr -= 2;
1664                 Done();
1665             }
1666         } else {
1667             if (isMemberAssignment && (base.m_object_value != object.m_object_value)) {
1668                 base = object;
1669                 CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
1670             }
1671             if (member.isWritable()) {
1672                 base.put(member, value);
1673                 if (hasUncaughtException()) {
1674                     stackPtr -= 2;
1675                     HandleException();
1676                 }
1677             }
1678         }
1679 
1680         *(--stackPtr) = QScriptValueImpl(x);
1681 
1682         ++iPtr;
1683     }   Next();
1684 
1685     I(PostDecr):
1686     {
1687         // ### most of the code is duplicated from PostIncr -- try to merge
1688         if (! stackPtr[0].isReference()) {
1689             stackPtr -= 1;
1690             throwSyntaxError(QLatin1String("invalid decrement operand"));
1691             HandleException();
1692         }
1693 
1694         QScriptValue::ResolveFlags mode = QScriptValue::ResolveFlags(stackPtr[0].m_int_value)
1695                                           | QScriptValue::ResolvePrototype;
1696 
1697         --stackPtr;
1698 
1699         QScriptValueImpl object = eng->toObject(stackPtr[-1]);
1700         if (!object.isObject()) {
1701             stackPtr -= 2;
1702             throwTypeError(QLatin1String("not an object"));
1703             HandleException();
1704         }
1705 
1706         QScriptNameIdImpl *memberName = 0;
1707         if (stackPtr[0].isString() && stackPtr[0].m_string_value->unique)
1708             memberName = stackPtr[0].m_string_value;
1709         else
1710             memberName = eng->nameId(stackPtr[0].toString(), /*persistent=*/false);
1711 
1712         QScript::Member member;
1713         QScriptValueImpl base;
1714         QScriptValueImpl value;
1715         QScriptObject *instance = object.m_object_value;
1716         const bool isMemberAssignment = (instance != m_scopeChain.m_object_value);
1717         if (instance->findMember(memberName, &member)) {
1718             if (!member.isGetterOrSetter()) {
1719                 QScriptValueImpl &r = instance->reference(member);
1720                 if (r.isNumber()) {
1721                     *(--stackPtr) = QScriptValueImpl(r.m_number_value);
1722                     r.decr();
1723                     ++iPtr;
1724                     Next();
1725                 }
1726             }
1727             base = object;
1728         } else if (! object.resolve_helper(memberName, &member, &base, mode, QScript::ReadWrite)) {
1729             if (!isMemberAssignment) {
1730                 stackPtr -= 2;
1731                 throwNotDefined(memberName);
1732                 HandleException();
1733             }
1734             base = object;
1735             CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
1736             base.put(member, undefined);
1737         }
1738 
1739         QScriptValueImpl getter;
1740         QScriptValueImpl setter;
1741         base.get(member, &value);
1742         if (hasUncaughtException()) {
1743             stackPtr -= 2;
1744             HandleException();
1745         } else if (member.isGetterOrSetter()) {
1746             if (member.isGetter()) {
1747                 getter = value;
1748                 if (!member.isSetter() && !base.m_object_value->findSetter(&member)) {
1749                     stackPtr -= 2;
1750                     throwError(QLatin1String("No setter defined"));
1751                     HandleException();
1752                 }
1753                 base.get(member, &setter);
1754             } else {
1755                 setter = value;
1756                 QScript::Member tmp = member;
1757                 if (!base.m_object_value->findGetter(&member)) {
1758                     stackPtr -= 2;
1759                     throwError(QLatin1String("No getter defined"));
1760                     HandleException();
1761                 }
1762                 base.get(member, &getter);
1763                 member = tmp;
1764             }
1765             value = getter.call(object);
1766             if (hasUncaughtException()) {
1767                 stackPtr -= 2;
1768                 Done();
1769             }
1770         }
1771 
1772         qsreal x = QScriptEnginePrivate::convertToNativeDouble(value);
1773 
1774         value = QScriptValueImpl(x - 1);
1775 
1776         if (member.isSetter()) {
1777             setter.call(object, QScriptValueImplList() << value);
1778             if (hasUncaughtException()) {
1779                 stackPtr -= 2;
1780                 Done();
1781             }
1782         } else {
1783             if (isMemberAssignment && (base.m_object_value != object.m_object_value)) {
1784                 base = object;
1785                 CREATE_MEMBER(base, memberName, &member, /*flags=*/0);
1786             }
1787             if (member.isWritable()) {
1788                 base.put(member, value);
1789                 if (hasUncaughtException()) {
1790                     stackPtr -= 2;
1791                     HandleException();
1792                 }
1793             }
1794         }
1795 
1796         *(--stackPtr) = QScriptValueImpl(x);
1797 
1798         ++iPtr;
1799     }   Next();
1800 
1801     I(InplaceAdd):
1802     {
1803         BEGIN_INPLACE_OPERATOR
1804 
1805         lhs = eng->toPrimitive(lhs);
1806         rhs = eng->toPrimitive(rhs);
1807         if (lhs.isString() || rhs.isString()) {
1808             if (lhs.isString() && !lhs.m_string_value->unique) {
1809                 lhs.m_string_value->s += QScriptEnginePrivate::convertToNativeString(rhs);
1810                 stackPtr -= 3;
1811                 *stackPtr = lhs;
1812             } else {
1813                 QString tmp = QScriptEnginePrivate::convertToNativeString(lhs);
1814                 tmp += QScriptEnginePrivate::convertToNativeString(rhs);
1815                 stackPtr -= 3;
1816                 eng->newString(stackPtr, tmp);
1817             }
1818         } else {
1819             qsreal tmp = QScriptEnginePrivate::convertToNativeDouble(lhs);
1820             tmp += QScriptEnginePrivate::convertToNativeDouble(rhs);
1821             stackPtr -= 3;
1822             *stackPtr = QScriptValueImpl(tmp);
1823         }
1824 
1825         END_INPLACE_OPERATOR
1826     }   Next();
1827 
1828     I(InplaceSub):
1829     {
1830         BEGIN_INPLACE_OPERATOR
1831 
1832         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs);
1833         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs);
1834 
1835         stackPtr -= 3;
1836         *stackPtr = QScriptValueImpl(v1 - v2);
1837 
1838         END_INPLACE_OPERATOR
1839     }   Next();
1840 
1841     I(InplaceAnd):
1842     {
1843         BEGIN_INPLACE_OPERATOR
1844 
1845         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs);
1846         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs);
1847 
1848         stackPtr -= 3;
1849         *stackPtr = QScriptValueImpl(v1 & v2);
1850 
1851         END_INPLACE_OPERATOR
1852     }   Next();
1853 
1854     I(InplaceDiv):
1855     {
1856         BEGIN_INPLACE_OPERATOR
1857 
1858         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs);
1859         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs);
1860 
1861         stackPtr -= 3;
1862         *stackPtr = QScriptValueImpl(v1 / v2);
1863 
1864         END_INPLACE_OPERATOR
1865     }   Next();
1866 
1867     I(InplaceLeftShift):
1868     {
1869         BEGIN_INPLACE_OPERATOR
1870 
1871         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs);
1872         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs);
1873 
1874         stackPtr -= 3;
1875         *stackPtr = QScriptValueImpl(v1 << v2);
1876 
1877         END_INPLACE_OPERATOR
1878     }   Next();
1879 
1880     I(InplaceMod):
1881     {
1882         BEGIN_INPLACE_OPERATOR
1883 
1884         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs);
1885         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs);
1886 
1887         stackPtr -= 3;
1888         *stackPtr = QScriptValueImpl(::fmod (v1, v2));
1889 
1890         END_INPLACE_OPERATOR
1891     }   Next();
1892 
1893     I(InplaceMul):
1894     {
1895         BEGIN_INPLACE_OPERATOR
1896 
1897         qsreal v1 = QScriptEnginePrivate::convertToNativeDouble(lhs);
1898         qsreal v2 = QScriptEnginePrivate::convertToNativeDouble(rhs);
1899 
1900         stackPtr -= 3;
1901         *stackPtr = QScriptValueImpl(v1 * v2);
1902 
1903         END_INPLACE_OPERATOR
1904     }   Next();
1905 
1906     I(InplaceOr):
1907     {
1908         BEGIN_INPLACE_OPERATOR
1909 
1910         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs);
1911         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs);
1912 
1913         stackPtr -= 3;
1914         *stackPtr = QScriptValueImpl(v1 | v2);
1915 
1916         END_INPLACE_OPERATOR
1917     }   Next();
1918 
1919     I(InplaceRightShift):
1920     {
1921         BEGIN_INPLACE_OPERATOR
1922 
1923         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs);
1924         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs);
1925 
1926         stackPtr -= 3;
1927         *stackPtr = QScriptValueImpl(v1 >> v2);
1928 
1929         END_INPLACE_OPERATOR
1930     }   Next();
1931 
1932     I(InplaceURightShift):
1933     {
1934         BEGIN_INPLACE_OPERATOR
1935 
1936         quint32 v1 = QScriptEnginePrivate::toUint32 (eng->convertToNativeDouble(lhs));
1937         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs);
1938 
1939         stackPtr -= 3;
1940         *stackPtr = QScriptValueImpl(v1 >> v2);
1941 
1942         END_INPLACE_OPERATOR
1943     }   Next();
1944 
1945     I(InplaceXor):
1946     {
1947         BEGIN_INPLACE_OPERATOR
1948 
1949         qint32 v1 = QScriptEnginePrivate::convertToNativeInt32(lhs);
1950         qint32 v2 = QScriptEnginePrivate::convertToNativeInt32(rhs);
1951 
1952         stackPtr -= 3;
1953         *stackPtr = QScriptValueImpl(v1 ^ v2);
1954 
1955         END_INPLACE_OPERATOR
1956     }   Next();
1957 
1958     I(MakeReference):
1959     {
1960         CHECK_TEMPSTACK(1);
1961         eng->newReference(++stackPtr, QScriptValue::ResolveLocal);
1962         ++iPtr;
1963     }   Next();
1964 
1965     I(TypeOf):
1966     {
1967         QScriptValueImpl value;
1968 
1969         bool isReference = stackPtr[0].isReference();
1970 
1971         if (! isReference) { // we have a value
1972             value = stackPtr[0];
1973         } else if (resolveField(eng, &stackPtr[-1], &value)) {
1974             stackPtr -= 2;
1975             if (hasUncaughtException()) {
1976                 stackPtr -= 1;
1977                 HandleException();
1978             }
1979         } else {
1980             value = undefined;
1981             stackPtr -= 2;
1982         }
1983 
1984         QString typeName;
1985 
1986         switch (value.type()) {
1987         case QScript::InvalidType:
1988             typeName = QLatin1String("invalid");
1989             break;
1990 
1991         case QScript::UndefinedType:
1992             typeName = QLatin1String("undefined");
1993             break;
1994 
1995         case QScript::NullType:
1996             typeName = QLatin1String("object");
1997             break;
1998 
1999         case QScript::BooleanType:
2000             typeName = QLatin1String("boolean");
2001             break;
2002 
2003         case QScript::IntegerType:
2004         case QScript::NumberType:
2005             typeName = QLatin1String("number");
2006             break;
2007 
2008         case QScript::StringType:
2009         case QScript::LazyStringType:
2010             typeName = QLatin1String("string");
2011             break;
2012 
2013         case QScript::ReferenceType:
2014             typeName = QLatin1String("reference");
2015             break;
2016 
2017         case QScript::PointerType:
2018             typeName = QLatin1String("pointer");
2019             break;
2020 
2021         case QScript::ObjectType:
2022             if (value.isFunction())
2023                 typeName = QLatin1String("function");
2024             else
2025                 typeName = QLatin1String("object");
2026             break;
2027         }
2028 
2029         eng->newString(stackPtr, typeName);
2030         ++iPtr;
2031     }   Next();
2032 
2033     I(Line):
2034     {
2035         eng->maybeGC();
2036         eng->maybeProcessEvents();
2037         if (hasUncaughtException())
2038             HandleException();
2039         if (eng->shouldAbort())
2040             Abort();
2041         currentLine = iPtr->operand[0].m_int_value;
2042         currentColumn = iPtr->operand[1].m_int_value;
2043 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2044         if (eng->shouldNotify()) {
2045             eng->notifyPositionChange(this);
2046             if (hasUncaughtException())
2047                 HandleException();
2048             if (eng->shouldAbort())
2049                 Abort();
2050         }
2051 #endif
2052         ++iPtr;
2053     }   Next();
2054 
2055     I(Delete):
2056     {
2057         bool result;
2058         if (! stackPtr[0].isReference())
2059             result = true;
2060 
2061         else {
2062             QScriptValueImpl object = stackPtr[-2];
2063             if (!object.isObject())
2064                 object = eng->toObject(object);
2065 
2066             QScriptNameIdImpl *nameId = 0;
2067             if (stackPtr[-1].isString() && stackPtr[-1].m_string_value->unique) {
2068                 nameId = stackPtr[-1].m_string_value;
2069             } else {
2070                 nameId = eng->nameId(QScriptEnginePrivate::convertToNativeString(stackPtr[-1]),
2071                                      /*persistent=*/false);
2072             }
2073             if (object.classInfo() == eng->m_class_with)
2074                 object = object.prototype();
2075             result = object.deleteProperty(nameId, QScriptValue::ResolveScope);
2076             stackPtr -= 2;
2077         }
2078 
2079         *stackPtr = QScriptValueImpl(result);
2080 
2081         ++iPtr;
2082     }   Next();
2083 
2084 
2085     I(NewEnumeration): {
2086         QScriptValueImpl e;
2087         QScriptValueImpl object = eng->toObject(stackPtr[0]);
2088         eng->enumerationConstructor->newEnumeration(&e, object);
2089         *stackPtr = e;
2090         ++iPtr;
2091     }   Next();
2092 
2093 
2094     I(ToFirstElement): {
2095         QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[0]);
2096         Q_ASSERT(e != 0);
2097         e->toFront();
2098         --stackPtr;
2099         ++iPtr;
2100     }   Next();
2101 
2102 
2103     I(HasNextElement): {
2104         QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[0]);
2105         Q_ASSERT(e != 0);
2106         e->hasNext(this, stackPtr);
2107         ++iPtr;
2108     }   Next();
2109 
2110 
2111     I(NextElement): {
2112         // the Enumeration should be located below the result of I(Resolve)
2113         if (! stackPtr[0].isReference()) {
2114             throwTypeError(QLatin1String("QScript.VM.NextElement"));
2115             HandleException();
2116         }
2117 
2118         QScript::Ext::Enumeration::Instance *e = eng->enumerationConstructor->get(stackPtr[-3]);
2119         if (! e) {
2120             throwTypeError(QLatin1String("QScript.VM.NextElement"));
2121             HandleException();
2122         }
2123         e->next(this, ++stackPtr);
2124         ++iPtr;
2125     }   Next();
2126 
2127 
2128     I(Pop):
2129     {
2130         --stackPtr;
2131         ++iPtr;
2132     }   Next();
2133 
2134     I(Sync):
2135     {
2136         m_result = *stackPtr;
2137         --stackPtr;
2138         ++iPtr;
2139     }   Next();
2140 
2141     I(Throw):
2142     {
2143         Q_ASSERT(stackPtr->isValid());
2144         m_result = *stackPtr--;
2145         if (!m_result.isError() && !exceptionHandlerContext())
2146             eng->m_exceptionBacktrace = backtrace();
2147         m_state = QScriptContext::ExceptionState;
2148 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2149         eng->notifyException(this);
2150 #endif
2151     }   HandleException();
2152 
2153     I(Ret):
2154     {
2155         Q_ASSERT(stackPtr->isValid());
2156         m_result = *stackPtr--;
2157         ++iPtr;
2158     }   Done();
2159 
2160     I(Halt):
2161     {
2162         ++iPtr;
2163     }   Done();
2164 
2165     I(EnterWith):
2166     {
2167         QScriptValueImpl object = eng->toObject(*stackPtr--);
2168         if (! object.isValid()) {
2169             throwTypeError(QLatin1String("value has no properties"));
2170             HandleException();
2171         }
2172         QScriptValueImpl withObject;
2173         eng->newObject(&withObject, object, eng->m_class_with);
2174         withObject.m_object_value->m_scope = m_scopeChain;
2175         m_scopeChain = withObject;
2176         ++iPtr;
2177     }   Next();
2178 
2179     I(LeaveWith):
2180     {
2181         QScriptValueImpl withObject = m_scopeChain;
2182         m_scopeChain = withObject.m_object_value->m_scope;
2183         ++iPtr;
2184     }   Next();
2185 
2186     I(BeginCatch):
2187     {
2188         // result contains the thrown object
2189         QScriptValueImpl object;
2190         eng->newObject(&object, undefined); // ### prototype
2191         QScript::Member member;
2192         CREATE_MEMBER(object, iPtr->operand[0].m_string_value, &member, /*flags=*/0);
2193         object.put(member, m_result);
2194         // make catch-object head of scopechain
2195         object.m_object_value->m_scope = m_scopeChain;
2196         m_scopeChain = object;
2197 
2198         catching = true;
2199         ++iPtr;
2200     }   Next();
2201 
2202     I(EndCatch):
2203     {
2204         // remove catch-object from scopechain
2205         QScriptValueImpl object = m_scopeChain;
2206         m_scopeChain = object.m_object_value->m_scope;
2207 
2208         catching = false;
2209         ++iPtr;
2210     }   Next();
2211 
2212     I(Debugger):
2213     {
2214 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2215         eng->notifyDebugger(this);
2216 #endif
2217         ++iPtr;
2218     }   Next();
2219 
2220 #ifndef Q_SCRIPT_DIRECT_CODE
2221     I(Dummy):
2222     { ; }
2223 
2224     } // end switch
2225 #endif
2226 
2227 Lhandle_exception:
2228     errorLineNumber = currentLine;
2229 
2230 Ldone:
2231     Q_ASSERT(m_result.isValid());
2232 
2233     if (m_state == QScriptContext::ExceptionState) {
2234         if (catching) {
2235             // exception thrown in catch -- clean up scopechain
2236             QScriptValueImpl object = m_scopeChain;
2237             m_scopeChain = object.m_object_value->m_scope;
2238             catching = false;
2239         }
2240 
2241         // see if we have an exception handler in this context
2242         const QScriptInstruction *exPtr = findExceptionHandler(iPtr);
2243         if (exPtr) {
2244             if (m_scopeChain.classInfo() == eng->m_class_with) {
2245                 // clean up effects of with-statements if necessary
2246                 int withLevel = 0;
2247                 for (++iPtr; iPtr != exPtr; ++iPtr) {
2248                     if (iPtr->op == QScriptInstruction::OP_EnterWith) {
2249                         ++withLevel;
2250                     } else if (iPtr->op == QScriptInstruction::OP_LeaveWith) {
2251                         --withLevel;
2252                         if (withLevel < 0) {
2253                             QScriptValueImpl withObject = m_scopeChain;
2254                             m_scopeChain = withObject.m_object_value->m_scope;
2255                         }
2256                     }
2257                 }
2258             } else {
2259                 iPtr = exPtr;
2260             }
2261             // go to the handler
2262             recover();
2263 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2264             eng->notifyExceptionCatch(this);
2265 #endif
2266             goto Ltop;
2267         } else {
2268             if (!parentContext()) {
2269                 // pop all the top-level with-objects
2270                 while ((m_scopeChain.classInfo() == eng->m_class_with)
2271                        && !m_scopeChain.internalValue().isValid()) {
2272                     QScriptValueImpl withObject = m_scopeChain;
2273                     m_scopeChain = withObject.m_object_value->m_scope;
2274                 }
2275             }
2276         }
2277     }
2278 
2279 Labort:
2280 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2281     eng->notifyFunctionExit(this);
2282 #endif
2283 
2284     eng->maybeGC();
2285 
2286     currentLine = oldCurrentLine;
2287     currentColumn = oldCurrentColumn;
2288     m_code = oldCode;
2289 
2290     eng->m_evaluating = wasEvaluating;
2291 }
2292 
throwError(QScriptContext::Error error,const QString & text)2293 QScriptValueImpl QScriptContextPrivate::throwError(QScriptContext::Error error, const QString &text)
2294 {
2295     QScriptEnginePrivate *eng_p = engine();
2296     QScript::Ecma::Error *ctor = eng_p->errorConstructor;
2297     m_result.invalidate();
2298     switch (error) {
2299     case QScriptContext::ReferenceError:
2300         ctor->newReferenceError(&m_result, text);
2301         break;
2302     case QScriptContext::SyntaxError:
2303         ctor->newSyntaxError(&m_result, text);
2304         break;
2305     case QScriptContext::TypeError:
2306         ctor->newTypeError(&m_result, text);
2307         break;
2308     case QScriptContext::RangeError:
2309         ctor->newRangeError(&m_result, text);
2310         break;
2311     case QScriptContext::URIError:
2312         ctor->newURIError(&m_result, text);
2313         break;
2314     case QScriptContext::UnknownError:
2315     default:
2316         ctor->newError(&m_result, text);
2317     }
2318     setDebugInformation(&m_result);
2319     m_state = QScriptContext::ExceptionState;
2320 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
2321         eng_p->notifyException(this);
2322 #endif
2323     return m_result;
2324 }
2325 
2326 #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
scriptId() const2327 qint64 QScriptContextPrivate::scriptId() const
2328 {
2329     if (!m_code)
2330         return -1;
2331     return m_code->astPool->id();
2332 }
2333 #endif
2334 
fileName() const2335 QString QScriptContextPrivate::fileName() const
2336 {
2337     if (!m_code)
2338         return QString();
2339     return m_code->astPool->fileName();
2340 }
2341 
functionName() const2342 QString QScriptContextPrivate::functionName() const
2343 {
2344     if (!m_callee.isValid())
2345         return QString();
2346     QScriptFunction *fun = m_callee.toFunction();
2347     if (fun)
2348         return fun->functionName();
2349     return QString();
2350 }
2351 
setDebugInformation(QScriptValueImpl * error) const2352 void QScriptContextPrivate::setDebugInformation(QScriptValueImpl *error) const
2353 {
2354     QScriptEnginePrivate *eng_p = engine();
2355     error->setProperty(QLatin1String("lineNumber"), QScriptValueImpl(currentLine));
2356     if (!fileName().isEmpty())
2357         error->setProperty(QLatin1String("fileName"), QScriptValueImpl(eng_p, fileName()));
2358 
2359     const QScriptContextPrivate *ctx = this;
2360     QScriptValueImpl stackArray = eng_p->newArray();
2361     int i = 0;
2362     while (ctx) {
2363         QScriptValueImpl obj = eng_p->newObject();
2364         obj.setProperty(QLatin1String("frame"), ctx->activationObject());
2365         obj.setProperty(QLatin1String("lineNumber"), QScriptValueImpl(ctx->currentLine));
2366         if (!ctx->fileName().isEmpty())
2367             obj.setProperty(QLatin1String("fileName"), QScriptValueImpl(eng_p, ctx->fileName()));
2368         if (!ctx->functionName().isEmpty())
2369             obj.setProperty(QLatin1String("functionName"), QScriptValueImpl(eng_p, ctx->functionName()));
2370         stackArray.setProperty(i, obj);
2371         ctx = ctx->parentContext();
2372         ++i;
2373     }
2374     error->setProperty(QLatin1String("stack"), stackArray);
2375 }
2376 
backtrace() const2377 QStringList QScriptContextPrivate::backtrace() const
2378 {
2379     QStringList result;
2380     const QScriptContextPrivate *ctx = this;
2381     while (ctx) {
2382         QString s;
2383         QString functionName = ctx->functionName();
2384         if (!functionName.isEmpty())
2385             s += functionName;
2386         else {
2387             if (ctx->parentContext()) {
2388                 if (ctx->callee().isFunction()
2389                     && ctx->callee().toFunction()->type() != QScriptFunction::Script) {
2390                     s += QLatin1String("<native>");
2391                 } else {
2392                     s += QLatin1String("<anonymous>");
2393                 }
2394             } else {
2395                 s += QLatin1String("<global>");
2396             }
2397         }
2398         s += QLatin1Char('(');
2399         for (int i = 0; i < ctx->argc; ++i) {
2400             if (i > 0)
2401                 s += QLatin1Char(',');
2402             QScriptValueImpl arg = ctx->args[i];
2403             if (arg.isObject())
2404                 s += QLatin1String("[object Object]"); // don't do a function call
2405             else
2406                 s += arg.toString();
2407         }
2408         s += QLatin1String(")@");
2409         s += ctx->fileName();
2410         s += QString::fromLatin1(":%0").arg(ctx->currentLine);
2411         result.append(s);
2412         ctx = ctx->parentContext();
2413     }
2414     return result;
2415 }
2416 
throwError(const QString & text)2417 QScriptValueImpl QScriptContextPrivate::throwError(const QString &text)
2418 {
2419     return throwError(QScriptContext::UnknownError, text);
2420 }
2421 
throwNotImplemented(const QString & name)2422 QScriptValueImpl QScriptContextPrivate::throwNotImplemented(const QString &name)
2423 {
2424     return throwTypeError(QString::fromUtf8("%1 is not implemented").arg(name));
2425 }
2426 
throwNotDefined(const QString & name)2427 QScriptValueImpl QScriptContextPrivate::throwNotDefined(const QString &name)
2428 {
2429     return throwError(QScriptContext::ReferenceError,
2430                       QString::fromUtf8("%1 is not defined").arg(name));
2431 }
2432 
throwNotDefined(QScriptNameIdImpl * nameId)2433 QScriptValueImpl QScriptContextPrivate::throwNotDefined(QScriptNameIdImpl *nameId)
2434 {
2435     return throwNotDefined(QScriptEnginePrivate::toString(nameId));
2436 }
2437 
eq_cmp_helper(QScriptValueImpl lhs,QScriptValueImpl rhs)2438 bool QScriptContextPrivate::eq_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs)
2439 {
2440     if (lhs.isNull() && rhs.isUndefined())
2441         return true;
2442 
2443     else if (lhs.isUndefined() && rhs.isNull())
2444         return true;
2445 
2446     else if (isNumerical(lhs) && rhs.isString())
2447         return QScriptEnginePrivate::convertToNativeDouble(lhs) == QScriptEnginePrivate::convertToNativeDouble(rhs);
2448 
2449     else if (lhs.isString() && isNumerical(rhs))
2450         return QScriptEnginePrivate::convertToNativeDouble(lhs) == QScriptEnginePrivate::convertToNativeDouble(rhs);
2451 
2452     else if (lhs.isBoolean())
2453         return eq_cmp(QScriptValueImpl(QScriptEnginePrivate::convertToNativeDouble(lhs)), rhs);
2454 
2455     else if (rhs.isBoolean())
2456         return eq_cmp(lhs, QScriptValueImpl(QScriptEnginePrivate::convertToNativeDouble(rhs)));
2457 
2458     else if (lhs.isObject() && ! rhs.isNull()) {
2459         lhs = lhs.engine()->toPrimitive(lhs);
2460 
2461         if (lhs.isValid() && ! lhs.isObject())
2462             return eq_cmp(lhs, rhs);
2463     }
2464 
2465     else if (rhs.isObject() && ! lhs.isNull()) {
2466         rhs = rhs.engine()->toPrimitive(rhs);
2467 
2468         if (rhs.isValid() && ! rhs.isObject())
2469             return eq_cmp(lhs, rhs);
2470     }
2471 
2472     return false;
2473 }
2474 
2475 #if defined(Q_CC_GNU) && __GNUC__ <= 3
lt_cmp(QScriptValueImpl lhs,QScriptValueImpl rhs)2476 bool QScriptContextPrivate::lt_cmp(QScriptValueImpl lhs, QScriptValueImpl rhs)
2477 {
2478     if (lhs.type() == rhs.type()) {
2479         switch (lhs.type()) {
2480         case QScript::InvalidType:
2481         case QScript::UndefinedType:
2482         case QScript::NullType:
2483             return false;
2484 
2485         case QScript::NumberType:
2486             return lhs.m_number_value < rhs.m_number_value;
2487 
2488         case QScript::IntegerType:
2489             return lhs.m_int_value < rhs.m_int_value;
2490 
2491         case QScript::BooleanType:
2492             return lhs.m_bool_value < rhs.m_bool_value;
2493 
2494         default:
2495             break;
2496         } // switch
2497     }
2498 #else
2499 bool QScriptContextPrivate::lt_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs)
2500 {
2501 #endif
2502     if ((lhs.type() == rhs.type()) && (lhs.type() == QScript::StringType))
2503         return lhs.m_string_value->s < rhs.m_string_value->s;
2504 
2505     if (lhs.isObject())
2506         lhs = lhs.engine()->toPrimitive(lhs, QScriptValueImpl::NumberTypeHint);
2507 
2508     if (rhs.isObject())
2509         rhs = rhs.engine()->toPrimitive(rhs, QScriptValueImpl::NumberTypeHint);
2510 
2511     if (lhs.isString() && rhs.isString())
2512         return QScriptEnginePrivate::convertToNativeString(lhs) < QScriptEnginePrivate::convertToNativeString(rhs);
2513 
2514     qsreal n1 = QScriptEnginePrivate::convertToNativeDouble(lhs);
2515     qsreal n2 = QScriptEnginePrivate::convertToNativeDouble(rhs);
2516 #if defined Q_CC_MSVC && !defined Q_CC_MSVC_NET
2517     if (qIsNaN(n1) || qIsNaN(n2))
2518         return false;
2519 #endif
2520     return n1 < n2;
2521 }
2522 
2523 bool QScriptContextPrivate::le_cmp_helper(QScriptValueImpl lhs, QScriptValueImpl rhs)
2524 {
2525     if ((lhs.type() == rhs.type()) && (lhs.type() == QScript::StringType))
2526         return lhs.m_string_value->s <= rhs.m_string_value->s;
2527 
2528     if (lhs.isObject())
2529         lhs = lhs.engine()->toPrimitive(lhs, QScriptValueImpl::NumberTypeHint);
2530 
2531     if (rhs.isObject())
2532         rhs = rhs.engine()->toPrimitive(rhs, QScriptValueImpl::NumberTypeHint);
2533 
2534     if (lhs.isString() && rhs.isString())
2535         return QScriptEnginePrivate::convertToNativeString(lhs) <= QScriptEnginePrivate::convertToNativeString(rhs);
2536 
2537     qsreal n1 = QScriptEnginePrivate::convertToNativeDouble(lhs);
2538     qsreal n2 = QScriptEnginePrivate::convertToNativeDouble(rhs);
2539     return n1 <= n2;
2540 }
2541 
2542 const QScriptInstruction *QScriptContextPrivate::findExceptionHandler(
2543     const QScriptInstruction *ip) const
2544 {
2545     Q_ASSERT(m_code);
2546     int offset = ip - m_code->firstInstruction;
2547     for (int i = 0; i < m_code->exceptionHandlers.count(); ++i) {
2548         QScript::ExceptionHandlerDescriptor e = m_code->exceptionHandlers.at(i);
2549         if (offset >= e.startInstruction() && offset <= e.endInstruction()) {
2550             return m_code->firstInstruction + e.handlerInstruction();
2551         }
2552     }
2553     return 0;
2554 }
2555 
2556 const QScriptInstruction *QScriptContextPrivate::findExceptionHandlerRecursive(
2557     const QScriptInstruction *ip, QScriptContextPrivate **handlerContext) const
2558 {
2559     const QScriptContextPrivate *ctx = this;
2560     const QScriptInstruction *iip = ip;
2561     while (ctx) {
2562         if (ctx->m_code) {
2563             const QScriptInstruction *ep = ctx->findExceptionHandler(iip);
2564             if (ep) {
2565                 Q_ASSERT(handlerContext);
2566                 *handlerContext = const_cast<QScriptContextPrivate*>(ctx);
2567                 return ep;
2568             }
2569         }
2570         ctx = ctx->parentContext();
2571         if (ctx)
2572             iip = ctx->iPtr;
2573     }
2574     return 0;
2575 }
2576 
2577 /*!
2578   Requires that iPtr in current context is in sync
2579 */
2580 QScriptContextPrivate *QScriptContextPrivate::exceptionHandlerContext() const
2581 {
2582     QScriptContextPrivate *handlerContext;
2583     if (findExceptionHandlerRecursive(iPtr, &handlerContext))
2584         return handlerContext;
2585     return 0;
2586 }
2587 
2588 QScriptContext *QScriptContextPrivate::get(QScriptContextPrivate *d)
2589 {
2590     if (d)
2591         return d->q_func();
2592     return 0;
2593 }
2594 
2595 QT_END_NAMESPACE
2596 
2597