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