1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qv4vme_moth_p.h"
41
42#include <QtCore/qjsondocument.h>
43#include <QtCore/qjsonobject.h>
44
45#include <private/qv4instr_moth_p.h>
46#include <private/qv4value_p.h>
47#include <private/qv4debugging_p.h>
48#include <private/qv4function_p.h>
49#include <private/qv4functionobject_p.h>
50#include <private/qv4math_p.h>
51#include <private/qv4scopedvalue_p.h>
52#include <private/qv4lookup_p.h>
53#include <private/qv4regexp_p.h>
54#include <private/qv4regexpobject_p.h>
55#include <private/qv4string_p.h>
56#include <private/qv4profiling_p.h>
57#include <private/qv4jscall_p.h>
58#include <private/qv4generatorobject_p.h>
59#include <private/qv4alloca_p.h>
60#include <private/qqmljavascriptexpression_p.h>
61#include <iostream>
62
63#if QT_CONFIG(qml_jit)
64#include <private/qv4baselinejit_p.h>
65#endif
66
67#include <qtqml_tracepoints_p.h>
68
69#undef COUNT_INSTRUCTIONS
70
71enum { ShowWhenDeoptimiationHappens = 0 };
72
73extern "C" {
74
75// This is the interface to Qt Creator's (new) QML debugger.
76
77/*! \internal
78 \since 5.5
79
80 This function is called uncondionally from VME::run().
81
82 An attached debugger can set a breakpoint here to
83 intercept calls to VME::run().
84 */
85
86Q_QML_EXPORT void qt_v4ResolvePendingBreakpointsHook()
87{
88}
89
90/*! \internal
91 \since 5.5
92
93 This function is called when a QML interpreter breakpoint
94 is hit.
95
96 An attached debugger can set a breakpoint here.
97*/
98Q_QML_EXPORT void qt_v4TriggeredBreakpointHook()
99{
100}
101
102/*! \internal
103 \since 5.5
104
105 The main entry point into "Native Mixed" Debugging.
106
107 Commands are passed as UTF-8 encoded JSON data.
108 The data has two compulsory fields:
109 \list
110 \li \c version: Version of the protocol (currently 1)
111 \li \c command: Name of the command
112 \endlist
113
114 Depending on \c command, more fields can be present.
115
116 Error is indicated by negative return values,
117 success by non-negative return values.
118
119 \c protocolVersion:
120 Returns version of implemented protocol.
121
122 \c insertBreakpoint:
123 Sets a breakpoint on a given file and line.
124 \list
125 \li \c fullName: Name of the QML/JS file
126 \li \c lineNumber: Line number in the file
127 \li \c condition: Breakpoint condition
128 \endlist
129 Returns a unique positive number as handle.
130
131 \c removeBreakpoint:
132 Removes a breakpoint from a given file and line.
133 \list
134 \li \c fullName: Name of the QML/JS file
135 \li \c lineNumber: Line number in the file
136 \li \c condition: Breakpoint condition
137 \endlist
138 Returns zero on success, a negative number on failure.
139
140 \c prepareStep:
141 Puts the interpreter in stepping mode.
142 Returns zero.
143
144*/
145Q_QML_EXPORT int qt_v4DebuggerHook(const char *json);
146
147
148} // extern "C"
149
150#if QT_CONFIG(qml_debug)
151static int qt_v4BreakpointCount = 0;
152static bool qt_v4IsDebugging = false;
153static bool qt_v4IsStepping = false;
154
155class Breakpoint
156{
157public:
158 Breakpoint() : bpNumber(0), lineNumber(-1) {}
159
160 bool matches(const QString &file, int line) const
161 {
162 return fullName == file && lineNumber == line;
163 }
164
165 int bpNumber;
166 int lineNumber;
167 QString fullName; // e.g. /opt/project/main.qml
168 QString engineName; // e.g. qrc:/main.qml
169 QString condition; // optional
170};
171
172static QVector<Breakpoint> qt_v4Breakpoints;
173static Breakpoint qt_v4LastStop;
174
175static void qt_v4TriggerBreakpoint(const Breakpoint &bp, QV4::Function *function)
176{
177 qt_v4LastStop = bp;
178
179 // Set up some auxiliary data for informational purpose.
180 // This is not part of the protocol.
181 QV4::Heap::String *functionName = function->name();
182 QByteArray functionNameUtf8;
183 if (functionName)
184 functionNameUtf8 = functionName->toQString().toUtf8();
185
186 qt_v4TriggeredBreakpointHook(); // Trigger Breakpoint.
187}
188
189int qt_v4DebuggerHook(const char *json)
190{
191 const int ProtocolVersion = 1;
192
193 enum {
194 Success = 0,
195 WrongProtocol,
196 NoSuchCommand,
197 NoSuchBreakpoint
198 };
199
200 QJsonDocument doc = QJsonDocument::fromJson(json);
201 QJsonObject ob = doc.object();
202 QByteArray command = ob.value(QLatin1String("command")).toString().toUtf8();
203
204 if (command == "protocolVersion") {
205 return ProtocolVersion; // Version number.
206 }
207
208 int version = ob.value(QLatin1String("version")).toString().toInt();
209 if (version != ProtocolVersion) {
210 return -WrongProtocol;
211 }
212
213 if (command == "insertBreakpoint") {
214 Breakpoint bp;
215 bp.bpNumber = ++qt_v4BreakpointCount;
216 bp.lineNumber = ob.value(QLatin1String("lineNumber")).toString().toInt();
217 bp.engineName = ob.value(QLatin1String("engineName")).toString();
218 bp.fullName = ob.value(QLatin1String("fullName")).toString();
219 bp.condition = ob.value(QLatin1String("condition")).toString();
220 qt_v4Breakpoints.append(bp);
221 qt_v4IsDebugging = true;
222 return bp.bpNumber;
223 }
224
225 if (command == "removeBreakpoint") {
226 int lineNumber = ob.value(QLatin1String("lineNumber")).toString().toInt();
227 QString fullName = ob.value(QLatin1String("fullName")).toString();
228 if (qt_v4Breakpoints.last().matches(fullName, lineNumber)) {
229 qt_v4Breakpoints.removeLast();
230 qt_v4IsDebugging = !qt_v4Breakpoints.isEmpty();
231 return Success;
232 }
233 for (int i = 0; i + 1 < qt_v4Breakpoints.size(); ++i) {
234 if (qt_v4Breakpoints.at(i).matches(fullName, lineNumber)) {
235 qt_v4Breakpoints[i] = qt_v4Breakpoints.takeLast();
236 return Success; // Ok.
237 }
238 }
239 return -NoSuchBreakpoint; // Failure
240 }
241
242 if (command == "prepareStep") {
243 qt_v4IsStepping = true;
244 return Success; // Ok.
245 }
246
247
248 return -NoSuchCommand; // Failure.
249}
250
251Q_NEVER_INLINE static void qt_v4CheckForBreak(QV4::CppStackFrame *frame)
252{
253 if (!qt_v4IsStepping && !qt_v4Breakpoints.size())
254 return;
255
256 const int lineNumber = frame->lineNumber();
257 QV4::Function *function = frame->v4Function;
258 QString engineName = function->sourceFile();
259
260 if (engineName.isEmpty())
261 return;
262
263 if (qt_v4IsStepping) {
264 if (qt_v4LastStop.lineNumber != lineNumber
265 || qt_v4LastStop.engineName != engineName) {
266 qt_v4IsStepping = false;
267 Breakpoint bp;
268 bp.bpNumber = 0;
269 bp.lineNumber = lineNumber;
270 bp.engineName = engineName;
271 qt_v4TriggerBreakpoint(bp, function);
272 return;
273 }
274 }
275
276 for (int i = qt_v4Breakpoints.size(); --i >= 0; ) {
277 const Breakpoint &bp = qt_v4Breakpoints.at(i);
278 if (bp.lineNumber != lineNumber)
279 continue;
280 if (bp.engineName != engineName)
281 continue;
282
283 qt_v4TriggerBreakpoint(bp, function);
284 }
285}
286
287Q_NEVER_INLINE static void debug_slowPath(QV4::ExecutionEngine *engine)
288{
289 QV4::Debugging::Debugger *debugger = engine->debugger();
290 if (debugger && debugger->pauseAtNextOpportunity())
291 debugger->maybeBreakAtInstruction();
292 if (qt_v4IsDebugging)
293 qt_v4CheckForBreak(engine->currentStackFrame);
294}
295
296#endif // QT_CONFIG(qml_debug)
297// End of debugger interface
298
299using namespace QV4;
300using namespace QV4::Moth;
301
302#ifdef COUNT_INSTRUCTIONS
303static struct InstrCount {
304 InstrCount() {
305 fprintf(stderr, "Counting instructions...\n");
306 for (int i = 0; i < MOTH_NUM_INSTRUCTIONS(); ++i)
307 hits[i] = 0;
308 }
309 ~InstrCount() {
310 fprintf(stderr, "Instruction count:\n");
311#define BLAH(I) \
312 fprintf(stderr, "%llu : %s\n", hits[int(Instr::Type::I)], #I);
313 FOR_EACH_MOTH_INSTR(BLAH)
314 #undef BLAH
315 }
316 quint64 hits[MOTH_NUM_INSTRUCTIONS()];
317 void hit(Instr::Type i) { hits[int(i)]++; }
318} instrCount;
319#endif // COUNT_INSTRUCTIONS
320
321#define MOTH_BEGIN_INSTR_COMMON(instr) \
322 { \
323 INSTR_##instr(MOTH_DECODE)
324
325#ifdef COUNT_INSTRUCTIONS
326# define MOTH_BEGIN_INSTR(instr) \
327 MOTH_BEGIN_INSTR_COMMON(instr) \
328 instrCount.hit(Instr::Type::instr);
329#else // !COUNT_INSTRUCTIONS
330# define MOTH_BEGIN_INSTR(instr) \
331 MOTH_BEGIN_INSTR_COMMON(instr)
332#endif // COUNT_INSTRUCTIONS
333
334#ifdef MOTH_COMPUTED_GOTO
335#define MOTH_END_INSTR(instr) \
336 MOTH_DISPATCH_SINGLE() \
337 }
338#else // !MOTH_COMPUTED_GOTO
339#define MOTH_END_INSTR(instr) \
340 continue; \
341 }
342#endif
343
344#define STACK_VALUE(temp) stack[temp]
345
346// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
347#ifdef CHECK_EXCEPTION
348#undef CHECK_EXCEPTION
349#endif
350#define CHECK_EXCEPTION \
351 if (engine->hasException || engine->isInterrupted.loadAcquire()) \
352 goto handleUnwind
353
354static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
355{
356 Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
357 while (level > 0) {
358 --level;
359 scope = scope->outer;
360 }
361 Q_ASSERT(scope);
362 return static_cast<Heap::CallContext *>(scope);
363}
364
365static inline const QV4::Value &constant(Function *function, int index)
366{
367 return function->compilationUnit->constants[index].asValue<Value>();
368}
369
370static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
371{
372 redo:
373 switch (lhs.quickType()) {
374 case QV4::Value::QT_ManagedOrUndefined:
375 if (lhs.isUndefined())
376 return false;
377 Q_FALLTHROUGH();
378 case QV4::Value::QT_ManagedOrUndefined1:
379 case QV4::Value::QT_ManagedOrUndefined2:
380 case QV4::Value::QT_ManagedOrUndefined3:
381 // LHS: Managed
382 if (lhs.m()->internalClass->vtable->isString)
383 return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs;
384 accumulator = lhs;
385 lhs = QV4::Value::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT));
386 goto redo;
387 case QV4::Value::QT_Empty:
388 Q_UNREACHABLE();
389 case QV4::Value::QT_Null:
390 return false;
391 case QV4::Value::QT_Bool:
392 case QV4::Value::QT_Int:
393 return lhs.int_32() == rhs;
394 default: // double
395 return lhs.doubleValue() == rhs;
396 }
397}
398
399#define STORE_IP() frame->instructionPointer = int(code - function->codeData);
400#define STORE_ACC() accumulator = acc;
401#define ACC Value::fromReturnedValue(acc)
402#define VALUE_TO_INT(i, val) \
403 int i; \
404 do { \
405 if (Q_LIKELY(val.integerCompatible())) { \
406 i = val.int_32(); \
407 } else { \
408 double d; \
409 if (val.isDouble()) \
410 d = val.doubleValue(); \
411 else { \
412 STORE_ACC(); \
413 d = val.toNumberImpl(); \
414 CHECK_EXCEPTION; \
415 } \
416 i = Double::toInt32(d); \
417 } \
418 } while (false)
419
420ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
421{
422 qt_v4ResolvePendingBreakpointsHook();
423 CHECK_STACK_LIMITS(engine);
424
425 Function *function = frame->v4Function;
426 Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
427 function->compilationUnit->fileName(),
428 function->compiledFunction->location.line,
429 function->compiledFunction->location.column);
430 Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
431 QV4::Debugging::Debugger *debugger = engine->debugger();
432
433#if QT_CONFIG(qml_jit)
434 if (debugger == nullptr) {
435 if (function->jittedCode == nullptr) {
436 if (engine->canJIT(function))
437 QV4::JIT::BaselineJIT(function).generate();
438 else
439 ++function->interpreterCallCount;
440 }
441 }
442#endif // QT_CONFIG(qml_jit)
443
444 // interpreter
445 if (debugger)
446 debugger->enteringFunction();
447
448 ReturnedValue result;
449 if (function->jittedCode != nullptr && debugger == nullptr) {
450 result = function->jittedCode(frame, engine);
451 } else {
452 // interpreter
453 result = interpret(frame, engine, function->codeData);
454 }
455
456 if (debugger)
457 debugger->leavingFunction(result);
458
459 return result;
460}
461
462QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code)
463{
464 QV4::Function *function = frame->v4Function;
465 QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>();
466 QV4::ReturnedValue acc = accumulator.asReturnedValue();
467 Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
468
469 MOTH_JUMP_TABLE;
470
471 for (;;) {
472 MOTH_DISPATCH()
473 Q_UNREACHABLE(); // only reached when the dispatch doesn't jump somewhere
474
475 MOTH_BEGIN_INSTR(LoadConst)
476 acc = constant(function, index).asReturnedValue();
477 MOTH_END_INSTR(LoadConst)
478
479 MOTH_BEGIN_INSTR(LoadNull)
480 acc = Encode::null();
481 MOTH_END_INSTR(LoadNull)
482
483 MOTH_BEGIN_INSTR(LoadZero)
484 acc = Encode(static_cast<int>(0));
485 MOTH_END_INSTR(LoadZero)
486
487 MOTH_BEGIN_INSTR(LoadTrue)
488 acc = Encode(true);
489 MOTH_END_INSTR(LoadTrue)
490
491 MOTH_BEGIN_INSTR(LoadFalse)
492 acc = Encode(false);
493 MOTH_END_INSTR(LoadFalse)
494
495 MOTH_BEGIN_INSTR(LoadUndefined)
496 acc = Encode::undefined();
497 MOTH_END_INSTR(LoadUndefined)
498
499 MOTH_BEGIN_INSTR(LoadInt)
500 acc = Encode(value);
501 MOTH_END_INSTR(LoadInt)
502
503 MOTH_BEGIN_INSTR(MoveConst)
504 STACK_VALUE(destTemp) = constant(function, constIndex);
505 MOTH_END_INSTR(MoveConst)
506
507 MOTH_BEGIN_INSTR(LoadReg)
508 acc = STACK_VALUE(reg).asReturnedValue();
509 MOTH_END_INSTR(LoadReg)
510
511 MOTH_BEGIN_INSTR(StoreReg)
512 STACK_VALUE(reg) = acc;
513 MOTH_END_INSTR(StoreReg)
514
515 MOTH_BEGIN_INSTR(MoveReg)
516 STACK_VALUE(destReg) = STACK_VALUE(srcReg);
517 MOTH_END_INSTR(MoveReg)
518
519 MOTH_BEGIN_INSTR(LoadImport)
520 acc = function->compilationUnit->imports[index]->asReturnedValue();
521 MOTH_END_INSTR(LoadImport)
522
523 MOTH_BEGIN_INSTR(LoadLocal)
524 auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
525 Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
526 acc = cc->locals[index].asReturnedValue();
527 MOTH_END_INSTR(LoadLocal)
528
529 MOTH_BEGIN_INSTR(StoreLocal)
530 CHECK_EXCEPTION;
531 auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
532 Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
533 QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
534 MOTH_END_INSTR(StoreLocal)
535
536 MOTH_BEGIN_INSTR(LoadScopedLocal)
537 auto cc = getScope(stack, scope);
538 acc = cc->locals[index].asReturnedValue();
539 MOTH_END_INSTR(LoadScopedLocal)
540
541 MOTH_BEGIN_INSTR(StoreScopedLocal)
542 CHECK_EXCEPTION;
543 auto cc = getScope(stack, scope);
544 QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
545 MOTH_END_INSTR(StoreScopedLocal)
546
547 MOTH_BEGIN_INSTR(LoadRuntimeString)
548 acc = function->compilationUnit->runtimeStrings[stringId]->asReturnedValue();
549 MOTH_END_INSTR(LoadRuntimeString)
550
551 MOTH_BEGIN_INSTR(MoveRegExp)
552 STACK_VALUE(destReg) = Runtime::RegexpLiteral::call(engine, regExpId);
553 MOTH_END_INSTR(MoveRegExp)
554
555 MOTH_BEGIN_INSTR(LoadClosure)
556 acc = Runtime::Closure::call(engine, value);
557 MOTH_END_INSTR(LoadClosure)
558
559 MOTH_BEGIN_INSTR(LoadName)
560 STORE_IP();
561 acc = Runtime::LoadName::call(engine, name);
562 CHECK_EXCEPTION;
563 MOTH_END_INSTR(LoadName)
564
565 MOTH_BEGIN_INSTR(LoadGlobalLookup)
566 STORE_IP();
567 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
568 acc = l->globalGetter(l, engine);
569 CHECK_EXCEPTION;
570 MOTH_END_INSTR(LoadGlobalLookup)
571
572 MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
573 STORE_IP();
574 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
575 acc = l->qmlContextPropertyGetter(l, engine, nullptr);
576 CHECK_EXCEPTION;
577 MOTH_END_INSTR(LoadQmlContextPropertyLookup)
578
579 MOTH_BEGIN_INSTR(StoreNameStrict)
580 STORE_IP();
581 STORE_ACC();
582 Runtime::StoreNameStrict::call(engine, name, accumulator);
583 CHECK_EXCEPTION;
584 MOTH_END_INSTR(StoreNameStrict)
585
586 MOTH_BEGIN_INSTR(StoreNameSloppy)
587 STORE_IP();
588 STORE_ACC();
589 Runtime::StoreNameSloppy::call(engine, name, accumulator);
590 CHECK_EXCEPTION;
591 MOTH_END_INSTR(StoreNameSloppy)
592
593 MOTH_BEGIN_INSTR(LoadElement)
594 STORE_IP();
595 STORE_ACC();
596 acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator);
597 CHECK_EXCEPTION;
598 MOTH_END_INSTR(LoadElement)
599
600 MOTH_BEGIN_INSTR(StoreElement)
601 STORE_IP();
602 STORE_ACC();
603 Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
604 CHECK_EXCEPTION;
605 MOTH_END_INSTR(StoreElement)
606
607 MOTH_BEGIN_INSTR(LoadProperty)
608 STORE_IP();
609 STORE_ACC();
610 acc = Runtime::LoadProperty::call(engine, accumulator, name);
611 CHECK_EXCEPTION;
612 MOTH_END_INSTR(LoadProperty)
613
614 MOTH_BEGIN_INSTR(GetLookup)
615 STORE_IP();
616 STORE_ACC();
617
618 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
619
620 if (accumulator.isNullOrUndefined()) {
621 QString message = QStringLiteral("Cannot read property '%1' of %2")
622 .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
623 .arg(accumulator.toQStringNoThrow());
624 acc = engine->throwTypeError(message);
625 goto handleUnwind;
626 }
627
628 acc = l->getter(l, engine, accumulator);
629 CHECK_EXCEPTION;
630 MOTH_END_INSTR(GetLookup)
631
632 MOTH_BEGIN_INSTR(StoreProperty)
633 STORE_IP();
634 STORE_ACC();
635 Runtime::StoreProperty::call(engine, STACK_VALUE(base), name, accumulator);
636 CHECK_EXCEPTION;
637 MOTH_END_INSTR(StoreProperty)
638
639 MOTH_BEGIN_INSTR(SetLookup)
640 STORE_IP();
641 STORE_ACC();
642 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
643 if (!l->setter(l, engine, STACK_VALUE(base), accumulator) && function->isStrict())
644 engine->throwTypeError();
645 CHECK_EXCEPTION;
646 MOTH_END_INSTR(SetLookup)
647
648 MOTH_BEGIN_INSTR(LoadSuperProperty)
649 STORE_IP();
650 STORE_ACC();
651 acc = Runtime::LoadSuperProperty::call(engine, STACK_VALUE(property));
652 CHECK_EXCEPTION;
653 MOTH_END_INSTR(LoadSuperProperty)
654
655 MOTH_BEGIN_INSTR(StoreSuperProperty)
656 STORE_IP();
657 STORE_ACC();
658 Runtime::StoreSuperProperty::call(engine, STACK_VALUE(property), accumulator);
659 CHECK_EXCEPTION;
660 MOTH_END_INSTR(StoreSuperProperty)
661
662 MOTH_BEGIN_INSTR(Yield)
663 frame->yield = code;
664 frame->yieldIsIterator = false;
665 return acc;
666 MOTH_END_INSTR(Yield)
667
668 MOTH_BEGIN_INSTR(YieldStar)
669 frame->yield = code;
670 frame->yieldIsIterator = true;
671 return acc;
672 MOTH_END_INSTR(YieldStar)
673
674 MOTH_BEGIN_INSTR(Resume)
675 // check exception, in case the generator was called with throw() or return()
676 if (engine->hasException) {
677 // an empty value indicates that the generator was called with return()
678 if (engine->exceptionValue->asReturnedValue() != Value::emptyValue().asReturnedValue())
679 goto handleUnwind;
680 engine->hasException = false;
681 *engine->exceptionValue = Value::undefinedValue();
682 } else {
683 code += offset;
684 }
685 MOTH_END_INSTR(Resume)
686
687 MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
688 STORE_ACC();
689 acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
690 CHECK_EXCEPTION;
691 MOTH_END_INSTR(IteratorNextForYieldStar)
692
693 MOTH_BEGIN_INSTR(CallValue)
694 STORE_IP();
695 Value func = STACK_VALUE(name);
696 if (Q_UNLIKELY(!func.isFunctionObject())) {
697 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
698 goto handleUnwind;
699 }
700 Value undef = Value::undefinedValue();
701 acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
702 CHECK_EXCEPTION;
703 MOTH_END_INSTR(CallValue)
704
705 MOTH_BEGIN_INSTR(CallWithReceiver)
706 STORE_IP();
707 Value func = STACK_VALUE(name);
708 if (Q_UNLIKELY(!func.isFunctionObject())) {
709 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
710 goto handleUnwind;
711 }
712 acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
713 CHECK_EXCEPTION;
714 MOTH_END_INSTR(CallWithReceiver)
715
716 MOTH_BEGIN_INSTR(CallProperty)
717 STORE_IP();
718 acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc);
719 CHECK_EXCEPTION;
720 MOTH_END_INSTR(CallProperty)
721
722 MOTH_BEGIN_INSTR(CallPropertyLookup)
723 STORE_IP();
724 Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
725
726 if (stack[base].isNullOrUndefined()) {
727 QString message = QStringLiteral("Cannot call method '%1' of %2")
728 .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
729 .arg(stack[base].toQStringNoThrow());
730 acc = engine->throwTypeError(message);
731 goto handleUnwind;
732 }
733
734 // ok to have the value on the stack here
735 Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base]));
736
737 if (Q_UNLIKELY(!f.isFunctionObject())) {
738 QString message = QStringLiteral("Property '%1' of object %2 is not a function")
739 .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
740 .arg(stack[base].toQStringNoThrow());
741 acc = engine->throwTypeError(message);
742 goto handleUnwind;
743 }
744
745 acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
746 CHECK_EXCEPTION;
747 MOTH_END_INSTR(CallPropertyLookup)
748
749 MOTH_BEGIN_INSTR(CallElement)
750 STORE_IP();
751 acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc);
752 CHECK_EXCEPTION;
753 MOTH_END_INSTR(CallElement)
754
755 MOTH_BEGIN_INSTR(CallName)
756 STORE_IP();
757 acc = Runtime::CallName::call(engine, name, stack + argv, argc);
758 CHECK_EXCEPTION;
759 MOTH_END_INSTR(CallName)
760
761 MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
762 STORE_IP();
763 acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
764 CHECK_EXCEPTION;
765 MOTH_END_INSTR(CallPossiblyDirectEval)
766
767 MOTH_BEGIN_INSTR(CallGlobalLookup)
768 STORE_IP();
769 acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
770 CHECK_EXCEPTION;
771 MOTH_END_INSTR(CallGlobalLookup)
772
773 MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
774 STORE_IP();
775 acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
776 CHECK_EXCEPTION;
777 MOTH_END_INSTR(CallQmlContextPropertyLookup)
778
779 MOTH_BEGIN_INSTR(CallWithSpread)
780 STORE_IP();
781 acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
782 CHECK_EXCEPTION;
783 MOTH_END_INSTR(CallWithSpread)
784
785 MOTH_BEGIN_INSTR(TailCall)
786 STORE_IP();
787 *engine->jsAlloca(1) = Primitive::fromInt32(argc);
788 *engine->jsAlloca(1) = Primitive::fromInt32(argv);
789 *engine->jsAlloca(1) = STACK_VALUE(thisObject);
790 *engine->jsAlloca(1) = STACK_VALUE(func);
791 return Runtime::TailCall::call(frame, engine);
792 CHECK_EXCEPTION;
793 MOTH_END_INSTR(TailCall)
794
795 MOTH_BEGIN_INSTR(Construct)
796 STORE_IP();
797 acc = Runtime::Construct::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
798 CHECK_EXCEPTION;
799 MOTH_END_INSTR(Construct)
800
801 MOTH_BEGIN_INSTR(ConstructWithSpread)
802 STORE_IP();
803 acc = Runtime::ConstructWithSpread::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
804 CHECK_EXCEPTION;
805 MOTH_END_INSTR(ConstructWithSpread)
806
807 MOTH_BEGIN_INSTR(SetUnwindHandler)
808 frame->unwindHandler = offset ? code + offset : nullptr;
809 MOTH_END_INSTR(SetUnwindHandler)
810
811 MOTH_BEGIN_INSTR(UnwindDispatch)
812 CHECK_EXCEPTION;
813 if (frame->unwindLevel) {
814 --frame->unwindLevel;
815 if (frame->unwindLevel)
816 goto handleUnwind;
817 code = frame->unwindLabel;
818 }
819 MOTH_END_INSTR(UnwindDispatch)
820
821 MOTH_BEGIN_INSTR(UnwindToLabel)
822 frame->unwindLevel = level;
823 frame->unwindLabel = code + offset;
824 goto handleUnwind;
825 MOTH_END_INSTR(UnwindToLabel)
826
827 MOTH_BEGIN_INSTR(DeadTemporalZoneCheck)
828 if (ACC.isEmpty()) {
829 STORE_IP();
830 STORE_ACC();
831 Runtime::ThrowReferenceError::call(engine, name);
832 goto handleUnwind;
833 }
834 MOTH_END_INSTR(DeadTemporalZoneCheck)
835
836 MOTH_BEGIN_INSTR(ThrowException)
837 STORE_IP();
838 STORE_ACC();
839 Runtime::ThrowException::call(engine, accumulator);
840 goto handleUnwind;
841 MOTH_END_INSTR(ThrowException)
842
843 MOTH_BEGIN_INSTR(GetException)
844 acc = engine->hasException ? engine->exceptionValue->asReturnedValue()
845 : Value::emptyValue().asReturnedValue();
846 engine->hasException = false;
847 MOTH_END_INSTR(HasException)
848
849 MOTH_BEGIN_INSTR(SetException)
850 if (acc != Value::emptyValue().asReturnedValue()) {
851 *engine->exceptionValue = acc;
852 engine->hasException = true;
853 }
854 MOTH_END_INSTR(SetException)
855
856 MOTH_BEGIN_INSTR(PushCatchContext)
857 Runtime::PushCatchContext::call(engine, index, name);
858 MOTH_END_INSTR(PushCatchContext)
859
860 MOTH_BEGIN_INSTR(CreateCallContext)
861 Runtime::PushCallContext::call(frame);
862 MOTH_END_INSTR(CreateCallContext)
863
864 MOTH_BEGIN_INSTR(PushWithContext)
865 STORE_IP();
866 STORE_ACC();
867 acc = Runtime::PushWithContext::call(engine, stack[CallData::Accumulator]);
868 CHECK_EXCEPTION;
869 MOTH_END_INSTR(PushWithContext)
870
871 MOTH_BEGIN_INSTR(PushBlockContext)
872 STORE_ACC();
873 Runtime::PushBlockContext::call(engine, index);
874 MOTH_END_INSTR(PushBlockContext)
875
876 MOTH_BEGIN_INSTR(CloneBlockContext)
877 STORE_ACC();
878 Runtime::CloneBlockContext::call(engine);
879 MOTH_END_INSTR(CloneBlockContext)
880
881 MOTH_BEGIN_INSTR(PushScriptContext)
882 Runtime::PushScriptContext::call(engine, index);
883 MOTH_END_INSTR(PushScriptContext)
884
885 MOTH_BEGIN_INSTR(PopScriptContext)
886 Runtime::PopScriptContext::call(engine);
887 MOTH_END_INSTR(PopScriptContext)
888
889 MOTH_BEGIN_INSTR(PopContext)
890 ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
891 STACK_VALUE(CallData::Context) = c->d()->outer;
892 MOTH_END_INSTR(PopContext)
893
894 MOTH_BEGIN_INSTR(GetIterator)
895 STORE_IP();
896 STORE_ACC();
897 acc = Runtime::GetIterator::call(engine, accumulator, iterator);
898 CHECK_EXCEPTION;
899 MOTH_END_INSTR(GetIterator)
900
901 MOTH_BEGIN_INSTR(IteratorNext)
902 STORE_IP();
903 STORE_ACC();
904 acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
905 STACK_VALUE(done) = acc;
906 CHECK_EXCEPTION;
907 MOTH_END_INSTR(IteratorNext)
908
909 MOTH_BEGIN_INSTR(IteratorClose)
910 STORE_IP();
911 STORE_ACC();
912 acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done));
913 CHECK_EXCEPTION;
914 MOTH_END_INSTR(IteratorClose)
915
916 MOTH_BEGIN_INSTR(DestructureRestElement)
917 STORE_IP();
918 STORE_ACC();
919 acc = Runtime::DestructureRestElement::call(engine, ACC);
920 CHECK_EXCEPTION;
921 MOTH_END_INSTR(DestructureRestElement)
922
923 MOTH_BEGIN_INSTR(DeleteProperty)
924 acc = Runtime::DeleteProperty::call(engine, function, STACK_VALUE(base), STACK_VALUE(index));
925 CHECK_EXCEPTION;
926 MOTH_END_INSTR(DeleteProperty)
927
928 MOTH_BEGIN_INSTR(DeleteName)
929 acc = Runtime::DeleteName::call(engine, function, name);
930 CHECK_EXCEPTION;
931 MOTH_END_INSTR(DeleteName)
932
933 MOTH_BEGIN_INSTR(TypeofName)
934 acc = Runtime::TypeofName::call(engine, name);
935 MOTH_END_INSTR(TypeofName)
936
937 MOTH_BEGIN_INSTR(TypeofValue)
938 STORE_ACC();
939 acc = Runtime::TypeofValue::call(engine, accumulator);
940 MOTH_END_INSTR(TypeofValue)
941
942 MOTH_BEGIN_INSTR(DeclareVar)
943 Runtime::DeclareVar::call(engine, isDeletable, varName);
944 MOTH_END_INSTR(DeclareVar)
945
946 MOTH_BEGIN_INSTR(DefineArray)
947 QV4::Value *arguments = stack + args;
948 acc = Runtime::ArrayLiteral::call(engine, arguments, argc);
949 MOTH_END_INSTR(DefineArray)
950
951 MOTH_BEGIN_INSTR(DefineObjectLiteral)
952 QV4::Value *arguments = stack + args;
953 acc = Runtime::ObjectLiteral::call(engine, internalClassId, arguments, argc);
954 MOTH_END_INSTR(DefineObjectLiteral)
955
956 MOTH_BEGIN_INSTR(CreateClass)
957 acc = Runtime::CreateClass::call(engine, classIndex, STACK_VALUE(heritage), stack + computedNames);
958 MOTH_END_INSTR(CreateClass)
959
960 MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
961 acc = Runtime::CreateMappedArgumentsObject::call(engine);
962 MOTH_END_INSTR(CreateMappedArgumentsObject)
963
964 MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
965 acc = Runtime::CreateUnmappedArgumentsObject::call(engine);
966 MOTH_END_INSTR(CreateUnmappedArgumentsObject)
967
968 MOTH_BEGIN_INSTR(CreateRestParameter)
969 acc = Runtime::CreateRestParameter::call(engine, argIndex);
970 MOTH_END_INSTR(CreateRestParameter)
971
972 MOTH_BEGIN_INSTR(ConvertThisToObject)
973 stack[CallData::This] = Runtime::ConvertThisToObject::call(engine, stack[CallData::This]);
974 CHECK_EXCEPTION;
975 MOTH_END_INSTR(ConvertThisToObject)
976
977 MOTH_BEGIN_INSTR(LoadSuperConstructor)
978 acc = Runtime::LoadSuperConstructor::call(engine, stack[CallData::Function]);
979 CHECK_EXCEPTION;
980 MOTH_END_INSTR(LoadSuperConstructor)
981
982 MOTH_BEGIN_INSTR(ToObject)
983 acc = ACC.toObject(engine)->asReturnedValue();
984 CHECK_EXCEPTION;
985 MOTH_END_INSTR(ToObject)
986
987 MOTH_BEGIN_INSTR(Jump)
988 code += offset;
989 MOTH_END_INSTR(Jump)
990
991 MOTH_BEGIN_INSTR(JumpTrue)
992 bool takeJump;
993 if (Q_LIKELY(ACC.integerCompatible()))
994 takeJump = ACC.int_32();
995 else
996 takeJump = ACC.toBoolean();
997 if (takeJump)
998 code += offset;
999 MOTH_END_INSTR(JumpTrue)
1000
1001 MOTH_BEGIN_INSTR(JumpFalse)
1002 bool takeJump;
1003 if (Q_LIKELY(ACC.integerCompatible()))
1004 takeJump = !ACC.int_32();
1005 else
1006 takeJump = !ACC.toBoolean();
1007 if (takeJump)
1008 code += offset;
1009 MOTH_END_INSTR(JumpFalse)
1010
1011 MOTH_BEGIN_INSTR(JumpNoException)
1012 if (!engine->hasException)
1013 code += offset;
1014 MOTH_END_INSTR(JumpNoException)
1015
1016 MOTH_BEGIN_INSTR(JumpNotUndefined)
1017 if (Q_LIKELY(acc != QV4::Encode::undefined()))
1018 code += offset;
1019 MOTH_END_INSTR(JumpNotUndefined)
1020
1021 MOTH_BEGIN_INSTR(CheckException)
1022 CHECK_EXCEPTION;
1023 MOTH_END_INSTR(CheckException)
1024
1025 MOTH_BEGIN_INSTR(CmpEqNull)
1026 acc = Encode(ACC.isNullOrUndefined());
1027 MOTH_END_INSTR(CmpEqNull)
1028
1029 MOTH_BEGIN_INSTR(CmpNeNull)
1030 acc = Encode(!ACC.isNullOrUndefined());
1031 MOTH_END_INSTR(CmpNeNull)
1032
1033 MOTH_BEGIN_INSTR(CmpEqInt)
1034 if (ACC.isIntOrBool()) {
1035 acc = Encode(ACC.int_32() == lhs);
1036 } else {
1037 STORE_ACC();
1038 acc = Encode(compareEqualInt(accumulator, ACC, lhs));
1039 CHECK_EXCEPTION;
1040 }
1041 MOTH_END_INSTR(CmpEqInt)
1042
1043 MOTH_BEGIN_INSTR(CmpNeInt)
1044 if (ACC.isIntOrBool()) {
1045 acc = Encode(bool(ACC.int_32() != lhs));
1046 } else {
1047 STORE_ACC();
1048 acc = Encode(!compareEqualInt(accumulator, ACC, lhs));
1049 CHECK_EXCEPTION;
1050 }
1051 MOTH_END_INSTR(CmpNeInt)
1052
1053 MOTH_BEGIN_INSTR(CmpEq)
1054 const Value left = STACK_VALUE(lhs);
1055 if (Q_LIKELY(left.asReturnedValue() == ACC.asReturnedValue())) {
1056 acc = Encode(!ACC.isNaN());
1057 } else if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1058 acc = Encode(left.int_32() == ACC.int_32());
1059 } else {
1060 STORE_ACC();
1061 acc = Encode(bool(Runtime::CompareEqual::call(left, accumulator)));
1062 CHECK_EXCEPTION;
1063 }
1064 MOTH_END_INSTR(CmpEq)
1065
1066 MOTH_BEGIN_INSTR(CmpNe)
1067 const Value left = STACK_VALUE(lhs);
1068 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1069 acc = Encode(bool(left.int_32() != ACC.int_32()));
1070 } else {
1071 STORE_ACC();
1072 acc = Encode(bool(!Runtime::CompareEqual::call(left, accumulator)));
1073 CHECK_EXCEPTION;
1074 }
1075 MOTH_END_INSTR(CmpNe)
1076
1077 MOTH_BEGIN_INSTR(CmpGt)
1078 const Value left = STACK_VALUE(lhs);
1079 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1080 acc = Encode(left.int_32() > ACC.int_32());
1081 } else if (left.isNumber() && ACC.isNumber()) {
1082 acc = Encode(left.asDouble() > ACC.asDouble());
1083 } else {
1084 STORE_ACC();
1085 acc = Encode(bool(Runtime::CompareGreaterThan::call(left, accumulator)));
1086 CHECK_EXCEPTION;
1087 }
1088 MOTH_END_INSTR(CmpGt)
1089
1090 MOTH_BEGIN_INSTR(CmpGe)
1091 const Value left = STACK_VALUE(lhs);
1092 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1093 acc = Encode(left.int_32() >= ACC.int_32());
1094 } else if (left.isNumber() && ACC.isNumber()) {
1095 acc = Encode(left.asDouble() >= ACC.asDouble());
1096 } else {
1097 STORE_ACC();
1098 acc = Encode(bool(Runtime::CompareGreaterEqual::call(left, accumulator)));
1099 CHECK_EXCEPTION;
1100 }
1101 MOTH_END_INSTR(CmpGe)
1102
1103 MOTH_BEGIN_INSTR(CmpLt)
1104 const Value left = STACK_VALUE(lhs);
1105 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1106 acc = Encode(left.int_32() < ACC.int_32());
1107 } else if (left.isNumber() && ACC.isNumber()) {
1108 acc = Encode(left.asDouble() < ACC.asDouble());
1109 } else {
1110 STORE_ACC();
1111 acc = Encode(bool(Runtime::CompareLessThan::call(left, accumulator)));
1112 CHECK_EXCEPTION;
1113 }
1114 MOTH_END_INSTR(CmpLt)
1115
1116 MOTH_BEGIN_INSTR(CmpLe)
1117 const Value left = STACK_VALUE(lhs);
1118 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1119 acc = Encode(left.int_32() <= ACC.int_32());
1120 } else if (left.isNumber() && ACC.isNumber()) {
1121 acc = Encode(left.asDouble() <= ACC.asDouble());
1122 } else {
1123 STORE_ACC();
1124 acc = Encode(bool(Runtime::CompareLessEqual::call(left, accumulator)));
1125 CHECK_EXCEPTION;
1126 }
1127 MOTH_END_INSTR(CmpLe)
1128
1129 MOTH_BEGIN_INSTR(CmpStrictEqual)
1130 if (STACK_VALUE(lhs).rawValue() == ACC.rawValue() && !ACC.isNaN()) {
1131 acc = Encode(true);
1132 } else {
1133 STORE_ACC();
1134 acc = Runtime::StrictEqual::call(STACK_VALUE(lhs), accumulator);
1135 CHECK_EXCEPTION;
1136 }
1137 MOTH_END_INSTR(CmpStrictEqual)
1138
1139 MOTH_BEGIN_INSTR(CmpStrictNotEqual)
1140 if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) {
1141 STORE_ACC();
1142 acc = Runtime::StrictNotEqual::call(STACK_VALUE(lhs), accumulator);
1143 CHECK_EXCEPTION;
1144 } else {
1145 acc = Encode(false);
1146 }
1147 MOTH_END_INSTR(CmpStrictNotEqual)
1148
1149 MOTH_BEGIN_INSTR(CmpIn)
1150 STORE_ACC();
1151 acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator);
1152 CHECK_EXCEPTION;
1153 MOTH_END_INSTR(CmpIn)
1154
1155 MOTH_BEGIN_INSTR(CmpInstanceOf)
1156 STORE_ACC();
1157 acc = Runtime::Instanceof::call(engine, STACK_VALUE(lhs), ACC);
1158 CHECK_EXCEPTION;
1159 MOTH_END_INSTR(CmpInstanceOf)
1160
1161 MOTH_BEGIN_INSTR(UNot)
1162 if (ACC.integerCompatible()) {
1163 acc = Encode(!static_cast<bool>(ACC.int_32()));
1164 } else {
1165 acc = Encode(!Value::toBooleanImpl(ACC));
1166 }
1167 MOTH_END_INSTR(UNot)
1168
1169 MOTH_BEGIN_INSTR(UPlus)
1170 if (Q_UNLIKELY(!ACC.isNumber())) {
1171 acc = Encode(ACC.toNumberImpl());
1172 CHECK_EXCEPTION;
1173 }
1174 MOTH_END_INSTR(UPlus)
1175
1176 MOTH_BEGIN_INSTR(UMinus)
1177 if (Q_LIKELY(ACC.integerCompatible())) {
1178 int a = ACC.int_32();
1179 if (a == 0 || a == std::numeric_limits<int>::min()) {
1180 acc = Encode(-static_cast<double>(a));
1181 } else {
1182 acc = sub_int32(0, ACC.int_32());
1183 }
1184 } else if (ACC.isDouble()) {
1185 acc ^= (1ull << 63); // simply flip sign bit
1186 } else {
1187 acc = Encode(-ACC.toNumberImpl());
1188 CHECK_EXCEPTION;
1189 }
1190 MOTH_END_INSTR(UMinus)
1191
1192 MOTH_BEGIN_INSTR(UCompl)
1193 VALUE_TO_INT(a, ACC);
1194 acc = Encode(~a);
1195 MOTH_END_INSTR(UCompl)
1196
1197 MOTH_BEGIN_INSTR(Increment)
1198 if (Q_LIKELY(ACC.integerCompatible())) {
1199 acc = add_int32(ACC.int_32(), 1);
1200 } else if (ACC.isDouble()) {
1201 acc = QV4::Encode(ACC.doubleValue() + 1.);
1202 } else {
1203 acc = Encode(ACC.toNumberImpl() + 1.);
1204 CHECK_EXCEPTION;
1205 }
1206 MOTH_END_INSTR(Increment)
1207
1208 MOTH_BEGIN_INSTR(Decrement)
1209 if (Q_LIKELY(ACC.integerCompatible())) {
1210 acc = sub_int32(ACC.int_32(), 1);
1211 } else if (ACC.isDouble()) {
1212 acc = QV4::Encode(ACC.doubleValue() - 1.);
1213 } else {
1214 acc = Encode(ACC.toNumberImpl() - 1.);
1215 CHECK_EXCEPTION;
1216 }
1217 MOTH_END_INSTR(Decrement)
1218
1219 MOTH_BEGIN_INSTR(Add)
1220 const Value left = STACK_VALUE(lhs);
1221 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1222 acc = add_int32(left.int_32(), ACC.int_32());
1223 } else if (left.isNumber() && ACC.isNumber()) {
1224 acc = Encode(left.asDouble() + ACC.asDouble());
1225 } else {
1226 STORE_ACC();
1227 acc = Runtime::Add::call(engine, left, accumulator);
1228 CHECK_EXCEPTION;
1229 }
1230 MOTH_END_INSTR(Add)
1231
1232 MOTH_BEGIN_INSTR(Sub)
1233 const Value left = STACK_VALUE(lhs);
1234 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1235 acc = sub_int32(left.int_32(), ACC.int_32());
1236 } else if (left.isNumber() && ACC.isNumber()) {
1237 acc = Encode(left.asDouble() - ACC.asDouble());
1238 } else {
1239 STORE_ACC();
1240 acc = Runtime::Sub::call(left, accumulator);
1241 CHECK_EXCEPTION;
1242 }
1243 MOTH_END_INSTR(Sub)
1244
1245 MOTH_BEGIN_INSTR(Exp)
1246 const Value left = STACK_VALUE(lhs);
1247 double base = left.toNumber();
1248 double exp = ACC.toNumber();
1249 if (qIsInf(exp) && (base == 1 || base == -1))
1250 acc = Encode(qSNaN());
1251 else
1252 acc = Encode(pow(base,exp));
1253 MOTH_END_INSTR(Exp)
1254
1255 MOTH_BEGIN_INSTR(Mul)
1256 const Value left = STACK_VALUE(lhs);
1257 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1258 acc = mul_int32(left.int_32(), ACC.int_32());
1259 } else if (left.isNumber() && ACC.isNumber()) {
1260 acc = Encode(left.asDouble() * ACC.asDouble());
1261 } else {
1262 STORE_ACC();
1263 acc = Runtime::Mul::call(left, accumulator);
1264 CHECK_EXCEPTION;
1265 }
1266 MOTH_END_INSTR(Mul)
1267
1268 MOTH_BEGIN_INSTR(Div)
1269 STORE_ACC();
1270 acc = Runtime::Div::call(STACK_VALUE(lhs), accumulator);
1271 CHECK_EXCEPTION;
1272 MOTH_END_INSTR(Div)
1273
1274 MOTH_BEGIN_INSTR(Mod)
1275 STORE_ACC();
1276 acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
1277 CHECK_EXCEPTION;
1278 MOTH_END_INSTR(Mod)
1279
1280 MOTH_BEGIN_INSTR(BitAnd)
1281 VALUE_TO_INT(l, STACK_VALUE(lhs));
1282 VALUE_TO_INT(a, ACC);
1283 acc = Encode(l & a);
1284 MOTH_END_INSTR(BitAnd)
1285
1286 MOTH_BEGIN_INSTR(BitOr)
1287 VALUE_TO_INT(l, STACK_VALUE(lhs));
1288 VALUE_TO_INT(a, ACC);
1289 acc = Encode(l | a);
1290 MOTH_END_INSTR(BitOr)
1291
1292 MOTH_BEGIN_INSTR(BitXor)
1293 VALUE_TO_INT(l, STACK_VALUE(lhs));
1294 VALUE_TO_INT(a, ACC);
1295 acc = Encode(l ^ a);
1296 MOTH_END_INSTR(BitXor)
1297
1298 MOTH_BEGIN_INSTR(UShr)
1299 VALUE_TO_INT(l, STACK_VALUE(lhs));
1300 VALUE_TO_INT(a, ACC);
1301 acc = Encode(static_cast<uint>(l) >> uint(a & 0x1f));
1302 MOTH_END_INSTR(UShr)
1303
1304 MOTH_BEGIN_INSTR(Shr)
1305 VALUE_TO_INT(l, STACK_VALUE(lhs));
1306 VALUE_TO_INT(a, ACC);
1307 acc = Encode(l >> (a & 0x1f));
1308 MOTH_END_INSTR(Shr)
1309
1310 MOTH_BEGIN_INSTR(Shl)
1311 VALUE_TO_INT(l, STACK_VALUE(lhs));
1312 VALUE_TO_INT(a, ACC);
1313 acc = Encode(l << (a & 0x1f));
1314 MOTH_END_INSTR(Shl)
1315
1316 MOTH_BEGIN_INSTR(BitAndConst)
1317 VALUE_TO_INT(a, ACC);
1318 acc = Encode(a & rhs);
1319 CHECK_EXCEPTION;
1320 MOTH_END_INSTR(BitAndConst)
1321
1322 MOTH_BEGIN_INSTR(BitOrConst)
1323 VALUE_TO_INT(a, ACC);
1324 acc = Encode(a | rhs);
1325 MOTH_END_INSTR(BitOrConst)
1326
1327 MOTH_BEGIN_INSTR(BitXorConst)
1328 VALUE_TO_INT(a, ACC);
1329 acc = Encode(a ^ rhs);
1330 MOTH_END_INSTR(BitXorConst)
1331
1332 MOTH_BEGIN_INSTR(UShrConst)
1333 acc = Encode(ACC.toUInt32() >> uint(rhs));
1334 MOTH_END_INSTR(UShrConst)
1335
1336 MOTH_BEGIN_INSTR(ShrConst)
1337 VALUE_TO_INT(a, ACC);
1338 acc = Encode(a >> rhs);
1339 MOTH_END_INSTR(ShrConst)
1340
1341 MOTH_BEGIN_INSTR(ShlConst)
1342 VALUE_TO_INT(a, ACC);
1343 acc = Encode(a << rhs);
1344 MOTH_END_INSTR(ShlConst)
1345
1346 MOTH_BEGIN_INSTR(Ret)
1347 return acc;
1348 MOTH_END_INSTR(Ret)
1349
1350 MOTH_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
1351 acc = Encode(Value::emptyValue());
1352 for (int i = firstReg, end = firstReg + count; i < end; ++i)
1353 STACK_VALUE(i) = acc;
1354 MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
1355
1356 MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
1357 if (Value::fromReturnedValue(acc).isNullOrUndefined()) {
1358 engine->throwTypeError();
1359 goto handleUnwind;
1360 }
1361 MOTH_END_INSTR(ThrowOnNullOrUndefined)
1362
1363 MOTH_BEGIN_INSTR(GetTemplateObject)
1364 acc = Runtime::GetTemplateObject::call(function, index);
1365 MOTH_END_INSTR(GetTemplateObject)
1366
1367 MOTH_BEGIN_INSTR(Debug)
1368#if QT_CONFIG(qml_debug)
1369 STORE_IP();
1370 debug_slowPath(engine);
1371#endif // QT_CONFIG(qml_debug)
1372 MOTH_END_INSTR(Debug)
1373
1374 handleUnwind:
1375 // We do start the exception handler in case of isInterrupted. The exception handler will
1376 // immediately abort, due to the same isInterrupted. We don't skip the exception handler
1377 // because the current behavior is easier to implement in the JIT.
1378 Q_ASSERT(engine->hasException || engine->isInterrupted.loadAcquire() || frame->unwindLevel);
1379 if (!frame->unwindHandler) {
1380 acc = Encode::undefined();
1381 return acc;
1382 }
1383 code = frame->unwindHandler;
1384 }
1385}
1386