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}
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 const QString message =
674 QStringLiteral("Cannot read property '%1' of %2")
675 .arg(engine->currentStackFrame->v4Function->compilationUnit
676 ->runtimeStrings[l->nameIndex]
677 ->toQString(),
678 accumulator.toQStringNoThrow());
679 acc = engine->throwTypeError(message);
680 goto handleUnwind;
681 }
682
683 acc = l->getter(engine, accumulator);
685 MOTH_END_INSTR(GetLookup)
686
687 MOTH_BEGIN_INSTR(GetOptionalLookup)
688 STORE_IP();
689 STORE_ACC();
690
691 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
692
693 if (accumulator.isNullOrUndefined()) {
694 code += offset;
695 } else {
696 acc = l->getter(engine, accumulator);
697 }
699 MOTH_END_INSTR(GetOptionalLookup)
700
701 MOTH_BEGIN_INSTR(StoreProperty)
702 STORE_IP();
703 STORE_ACC();
704 Runtime::StoreProperty::call(engine, STACK_VALUE(base), name, accumulator);
706 MOTH_END_INSTR(StoreProperty)
707
708 MOTH_BEGIN_INSTR(SetLookup)
709 STORE_IP();
710 STORE_ACC();
711 QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
712 if (!l->setter(engine, STACK_VALUE(base), accumulator) && function->isStrict())
713 engine->throwTypeError();
715 MOTH_END_INSTR(SetLookup)
716
717 MOTH_BEGIN_INSTR(LoadSuperProperty)
718 STORE_IP();
719 acc = Runtime::LoadSuperProperty::call(engine, STACK_VALUE(property));
721 MOTH_END_INSTR(LoadSuperProperty)
722
723 MOTH_BEGIN_INSTR(StoreSuperProperty)
724 STORE_IP();
725 STORE_ACC();
726 Runtime::StoreSuperProperty::call(engine, STACK_VALUE(property), accumulator);
728 MOTH_END_INSTR(StoreSuperProperty)
729
730 MOTH_BEGIN_INSTR(Yield)
731 frame->setYield(code);
732 frame->setYieldIsIterator(false);
733 return acc;
734 MOTH_END_INSTR(Yield)
735
736 MOTH_BEGIN_INSTR(YieldStar)
737 frame->setYield(code);
738 frame->setYieldIsIterator(true);
739 return acc;
740 MOTH_END_INSTR(YieldStar)
741
742 MOTH_BEGIN_INSTR(Resume)
743 // check exception, in case the generator was called with throw() or return()
744 if (engine->hasException) {
745 // an empty value indicates that the generator was called with return()
746 if (engine->exceptionValue->asReturnedValue() != Value::emptyValue().asReturnedValue())
747 goto handleUnwind;
748 engine->hasException = false;
749 *engine->exceptionValue = Value::undefinedValue();
750 } else {
751 code += offset;
752 }
753 MOTH_END_INSTR(Resume)
754
755 MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
756 STORE_ACC();
757 acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
758 if (ACC.toBoolean())
759 code += offset;
760 MOTH_END_INSTR(IteratorNextForYieldStar)
761
762 MOTH_BEGIN_INSTR(CallValue)
763 STORE_IP();
764 Value func = STACK_VALUE(name);
765 if (Q_UNLIKELY(!func.isFunctionObject())) {
766 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
767 goto handleUnwind;
768 }
769 Value undef = Value::undefinedValue();
770 acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
772 MOTH_END_INSTR(CallValue)
773
774 MOTH_BEGIN_INSTR(CallWithReceiver)
775 STORE_IP();
776 Value func = STACK_VALUE(name);
777 if (Q_UNLIKELY(!func.isFunctionObject())) {
778 acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
779 goto handleUnwind;
780 }
781 acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
783 MOTH_END_INSTR(CallWithReceiver)
784
785 MOTH_BEGIN_INSTR(CallProperty)
786 STORE_IP();
787 acc = Runtime::CallProperty::call(engine, STACK_VALUE(base), name, stack + argv, argc);
789 MOTH_END_INSTR(CallProperty)
790
791 MOTH_BEGIN_INSTR(CallPropertyLookup)
792 STORE_IP();
793 Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
794
795 if (STACK_VALUE(base).isNullOrUndefined()) {
796 const QString message =
797 QStringLiteral("Cannot call method '%1' of %2")
798 .arg(engine->currentStackFrame->v4Function->compilationUnit
799 ->runtimeStrings[l->nameIndex]
800 ->toQString(),
801 STACK_VALUE(base).toQStringNoThrow());
802 acc = engine->throwTypeError(message);
803 goto handleUnwind;
804 }
805
806 // ok to have the value on the stack here
807 Value f = Value::fromReturnedValue(l->getter(engine, STACK_VALUE(base)));
808
809 if (Q_LIKELY(f.isFunctionObject())) {
810 acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
811 } else if (QmlSignalHandler *handler = f.as<QmlSignalHandler>()) {
812 acc = handler->call(stack + base, stack + argv, argc);
813 } else {
814 const QString message =
815 QStringLiteral("Property '%1' of object %2 is not a function")
816 .arg(engine->currentStackFrame->v4Function->compilationUnit
817 ->runtimeStrings[l->nameIndex]
818 ->toQString(),
819 STACK_VALUE(base).toQStringNoThrow());
820 acc = engine->throwTypeError(message);
821 goto handleUnwind;
822 }
823
825 MOTH_END_INSTR(CallPropertyLookup)
826
827 MOTH_BEGIN_INSTR(CallName)
828 STORE_IP();
829 acc = Runtime::CallName::call(engine, name, stack + argv, argc);
831 MOTH_END_INSTR(CallName)
832
833 MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
834 STORE_IP();
835 acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
837 MOTH_END_INSTR(CallPossiblyDirectEval)
838
839 MOTH_BEGIN_INSTR(CallGlobalLookup)
840 STORE_IP();
841 acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
843 MOTH_END_INSTR(CallGlobalLookup)
844
845 MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
846 STORE_IP();
847 acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
849 MOTH_END_INSTR(CallQmlContextPropertyLookup)
850
851 MOTH_BEGIN_INSTR(CallWithSpread)
852 STORE_IP();
853 acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
855 MOTH_END_INSTR(CallWithSpread)
856
857 MOTH_BEGIN_INSTR(TailCall)
858 STORE_IP();
859 *engine->jsAlloca(1) = Primitive::fromInt32(argc);
860 *engine->jsAlloca(1) = Primitive::fromInt32(argv);
861 *engine->jsAlloca(1) = STACK_VALUE(thisObject);
862 *engine->jsAlloca(1) = STACK_VALUE(func);
863 return Runtime::TailCall::call(frame, engine);
865 MOTH_END_INSTR(TailCall)
866
867 MOTH_BEGIN_INSTR(Construct)
868 STORE_IP();
869 STORE_ACC();
870 acc = Runtime::Construct::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
872 MOTH_END_INSTR(Construct)
873
874 MOTH_BEGIN_INSTR(ConstructWithSpread)
875 STORE_IP();
876 STORE_ACC();
877 acc = Runtime::ConstructWithSpread::call(engine, STACK_VALUE(func), ACC, stack + argv, argc);
879 MOTH_END_INSTR(ConstructWithSpread)
880
881 MOTH_BEGIN_INSTR(SetUnwindHandler)
882 frame->unwindHandler = offset ? code + offset : nullptr;
883 MOTH_END_INSTR(SetUnwindHandler)
884
885 MOTH_BEGIN_INSTR(UnwindDispatch)
887 if (frame->unwindLevel) {
888 --frame->unwindLevel;
889 if (frame->unwindLevel)
890 goto handleUnwind;
891 code = frame->unwindLabel;
892 }
893 MOTH_END_INSTR(UnwindDispatch)
894
895 MOTH_BEGIN_INSTR(UnwindToLabel)
896 frame->unwindLevel = level;
897 frame->unwindLabel = code + offset;
898 goto handleUnwind;
899 MOTH_END_INSTR(UnwindToLabel)
900
901 MOTH_BEGIN_INSTR(DeadTemporalZoneCheck)
902 if (ACC.isEmpty()) {
903 STORE_IP();
904 Runtime::ThrowReferenceError::call(engine, name);
905 goto handleUnwind;
906 }
907 MOTH_END_INSTR(DeadTemporalZoneCheck)
908
909 MOTH_BEGIN_INSTR(ThrowException)
910 STORE_IP();
911 STORE_ACC();
912 Runtime::ThrowException::call(engine, accumulator);
913 goto handleUnwind;
914 MOTH_END_INSTR(ThrowException)
915
916 MOTH_BEGIN_INSTR(GetException)
917 acc = engine->hasException ? engine->exceptionValue->asReturnedValue()
918 : Value::emptyValue().asReturnedValue();
919 engine->hasException = false;
920 MOTH_END_INSTR(GetException)
921
922 MOTH_BEGIN_INSTR(SetException)
923 if (acc != Value::emptyValue().asReturnedValue()) {
924 *engine->exceptionValue = acc;
925 engine->hasException = true;
926 }
927 MOTH_END_INSTR(SetException)
928
929 MOTH_BEGIN_INSTR(PushCatchContext)
930 Runtime::PushCatchContext::call(engine, index, name);
931 MOTH_END_INSTR(PushCatchContext)
932
933 MOTH_BEGIN_INSTR(CreateCallContext)
934 Runtime::PushCallContext::call(frame);
935 MOTH_END_INSTR(CreateCallContext)
936
937 MOTH_BEGIN_INSTR(PushWithContext)
938 STORE_IP();
939 STORE_ACC();
940 acc = Runtime::PushWithContext::call(engine, STACK_VALUE(CallData::Accumulator));
942 MOTH_END_INSTR(PushWithContext)
943
944 MOTH_BEGIN_INSTR(PushBlockContext)
945 STORE_ACC();
946 Runtime::PushBlockContext::call(engine, index);
947 MOTH_END_INSTR(PushBlockContext)
948
949 MOTH_BEGIN_INSTR(CloneBlockContext)
950 STORE_ACC();
951 Runtime::CloneBlockContext::call(engine);
952 MOTH_END_INSTR(CloneBlockContext)
953
954 MOTH_BEGIN_INSTR(PushScriptContext)
955 Runtime::PushScriptContext::call(engine, index);
956 MOTH_END_INSTR(PushScriptContext)
957
958 MOTH_BEGIN_INSTR(PopScriptContext)
959 Runtime::PopScriptContext::call(engine);
960 MOTH_END_INSTR(PopScriptContext)
961
962 MOTH_BEGIN_INSTR(PopContext)
963 ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context);
964 STACK_VALUE(CallData::Context) = c->d()->outer;
965 MOTH_END_INSTR(PopContext)
966
967 MOTH_BEGIN_INSTR(GetIterator)
968 STORE_IP();
969 STORE_ACC();
970 acc = Runtime::GetIterator::call(engine, accumulator, iterator);
972 MOTH_END_INSTR(GetIterator)
973
974 MOTH_BEGIN_INSTR(IteratorNext)
975 STORE_IP();
976 STORE_ACC();
977 acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
978 if (ACC.toBoolean())
979 code += offset;
980 MOTH_END_INSTR(IteratorNext)
981
982 MOTH_BEGIN_INSTR(IteratorClose)
983 STORE_IP();
984 STORE_ACC();
985 acc = Runtime::IteratorClose::call(engine, accumulator);
986 MOTH_END_INSTR(IteratorClose)
987
988 MOTH_BEGIN_INSTR(DestructureRestElement)
989 STORE_IP();
990 STORE_ACC();
991 acc = Runtime::DestructureRestElement::call(engine, ACC);
993 MOTH_END_INSTR(DestructureRestElement)
994
995 MOTH_BEGIN_INSTR(DeleteProperty)
996 acc = Runtime::DeleteProperty::call(engine, function, STACK_VALUE(base), STACK_VALUE(index));
998 MOTH_END_INSTR(DeleteProperty)
999
1000 MOTH_BEGIN_INSTR(DeleteName)
1001 acc = Runtime::DeleteName::call(engine, function, name);
1003 MOTH_END_INSTR(DeleteName)
1004
1005 MOTH_BEGIN_INSTR(TypeofName)
1006 acc = Runtime::TypeofName::call(engine, name);
1007 MOTH_END_INSTR(TypeofName)
1008
1009 MOTH_BEGIN_INSTR(TypeofValue)
1010 STORE_ACC();
1011 acc = Runtime::TypeofValue::call(engine, accumulator);
1012 MOTH_END_INSTR(TypeofValue)
1013
1014 MOTH_BEGIN_INSTR(DeclareVar)
1015 Runtime::DeclareVar::call(engine, isDeletable, varName);
1016 MOTH_END_INSTR(DeclareVar)
1017
1018 MOTH_BEGIN_INSTR(DefineArray)
1019 QV4::Value *arguments = stack + args;
1020 acc = Runtime::ArrayLiteral::call(engine, arguments, argc);
1021 MOTH_END_INSTR(DefineArray)
1022
1023 MOTH_BEGIN_INSTR(DefineObjectLiteral)
1024 QV4::Value *arguments = stack + args;
1025 acc = Runtime::ObjectLiteral::call(engine, internalClassId, arguments, argc);
1026 MOTH_END_INSTR(DefineObjectLiteral)
1027
1028 MOTH_BEGIN_INSTR(CreateClass)
1029 acc = Runtime::CreateClass::call(engine, classIndex, STACK_VALUE(heritage), stack + computedNames);
1030 MOTH_END_INSTR(CreateClass)
1031
1032 MOTH_BEGIN_INSTR(CreateMappedArgumentsObject)
1033 acc = Runtime::CreateMappedArgumentsObject::call(engine);
1034 MOTH_END_INSTR(CreateMappedArgumentsObject)
1035
1036 MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject)
1037 acc = Runtime::CreateUnmappedArgumentsObject::call(engine);
1038 MOTH_END_INSTR(CreateUnmappedArgumentsObject)
1039
1040 MOTH_BEGIN_INSTR(CreateRestParameter)
1041 acc = Runtime::CreateRestParameter::call(engine, argIndex);
1042 MOTH_END_INSTR(CreateRestParameter)
1043
1044 MOTH_BEGIN_INSTR(ConvertThisToObject)
1045 STORE_ACC();
1046 stack[CallData::This] = Runtime::ConvertThisToObject::call(
1047 engine, STACK_VALUE(CallData::This));
1049 MOTH_END_INSTR(ConvertThisToObject)
1050
1051 MOTH_BEGIN_INSTR(LoadSuperConstructor)
1052 acc = Runtime::LoadSuperConstructor::call(engine, STACK_VALUE(CallData::Function));
1054 MOTH_END_INSTR(LoadSuperConstructor)
1055
1056 MOTH_BEGIN_INSTR(ToObject)
1057 STORE_ACC();
1058 acc = ACC.toObject(engine)->asReturnedValue();
1060 MOTH_END_INSTR(ToObject)
1061
1062 MOTH_BEGIN_INSTR(Jump)
1063 code += offset;
1064 MOTH_END_INSTR(Jump)
1065
1066 MOTH_BEGIN_INSTR(JumpTrue)
1067 bool takeJump;
1068 if (Q_LIKELY(ACC.integerCompatible()))
1069 takeJump = ACC.int_32();
1070 else
1071 takeJump = ACC.toBoolean();
1072 if (takeJump)
1073 code += offset;
1074 MOTH_END_INSTR(JumpTrue)
1075
1076 MOTH_BEGIN_INSTR(JumpFalse)
1077 bool takeJump;
1078 if (Q_LIKELY(ACC.integerCompatible()))
1079 takeJump = !ACC.int_32();
1080 else
1081 takeJump = !ACC.toBoolean();
1082 if (takeJump)
1083 code += offset;
1084 MOTH_END_INSTR(JumpFalse)
1085
1086 MOTH_BEGIN_INSTR(JumpNoException)
1087 if (!engine->hasException)
1088 code += offset;
1089 MOTH_END_INSTR(JumpNoException)
1090
1091 MOTH_BEGIN_INSTR(JumpNotUndefined)
1092 if (Q_LIKELY(acc != QV4::Encode::undefined()))
1093 code += offset;
1094 MOTH_END_INSTR(JumpNotUndefined)
1095
1096 MOTH_BEGIN_INSTR(CheckException)
1098 MOTH_END_INSTR(CheckException)
1099
1100 MOTH_BEGIN_INSTR(CmpEqNull)
1101 acc = Encode(ACC.isNullOrUndefined());
1102 MOTH_END_INSTR(CmpEqNull)
1103
1104 MOTH_BEGIN_INSTR(CmpNeNull)
1105 acc = Encode(!ACC.isNullOrUndefined());
1106 MOTH_END_INSTR(CmpNeNull)
1107
1108 MOTH_BEGIN_INSTR(CmpEqInt)
1109 if (ACC.isIntOrBool()) {
1110 acc = Encode(ACC.int_32() == lhs);
1111 } else {
1112 STORE_ACC();
1113 acc = Encode(compareEqualInt(accumulator, ACC, lhs));
1115 }
1116 MOTH_END_INSTR(CmpEqInt)
1117
1118 MOTH_BEGIN_INSTR(CmpNeInt)
1119 if (ACC.isIntOrBool()) {
1120 acc = Encode(bool(ACC.int_32() != lhs));
1121 } else {
1122 STORE_ACC();
1123 acc = Encode(!compareEqualInt(accumulator, ACC, lhs));
1125 }
1126 MOTH_END_INSTR(CmpNeInt)
1127
1128 MOTH_BEGIN_INSTR(CmpEq)
1129 const Value left = STACK_VALUE(lhs);
1130 if (Q_LIKELY(left.asReturnedValue() == ACC.asReturnedValue())) {
1131 acc = Encode(!ACC.isNaN());
1132 } else if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1133 acc = Encode(left.int_32() == ACC.int_32());
1134 } else {
1135 STORE_ACC();
1136 acc = Encode(bool(Runtime::CompareEqual::call(left, accumulator)));
1138 }
1139 MOTH_END_INSTR(CmpEq)
1140
1141 MOTH_BEGIN_INSTR(CmpNe)
1142 const Value left = STACK_VALUE(lhs);
1143 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1144 acc = Encode(bool(left.int_32() != ACC.int_32()));
1145 } else {
1146 STORE_ACC();
1147 acc = Encode(bool(!Runtime::CompareEqual::call(left, accumulator)));
1149 }
1150 MOTH_END_INSTR(CmpNe)
1151
1152 MOTH_BEGIN_INSTR(CmpGt)
1153 const Value left = STACK_VALUE(lhs);
1154 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1155 acc = Encode(left.int_32() > ACC.int_32());
1156 } else if (left.isNumber() && ACC.isNumber()) {
1157 acc = Encode(left.asDouble() > ACC.asDouble());
1158 } else {
1159 STORE_ACC();
1160 acc = Encode(bool(Runtime::CompareGreaterThan::call(left, accumulator)));
1162 }
1163 MOTH_END_INSTR(CmpGt)
1164
1165 MOTH_BEGIN_INSTR(CmpGe)
1166 const Value left = STACK_VALUE(lhs);
1167 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1168 acc = Encode(left.int_32() >= ACC.int_32());
1169 } else if (left.isNumber() && ACC.isNumber()) {
1170 acc = Encode(left.asDouble() >= ACC.asDouble());
1171 } else {
1172 STORE_ACC();
1173 acc = Encode(bool(Runtime::CompareGreaterEqual::call(left, accumulator)));
1175 }
1176 MOTH_END_INSTR(CmpGe)
1177
1178 MOTH_BEGIN_INSTR(CmpLt)
1179 const Value left = STACK_VALUE(lhs);
1180 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1181 acc = Encode(left.int_32() < ACC.int_32());
1182 } else if (left.isNumber() && ACC.isNumber()) {
1183 acc = Encode(left.asDouble() < ACC.asDouble());
1184 } else {
1185 STORE_ACC();
1186 acc = Encode(bool(Runtime::CompareLessThan::call(left, accumulator)));
1188 }
1189 MOTH_END_INSTR(CmpLt)
1190
1191 MOTH_BEGIN_INSTR(CmpLe)
1192 const Value left = STACK_VALUE(lhs);
1193 if (Q_LIKELY(left.isInteger() && ACC.isInteger())) {
1194 acc = Encode(left.int_32() <= ACC.int_32());
1195 } else if (left.isNumber() && ACC.isNumber()) {
1196 acc = Encode(left.asDouble() <= ACC.asDouble());
1197 } else {
1198 STORE_ACC();
1199 acc = Encode(bool(Runtime::CompareLessEqual::call(left, accumulator)));
1201 }
1202 MOTH_END_INSTR(CmpLe)
1203
1204 MOTH_BEGIN_INSTR(CmpStrictEqual)
1205 if (STACK_VALUE(lhs).rawValue() == ACC.rawValue() && !ACC.isNaN()) {
1206 acc = Encode(true);
1207 } else {
1208 STORE_ACC();
1209 acc = Runtime::StrictEqual::call(STACK_VALUE(lhs), accumulator);
1211 }
1212 MOTH_END_INSTR(CmpStrictEqual)
1213
1214 MOTH_BEGIN_INSTR(CmpStrictNotEqual)
1215 if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) {
1216 STORE_ACC();
1217 acc = Runtime::StrictNotEqual::call(STACK_VALUE(lhs), accumulator);
1219 } else {
1220 acc = Encode(false);
1221 }
1222 MOTH_END_INSTR(CmpStrictNotEqual)
1223
1224 MOTH_BEGIN_INSTR(CmpIn)
1225 STORE_IP();
1226 STORE_ACC();
1227 acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator);
1229 MOTH_END_INSTR(CmpIn)
1230
1231 MOTH_BEGIN_INSTR(CmpInstanceOf)
1232 STORE_ACC();
1233 acc = Runtime::Instanceof::call(engine, STACK_VALUE(lhs), ACC);
1235 MOTH_END_INSTR(CmpInstanceOf)
1236
1237 MOTH_BEGIN_INSTR(UNot)
1238 if (ACC.integerCompatible()) {
1239 acc = Encode(!static_cast<bool>(ACC.int_32()));
1240 } else {
1241 acc = Encode(!Value::toBooleanImpl(ACC));
1242 }
1243 MOTH_END_INSTR(UNot)
1244
1245 MOTH_BEGIN_INSTR(UPlus)
1246 if (Q_UNLIKELY(!ACC.isNumber())) {
1247 acc = Encode(ACC.toNumberImpl());
1249 }
1250 MOTH_END_INSTR(UPlus)
1251
1252 MOTH_BEGIN_INSTR(UMinus)
1253 if (Q_LIKELY(ACC.integerCompatible())) {
1254 int a = ACC.int_32();
1255 if (a == 0 || a == std::numeric_limits<int>::min()) {
1256 acc = Encode(-static_cast<double>(a));
1257 } else {
1258 acc = sub_int32(0, ACC.int_32());
1259 }
1260 } else if (ACC.isDouble()) {
1261 acc ^= (1ull << 63); // simply flip sign bit
1262 } else {
1263 acc = Encode(-ACC.toNumberImpl());
1265 }
1266 MOTH_END_INSTR(UMinus)
1267
1268 MOTH_BEGIN_INSTR(UCompl)
1269 VALUE_TO_INT(a, ACC);
1270 acc = Encode(~a);
1271 MOTH_END_INSTR(UCompl)
1272
1273 MOTH_BEGIN_INSTR(Increment)
1274 if (Q_LIKELY(ACC.integerCompatible())) {
1275 acc = add_int32(ACC.int_32(), 1);
1276 } else if (ACC.isDouble()) {
1277 acc = QV4::Encode(ACC.doubleValue() + 1.);
1278 } else {
1279 acc = Encode(ACC.toNumberImpl() + 1.);
1281 }
1282 MOTH_END_INSTR(Increment)
1283
1284 MOTH_BEGIN_INSTR(Decrement)
1285 if (Q_LIKELY(ACC.integerCompatible())) {
1286 acc = sub_int32(ACC.int_32(), 1);
1287 } else if (ACC.isDouble()) {
1288 acc = QV4::Encode(ACC.doubleValue() - 1.);
1289 } else {
1290 acc = Encode(ACC.toNumberImpl() - 1.);
1292 }
1293 MOTH_END_INSTR(Decrement)
1294
1295 MOTH_BEGIN_INSTR(Add)
1296 const Value left = STACK_VALUE(lhs);
1297 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1298 acc = add_int32(left.int_32(), ACC.int_32());
1299 } else if (left.isNumber() && ACC.isNumber()) {
1300 acc = Encode(left.asDouble() + ACC.asDouble());
1301 } else {
1302 STORE_ACC();
1303 acc = Runtime::Add::call(engine, left, accumulator);
1305 }
1306 MOTH_END_INSTR(Add)
1307
1308 MOTH_BEGIN_INSTR(Sub)
1309 const Value left = STACK_VALUE(lhs);
1310 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1311 acc = sub_int32(left.int_32(), ACC.int_32());
1312 } else if (left.isNumber() && ACC.isNumber()) {
1313 acc = Encode(left.asDouble() - ACC.asDouble());
1314 } else {
1315 STORE_ACC();
1316 acc = Runtime::Sub::call(left, accumulator);
1318 }
1319 MOTH_END_INSTR(Sub)
1320
1322 const Value left = STACK_VALUE(lhs);
1323 STORE_ACC();
1324 acc = Runtime::As::call(engine, left, accumulator);
1325 MOTH_END_INSTR(As)
1326
1327 MOTH_BEGIN_INSTR(Exp)
1328 const Value left = STACK_VALUE(lhs);
1329 double base = left.toNumber();
1330 double exp = ACC.toNumber();
1331 acc = Encode(QQmlPrivate::jsExponentiate(base, exp));
1332 MOTH_END_INSTR(Exp)
1333
1334 MOTH_BEGIN_INSTR(Mul)
1335 const Value left = STACK_VALUE(lhs);
1336 if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
1337 acc = mul_int32(left.int_32(), ACC.int_32());
1338 } else if (left.isNumber() && ACC.isNumber()) {
1339 acc = Encode(left.asDouble() * ACC.asDouble());
1340 } else {
1341 STORE_ACC();
1342 acc = Runtime::Mul::call(left, accumulator);
1344 }
1345 MOTH_END_INSTR(Mul)
1346
1347 MOTH_BEGIN_INSTR(Div)
1348 STORE_ACC();
1349 acc = Runtime::Div::call(STACK_VALUE(lhs), accumulator);
1351 MOTH_END_INSTR(Div)
1352
1353 MOTH_BEGIN_INSTR(Mod)
1354 STORE_ACC();
1355 acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
1357 MOTH_END_INSTR(Mod)
1358
1359 MOTH_BEGIN_INSTR(BitAnd)
1360 VALUE_TO_INT(l, STACK_VALUE(lhs));
1361 VALUE_TO_INT(a, ACC);
1362 acc = Encode(l & a);
1363 MOTH_END_INSTR(BitAnd)
1364
1365 MOTH_BEGIN_INSTR(BitOr)
1366 VALUE_TO_INT(l, STACK_VALUE(lhs));
1367 VALUE_TO_INT(a, ACC);
1368 acc = Encode(l | a);
1369 MOTH_END_INSTR(BitOr)
1370
1371 MOTH_BEGIN_INSTR(BitXor)
1372 VALUE_TO_INT(l, STACK_VALUE(lhs));
1373 VALUE_TO_INT(a, ACC);
1374 acc = Encode(l ^ a);
1375 MOTH_END_INSTR(BitXor)
1376
1377 MOTH_BEGIN_INSTR(UShr)
1378 VALUE_TO_INT(l, STACK_VALUE(lhs));
1379 VALUE_TO_INT(a, ACC);
1380 acc = Encode(static_cast<uint>(l) >> uint(a & 0x1f));
1381 MOTH_END_INSTR(UShr)
1382
1383 MOTH_BEGIN_INSTR(Shr)
1384 VALUE_TO_INT(l, STACK_VALUE(lhs));
1385 VALUE_TO_INT(a, ACC);
1386 acc = Encode(l >> (a & 0x1f));
1387 MOTH_END_INSTR(Shr)
1388
1389 MOTH_BEGIN_INSTR(Shl)
1390 VALUE_TO_INT(l, STACK_VALUE(lhs));
1391 VALUE_TO_INT(a, ACC);
1392 acc = Encode(l << (a & 0x1f));
1393 MOTH_END_INSTR(Shl)
1394
1395 MOTH_BEGIN_INSTR(BitAndConst)
1396 VALUE_TO_INT(a, ACC);
1397 acc = Encode(a & rhs);
1399 MOTH_END_INSTR(BitAndConst)
1400
1401 MOTH_BEGIN_INSTR(BitOrConst)
1402 VALUE_TO_INT(a, ACC);
1403 acc = Encode(a | rhs);
1404 MOTH_END_INSTR(BitOrConst)
1405
1406 MOTH_BEGIN_INSTR(BitXorConst)
1407 VALUE_TO_INT(a, ACC);
1408 acc = Encode(a ^ rhs);
1409 MOTH_END_INSTR(BitXorConst)
1410
1411 MOTH_BEGIN_INSTR(UShrConst)
1412 acc = Encode(ACC.toUInt32() >> uint(rhs));
1413 MOTH_END_INSTR(UShrConst)
1414
1415 MOTH_BEGIN_INSTR(ShrConst)
1416 VALUE_TO_INT(a, ACC);
1417 acc = Encode(a >> rhs);
1418 MOTH_END_INSTR(ShrConst)
1419
1420 MOTH_BEGIN_INSTR(ShlConst)
1421 VALUE_TO_INT(a, ACC);
1422 acc = Encode(a << rhs);
1423 MOTH_END_INSTR(ShlConst)
1424
1425 MOTH_BEGIN_INSTR(Ret)
1426 return acc;
1427 MOTH_END_INSTR(Ret)
1428
1429 MOTH_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
1430 acc = Encode(Value::emptyValue());
1431 for (int i = firstReg, end = firstReg + count; i < end; ++i)
1432 STACK_VALUE(i) = acc;
1433 MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
1434
1435 MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
1436 if (Value::fromReturnedValue(acc).isNullOrUndefined()) {
1437 engine->throwTypeError();
1438 goto handleUnwind;
1439 }
1440 MOTH_END_INSTR(ThrowOnNullOrUndefined)
1441
1442 MOTH_BEGIN_INSTR(GetTemplateObject)
1443 acc = Runtime::GetTemplateObject::call(function, index);
1444 MOTH_END_INSTR(GetTemplateObject)
1445
1446 MOTH_BEGIN_INSTR(Debug)
1447#if QT_CONFIG(qml_debug)
1448 STORE_IP();
1449 debug_slowPath(engine);
1450#endif // QT_CONFIG(qml_debug)
1451 MOTH_END_INSTR(Debug)
1452
1453 handleUnwind:
1454 // We do start the exception handler in case of isInterrupted. The exception handler will
1455 // immediately abort, due to the same isInterrupted. We don't skip the exception handler
1456 // because the current behavior is easier to implement in the JIT.
1457 Q_ASSERT(engine->hasException || engine->isInterrupted.loadRelaxed() || frame->unwindLevel);
1458 if (!frame->unwindHandler) {
1459 acc = Encode::undefined();
1460 return acc;
1461 }
1462 code = frame->unwindHandler;
1463 }
1464}
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()