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(key: QLatin1String("command")).toString().toUtf8();
203
204 if (command == "protocolVersion") {
205 return ProtocolVersion; // Version number.
206 }
207
208 int version = ob.value(key: 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(key: QLatin1String("lineNumber")).toString().toInt();
217 bp.engineName = ob.value(key: QLatin1String("engineName")).toString();
218 bp.fullName = ob.value(key: QLatin1String("fullName")).toString();
219 bp.condition = ob.value(key: QLatin1String("condition")).toString();
220 qt_v4Breakpoints.append(t: bp);
221 qt_v4IsDebugging = true;
222 return bp.bpNumber;
223 }
224
225 if (command == "removeBreakpoint") {
226 int lineNumber = ob.value(key: QLatin1String("lineNumber")).toString().toInt();
227 QString fullName = ob.value(key: QLatin1String("fullName")).toString();
228 if (qt_v4Breakpoints.last().matches(file: fullName, line: 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(file: fullName, line: 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(frame: 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
344static inline QV4::Value &stackValue(QV4::Value *stack, size_t slot, const CppStackFrame *frame)
345{
346 Q_ASSERT(slot < CallData::HeaderSize() / sizeof(QV4::StaticValue)
347 + frame->jsFrame->argc()
348 + frame->v4Function->compiledFunction->nRegisters);
349 Q_UNUSED(frame);
350
351 return stack[slot];
352}
353
354#define STACK_VALUE(temp) stackValue(stack, temp, frame)
355
356// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
357#ifdef CHECK_EXCEPTION
358#undef CHECK_EXCEPTION
359#endif
360#define CHECK_EXCEPTION \
361 if (engine->hasException || engine->isInterrupted.loadAcquire()) \
362 goto handleUnwind
363
364static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
365{
366 Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
367 while (level > 0) {
368 --level;
369 scope = scope->outer;
370 }
371 Q_ASSERT(scope);
372 return static_cast<Heap::CallContext *>(scope);
373}
374
375static inline const QV4::Value &constant(Function *function, int index)
376{
377 return function->compilationUnit->constants[index].asValue<QV4::Value>();
378}
379
380static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
381{
382 redo:
383 switch (lhs.quickType()) {
384 case QV4::Value::QT_ManagedOrUndefined:
385 if (lhs.isUndefined())
386 return false;
387 Q_FALLTHROUGH();
388 case QV4::Value::QT_ManagedOrUndefined1:
389 case QV4::Value::QT_ManagedOrUndefined2:
390 case QV4::Value::QT_ManagedOrUndefined3:
391 // LHS: Managed
392 if (lhs.m()->internalClass->vtable->isString)
393 return RuntimeHelpers::stringToNumber(s: static_cast<String &>(lhs).toQString()) == rhs;
394 accumulator = lhs;
395 lhs = QV4::Value::fromReturnedValue(val: RuntimeHelpers::objectDefaultValue(object: &static_cast<QV4::Object &>(accumulator), typeHint: PREFERREDTYPE_HINT));
396 goto redo;
397 case QV4::Value::QT_Empty:
398 Q_UNREACHABLE();
399 case QV4::Value::QT_Null:
400 return false;
401 case QV4::Value::QT_Bool:
402 case QV4::Value::QT_Int:
403 return lhs.int_32() == rhs;
404 default: // double
405 return lhs.doubleValue() == rhs;
406 }
407}
408
409#define STORE_IP() frame->instructionPointer = int(code - function->codeData);
410#define STORE_ACC() accumulator = acc;
411#define ACC Value::fromReturnedValue(acc)
412#define VALUE_TO_INT(i, val) \
413 int i; \
414 do { \
415 if (Q_LIKELY(val.integerCompatible())) { \
416 i = val.int_32(); \
417 } else { \
418 double d; \
419 if (val.isDouble()) \
420 d = val.doubleValue(); \
421 else { \
422 STORE_ACC(); \
423 d = val.toNumberImpl(); \
424 CHECK_EXCEPTION; \
425 } \
426 i = Double::toInt32(d); \
427 } \
428 } while (false)
429
430ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
431{
432 qt_v4ResolvePendingBreakpointsHook();
433 CHECK_STACK_LIMITS(engine);
434
435 Function *function = frame->v4Function;
436 Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
437 function->executableCompilationUnit()->fileName(),
438 function->compiledFunction->location.line,
439 function->compiledFunction->location.column);
440 Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
441 QV4::Debugging::Debugger *debugger = engine->debugger();
442
443#if QT_CONFIG(qml_jit)
444 if (debugger == nullptr) {
445 // Check for codeRef here. In rare cases the JIT compilation may fail, which leaves us
446 // with a (useless) codeRef, but no jittedCode. In that case, don't try to JIT again every
447 // time we execute the function, but just interpret instead.
448 if (function->codeRef == nullptr) {
449 if (engine->canJIT(f: function))
450 QV4::JIT::BaselineJIT(function).generate();
451 else
452 ++function->interpreterCallCount;
453 }
454 }
455#endif // QT_CONFIG(qml_jit)
456
457 // interpreter
458 if (debugger)
459 debugger->enteringFunction();
460
461 ReturnedValue result;
462 if (function->jittedCode != nullptr && debugger == nullptr) {
463 result = function->jittedCode(frame, engine);
464 } else {
465 // interpreter
466 result = interpret(frame, engine, codeEntry: function->codeData);
467 }
468
469 if (debugger)
470 debugger->leavingFunction(retVal: result);
471
472 return result;
473}
474
475QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code)
476{
477 QV4::Function *function = frame->v4Function;
478 QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>();
479 QV4::ReturnedValue acc = accumulator.asReturnedValue();
480 Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
481
482 MOTH_JUMP_TABLE;
483
484 for (;;) {
485 MOTH_DISPATCH()
486 Q_UNREACHABLE(); // only reached when the dispatch doesn't jump somewhere
487
488 MOTH_BEGIN_INSTR(LoadConst)
489 acc = constant(function, index).asReturnedValue();
490 MOTH_END_INSTR(LoadConst)
491
492 MOTH_BEGIN_INSTR(LoadNull)
493 acc = Encode::null();
494 MOTH_END_INSTR(LoadNull)
495
496 MOTH_BEGIN_INSTR(LoadZero)
497 acc = Encode(static_cast<int>(0));
498 MOTH_END_INSTR(LoadZero)
499
500 MOTH_BEGIN_INSTR(LoadTrue)
501 acc = Encode(true);
502 MOTH_END_INSTR(LoadTrue)
503
504 MOTH_BEGIN_INSTR(LoadFalse)
505 acc = Encode(false);
506 MOTH_END_INSTR(LoadFalse)
507
508 MOTH_BEGIN_INSTR(LoadUndefined)
509 acc = Encode::undefined();
510 MOTH_END_INSTR(LoadUndefined)
511
512 MOTH_BEGIN_INSTR(LoadInt)
513 acc = Encode(value);
514 MOTH_END_INSTR(LoadInt)
515
516 MOTH_BEGIN_INSTR(MoveConst)
517 STACK_VALUE(destTemp) = constant(function, index: constIndex);
518 MOTH_END_INSTR(MoveConst)
519
520 MOTH_BEGIN_INSTR(LoadReg)
521 acc = STACK_VALUE(reg).asReturnedValue();
522 MOTH_END_INSTR(LoadReg)
523
524 MOTH_BEGIN_INSTR(StoreReg)
525 STACK_VALUE(reg) = acc;
526 MOTH_END_INSTR(StoreReg)
527
528 MOTH_BEGIN_INSTR(MoveReg)
529 STACK_VALUE(destReg) = STACK_VALUE(srcReg);
530 MOTH_END_INSTR(MoveReg)
531
532 MOTH_BEGIN_INSTR(LoadImport)
533 acc = function->compilationUnit->imports[index]->asReturnedValue();
534 MOTH_END_INSTR(LoadImport)
535
536 MOTH_BEGIN_INSTR(LoadLocal)
537 auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
538 Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
539 acc = cc->locals[index].asReturnedValue();
540 MOTH_END_INSTR(LoadLocal)
541
542 MOTH_BEGIN_INSTR(StoreLocal)
543 CHECK_EXCEPTION;
544 auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
545 Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
546 QV4::WriteBarrier::write(engine, base: cc, slot: cc->locals.values[index].data_ptr(), value: acc);
547 MOTH_END_INSTR(StoreLocal)
548
549 MOTH_BEGIN_INSTR(LoadScopedLocal)
550 auto cc = getScope(stack, level: scope);
551 acc = cc->locals[index].asReturnedValue();
552 MOTH_END_INSTR(LoadScopedLocal)
553
554 MOTH_BEGIN_INSTR(StoreScopedLocal)
555 CHECK_EXCEPTION;
556 auto cc = getScope(stack, level: scope);
557 QV4::WriteBarrier::write(engine, base: cc, slot: cc->locals.values[index].data_ptr(), value: acc);
558 MOTH_END_INSTR(StoreScopedLocal)
559
560 MOTH_BEGIN_INSTR(LoadRuntimeString)
561 acc = function->compilationUnit->runtimeStrings[stringId]->asReturnedValue();
562 MOTH_END_INSTR(LoadRuntimeString)
563
564 MOTH_BEGIN_INSTR(MoveRegExp)
565 STACK_VALUE(destReg) = Runtime::RegexpLiteral::call(engine, regExpId);
566 MOTH_END_INSTR(MoveRegExp)
567
568 MOTH_BEGIN_INSTR(LoadClosure)
569 acc = Runtime::Closure::call(engine, value);
570 MOTH_END_INSTR(LoadClosure)
571
572 MOTH_BEGIN_INSTR(LoadName)
573 STORE_IP();
574 acc = Runtime::LoadName::call(engine, name);
575 CHECK_EXCEPTION;
576 MOTH_END_INSTR(LoadName)
577
578 MOTH_BEGIN_INSTR(LoadGlobalLookup)
579 STORE_IP();
580 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
581 acc = l->globalGetter(l, engine);
582 CHECK_EXCEPTION;
583 MOTH_END_INSTR(LoadGlobalLookup)
584
585 MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
586 STORE_IP();
587 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
588 acc = l->qmlContextPropertyGetter(l, engine, nullptr);
589 CHECK_EXCEPTION;
590 MOTH_END_INSTR(LoadQmlContextPropertyLookup)
591
592 MOTH_BEGIN_INSTR(StoreNameStrict)
593 STORE_IP();
594 STORE_ACC();
595 Runtime::StoreNameStrict::call(engine, name, accumulator);
596 CHECK_EXCEPTION;
597 MOTH_END_INSTR(StoreNameStrict)
598
599 MOTH_BEGIN_INSTR(StoreNameSloppy)
600 STORE_IP();
601 STORE_ACC();
602 Runtime::StoreNameSloppy::call(engine, name, accumulator);
603 CHECK_EXCEPTION;
604 MOTH_END_INSTR(StoreNameSloppy)
605
606 MOTH_BEGIN_INSTR(LoadElement)
607 STORE_IP();
608 STORE_ACC();
609 acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator);
610 CHECK_EXCEPTION;
611 MOTH_END_INSTR(LoadElement)
612
613 MOTH_BEGIN_INSTR(StoreElement)
614 STORE_IP();
615 STORE_ACC();
616 Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
617 CHECK_EXCEPTION;
618 MOTH_END_INSTR(StoreElement)
619
620 MOTH_BEGIN_INSTR(LoadProperty)
621 STORE_IP();
622 STORE_ACC();
623 acc = Runtime::LoadProperty::call(engine, accumulator, name);
624 CHECK_EXCEPTION;
625 MOTH_END_INSTR(LoadProperty)
626
627 MOTH_BEGIN_INSTR(GetLookup)
628 STORE_IP();
629 STORE_ACC();
630
631 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
632
633 if (accumulator.isNullOrUndefined()) {
634 QString message = QStringLiteral("Cannot read property '%1' of %2")
635 .arg(a: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
636 .arg(a: accumulator.toQStringNoThrow());
637 acc = engine->throwTypeError(message);
638 goto handleUnwind;
639 }
640
641 acc = l->getter(l, engine, accumulator);
642 CHECK_EXCEPTION;
643 MOTH_END_INSTR(GetLookup)
644
645 MOTH_BEGIN_INSTR(StoreProperty)
646 STORE_IP();
647 STORE_ACC();
648 Runtime::StoreProperty::call(engine, STACK_VALUE(base), name, accumulator);
649 CHECK_EXCEPTION;
650 MOTH_END_INSTR(StoreProperty)
651
652 MOTH_BEGIN_INSTR(SetLookup)
653 STORE_IP();
654 STORE_ACC();
655 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
656 if (!l->setter(l, engine, STACK_VALUE(base), accumulator) && function->isStrict())
657 engine->throwTypeError();
658 CHECK_EXCEPTION;
659 MOTH_END_INSTR(SetLookup)
660
661 MOTH_BEGIN_INSTR(LoadSuperProperty)
662 STORE_IP();
663 acc = Runtime::LoadSuperProperty::call(engine, STACK_VALUE(property));
664 CHECK_EXCEPTION;
665 MOTH_END_INSTR(LoadSuperProperty)
666
667 MOTH_BEGIN_INSTR(StoreSuperProperty)
668 STORE_IP();
669 STORE_ACC();
670 Runtime::StoreSuperProperty::call(engine, STACK_VALUE(property), accumulator);
671 CHECK_EXCEPTION;
672 MOTH_END_INSTR(StoreSuperProperty)
673
674 MOTH_BEGIN_INSTR(Yield)
675 frame->yield = code;
676 frame->yieldIsIterator = false;
677 return acc;
678 MOTH_END_INSTR(Yield)
679
680 MOTH_BEGIN_INSTR(YieldStar)
681 frame->yield = code;
682 frame->yieldIsIterator = true;
683 return acc;
684 MOTH_END_INSTR(YieldStar)
685
686 MOTH_BEGIN_INSTR(Resume)
687 // check exception, in case the generator was called with throw() or return()
688 if (engine->hasException) {
689 // an empty value indicates that the generator was called with return()
690 if (engine->exceptionValue->asReturnedValue() != Value::emptyValue().asReturnedValue())
691 goto handleUnwind;
692 engine->hasException = false;
693 *engine->exceptionValue = Value::undefinedValue();
694 } else {
695 code += offset;
696 }
697 MOTH_END_INSTR(Resume)
698
699 MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
700 STORE_ACC();
701 acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
702 CHECK_EXCEPTION;
703 MOTH_END_INSTR(IteratorNextForYieldStar)
704
705 MOTH_BEGIN_INSTR(CallValue)
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(a: func.toQStringNoThrow()));
710 goto handleUnwind;
711 }
712 Value undef = Value::undefinedValue();
713 acc = static_cast<const FunctionObject &>(func).call(thisObject: &undef, argv: stack + argv, argc);
714 CHECK_EXCEPTION;
715 MOTH_END_INSTR(CallValue)
716
717 MOTH_BEGIN_INSTR(CallWithReceiver)
718 STORE_IP();
719 Value func = STACK_VALUE(name);
720 if (Q_UNLIKELY(!func.isFunctionObject())) {
721 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(a: func.toQStringNoThrow()));
722 goto handleUnwind;
723 }
724 acc = static_cast<const FunctionObject &>(func).call(thisObject: stack + thisObject, argv: stack + argv, argc);
725 CHECK_EXCEPTION;
726 MOTH_END_INSTR(CallWithReceiver)
727
728 MOTH_BEGIN_INSTR(CallProperty)
729 STORE_IP();
730 acc = Runtime::CallProperty::call(engine, STACK_VALUE(base), name, stack + argv, argc);
731 CHECK_EXCEPTION;
732 MOTH_END_INSTR(CallProperty)
733
734 MOTH_BEGIN_INSTR(CallPropertyLookup)
735 STORE_IP();
736 Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
737
738 if (STACK_VALUE(base).isNullOrUndefined()) {
739 QString message = QStringLiteral("Cannot call method '%1' of %2")
740 .arg(a: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
741 .arg(STACK_VALUE(base).toQStringNoThrow());
742 acc = engine->throwTypeError(message);
743 goto handleUnwind;
744 }
745
746 // ok to have the value on the stack here
747 Value f = Value::fromReturnedValue(val: l->getter(l, engine, STACK_VALUE(base)));
748
749 if (Q_UNLIKELY(!f.isFunctionObject())) {
750 QString message = QStringLiteral("Property '%1' of object %2 is not a function")
751 .arg(a: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
752 .arg(STACK_VALUE(base).toQStringNoThrow());
753 acc = engine->throwTypeError(message);
754 goto handleUnwind;
755 }
756
757 acc = static_cast<FunctionObject &>(f).call(thisObject: stack + base, argv: stack + argv, argc);
758 CHECK_EXCEPTION;
759 MOTH_END_INSTR(CallPropertyLookup)
760
761 MOTH_BEGIN_INSTR(CallElement)
762 STORE_IP();
763 acc = Runtime::CallElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), stack + argv, argc);
764 CHECK_EXCEPTION;
765 MOTH_END_INSTR(CallElement)
766
767 MOTH_BEGIN_INSTR(CallName)
768 STORE_IP();
769 acc = Runtime::CallName::call(engine, name, stack + argv, argc);
770 CHECK_EXCEPTION;
771 MOTH_END_INSTR(CallName)
772
773 MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
774 STORE_IP();
775 acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
776 CHECK_EXCEPTION;
777 MOTH_END_INSTR(CallPossiblyDirectEval)
778
779 MOTH_BEGIN_INSTR(CallGlobalLookup)
780 STORE_IP();
781 acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
782 CHECK_EXCEPTION;
783 MOTH_END_INSTR(CallGlobalLookup)
784
785 MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
786 STORE_IP();
787 acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
788 CHECK_EXCEPTION;
789 MOTH_END_INSTR(CallQmlContextPropertyLookup)
790
791 MOTH_BEGIN_INSTR(CallWithSpread)
792 STORE_IP();
793 acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
794 CHECK_EXCEPTION;
795 MOTH_END_INSTR(CallWithSpread)
796
797 MOTH_BEGIN_INSTR(TailCall)
798 STORE_IP();
799 *engine->jsAlloca(nValues: 1) = Primitive::fromInt32(i: argc);
800 *engine->jsAlloca(nValues: 1) = Primitive::fromInt32(i: argv);
801 *engine->jsAlloca(nValues: 1) = STACK_VALUE(thisObject);
802 *engine->jsAlloca(nValues: 1) = STACK_VALUE(func);
803 return Runtime::TailCall::call(frame, engine);
804 CHECK_EXCEPTION;
805 MOTH_END_INSTR(TailCall)
806
807 MOTH_BEGIN_INSTR(Construct)
808 STORE_IP();
809 STORE_ACC();
810 acc = Runtime::Construct::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
811 CHECK_EXCEPTION;
812 MOTH_END_INSTR(Construct)
813
814 MOTH_BEGIN_INSTR(ConstructWithSpread)
815 STORE_IP();
816 STORE_ACC();
817 acc = Runtime::ConstructWithSpread::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
818 CHECK_EXCEPTION;
819 MOTH_END_INSTR(ConstructWithSpread)
820
821 MOTH_BEGIN_INSTR(SetUnwindHandler)
822 frame->unwindHandler = offset ? code + offset : nullptr;
823 MOTH_END_INSTR(SetUnwindHandler)
824
825 MOTH_BEGIN_INSTR(UnwindDispatch)
826 CHECK_EXCEPTION;
827 if (frame->unwindLevel) {
828 --frame->unwindLevel;
829 if (frame->unwindLevel)
830 goto handleUnwind;
831 code = frame->unwindLabel;
832 }
833 MOTH_END_INSTR(UnwindDispatch)
834
835 MOTH_BEGIN_INSTR(UnwindToLabel)
836 frame->unwindLevel = level;
837 frame->unwindLabel = code + offset;
838 goto handleUnwind;
839 MOTH_END_INSTR(UnwindToLabel)
840
841 MOTH_BEGIN_INSTR(DeadTemporalZoneCheck)
842 if (ACC.isEmpty()) {
843 STORE_IP();
844 Runtime::ThrowReferenceError::call(engine, name);
845 goto handleUnwind;
846 }
847 MOTH_END_INSTR(DeadTemporalZoneCheck)
848
849 MOTH_BEGIN_INSTR(ThrowException)
850 STORE_IP();
851 STORE_ACC();
852 Runtime::ThrowException::call(engine, accumulator);
853 goto handleUnwind;
854 MOTH_END_INSTR(ThrowException)
855
856 MOTH_BEGIN_INSTR(GetException)
857 acc = engine->hasException ? engine->exceptionValue->asReturnedValue()
858 : Value::emptyValue().asReturnedValue();
859 engine->hasException = false;
860 MOTH_END_INSTR(HasException)
861
862 MOTH_BEGIN_INSTR(SetException)
863 if (acc != Value::emptyValue().asReturnedValue()) {
864 *engine->exceptionValue = acc;
865 engine->hasException = true;
866 }
867 MOTH_END_INSTR(SetException)
868
869 MOTH_BEGIN_INSTR(PushCatchContext)
870 Runtime::PushCatchContext::call(engine, index, name);
871 MOTH_END_INSTR(PushCatchContext)
872
873 MOTH_BEGIN_INSTR(CreateCallContext)
874 Runtime::PushCallContext::call(frame);
875 MOTH_END_INSTR(CreateCallContext)
876
877 MOTH_BEGIN_INSTR(PushWithContext)
878 STORE_IP();
879 STORE_ACC();
880 acc = Runtime::PushWithContext::call(engine, STACK_VALUE(CallData::Accumulator));
881 CHECK_EXCEPTION;
882 MOTH_END_INSTR(PushWithContext)
883
884 MOTH_BEGIN_INSTR(PushBlockContext)
885 STORE_ACC();
886 Runtime::PushBlockContext::call(engine, index);
887 MOTH_END_INSTR(PushBlockContext)
888
889 MOTH_BEGIN_INSTR(CloneBlockContext)
890 STORE_ACC();
891 Runtime::CloneBlockContext::call(engine);
892 MOTH_END_INSTR(CloneBlockContext)
893
894 MOTH_BEGIN_INSTR(PushScriptContext)
895 Runtime::PushScriptContext::call(engine, index);
896 MOTH_END_INSTR(PushScriptContext)
897
898 MOTH_BEGIN_INSTR(PopScriptContext)
899 Runtime::PopScriptContext::call(engine);
900 MOTH_END_INSTR(PopScriptContext)
901
902 MOTH_BEGIN_INSTR(PopContext)
903 ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
904 STACK_VALUE(CallData::Context) = c->d()->outer;
905 MOTH_END_INSTR(PopContext)
906
907 MOTH_BEGIN_INSTR(GetIterator)
908 STORE_IP();
909 STORE_ACC();
910 acc = Runtime::GetIterator::call(engine, accumulator, iterator);
911 CHECK_EXCEPTION;
912 MOTH_END_INSTR(GetIterator)
913
914 MOTH_BEGIN_INSTR(IteratorNext)
915 STORE_IP();
916 STORE_ACC();
917 acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
918 STACK_VALUE(done) = acc;
919 CHECK_EXCEPTION;
920 MOTH_END_INSTR(IteratorNext)
921
922 MOTH_BEGIN_INSTR(IteratorClose)
923 STORE_IP();
924 STORE_ACC();
925 acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done));
926 CHECK_EXCEPTION;
927 MOTH_END_INSTR(IteratorClose)
928
929 MOTH_BEGIN_INSTR(DestructureRestElement)
930 STORE_IP();
931 STORE_ACC();
932 acc = Runtime::DestructureRestElement::call(engine, ACC);
933 CHECK_EXCEPTION;
934 MOTH_END_INSTR(DestructureRestElement)
935
936 MOTH_BEGIN_INSTR(DeleteProperty)
937 acc = Runtime::DeleteProperty::call(engine, function, STACK_VALUE(base), STACK_VALUE(index));
938 CHECK_EXCEPTION;
939 MOTH_END_INSTR(DeleteProperty)
940
941 MOTH_BEGIN_INSTR(DeleteName)
942 acc = Runtime::DeleteName::call(engine, function, name);
943 CHECK_EXCEPTION;
944 MOTH_END_INSTR(DeleteName)
945
946 MOTH_BEGIN_INSTR(TypeofName)
947 acc = Runtime::TypeofName::call(engine, name);
948 MOTH_END_INSTR(TypeofName)
949
950 MOTH_BEGIN_INSTR(TypeofValue)
951 STORE_ACC();
952 acc = Runtime::TypeofValue::call(engine, accumulator);
953 MOTH_END_INSTR(TypeofValue)
954
955 MOTH_BEGIN_INSTR(DeclareVar)
956 Runtime::DeclareVar::call(engine, isDeletable, varName);
957 MOTH_END_INSTR(DeclareVar)
958
959 MOTH_BEGIN_INSTR(DefineArray)
960 QV4::Value *arguments = stack + args;
961 acc = Runtime::ArrayLiteral::call(engine, arguments, argc);
962 MOTH_END_INSTR(DefineArray)
963
964 MOTH_BEGIN_INSTR(DefineObjectLiteral)
965 QV4::Value *arguments = stack + args;
966 acc = Runtime::ObjectLiteral::call(engine, internalClassId, arguments, argc);
967 MOTH_END_INSTR(DefineObjectLiteral)
968
969 MOTH_BEGIN_INSTR(CreateClass)
970 acc = Runtime::CreateClass::call(engine, classIndex, STACK_VALUE(heritage), stack + computedNames);
971 MOTH_END_INSTR(CreateClass)
972
973 MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
974 acc = Runtime::CreateMappedArgumentsObject::call(engine);
975 MOTH_END_INSTR(CreateMappedArgumentsObject)
976
977 MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
978 acc = Runtime::CreateUnmappedArgumentsObject::call(engine);
979 MOTH_END_INSTR(CreateUnmappedArgumentsObject)
980
981 MOTH_BEGIN_INSTR(CreateRestParameter)
982 acc = Runtime::CreateRestParameter::call(engine, argIndex);
983 MOTH_END_INSTR(CreateRestParameter)
984
985 MOTH_BEGIN_INSTR(ConvertThisToObject)
986 STORE_ACC();
987 stack[CallData::This] = Runtime::ConvertThisToObject::call(
988 engine, STACK_VALUE(CallData::This));
989 CHECK_EXCEPTION;
990 MOTH_END_INSTR(ConvertThisToObject)
991
992 MOTH_BEGIN_INSTR(LoadSuperConstructor)
993 acc = Runtime::LoadSuperConstructor::call(engine, STACK_VALUE(CallData::Function));
994 CHECK_EXCEPTION;
995 MOTH_END_INSTR(LoadSuperConstructor)
996
997 MOTH_BEGIN_INSTR(ToObject)
998 STORE_ACC();
999 acc = ACC.toObject(e: engine)->asReturnedValue();
1000 CHECK_EXCEPTION;
1001 MOTH_END_INSTR(ToObject)
1002
1003 MOTH_BEGIN_INSTR(Jump)
1004 code += offset;
1005 MOTH_END_INSTR(Jump)
1006
1007 MOTH_BEGIN_INSTR(JumpTrue)
1008 bool takeJump;
1009 if (Q_LIKELY(ACC.integerCompatible()))
1010 takeJump = ACC.int_32();
1011 else
1012 takeJump = ACC.toBoolean();
1013 if (takeJump)
1014 code += offset;
1015 MOTH_END_INSTR(JumpTrue)
1016
1017 MOTH_BEGIN_INSTR(JumpFalse)
1018 bool takeJump;
1019 if (Q_LIKELY(ACC.integerCompatible()))
1020 takeJump = !ACC.int_32();
1021 else
1022 takeJump = !ACC.toBoolean();
1023 if (takeJump)
1024 code += offset;
1025 MOTH_END_INSTR(JumpFalse)
1026
1027 MOTH_BEGIN_INSTR(JumpNoException)
1028 if (!engine->hasException)
1029 code += offset;
1030 MOTH_END_INSTR(JumpNoException)
1031
1032 MOTH_BEGIN_INSTR(JumpNotUndefined)
1033 if (Q_LIKELY(acc != QV4::Encode::undefined()))
1034 code += offset;
1035 MOTH_END_INSTR(JumpNotUndefined)
1036
1037 MOTH_BEGIN_INSTR(CheckException)
1038 CHECK_EXCEPTION;
1039 MOTH_END_INSTR(CheckException)
1040
1041 MOTH_BEGIN_INSTR(CmpEqNull)
1042 acc = Encode(ACC.isNullOrUndefined());
1043 MOTH_END_INSTR(CmpEqNull)
1044
1045 MOTH_BEGIN_INSTR(CmpNeNull)
1046 acc = Encode(!ACC.isNullOrUndefined());
1047 MOTH_END_INSTR(CmpNeNull)
1048
1049 MOTH_BEGIN_INSTR(CmpEqInt)
1050 if (ACC.isIntOrBool()) {
1051 acc = Encode(ACC.int_32() == lhs);
1052 } else {
1053 STORE_ACC();
1054 acc = Encode(compareEqualInt(accumulator, ACC, rhs: lhs));
1055 CHECK_EXCEPTION;
1056 }
1057 MOTH_END_INSTR(CmpEqInt)
1058
1059 MOTH_BEGIN_INSTR(CmpNeInt)
1060 if (ACC.isIntOrBool()) {
1061 acc = Encode(bool(ACC.int_32() != lhs));
1062 } else {
1063 STORE_ACC();
1064 acc = Encode(!compareEqualInt(accumulator, ACC, rhs: lhs));
1065 CHECK_EXCEPTION;
1066 }
1067 MOTH_END_INSTR(CmpNeInt)
1068
1069 MOTH_BEGIN_INSTR(CmpEq)
1070 const Value left = STACK_VALUE(lhs);
1071 if (Q_LIKELY(left.asReturnedValue() == ACC.asReturnedValue())) {
1072 acc = Encode(!ACC.isNaN());
1073 } else if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1074 acc = Encode(left.int_32() == ACC.int_32());
1075 } else {
1076 STORE_ACC();
1077 acc = Encode(bool(Runtime::CompareEqual::call(left, accumulator)));
1078 CHECK_EXCEPTION;
1079 }
1080 MOTH_END_INSTR(CmpEq)
1081
1082 MOTH_BEGIN_INSTR(CmpNe)
1083 const Value left = STACK_VALUE(lhs);
1084 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1085 acc = Encode(bool(left.int_32() != ACC.int_32()));
1086 } else {
1087 STORE_ACC();
1088 acc = Encode(bool(!Runtime::CompareEqual::call(left, accumulator)));
1089 CHECK_EXCEPTION;
1090 }
1091 MOTH_END_INSTR(CmpNe)
1092
1093 MOTH_BEGIN_INSTR(CmpGt)
1094 const Value left = STACK_VALUE(lhs);
1095 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1096 acc = Encode(left.int_32() > ACC.int_32());
1097 } else if (left.isNumber() && ACC.isNumber()) {
1098 acc = Encode(left.asDouble() > ACC.asDouble());
1099 } else {
1100 STORE_ACC();
1101 acc = Encode(bool(Runtime::CompareGreaterThan::call(left, accumulator)));
1102 CHECK_EXCEPTION;
1103 }
1104 MOTH_END_INSTR(CmpGt)
1105
1106 MOTH_BEGIN_INSTR(CmpGe)
1107 const Value left = STACK_VALUE(lhs);
1108 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1109 acc = Encode(left.int_32() >= ACC.int_32());
1110 } else if (left.isNumber() && ACC.isNumber()) {
1111 acc = Encode(left.asDouble() >= ACC.asDouble());
1112 } else {
1113 STORE_ACC();
1114 acc = Encode(bool(Runtime::CompareGreaterEqual::call(left, accumulator)));
1115 CHECK_EXCEPTION;
1116 }
1117 MOTH_END_INSTR(CmpGe)
1118
1119 MOTH_BEGIN_INSTR(CmpLt)
1120 const Value left = STACK_VALUE(lhs);
1121 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1122 acc = Encode(left.int_32() < ACC.int_32());
1123 } else if (left.isNumber() && ACC.isNumber()) {
1124 acc = Encode(left.asDouble() < ACC.asDouble());
1125 } else {
1126 STORE_ACC();
1127 acc = Encode(bool(Runtime::CompareLessThan::call(left, accumulator)));
1128 CHECK_EXCEPTION;
1129 }
1130 MOTH_END_INSTR(CmpLt)
1131
1132 MOTH_BEGIN_INSTR(CmpLe)
1133 const Value left = STACK_VALUE(lhs);
1134 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1135 acc = Encode(left.int_32() <= ACC.int_32());
1136 } else if (left.isNumber() && ACC.isNumber()) {
1137 acc = Encode(left.asDouble() <= ACC.asDouble());
1138 } else {
1139 STORE_ACC();
1140 acc = Encode(bool(Runtime::CompareLessEqual::call(left, accumulator)));
1141 CHECK_EXCEPTION;
1142 }
1143 MOTH_END_INSTR(CmpLe)
1144
1145 MOTH_BEGIN_INSTR(CmpStrictEqual)
1146 if (STACK_VALUE(lhs).rawValue() == ACC.rawValue() && !ACC.isNaN()) {
1147 acc = Encode(true);
1148 } else {
1149 STORE_ACC();
1150 acc = Runtime::StrictEqual::call(STACK_VALUE(lhs), accumulator);
1151 CHECK_EXCEPTION;
1152 }
1153 MOTH_END_INSTR(CmpStrictEqual)
1154
1155 MOTH_BEGIN_INSTR(CmpStrictNotEqual)
1156 if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) {
1157 STORE_ACC();
1158 acc = Runtime::StrictNotEqual::call(STACK_VALUE(lhs), accumulator);
1159 CHECK_EXCEPTION;
1160 } else {
1161 acc = Encode(false);
1162 }
1163 MOTH_END_INSTR(CmpStrictNotEqual)
1164
1165 MOTH_BEGIN_INSTR(CmpIn)
1166 STORE_ACC();
1167 acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator);
1168 CHECK_EXCEPTION;
1169 MOTH_END_INSTR(CmpIn)
1170
1171 MOTH_BEGIN_INSTR(CmpInstanceOf)
1172 STORE_ACC();
1173 acc = Runtime::Instanceof::call(engine, STACK_VALUE(lhs), ACC);
1174 CHECK_EXCEPTION;
1175 MOTH_END_INSTR(CmpInstanceOf)
1176
1177 MOTH_BEGIN_INSTR(UNot)
1178 if (ACC.integerCompatible()) {
1179 acc = Encode(!static_cast<bool>(ACC.int_32()));
1180 } else {
1181 acc = Encode(!Value::toBooleanImpl(ACC));
1182 }
1183 MOTH_END_INSTR(UNot)
1184
1185 MOTH_BEGIN_INSTR(UPlus)
1186 if (Q_UNLIKELY(!ACC.isNumber())) {
1187 acc = Encode(ACC.toNumberImpl());
1188 CHECK_EXCEPTION;
1189 }
1190 MOTH_END_INSTR(UPlus)
1191
1192 MOTH_BEGIN_INSTR(UMinus)
1193 if (Q_LIKELY(ACC.integerCompatible())) {
1194 int a = ACC.int_32();
1195 if (a == 0 || a == std::numeric_limits<int>::min()) {
1196 acc = Encode(-static_cast<double>(a));
1197 } else {
1198 acc = sub_int32(a: 0, ACC.int_32());
1199 }
1200 } else if (ACC.isDouble()) {
1201 acc ^= (1ull << 63); // simply flip sign bit
1202 } else {
1203 acc = Encode(-ACC.toNumberImpl());
1204 CHECK_EXCEPTION;
1205 }
1206 MOTH_END_INSTR(UMinus)
1207
1208 MOTH_BEGIN_INSTR(UCompl)
1209 VALUE_TO_INT(a, ACC);
1210 acc = Encode(~a);
1211 MOTH_END_INSTR(UCompl)
1212
1213 MOTH_BEGIN_INSTR(Increment)
1214 if (Q_LIKELY(ACC.integerCompatible())) {
1215 acc = add_int32(ACC.int_32(), b: 1);
1216 } else if (ACC.isDouble()) {
1217 acc = QV4::Encode(ACC.doubleValue() + 1.);
1218 } else {
1219 acc = Encode(ACC.toNumberImpl() + 1.);
1220 CHECK_EXCEPTION;
1221 }
1222 MOTH_END_INSTR(Increment)
1223
1224 MOTH_BEGIN_INSTR(Decrement)
1225 if (Q_LIKELY(ACC.integerCompatible())) {
1226 acc = sub_int32(ACC.int_32(), b: 1);
1227 } else if (ACC.isDouble()) {
1228 acc = QV4::Encode(ACC.doubleValue() - 1.);
1229 } else {
1230 acc = Encode(ACC.toNumberImpl() - 1.);
1231 CHECK_EXCEPTION;
1232 }
1233 MOTH_END_INSTR(Decrement)
1234
1235 MOTH_BEGIN_INSTR(Add)
1236 const Value left = STACK_VALUE(lhs);
1237 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1238 acc = add_int32(a: left.int_32(), ACC.int_32());
1239 } else if (left.isNumber() && ACC.isNumber()) {
1240 acc = Encode(left.asDouble() + ACC.asDouble());
1241 } else {
1242 STORE_ACC();
1243 acc = Runtime::Add::call(engine, left, accumulator);
1244 CHECK_EXCEPTION;
1245 }
1246 MOTH_END_INSTR(Add)
1247
1248 MOTH_BEGIN_INSTR(Sub)
1249 const Value left = STACK_VALUE(lhs);
1250 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1251 acc = sub_int32(a: left.int_32(), ACC.int_32());
1252 } else if (left.isNumber() && ACC.isNumber()) {
1253 acc = Encode(left.asDouble() - ACC.asDouble());
1254 } else {
1255 STORE_ACC();
1256 acc = Runtime::Sub::call(left, accumulator);
1257 CHECK_EXCEPTION;
1258 }
1259 MOTH_END_INSTR(Sub)
1260
1261 MOTH_BEGIN_INSTR(Exp)
1262 const Value left = STACK_VALUE(lhs);
1263 double base = left.toNumber();
1264 double exp = ACC.toNumber();
1265 if (qIsInf(d: exp) && (base == 1 || base == -1))
1266 acc = Encode(qQNaN());
1267 else
1268 acc = Encode(pow(x: base,y: exp));
1269 MOTH_END_INSTR(Exp)
1270
1271 MOTH_BEGIN_INSTR(Mul)
1272 const Value left = STACK_VALUE(lhs);
1273 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1274 acc = mul_int32(a: left.int_32(), ACC.int_32());
1275 } else if (left.isNumber() && ACC.isNumber()) {
1276 acc = Encode(left.asDouble() * ACC.asDouble());
1277 } else {
1278 STORE_ACC();
1279 acc = Runtime::Mul::call(left, accumulator);
1280 CHECK_EXCEPTION;
1281 }
1282 MOTH_END_INSTR(Mul)
1283
1284 MOTH_BEGIN_INSTR(Div)
1285 STORE_ACC();
1286 acc = Runtime::Div::call(STACK_VALUE(lhs), accumulator);
1287 CHECK_EXCEPTION;
1288 MOTH_END_INSTR(Div)
1289
1290 MOTH_BEGIN_INSTR(Mod)
1291 STORE_ACC();
1292 acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
1293 CHECK_EXCEPTION;
1294 MOTH_END_INSTR(Mod)
1295
1296 MOTH_BEGIN_INSTR(BitAnd)
1297 VALUE_TO_INT(l, STACK_VALUE(lhs));
1298 VALUE_TO_INT(a, ACC);
1299 acc = Encode(l & a);
1300 MOTH_END_INSTR(BitAnd)
1301
1302 MOTH_BEGIN_INSTR(BitOr)
1303 VALUE_TO_INT(l, STACK_VALUE(lhs));
1304 VALUE_TO_INT(a, ACC);
1305 acc = Encode(l | a);
1306 MOTH_END_INSTR(BitOr)
1307
1308 MOTH_BEGIN_INSTR(BitXor)
1309 VALUE_TO_INT(l, STACK_VALUE(lhs));
1310 VALUE_TO_INT(a, ACC);
1311 acc = Encode(l ^ a);
1312 MOTH_END_INSTR(BitXor)
1313
1314 MOTH_BEGIN_INSTR(UShr)
1315 VALUE_TO_INT(l, STACK_VALUE(lhs));
1316 VALUE_TO_INT(a, ACC);
1317 acc = Encode(static_cast<uint>(l) >> uint(a & 0x1f));
1318 MOTH_END_INSTR(UShr)
1319
1320 MOTH_BEGIN_INSTR(Shr)
1321 VALUE_TO_INT(l, STACK_VALUE(lhs));
1322 VALUE_TO_INT(a, ACC);
1323 acc = Encode(l >> (a & 0x1f));
1324 MOTH_END_INSTR(Shr)
1325
1326 MOTH_BEGIN_INSTR(Shl)
1327 VALUE_TO_INT(l, STACK_VALUE(lhs));
1328 VALUE_TO_INT(a, ACC);
1329 acc = Encode(l << (a & 0x1f));
1330 MOTH_END_INSTR(Shl)
1331
1332 MOTH_BEGIN_INSTR(BitAndConst)
1333 VALUE_TO_INT(a, ACC);
1334 acc = Encode(a & rhs);
1335 CHECK_EXCEPTION;
1336 MOTH_END_INSTR(BitAndConst)
1337
1338 MOTH_BEGIN_INSTR(BitOrConst)
1339 VALUE_TO_INT(a, ACC);
1340 acc = Encode(a | rhs);
1341 MOTH_END_INSTR(BitOrConst)
1342
1343 MOTH_BEGIN_INSTR(BitXorConst)
1344 VALUE_TO_INT(a, ACC);
1345 acc = Encode(a ^ rhs);
1346 MOTH_END_INSTR(BitXorConst)
1347
1348 MOTH_BEGIN_INSTR(UShrConst)
1349 acc = Encode(ACC.toUInt32() >> uint(rhs));
1350 MOTH_END_INSTR(UShrConst)
1351
1352 MOTH_BEGIN_INSTR(ShrConst)
1353 VALUE_TO_INT(a, ACC);
1354 acc = Encode(a >> rhs);
1355 MOTH_END_INSTR(ShrConst)
1356
1357 MOTH_BEGIN_INSTR(ShlConst)
1358 VALUE_TO_INT(a, ACC);
1359 acc = Encode(a << rhs);
1360 MOTH_END_INSTR(ShlConst)
1361
1362 MOTH_BEGIN_INSTR(Ret)
1363 return acc;
1364 MOTH_END_INSTR(Ret)
1365
1366 MOTH_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
1367 acc = Encode(Value::emptyValue());
1368 for (int i = firstReg, end = firstReg + count; i < end; ++i)
1369 STACK_VALUE(i) = acc;
1370 MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
1371
1372 MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
1373 if (Value::fromReturnedValue(val: acc).isNullOrUndefined()) {
1374 engine->throwTypeError();
1375 goto handleUnwind;
1376 }
1377 MOTH_END_INSTR(ThrowOnNullOrUndefined)
1378
1379 MOTH_BEGIN_INSTR(GetTemplateObject)
1380 acc = Runtime::GetTemplateObject::call(function, index);
1381 MOTH_END_INSTR(GetTemplateObject)
1382
1383 MOTH_BEGIN_INSTR(Debug)
1384#if QT_CONFIG(qml_debug)
1385 STORE_IP();
1386 debug_slowPath(engine);
1387#endif // QT_CONFIG(qml_debug)
1388 MOTH_END_INSTR(Debug)
1389
1390 handleUnwind:
1391 // We do start the exception handler in case of isInterrupted. The exception handler will
1392 // immediately abort, due to the same isInterrupted. We don't skip the exception handler
1393 // because the current behavior is easier to implement in the JIT.
1394 Q_ASSERT(engine->hasException || engine->isInterrupted.loadAcquire() || frame->unwindLevel);
1395 if (!frame->unwindHandler) {
1396 acc = Encode::undefined();
1397 return acc;
1398 }
1399 code = frame->unwindHandler;
1400 }
1401}
1402

source code of qtdeclarative/src/qml/jsruntime/qv4vme_moth.cpp