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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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