source: trunk/src/script/qscriptcontext_p.cpp@ 350

Last change on this file since 350 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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