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