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
144QVector<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}
455
456ReturnedValue VME::exec(JSTypesStackFrame *frame, ExecutionEngine *engine)
457{
459 CHECK_STACK_LIMITS(engine);
460
461 Function *function = frame->v4Function;
462 Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
463 function->executableCompilationUnit()->fileName(),
464 function->compiledFunction->location.line(),
465 function->compiledFunction->location.column());
466 Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
467 QV4::Debugging::Debugger *debugger = engine->debugger();
468
469#if QT_CONFIG(qml_jit)
470 if (debugger == nullptr) {
471 // Check for codeRef here. In rare cases the JIT compilation may fail, which leaves us
472 // with a (useless) codeRef, but no jittedCode. In that case, don't try to JIT again every
473 // time we execute the function, but just interpret instead.
474 if (function->codeRef == nullptr) {
475 if (engine->canJIT(function))
476 QV4::JIT::BaselineJIT(function).generate();
477 else
478 ++function->interpreterCallCount;
479 }
480 }
481#endif // QT_CONFIG(qml_jit)
482
483 // interpreter
484 if (debugger)
485 debugger->enteringFunction();
486
487 ReturnedValue result;
488 Q_ASSERT(function->kind != Function::AotCompiled);
489 if (function->jittedCode != nullptr && debugger == nullptr) {
490 result = function->jittedCode(frame, engine);
491 } else {
492 // interpreter
493 result = interpret(frame, engine, function->codeData);
494 }
495
496 if (debugger)
497 debugger->leavingFunction(result);
498
499 return result;
500}
501
502QV4::ReturnedValue VME::interpret(JSTypesStackFrame *frame, ExecutionEngine *engine, const char *code)
503{
504 QV4::Function *function = frame->v4Function;
505 QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>();
506 QV4::ReturnedValue acc = accumulator.asReturnedValue();
507 Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
508
509 MOTH_JUMP_TABLE;
510
511 for (;;) {
512 MOTH_DISPATCH()
513 Q_UNREACHABLE(); // only reached when the dispatch doesn't jump somewhere
514
515 MOTH_BEGIN_INSTR(LoadConst)
516 acc = constant(function, index).asReturnedValue();
517 MOTH_END_INSTR(LoadConst)
518
519 MOTH_BEGIN_INSTR(LoadNull)
520 acc = Encode::null();
521 MOTH_END_INSTR(LoadNull)
522
523 MOTH_BEGIN_INSTR(LoadZero)
524 acc = Encode(static_cast<int>(0));
525 MOTH_END_INSTR(LoadZero)
526
527 MOTH_BEGIN_INSTR(LoadTrue)
528 acc = Encode(true);
529 MOTH_END_INSTR(LoadTrue)
530
531 MOTH_BEGIN_INSTR(LoadFalse)
532 acc = Encode(false);
533 MOTH_END_INSTR(LoadFalse)
534
535 MOTH_BEGIN_INSTR(LoadUndefined)
536 acc = Encode::undefined();
537 MOTH_END_INSTR(LoadUndefined)
538
539 MOTH_BEGIN_INSTR(LoadInt)
540 acc = Encode(value);
541 MOTH_END_INSTR(LoadInt)
542
543 MOTH_BEGIN_INSTR(MoveConst)
544 STACK_VALUE(destTemp) = constant(function, constIndex);
545 MOTH_END_INSTR(MoveConst)
546
547 MOTH_BEGIN_INSTR(LoadReg)
548 acc = STACK_VALUE(reg).asReturnedValue();
549 MOTH_END_INSTR(LoadReg)
550
551 MOTH_BEGIN_INSTR(StoreReg)
552 STACK_VALUE(reg) = acc;
553 MOTH_END_INSTR(StoreReg)
554
555 MOTH_BEGIN_INSTR(MoveReg)
556 STACK_VALUE(destReg) = STACK_VALUE(srcReg);
557 MOTH_END_INSTR(MoveReg)
558
559 MOTH_BEGIN_INSTR(LoadImport)
560 acc = function->compilationUnit->imports[index]->asReturnedValue();
561 MOTH_END_INSTR(LoadImport)
562
563 MOTH_BEGIN_INSTR(LoadLocal)
564 auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
565 Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
566 acc = cc->locals[index].asReturnedValue();
567 MOTH_END_INSTR(LoadLocal)
568
569 MOTH_BEGIN_INSTR(StoreLocal)
571 auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
572 Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
573 QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
574 MOTH_END_INSTR(StoreLocal)
575
576 MOTH_BEGIN_INSTR(LoadScopedLocal)
577 auto cc = getScope(stack, scope);
578 acc = cc->locals[index].asReturnedValue();
579 MOTH_END_INSTR(LoadScopedLocal)
580
581 MOTH_BEGIN_INSTR(StoreScopedLocal)
583 auto cc = getScope(stack, scope);
584 QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
585 MOTH_END_INSTR(StoreScopedLocal)
586
587 MOTH_BEGIN_INSTR(LoadRuntimeString)
588 acc = function->compilationUnit->runtimeStrings[stringId]->asReturnedValue();
589 MOTH_END_INSTR(LoadRuntimeString)
590
591 MOTH_BEGIN_INSTR(MoveRegExp)
592 STACK_VALUE(destReg) = Runtime::RegexpLiteral::call(engine, regExpId);
593 MOTH_END_INSTR(MoveRegExp)
594
595 MOTH_BEGIN_INSTR(LoadClosure)
596 acc = Runtime::Closure::call(engine, value);
597 MOTH_END_INSTR(LoadClosure)
598
599 MOTH_BEGIN_INSTR(LoadName)
600 STORE_IP();
601 acc = Runtime::LoadName::call(engine, name);
603 MOTH_END_INSTR(LoadName)
604
605 MOTH_BEGIN_INSTR(LoadGlobalLookup)
606 STORE_IP();
607 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
608 acc = l->globalGetter(engine);
610 MOTH_END_INSTR(LoadGlobalLookup)
611
612 MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
613 STORE_IP();
614 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
615 acc = l->contextGetter(engine, nullptr);
617 MOTH_END_INSTR(LoadQmlContextPropertyLookup)
618
619 MOTH_BEGIN_INSTR(StoreNameStrict)
620 STORE_IP();
621 STORE_ACC();
622 Runtime::StoreNameStrict::call(engine, name, accumulator);
624 MOTH_END_INSTR(StoreNameStrict)
625
626 MOTH_BEGIN_INSTR(StoreNameSloppy)
627 STORE_IP();
628 STORE_ACC();
629 Runtime::StoreNameSloppy::call(engine, name, accumulator);
631 MOTH_END_INSTR(StoreNameSloppy)
632
633 MOTH_BEGIN_INSTR(LoadElement)
634 STORE_IP();
635 STORE_ACC();
636 acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator);
638 MOTH_END_INSTR(LoadElement)
639
640 MOTH_BEGIN_INSTR(StoreElement)
641 STORE_IP();
642 STORE_ACC();
643 Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
645 MOTH_END_INSTR(StoreElement)
646
647 MOTH_BEGIN_INSTR(LoadProperty)
648 STORE_IP();
649 STORE_ACC();
650 acc = Runtime::LoadProperty::call(engine, accumulator, name);
652 MOTH_END_INSTR(LoadProperty)
653
654 MOTH_BEGIN_INSTR(LoadOptionalProperty)
655 STORE_IP();
656 STORE_ACC();
657 if (accumulator.isNullOrUndefined()) {
658 acc = Encode::undefined();
659 code += offset;
660 } else {
661 acc = Runtime::LoadProperty::call(engine, accumulator, name);
662 }
664 MOTH_END_INSTR(LoadOptionalProperty)
665
666 MOTH_BEGIN_INSTR(GetLookup)
667 STORE_IP();
668 STORE_ACC();
669
670 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
671
672 if (accumulator.isNullOrUndefined()) {
673 QString message = QStringLiteral("Cannot read property '%1' of %2")
674 .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
675 .arg(accumulator.toQStringNoThrow());
676 acc = engine->throwTypeError(message);
677 goto handleUnwind;
678 }
679
680 acc = l->getter(engine, accumulator);
682 MOTH_END_INSTR(GetLookup)
683
684 MOTH_BEGIN_INSTR(GetOptionalLookup)
685 STORE_IP();
686 STORE_ACC();
687
688 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
689
690 if (accumulator.isNullOrUndefined()) {
691 code += offset;
692 } else {
693 acc = l->getter(engine, accumulator);
694 }
696 MOTH_END_INSTR(GetOptionalLookup)
697
698 MOTH_BEGIN_INSTR(StoreProperty)
699 STORE_IP();
700 STORE_ACC();
701 Runtime::StoreProperty::call(engine, STACK_VALUE(base), name, accumulator);
703 MOTH_END_INSTR(StoreProperty)
704
705 MOTH_BEGIN_INSTR(SetLookup)
706 STORE_IP();
707 STORE_ACC();
708 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
709 if (!l->setter(engine, STACK_VALUE(base), accumulator) && function->isStrict())
710 engine->throwTypeError();
712 MOTH_END_INSTR(SetLookup)
713
714 MOTH_BEGIN_INSTR(LoadSuperProperty)
715 STORE_IP();
716 acc = Runtime::LoadSuperProperty::call(engine, STACK_VALUE(property));
718 MOTH_END_INSTR(LoadSuperProperty)
719
720 MOTH_BEGIN_INSTR(StoreSuperProperty)
721 STORE_IP();
722 STORE_ACC();
723 Runtime::StoreSuperProperty::call(engine, STACK_VALUE(property), accumulator);
725 MOTH_END_INSTR(StoreSuperProperty)
726
727 MOTH_BEGIN_INSTR(Yield)
728 frame->setYield(code);
729 frame->setYieldIsIterator(false);
730 return acc;
731 MOTH_END_INSTR(Yield)
732
733 MOTH_BEGIN_INSTR(YieldStar)
734 frame->setYield(code);
735 frame->setYieldIsIterator(true);
736 return acc;
737 MOTH_END_INSTR(YieldStar)
738
739 MOTH_BEGIN_INSTR(Resume)
740 // check exception, in case the generator was called with throw() or return()
741 if (engine->hasException) {
742 // an empty value indicates that the generator was called with return()
743 if (engine->exceptionValue->asReturnedValue() != Value::emptyValue().asReturnedValue())
744 goto handleUnwind;
745 engine->hasException = false;
746 *engine->exceptionValue = Value::undefinedValue();
747 } else {
748 code += offset;
749 }
750 MOTH_END_INSTR(Resume)
751
752 MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
753 STORE_ACC();
754 acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
755 if (ACC.toBoolean())
756 code += offset;
757 MOTH_END_INSTR(IteratorNextForYieldStar)
758
759 MOTH_BEGIN_INSTR(CallValue)
760 STORE_IP();
761 Value func = STACK_VALUE(name);
762 if (Q_UNLIKELY(!func.isFunctionObject())) {
763 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
764 goto handleUnwind;
765 }
766 Value undef = Value::undefinedValue();
767 acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
769 MOTH_END_INSTR(CallValue)
770
771 MOTH_BEGIN_INSTR(CallWithReceiver)
772 STORE_IP();
773 Value func = STACK_VALUE(name);
774 if (Q_UNLIKELY(!func.isFunctionObject())) {
775 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
776 goto handleUnwind;
777 }
778 acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
780 MOTH_END_INSTR(CallWithReceiver)
781
782 MOTH_BEGIN_INSTR(CallProperty)
783 STORE_IP();
784 acc = Runtime::CallProperty::call(engine, STACK_VALUE(base), name, stack + argv, argc);
786 MOTH_END_INSTR(CallProperty)
787
788 MOTH_BEGIN_INSTR(CallPropertyLookup)
789 STORE_IP();
790 Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
791
792 if (STACK_VALUE(base).isNullOrUndefined()) {
793 QString message = QStringLiteral("Cannot call method '%1' of %2")
794 .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
795 .arg(STACK_VALUE(base).toQStringNoThrow());
796 acc = engine->throwTypeError(message);
797 goto handleUnwind;
798 }
799
800 // ok to have the value on the stack here
801 Value f = Value::fromReturnedValue(l->getter(engine, STACK_VALUE(base)));
802
803 if (Q_LIKELY(f.isFunctionObject())) {
804 acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
805 } else if (QmlSignalHandler *handler = f.as<QmlSignalHandler>()) {
806 acc = handler->call(stack + base, stack + argv, argc);
807 } else {
808 const QString message = QStringLiteral("Property '%1' of object %2 is not a function")
809 .arg(engine->currentStackFrame->v4Function->compilationUnit
810 ->runtimeStrings[l->nameIndex]->toQString())
811 .arg(STACK_VALUE(base).toQStringNoThrow());
812 acc = engine->throwTypeError(message);
813 goto handleUnwind;
814 }
815
817 MOTH_END_INSTR(CallPropertyLookup)
818
819 MOTH_BEGIN_INSTR(CallName)
820 STORE_IP();
821 acc = Runtime::CallName::call(engine, name, stack + argv, argc);
823 MOTH_END_INSTR(CallName)
824
825 MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
826 STORE_IP();
827 acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
829 MOTH_END_INSTR(CallPossiblyDirectEval)
830
831 MOTH_BEGIN_INSTR(CallGlobalLookup)
832 STORE_IP();
833 acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
835 MOTH_END_INSTR(CallGlobalLookup)
836
837 MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
838 STORE_IP();
839 acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
841 MOTH_END_INSTR(CallQmlContextPropertyLookup)
842
843 MOTH_BEGIN_INSTR(CallWithSpread)
844 STORE_IP();
845 acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
847 MOTH_END_INSTR(CallWithSpread)
848
849 MOTH_BEGIN_INSTR(TailCall)
850 STORE_IP();
851 *engine->jsAlloca(1) = Primitive::fromInt32(argc);
852 *engine->jsAlloca(1) = Primitive::fromInt32(argv);
853 *engine->jsAlloca(1) = STACK_VALUE(thisObject);
854 *engine->jsAlloca(1) = STACK_VALUE(func);
855 return Runtime::TailCall::call(frame, engine);
857 MOTH_END_INSTR(TailCall)
858
859 MOTH_BEGIN_INSTR(Construct)
860 STORE_IP();
861 STORE_ACC();
862 acc = Runtime::Construct::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
864 MOTH_END_INSTR(Construct)
865
866 MOTH_BEGIN_INSTR(ConstructWithSpread)
867 STORE_IP();
868 STORE_ACC();
869 acc = Runtime::ConstructWithSpread::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
871 MOTH_END_INSTR(ConstructWithSpread)
872
873 MOTH_BEGIN_INSTR(SetUnwindHandler)
874 frame->unwindHandler = offset ? code + offset : nullptr;
875 MOTH_END_INSTR(SetUnwindHandler)
876
877 MOTH_BEGIN_INSTR(UnwindDispatch)
879 if (frame->unwindLevel) {
880 --frame->unwindLevel;
881 if (frame->unwindLevel)
882 goto handleUnwind;
883 code = frame->unwindLabel;
884 }
885 MOTH_END_INSTR(UnwindDispatch)
886
887 MOTH_BEGIN_INSTR(UnwindToLabel)
888 frame->unwindLevel = level;
889 frame->unwindLabel = code + offset;
890 goto handleUnwind;
891 MOTH_END_INSTR(UnwindToLabel)
892
893 MOTH_BEGIN_INSTR(DeadTemporalZoneCheck)
894 if (ACC.isEmpty()) {
895 STORE_IP();
896 Runtime::ThrowReferenceError::call(engine, name);
897 goto handleUnwind;
898 }
899 MOTH_END_INSTR(DeadTemporalZoneCheck)
900
901 MOTH_BEGIN_INSTR(ThrowException)
902 STORE_IP();
903 STORE_ACC();
904 Runtime::ThrowException::call(engine, accumulator);
905 goto handleUnwind;
906 MOTH_END_INSTR(ThrowException)
907
908 MOTH_BEGIN_INSTR(GetException)
909 acc = engine->hasException ? engine->exceptionValue->asReturnedValue()
910 : Value::emptyValue().asReturnedValue();
911 engine->hasException = false;
912 MOTH_END_INSTR(GetException)
913
914 MOTH_BEGIN_INSTR(SetException)
915 if (acc != Value::emptyValue().asReturnedValue()) {
916 *engine->exceptionValue = acc;
917 engine->hasException = true;
918 }
919 MOTH_END_INSTR(SetException)
920
921 MOTH_BEGIN_INSTR(PushCatchContext)
922 Runtime::PushCatchContext::call(engine, index, name);
923 MOTH_END_INSTR(PushCatchContext)
924
925 MOTH_BEGIN_INSTR(CreateCallContext)
926 Runtime::PushCallContext::call(frame);
927 MOTH_END_INSTR(CreateCallContext)
928
929 MOTH_BEGIN_INSTR(PushWithContext)
930 STORE_IP();
931 STORE_ACC();
932 acc = Runtime::PushWithContext::call(engine, STACK_VALUE(CallData::Accumulator));
934 MOTH_END_INSTR(PushWithContext)
935
936 MOTH_BEGIN_INSTR(PushBlockContext)
937 STORE_ACC();
938 Runtime::PushBlockContext::call(engine, index);
939 MOTH_END_INSTR(PushBlockContext)
940
941 MOTH_BEGIN_INSTR(CloneBlockContext)
942 STORE_ACC();
943 Runtime::CloneBlockContext::call(engine);
944 MOTH_END_INSTR(CloneBlockContext)
945
946 MOTH_BEGIN_INSTR(PushScriptContext)
947 Runtime::PushScriptContext::call(engine, index);
948 MOTH_END_INSTR(PushScriptContext)
949
950 MOTH_BEGIN_INSTR(PopScriptContext)
951 Runtime::PopScriptContext::call(engine);
952 MOTH_END_INSTR(PopScriptContext)
953
954 MOTH_BEGIN_INSTR(PopContext)
955 ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
956 STACK_VALUE(CallData::Context) = c->d()->outer;
957 MOTH_END_INSTR(PopContext)
958
959 MOTH_BEGIN_INSTR(GetIterator)
960 STORE_IP();
961 STORE_ACC();
962 acc = Runtime::GetIterator::call(engine, accumulator, iterator);
964 MOTH_END_INSTR(GetIterator)
965
966 MOTH_BEGIN_INSTR(IteratorNext)
967 STORE_IP();
968 STORE_ACC();
969 acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
970 if (ACC.toBoolean())
971 code += offset;
972 MOTH_END_INSTR(IteratorNext)
973
974 MOTH_BEGIN_INSTR(IteratorClose)
975 STORE_IP();
976 STORE_ACC();
977 acc = Runtime::IteratorClose::call(engine, accumulator);
978 MOTH_END_INSTR(IteratorClose)
979
980 MOTH_BEGIN_INSTR(DestructureRestElement)
981 STORE_IP();
982 STORE_ACC();
983 acc = Runtime::DestructureRestElement::call(engine, ACC);
985 MOTH_END_INSTR(DestructureRestElement)
986
987 MOTH_BEGIN_INSTR(DeleteProperty)
988 acc = Runtime::DeleteProperty::call(engine, function, STACK_VALUE(base), STACK_VALUE(index));
990 MOTH_END_INSTR(DeleteProperty)
991
992 MOTH_BEGIN_INSTR(DeleteName)
993 acc = Runtime::DeleteName::call(engine, function, name);
995 MOTH_END_INSTR(DeleteName)
996
997 MOTH_BEGIN_INSTR(TypeofName)
998 acc = Runtime::TypeofName::call(engine, name);
999 MOTH_END_INSTR(TypeofName)
1000
1001 MOTH_BEGIN_INSTR(TypeofValue)
1002 STORE_ACC();
1003 acc = Runtime::TypeofValue::call(engine, accumulator);
1004 MOTH_END_INSTR(TypeofValue)
1005
1006 MOTH_BEGIN_INSTR(DeclareVar)
1007 Runtime::DeclareVar::call(engine, isDeletable, varName);
1008 MOTH_END_INSTR(DeclareVar)
1009
1010 MOTH_BEGIN_INSTR(DefineArray)
1011 QV4::Value *arguments = stack + args;
1012 acc = Runtime::ArrayLiteral::call(engine, arguments, argc);
1013 MOTH_END_INSTR(DefineArray)
1014
1015 MOTH_BEGIN_INSTR(DefineObjectLiteral)
1016 QV4::Value *arguments = stack + args;
1017 acc = Runtime::ObjectLiteral::call(engine, internalClassId, arguments, argc);
1018 MOTH_END_INSTR(DefineObjectLiteral)
1019
1020 MOTH_BEGIN_INSTR(CreateClass)
1021 acc = Runtime::CreateClass::call(engine, classIndex, STACK_VALUE(heritage), stack + computedNames);
1022 MOTH_END_INSTR(CreateClass)
1023
1024 MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
1025 acc = Runtime::CreateMappedArgumentsObject::call(engine);
1026 MOTH_END_INSTR(CreateMappedArgumentsObject)
1027
1028 MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
1029 acc = Runtime::CreateUnmappedArgumentsObject::call(engine);
1030 MOTH_END_INSTR(CreateUnmappedArgumentsObject)
1031
1032 MOTH_BEGIN_INSTR(CreateRestParameter)
1033 acc = Runtime::CreateRestParameter::call(engine, argIndex);
1034 MOTH_END_INSTR(CreateRestParameter)
1035
1036 MOTH_BEGIN_INSTR(ConvertThisToObject)
1037 STORE_ACC();
1038 stack[CallData::This] = Runtime::ConvertThisToObject::call(
1039 engine, STACK_VALUE(CallData::This));
1041 MOTH_END_INSTR(ConvertThisToObject)
1042
1043 MOTH_BEGIN_INSTR(LoadSuperConstructor)
1044 acc = Runtime::LoadSuperConstructor::call(engine, STACK_VALUE(CallData::Function));
1046 MOTH_END_INSTR(LoadSuperConstructor)
1047
1048 MOTH_BEGIN_INSTR(ToObject)
1049 STORE_ACC();
1050 acc = ACC.toObject(engine)->asReturnedValue();
1052 MOTH_END_INSTR(ToObject)
1053
1054 MOTH_BEGIN_INSTR(Jump)
1055 code += offset;
1056 MOTH_END_INSTR(Jump)
1057
1058 MOTH_BEGIN_INSTR(JumpTrue)
1059 bool takeJump;
1060 if (Q_LIKELY(ACC.integerCompatible()))
1061 takeJump = ACC.int_32();
1062 else
1063 takeJump = ACC.toBoolean();
1064 if (takeJump)
1065 code += offset;
1066 MOTH_END_INSTR(JumpTrue)
1067
1068 MOTH_BEGIN_INSTR(JumpFalse)
1069 bool takeJump;
1070 if (Q_LIKELY(ACC.integerCompatible()))
1071 takeJump = !ACC.int_32();
1072 else
1073 takeJump = !ACC.toBoolean();
1074 if (takeJump)
1075 code += offset;
1076 MOTH_END_INSTR(JumpFalse)
1077
1078 MOTH_BEGIN_INSTR(JumpNoException)
1079 if (!engine->hasException)
1080 code += offset;
1081 MOTH_END_INSTR(JumpNoException)
1082
1083 MOTH_BEGIN_INSTR(JumpNotUndefined)
1084 if (Q_LIKELY(acc != QV4::Encode::undefined()))
1085 code += offset;
1086 MOTH_END_INSTR(JumpNotUndefined)
1087
1088 MOTH_BEGIN_INSTR(CheckException)
1090 MOTH_END_INSTR(CheckException)
1091
1092 MOTH_BEGIN_INSTR(CmpEqNull)
1093 acc = Encode(ACC.isNullOrUndefined());
1094 MOTH_END_INSTR(CmpEqNull)
1095
1096 MOTH_BEGIN_INSTR(CmpNeNull)
1097 acc = Encode(!ACC.isNullOrUndefined());
1098 MOTH_END_INSTR(CmpNeNull)
1099
1100 MOTH_BEGIN_INSTR(CmpEqInt)
1101 if (ACC.isIntOrBool()) {
1102 acc = Encode(ACC.int_32() == lhs);
1103 } else {
1104 STORE_ACC();
1105 acc = Encode(compareEqualInt(accumulator, ACC, lhs));
1107 }
1108 MOTH_END_INSTR(CmpEqInt)
1109
1110 MOTH_BEGIN_INSTR(CmpNeInt)
1111 if (ACC.isIntOrBool()) {
1112 acc = Encode(bool(ACC.int_32() != lhs));
1113 } else {
1114 STORE_ACC();
1115 acc = Encode(!compareEqualInt(accumulator, ACC, lhs));
1117 }
1118 MOTH_END_INSTR(CmpNeInt)
1119
1120 MOTH_BEGIN_INSTR(CmpEq)
1121 const Value left = STACK_VALUE(lhs);
1122 if (Q_LIKELY(left.asReturnedValue() == ACC.asReturnedValue())) {
1123 acc = Encode(!ACC.isNaN());
1124 } else if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1125 acc = Encode(left.int_32() == ACC.int_32());
1126 } else {
1127 STORE_ACC();
1128 acc = Encode(bool(Runtime::CompareEqual::call(left, accumulator)));
1130 }
1131 MOTH_END_INSTR(CmpEq)
1132
1133 MOTH_BEGIN_INSTR(CmpNe)
1134 const Value left = STACK_VALUE(lhs);
1135 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1136 acc = Encode(bool(left.int_32() != ACC.int_32()));
1137 } else {
1138 STORE_ACC();
1139 acc = Encode(bool(!Runtime::CompareEqual::call(left, accumulator)));
1141 }
1142 MOTH_END_INSTR(CmpNe)
1143
1144 MOTH_BEGIN_INSTR(CmpGt)
1145 const Value left = STACK_VALUE(lhs);
1146 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1147 acc = Encode(left.int_32() > ACC.int_32());
1148 } else if (left.isNumber() && ACC.isNumber()) {
1149 acc = Encode(left.asDouble() > ACC.asDouble());
1150 } else {
1151 STORE_ACC();
1152 acc = Encode(bool(Runtime::CompareGreaterThan::call(left, accumulator)));
1154 }
1155 MOTH_END_INSTR(CmpGt)
1156
1157 MOTH_BEGIN_INSTR(CmpGe)
1158 const Value left = STACK_VALUE(lhs);
1159 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1160 acc = Encode(left.int_32() >= ACC.int_32());
1161 } else if (left.isNumber() && ACC.isNumber()) {
1162 acc = Encode(left.asDouble() >= ACC.asDouble());
1163 } else {
1164 STORE_ACC();
1165 acc = Encode(bool(Runtime::CompareGreaterEqual::call(left, accumulator)));
1167 }
1168 MOTH_END_INSTR(CmpGe)
1169
1170 MOTH_BEGIN_INSTR(CmpLt)
1171 const Value left = STACK_VALUE(lhs);
1172 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1173 acc = Encode(left.int_32() < ACC.int_32());
1174 } else if (left.isNumber() && ACC.isNumber()) {
1175 acc = Encode(left.asDouble() < ACC.asDouble());
1176 } else {
1177 STORE_ACC();
1178 acc = Encode(bool(Runtime::CompareLessThan::call(left, accumulator)));
1180 }
1181 MOTH_END_INSTR(CmpLt)
1182
1183 MOTH_BEGIN_INSTR(CmpLe)
1184 const Value left = STACK_VALUE(lhs);
1185 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1186 acc = Encode(left.int_32() <= ACC.int_32());
1187 } else if (left.isNumber() && ACC.isNumber()) {
1188 acc = Encode(left.asDouble() <= ACC.asDouble());
1189 } else {
1190 STORE_ACC();
1191 acc = Encode(bool(Runtime::CompareLessEqual::call(left, accumulator)));
1193 }
1194 MOTH_END_INSTR(CmpLe)
1195
1196 MOTH_BEGIN_INSTR(CmpStrictEqual)
1197 if (STACK_VALUE(lhs).rawValue() == ACC.rawValue() && !ACC.isNaN()) {
1198 acc = Encode(true);
1199 } else {
1200 STORE_ACC();
1201 acc = Runtime::StrictEqual::call(STACK_VALUE(lhs), accumulator);
1203 }
1204 MOTH_END_INSTR(CmpStrictEqual)
1205
1206 MOTH_BEGIN_INSTR(CmpStrictNotEqual)
1207 if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) {
1208 STORE_ACC();
1209 acc = Runtime::StrictNotEqual::call(STACK_VALUE(lhs), accumulator);
1211 } else {
1212 acc = Encode(false);
1213 }
1214 MOTH_END_INSTR(CmpStrictNotEqual)
1215
1216 MOTH_BEGIN_INSTR(CmpIn)
1217 STORE_IP();
1218 STORE_ACC();
1219 acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator);
1221 MOTH_END_INSTR(CmpIn)
1222
1223 MOTH_BEGIN_INSTR(CmpInstanceOf)
1224 STORE_ACC();
1225 acc = Runtime::Instanceof::call(engine, STACK_VALUE(lhs), ACC);
1227 MOTH_END_INSTR(CmpInstanceOf)
1228
1229 MOTH_BEGIN_INSTR(UNot)
1230 if (ACC.integerCompatible()) {
1231 acc = Encode(!static_cast<bool>(ACC.int_32()));
1232 } else {
1233 acc = Encode(!Value::toBooleanImpl(ACC));
1234 }
1235 MOTH_END_INSTR(UNot)
1236
1237 MOTH_BEGIN_INSTR(UPlus)
1238 if (Q_UNLIKELY(!ACC.isNumber())) {
1239 acc = Encode(ACC.toNumberImpl());
1241 }
1242 MOTH_END_INSTR(UPlus)
1243
1244 MOTH_BEGIN_INSTR(UMinus)
1245 if (Q_LIKELY(ACC.integerCompatible())) {
1246 int a = ACC.int_32();
1247 if (a == 0 || a == std::numeric_limits<int>::min()) {
1248 acc = Encode(-static_cast<double>(a));
1249 } else {
1250 acc = sub_int32(0, ACC.int_32());
1251 }
1252 } else if (ACC.isDouble()) {
1253 acc ^= (1ull << 63); // simply flip sign bit
1254 } else {
1255 acc = Encode(-ACC.toNumberImpl());
1257 }
1258 MOTH_END_INSTR(UMinus)
1259
1260 MOTH_BEGIN_INSTR(UCompl)
1261 VALUE_TO_INT(a, ACC);
1262 acc = Encode(~a);
1263 MOTH_END_INSTR(UCompl)
1264
1265 MOTH_BEGIN_INSTR(Increment)
1266 if (Q_LIKELY(ACC.integerCompatible())) {
1267 acc = add_int32(ACC.int_32(), 1);
1268 } else if (ACC.isDouble()) {
1269 acc = QV4::Encode(ACC.doubleValue() + 1.);
1270 } else {
1271 acc = Encode(ACC.toNumberImpl() + 1.);
1273 }
1274 MOTH_END_INSTR(Increment)
1275
1276 MOTH_BEGIN_INSTR(Decrement)
1277 if (Q_LIKELY(ACC.integerCompatible())) {
1278 acc = sub_int32(ACC.int_32(), 1);
1279 } else if (ACC.isDouble()) {
1280 acc = QV4::Encode(ACC.doubleValue() - 1.);
1281 } else {
1282 acc = Encode(ACC.toNumberImpl() - 1.);
1284 }
1285 MOTH_END_INSTR(Decrement)
1286
1287 MOTH_BEGIN_INSTR(Add)
1288 const Value left = STACK_VALUE(lhs);
1289 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1290 acc = add_int32(left.int_32(), ACC.int_32());
1291 } else if (left.isNumber() && ACC.isNumber()) {
1292 acc = Encode(left.asDouble() + ACC.asDouble());
1293 } else {
1294 STORE_ACC();
1295 acc = Runtime::Add::call(engine, left, accumulator);
1297 }
1298 MOTH_END_INSTR(Add)
1299
1300 MOTH_BEGIN_INSTR(Sub)
1301 const Value left = STACK_VALUE(lhs);
1302 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1303 acc = sub_int32(left.int_32(), ACC.int_32());
1304 } else if (left.isNumber() && ACC.isNumber()) {
1305 acc = Encode(left.asDouble() - ACC.asDouble());
1306 } else {
1307 STORE_ACC();
1308 acc = Runtime::Sub::call(left, accumulator);
1310 }
1311 MOTH_END_INSTR(Sub)
1312
1314 const Value left = STACK_VALUE(lhs);
1315 STORE_ACC();
1316 acc = Runtime::As::call(engine, left, accumulator);
1317 MOTH_END_INSTR(As)
1318
1319 MOTH_BEGIN_INSTR(Exp)
1320 const Value left = STACK_VALUE(lhs);
1321 double base = left.toNumber();
1322 double exp = ACC.toNumber();
1323 acc = Encode(QQmlPrivate::jsExponentiate(base, exp));
1324 MOTH_END_INSTR(Exp)
1325
1326 MOTH_BEGIN_INSTR(Mul)
1327 const Value left = STACK_VALUE(lhs);
1328 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1329 acc = mul_int32(left.int_32(), ACC.int_32());
1330 } else if (left.isNumber() && ACC.isNumber()) {
1331 acc = Encode(left.asDouble() * ACC.asDouble());
1332 } else {
1333 STORE_ACC();
1334 acc = Runtime::Mul::call(left, accumulator);
1336 }
1337 MOTH_END_INSTR(Mul)
1338
1339 MOTH_BEGIN_INSTR(Div)
1340 STORE_ACC();
1341 acc = Runtime::Div::call(STACK_VALUE(lhs), accumulator);
1343 MOTH_END_INSTR(Div)
1344
1345 MOTH_BEGIN_INSTR(Mod)
1346 STORE_ACC();
1347 acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
1349 MOTH_END_INSTR(Mod)
1350
1351 MOTH_BEGIN_INSTR(BitAnd)
1352 VALUE_TO_INT(l, STACK_VALUE(lhs));
1353 VALUE_TO_INT(a, ACC);
1354 acc = Encode(l & a);
1355 MOTH_END_INSTR(BitAnd)
1356
1357 MOTH_BEGIN_INSTR(BitOr)
1358 VALUE_TO_INT(l, STACK_VALUE(lhs));
1359 VALUE_TO_INT(a, ACC);
1360 acc = Encode(l | a);
1361 MOTH_END_INSTR(BitOr)
1362
1363 MOTH_BEGIN_INSTR(BitXor)
1364 VALUE_TO_INT(l, STACK_VALUE(lhs));
1365 VALUE_TO_INT(a, ACC);
1366 acc = Encode(l ^ a);
1367 MOTH_END_INSTR(BitXor)
1368
1369 MOTH_BEGIN_INSTR(UShr)
1370 VALUE_TO_INT(l, STACK_VALUE(lhs));
1371 VALUE_TO_INT(a, ACC);
1372 acc = Encode(static_cast<uint>(l) >> uint(a & 0x1f));
1373 MOTH_END_INSTR(UShr)
1374
1375 MOTH_BEGIN_INSTR(Shr)
1376 VALUE_TO_INT(l, STACK_VALUE(lhs));
1377 VALUE_TO_INT(a, ACC);
1378 acc = Encode(l >> (a & 0x1f));
1379 MOTH_END_INSTR(Shr)
1380
1381 MOTH_BEGIN_INSTR(Shl)
1382 VALUE_TO_INT(l, STACK_VALUE(lhs));
1383 VALUE_TO_INT(a, ACC);
1384 acc = Encode(l << (a & 0x1f));
1385 MOTH_END_INSTR(Shl)
1386
1387 MOTH_BEGIN_INSTR(BitAndConst)
1388 VALUE_TO_INT(a, ACC);
1389 acc = Encode(a & rhs);
1391 MOTH_END_INSTR(BitAndConst)
1392
1393 MOTH_BEGIN_INSTR(BitOrConst)
1394 VALUE_TO_INT(a, ACC);
1395 acc = Encode(a | rhs);
1396 MOTH_END_INSTR(BitOrConst)
1397
1398 MOTH_BEGIN_INSTR(BitXorConst)
1399 VALUE_TO_INT(a, ACC);
1400 acc = Encode(a ^ rhs);
1401 MOTH_END_INSTR(BitXorConst)
1402
1403 MOTH_BEGIN_INSTR(UShrConst)
1404 acc = Encode(ACC.toUInt32() >> uint(rhs));
1405 MOTH_END_INSTR(UShrConst)
1406
1407 MOTH_BEGIN_INSTR(ShrConst)
1408 VALUE_TO_INT(a, ACC);
1409 acc = Encode(a >> rhs);
1410 MOTH_END_INSTR(ShrConst)
1411
1412 MOTH_BEGIN_INSTR(ShlConst)
1413 VALUE_TO_INT(a, ACC);
1414 acc = Encode(a << rhs);
1415 MOTH_END_INSTR(ShlConst)
1416
1417 MOTH_BEGIN_INSTR(Ret)
1418 return acc;
1419 MOTH_END_INSTR(Ret)
1420
1421 MOTH_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
1422 acc = Encode(Value::emptyValue());
1423 for (int i = firstReg, end = firstReg + count; i < end; ++i)
1424 STACK_VALUE(i) = acc;
1425 MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
1426
1427 MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
1428 if (Value::fromReturnedValue(acc).isNullOrUndefined()) {
1429 engine->throwTypeError();
1430 goto handleUnwind;
1431 }
1432 MOTH_END_INSTR(ThrowOnNullOrUndefined)
1433
1434 MOTH_BEGIN_INSTR(GetTemplateObject)
1435 acc = Runtime::GetTemplateObject::call(function, index);
1436 MOTH_END_INSTR(GetTemplateObject)
1437
1438 MOTH_BEGIN_INSTR(Debug)
1439#if QT_CONFIG(qml_debug)
1440 STORE_IP();
1441 debug_slowPath(engine);
1442#endif // QT_CONFIG(qml_debug)
1443 MOTH_END_INSTR(Debug)
1444
1445 handleUnwind:
1446 // We do start the exception handler in case of isInterrupted. The exception handler will
1447 // immediately abort, due to the same isInterrupted. We don't skip the exception handler
1448 // because the current behavior is easier to implement in the JIT.
1449 Q_ASSERT(engine->hasException || engine->isInterrupted.loadRelaxed() || frame->unwindLevel);
1450 if (!frame->unwindHandler) {
1451 acc = Encode::undefined();
1452 return acc;
1453 }
1454 code = frame->unwindHandler;
1455 }
1456}
Definition qjsvalue.h:23
#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()