/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv4instr_moth_p.h" #include using namespace QV4; using namespace QV4::Moth; int InstrInfo::size(Instr::Type type) { #define MOTH_RETURN_INSTR_SIZE(I) case Instr::Type::I: return InstrMeta::Size; switch (type) { FOR_EACH_MOTH_INSTR(MOTH_RETURN_INSTR_SIZE) } #undef MOTH_RETURN_INSTR_SIZE Q_UNREACHABLE(); } static QByteArray alignedNumber(int n) { QByteArray number = QByteArray::number(n); while (number.size() < 8) number.prepend(' '); return number; } static QByteArray alignedLineNumber(int line) { if (line > 0) return alignedNumber(static_cast(line)); return QByteArray(" "); } static QByteArray rawBytes(const char *data, int n) { QByteArray ba; while (n) { uint num = *reinterpret_cast(data); if (num < 16) ba += '0'; ba += QByteArray::number(num, 16) + " "; ++data; --n; } while (ba.size() < 25) ba += ' '; return ba; } static QString toString(QV4::ReturnedValue v) { #ifdef V4_BOOTSTRAP return QStringLiteral("string-const(%1)").arg(v); #else // !V4_BOOTSTRAP Value val = Value::fromReturnedValue(v); QString result; if (val.isInt32()) result = QLatin1String("int "); else if (val.isDouble()) result = QLatin1String("double "); if (val.isEmpty()) result += QLatin1String("empty"); else result += val.toQStringNoThrow(); return result; #endif // V4_BOOTSTRAP } #define ABSOLUTE_OFFSET() \ (code - start + offset) #define MOTH_BEGIN_INSTR(instr) \ { \ INSTR_##instr(MOTH_DECODE_WITH_BASE) \ QDebug d = qDebug(); \ d.noquote(); \ d.nospace(); \ d << alignedLineNumber(line) << alignedNumber(codeOffset).constData() << ": " \ << rawBytes(base_ptr, int(code - base_ptr)) << #instr << " "; #define MOTH_END_INSTR(instr) \ continue; \ } QT_BEGIN_NAMESPACE namespace QV4 { namespace Moth { const int InstrInfo::argumentCount[] = { FOR_EACH_MOTH_INSTR(MOTH_COLLECT_NARGS) }; void dumpConstantTable(const Value *constants, uint count) { QDebug d = qDebug(); d.nospace(); for (uint i = 0; i < count; ++i) d << alignedNumber(int(i)).constData() << ": " << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n"; } QString dumpRegister(int reg, int nFormals) { Q_STATIC_ASSERT(offsetof(CallData, function) == 0); Q_STATIC_ASSERT(offsetof(CallData, context) == sizeof(Value)); Q_STATIC_ASSERT(offsetof(CallData, accumulator) == 2*sizeof(Value)); Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 3*sizeof(Value)); if (reg == CallData::Function) return QStringLiteral("(function)"); else if (reg == CallData::Context) return QStringLiteral("(context)"); else if (reg == CallData::Accumulator) return QStringLiteral("(accumulator)"); else if (reg == CallData::This) return QStringLiteral("(this)"); else if (reg == CallData::Argc) return QStringLiteral("(argc)"); reg -= 4; if (reg <= nFormals) return QStringLiteral("a%1").arg(reg); reg -= nFormals; return QStringLiteral("r%1").arg(reg); } QString dumpArguments(int argc, int argv, int nFormals) { if (!argc) return QStringLiteral("()"); return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")"); } void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector &lineNumberMapping) { MOTH_JUMP_TABLE; auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) { return entry.codeOffset < offset; }; int lastLine = -1; const char *start = code; const char *end = code + len; while (code < end) { const CompiledData::CodeOffsetToLine *codeToLine = std::lower_bound(lineNumberMapping.constBegin(), lineNumberMapping.constEnd(), static_cast(code - start) + 1, findLine) - 1; int line = int(codeToLine->line); if (line != lastLine) lastLine = line; else line = -1; int codeOffset = int(code - start); MOTH_DISPATCH() MOTH_BEGIN_INSTR(LoadReg) d << dumpRegister(reg, nFormals); MOTH_END_INSTR(LoadReg) MOTH_BEGIN_INSTR(StoreReg) d << dumpRegister(reg, nFormals); MOTH_END_INSTR(StoreReg) MOTH_BEGIN_INSTR(MoveReg) d << dumpRegister(destReg, nFormals) << ", " << dumpRegister(srcReg, nFormals); MOTH_END_INSTR(MoveReg) MOTH_BEGIN_INSTR(LoadConst) d << "C" << index; MOTH_END_INSTR(LoadConst) MOTH_BEGIN_INSTR(LoadNull) MOTH_END_INSTR(LoadNull) MOTH_BEGIN_INSTR(LoadZero) MOTH_END_INSTR(LoadZero) MOTH_BEGIN_INSTR(LoadTrue) MOTH_END_INSTR(LoadTrue) MOTH_BEGIN_INSTR(LoadFalse) MOTH_END_INSTR(LoadFalse) MOTH_BEGIN_INSTR(LoadUndefined) MOTH_END_INSTR(LoadUndefined) MOTH_BEGIN_INSTR(LoadInt) d << value; MOTH_END_INSTR(LoadInt) MOTH_BEGIN_INSTR(MoveConst) d << dumpRegister(destTemp, nFormals) << ", C" << constIndex; MOTH_END_INSTR(MoveConst) MOTH_BEGIN_INSTR(LoadLocal) if (index < nLocals) d << "l" << index; else d << "a" << (index - nLocals); MOTH_END_INSTR(LoadLocal) MOTH_BEGIN_INSTR(StoreLocal) if (index < nLocals) d << "l" << index; else d << "a" << (index - nLocals); MOTH_END_INSTR(StoreLocal) MOTH_BEGIN_INSTR(LoadScopedLocal) if (index < nLocals) d << "l" << index << "@" << scope; else d << "a" << (index - nLocals) << "@" << scope; MOTH_END_INSTR(LoadScopedLocal) MOTH_BEGIN_INSTR(StoreScopedLocal) if (index < nLocals) d << ", " << "l" << index << "@" << scope; else d << ", " << "a" << (index - nLocals) << "@" << scope; MOTH_END_INSTR(StoreScopedLocal) MOTH_BEGIN_INSTR(LoadRuntimeString) d << stringId; MOTH_END_INSTR(LoadRuntimeString) MOTH_BEGIN_INSTR(MoveRegExp) d << dumpRegister(destReg, nFormals) << ", " <"; MOTH_END_INSTR(SetExceptionHandler) MOTH_BEGIN_INSTR(ThrowException) MOTH_END_INSTR(ThrowException) MOTH_BEGIN_INSTR(GetException) MOTH_END_INSTR(HasException) MOTH_BEGIN_INSTR(SetException) MOTH_END_INSTR(SetExceptionFlag) MOTH_BEGIN_INSTR(CreateCallContext) MOTH_END_INSTR(CreateCallContext) MOTH_BEGIN_INSTR(PushCatchContext) d << dumpRegister(reg, nFormals) << ", " << name; MOTH_END_INSTR(PushCatchContext) MOTH_BEGIN_INSTR(PushWithContext) d << dumpRegister(reg, nFormals); MOTH_END_INSTR(PushWithContext) MOTH_BEGIN_INSTR(PopContext) d << dumpRegister(reg, nFormals); MOTH_END_INSTR(PopContext) MOTH_BEGIN_INSTR(ForeachIteratorObject) MOTH_END_INSTR(ForeachIteratorObject) MOTH_BEGIN_INSTR(ForeachNextPropertyName) MOTH_END_INSTR(ForeachNextPropertyName) MOTH_BEGIN_INSTR(DeleteMember) d << dumpRegister(base, nFormals) << "[" << member << "]"; MOTH_END_INSTR(DeleteMember) MOTH_BEGIN_INSTR(DeleteSubscript) d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"; MOTH_END_INSTR(DeleteSubscript) MOTH_BEGIN_INSTR(DeleteName) d << name; MOTH_END_INSTR(DeleteName) MOTH_BEGIN_INSTR(TypeofName) d << name; MOTH_END_INSTR(TypeofName) MOTH_BEGIN_INSTR(TypeofValue) MOTH_END_INSTR(TypeofValue) MOTH_BEGIN_INSTR(DeclareVar) d << isDeletable << ", " << varName; MOTH_END_INSTR(DeclareVar) MOTH_BEGIN_INSTR(DefineArray) d << dumpRegister(args, nFormals) << ", " << argc; MOTH_END_INSTR(DefineArray) MOTH_BEGIN_INSTR(DefineObjectLiteral) d << dumpRegister(args, nFormals) << ", " << internalClassId << ", " << arrayValueCount << ", " << arrayGetterSetterCountAndFlags; MOTH_END_INSTR(DefineObjectLiteral) MOTH_BEGIN_INSTR(CreateMappedArgumentsObject) MOTH_END_INSTR(CreateMappedArgumentsObject) MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject) MOTH_END_INSTR(CreateUnmappedArgumentsObject) MOTH_BEGIN_INSTR(ConvertThisToObject) MOTH_END_INSTR(ConvertThisToObject) MOTH_BEGIN_INSTR(Construct) d << "new" << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals); MOTH_END_INSTR(Construct) MOTH_BEGIN_INSTR(Jump) d << ABSOLUTE_OFFSET(); MOTH_END_INSTR(Jump) MOTH_BEGIN_INSTR(JumpTrue) d << ABSOLUTE_OFFSET(); MOTH_END_INSTR(JumpTrue) MOTH_BEGIN_INSTR(JumpFalse) d << ABSOLUTE_OFFSET(); MOTH_END_INSTR(JumpFalse) MOTH_BEGIN_INSTR(CmpEqNull) MOTH_END_INSTR(CmpEqNull) MOTH_BEGIN_INSTR(CmpNeNull) MOTH_END_INSTR(CmpNeNull) MOTH_BEGIN_INSTR(CmpEqInt) d << lhs; MOTH_END_INSTR(CmpEq) MOTH_BEGIN_INSTR(CmpNeInt) d << lhs; MOTH_END_INSTR(CmpNeInt) MOTH_BEGIN_INSTR(CmpEq) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpEq) MOTH_BEGIN_INSTR(CmpNe) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpNe) MOTH_BEGIN_INSTR(CmpGt) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpGt) MOTH_BEGIN_INSTR(CmpGe) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpGe) MOTH_BEGIN_INSTR(CmpLt) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpLt) MOTH_BEGIN_INSTR(CmpLe) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpLe) MOTH_BEGIN_INSTR(CmpStrictEqual) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpStrictEqual) MOTH_BEGIN_INSTR(CmpStrictNotEqual) d << dumpRegister(lhs, nFormals); MOTH_END_INSTR(CmpStrictNotEqual) MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt) d << dumpRegister(lhs, nFormals) << ", " << rhs << " " << ABSOLUTE_OFFSET(); MOTH_END_INSTR(JumpStrictEqualStackSlotInt) MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt) d << dumpRegister(lhs, nFormals) << ", " << rhs << " " << ABSOLUTE_OFFSET(); MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt) MOTH_BEGIN_INSTR(UNot) MOTH_END_INSTR(UNot) MOTH_BEGIN_INSTR(UPlus) MOTH_END_INSTR(UPlus) MOTH_BEGIN_INSTR(UMinus) MOTH_END_INSTR(UMinus) MOTH_BEGIN_INSTR(UCompl) MOTH_END_INSTR(UCompl) MOTH_BEGIN_INSTR(Increment) MOTH_END_INSTR(PreIncrement) MOTH_BEGIN_INSTR(Decrement) MOTH_END_INSTR(PreDecrement) MOTH_BEGIN_INSTR(Add) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Add) MOTH_BEGIN_INSTR(BitAnd) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(BitAnd) MOTH_BEGIN_INSTR(BitOr) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(BitOr) MOTH_BEGIN_INSTR(BitXor) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(BitXor) MOTH_BEGIN_INSTR(UShr) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(UShr) MOTH_BEGIN_INSTR(Shr) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Shr) MOTH_BEGIN_INSTR(Shl) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Shl) MOTH_BEGIN_INSTR(BitAndConst) d << "acc, " << rhs; MOTH_END_INSTR(BitAndConst) MOTH_BEGIN_INSTR(BitOrConst) d << "acc, " << rhs; MOTH_END_INSTR(BitOr) MOTH_BEGIN_INSTR(BitXorConst) d << "acc, " << rhs; MOTH_END_INSTR(BitXor) MOTH_BEGIN_INSTR(UShrConst) d << "acc, " << rhs; MOTH_END_INSTR(UShrConst) MOTH_BEGIN_INSTR(ShrConst) d << "acc, " << rhs; MOTH_END_INSTR(ShrConst) MOTH_BEGIN_INSTR(ShlConst) d << "acc, " << rhs; MOTH_END_INSTR(ShlConst) MOTH_BEGIN_INSTR(Mul) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Mul) MOTH_BEGIN_INSTR(Div) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Div) MOTH_BEGIN_INSTR(Mod) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Mod) MOTH_BEGIN_INSTR(Sub) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(Sub) MOTH_BEGIN_INSTR(CmpIn) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(CmpIn) MOTH_BEGIN_INSTR(CmpInstanceOf) d << dumpRegister(lhs, nFormals) << ", acc"; MOTH_END_INSTR(CmpInstanceOf) MOTH_BEGIN_INSTR(Ret) MOTH_END_INSTR(Ret) MOTH_BEGIN_INSTR(Debug) MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(LoadQmlContext) d << dumpRegister(result, nFormals); MOTH_END_INSTR(LoadQmlContext) MOTH_BEGIN_INSTR(LoadQmlImportedScripts) d << dumpRegister(result, nFormals); MOTH_END_INSTR(LoadQmlImportedScripts) } } } } QT_END_NAMESPACE