aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-07-02 13:32:46 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-07-03 11:18:57 +0000
commita2372fd2c643615687ea3b8b1ccf53d699b6debd (patch)
treed86a2b3f6ea56d92b70ef25b26dd1f7fa401f260
parent386036e23b67d6aa6d10ff166a1904f18c304a8a (diff)
Allow for more than 128 bytecode instructions
Instructions always occupy two numbers, an even and the following odd one, for the single byte and four byte encoding. An instruction of 0x0 is now a NOP, but 0x1 implies that the instruction type is using two bytes, and the following byte needs to be read as well to get the correct instruction type. Encoding and decoding of those two byte instructions is fully transparent, and adding more instructions now doesn't require any special handling. The first 127 instructions in the FOR_EACH_MOTH_INSTR macro will get a single byte encoding, the remaining ones will use two bytes. When adding new instructions, make sure to put often used and fast instructions into the first 127 instructions, while adding rarely used (or slow) instructions to the end (before Debug though). Change-Id: Id772a109641ab68feb228c3abd05f41ae7075e94 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp16
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp6
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h163
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp2
4 files changed, 108 insertions, 79 deletions
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index 6efeac2a31..7e1f49ee86 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -75,8 +75,9 @@ void BytecodeGenerator::packInstruction(I &i)
type = Instr::narrowInstructionType(type);
int instructionsAsInts[sizeof(Instr)/sizeof(int)] = {};
int nMembers = Moth::InstrInfo::argumentCount[static_cast<int>(i.type)];
+ uchar *code = i.packed + Instr::encodedLength(type);
for (int j = 0; j < nMembers; ++j) {
- instructionsAsInts[j] = qFromLittleEndian<qint32>(i.packed + 1 + j * sizeof(int));
+ instructionsAsInts[j] = qFromLittleEndian<qint32>(code + j * sizeof(int));
}
enum {
Normal,
@@ -88,11 +89,10 @@ void BytecodeGenerator::packInstruction(I &i)
break;
}
}
- uchar *code = i.packed;
+ code = i.packed;
switch (width) {
case Normal:
- Instr::pack(code, type);
- ++code;
+ code = Instr::pack(code, type);
for (int n = 0; n < nMembers; ++n) {
qint8 v = static_cast<qint8>(instructionsAsInts[n]);
memcpy(code, &v, 1);
@@ -225,12 +225,10 @@ QT_WARNING_POP
const int argCount = Moth::InstrInfo::argumentCount[static_cast<int>(type)];
int s = argCount*sizeof(int);
if (offsetOfOffset != -1)
- offsetOfOffset += 1;
- I instr{type, static_cast<short>(s + 1), 0, currentLine, offsetOfOffset, -1, "\0\0" };
+ offsetOfOffset += Instr::encodedLength(type);
+ I instr{type, static_cast<short>(s + Instr::encodedLength(type)), 0, currentLine, offsetOfOffset, -1, "\0\0" };
uchar *code = instr.packed;
- Instr::pack(code, Instr::wideInstructionType(type));
- ++code;
- Q_ASSERT(static_cast<uint>(Instr::wideInstructionType(type)) < 256);
+ code = Instr::pack(code, Instr::wideInstructionType(type));
for (int j = 0; j < argCount; ++j) {
qToLittleEndian<qint32>(i.argumentsAsInts[j], code);
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 6773f97c8b..8e474b3783 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -48,7 +48,7 @@ int InstrInfo::size(Instr::Type type)
{
#define MOTH_RETURN_INSTR_SIZE(I) case Instr::Type::I: case Instr::Type::I##_Wide: return InstrMeta<int(Instr::Type::I)>::Size;
switch (type) {
- FOR_EACH_MOTH_INSTR(MOTH_RETURN_INSTR_SIZE)
+ FOR_EACH_MOTH_INSTR_ALL(MOTH_RETURN_INSTR_SIZE)
}
#undef MOTH_RETURN_INSTR_SIZE
Q_UNREACHABLE();
@@ -111,6 +111,8 @@ static QString toString(QV4::ReturnedValue v)
QDebug d = qDebug(); \
d.noquote(); \
d.nospace(); \
+ if (static_cast<int>(Instr::Type::instr) >= 0x100) \
+ --base_ptr; \
d << alignedLineNumber(line) << alignedNumber(codeOffset).constData() << ": " \
<< rawBytes(base_ptr, int(code - base_ptr)) << #instr << " ";
@@ -123,7 +125,7 @@ namespace QV4 {
namespace Moth {
const int InstrInfo::argumentCount[] = {
- FOR_EACH_MOTH_INSTR(MOTH_COLLECT_NARGS)
+ FOR_EACH_MOTH_INSTR_ALL(MOTH_COLLECT_NARGS)
};
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 29fc28c128..4e2dd370c4 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -62,6 +62,7 @@ QT_BEGIN_NAMESPACE
op##_INSTRUCTION(name, nargs, __VA_ARGS__)
/* for all jump instructions, the offset has to come last, to simplify the job of the bytecode generator */
+#define INSTR_Nop(op) INSTRUCTION(op, Nop, 0)
#define INSTR_Ret(op) INSTRUCTION(op, Ret, 0)
#define INSTR_Debug(op) INSTRUCTION(op, Debug, 0)
#define INSTR_LoadConst(op) INSTRUCTION(op, LoadConst, 1, index)
@@ -191,10 +192,12 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadQmlContext(op) INSTRUCTION(op, LoadQmlContext, 1, result)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
+#define FOR_EACH_MOTH_INSTR_ALL(F) \
+ F(Nop) \
+ FOR_EACH_MOTH_INSTR(F)
#define FOR_EACH_MOTH_INSTR(F) \
F(Ret) \
- F(Debug) \
F(LoadConst) \
F(LoadZero) \
F(LoadTrue) \
@@ -202,6 +205,7 @@ QT_BEGIN_NAMESPACE
F(LoadNull) \
F(LoadUndefined) \
F(LoadInt) \
+ F(LoadRuntimeString) \
F(MoveConst) \
F(LoadReg) \
F(StoreReg) \
@@ -210,7 +214,6 @@ QT_BEGIN_NAMESPACE
F(StoreLocal) \
F(LoadScopedLocal) \
F(StoreScopedLocal) \
- F(LoadRuntimeString) \
F(MoveRegExp) \
F(LoadClosure) \
F(LoadName) \
@@ -230,51 +233,7 @@ QT_BEGIN_NAMESPACE
F(LoadScopeObjectProperty) \
F(LoadContextObjectProperty) \
F(LoadIdObject) \
- F(Yield) \
- F(Resume) \
- F(CallValue) \
- F(CallProperty) \
- F(CallPropertyLookup) \
- F(CallElement) \
- F(CallName) \
- F(CallPossiblyDirectEval) \
- F(CallGlobalLookup) \
- F(CallScopeObjectProperty) \
- F(CallContextObjectProperty) \
- F(CallWithSpread) \
- F(Construct) \
- F(ConstructWithSpread) \
- F(SetUnwindHandler) \
- F(UnwindDispatch) \
- F(UnwindToLabel) \
- F(ThrowException) \
- F(GetException) \
- F(SetException) \
- F(CreateCallContext) \
- F(PushCatchContext) \
- F(PushWithContext) \
- F(PushBlockContext) \
- F(CloneBlockContext) \
- F(PushScriptContext) \
- F(PopScriptContext) \
- F(PopContext) \
- F(GetIterator) \
- F(IteratorNext) \
- F(IteratorClose) \
- F(DestructureRestElement) \
- F(DeleteProperty) \
- F(DeleteName) \
- F(TypeofName) \
- F(TypeofValue) \
- F(DeclareVar) \
- F(DefineArray) \
- F(DefineObjectLiteral) \
- F(CreateClass) \
- F(CreateMappedArgumentsObject) \
- F(CreateUnmappedArgumentsObject) \
- F(CreateRestParameter) \
F(ConvertThisToObject) \
- F(LoadSuperConstructor) \
F(ToObject) \
F(Jump) \
F(JumpTrue) \
@@ -319,9 +278,55 @@ QT_BEGIN_NAMESPACE
F(Div) \
F(Mod) \
F(Sub) \
+ F(CallValue) \
+ F(CallProperty) \
+ F(CallPropertyLookup) \
+ F(CallElement) \
+ F(CallName) \
+ F(CallPossiblyDirectEval) \
+ F(CallGlobalLookup) \
+ F(CallScopeObjectProperty) \
+ F(CallContextObjectProperty) \
+ F(CallWithSpread) \
+ F(Construct) \
+ F(ConstructWithSpread) \
+ F(SetUnwindHandler) \
+ F(UnwindDispatch) \
+ F(UnwindToLabel) \
+ F(ThrowException) \
+ F(GetException) \
+ F(SetException) \
+ F(CreateCallContext) \
+ F(PushCatchContext) \
+ F(PushWithContext) \
+ F(PushBlockContext) \
+ F(CloneBlockContext) \
+ F(PopContext) \
+ F(GetIterator) \
+ F(IteratorNext) \
+ F(IteratorClose) \
+ F(DestructureRestElement) \
+ F(DeleteProperty) \
+ F(DeleteName) \
+ F(TypeofName) \
+ F(TypeofValue) \
+ F(DeclareVar) \
+ F(DefineArray) \
+ F(DefineObjectLiteral) \
+ F(CreateMappedArgumentsObject) \
+ F(CreateUnmappedArgumentsObject) \
+ F(CreateRestParameter) \
F(LoadQmlContext) \
- F(LoadQmlImportedScripts)
-#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::LoadQmlImportedScripts_Wide))
+ F(LoadQmlImportedScripts) \
+ F(Yield) \
+ F(Resume) \
+ F(CreateClass) \
+ F(LoadSuperConstructor) \
+ F(PushScriptContext) \
+ F(PopScriptContext) \
+ F(Debug) \
+
+#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::Debug_Wide) + 1)
#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
// icc before version 1200 doesn't support computed goto, and at least up to version 18.0.0 the
@@ -439,27 +444,44 @@ QT_BEGIN_NAMESPACE
#define MOTH_JUMP_TABLE \
static const void *jumpTable[] = { \
- FOR_EACH_MOTH_INSTR(COLLECT_LABELS) \
+ FOR_EACH_MOTH_INSTR_ALL(COLLECT_LABELS) \
};
-#define MOTH_DISPATCH() \
+#define MOTH_DISPATCH_SINGLE() \
goto *jumpTable[*reinterpret_cast<const uchar *>(code)];
+
+#define MOTH_DISPATCH() \
+ MOTH_DISPATCH_SINGLE() \
+ op_byte_Nop: \
+ ++code; \
+ MOTH_DISPATCH_SINGLE() \
+ op_int_Nop: /* wide prefix */ \
+ ++code; \
+ goto *jumpTable[0x100 | *reinterpret_cast<const uchar *>(code)];
#else
#define MOTH_JUMP_TABLE
#define MOTH_INSTR_CASE_AND_JUMP(instr) \
- INSTR_##instr(GET_CASE_AND_JUMP)
-#define GET_CASE_AND_JUMP_INSTRUCTION(name, ...) \
- case static_cast<uchar>(Instr::Type::name): goto op_byte_##name;
-#define MOTH_INSTR_CASE_AND_JUMP_WIDE(instr) \
+ INSTR_##instr(GET_CASE_AND_JUMP) \
INSTR_##instr(GET_CASE_AND_JUMP_WIDE)
+#define GET_CASE_AND_JUMP_INSTRUCTION(name, ...) \
+ case Instr::Type::name: goto op_byte_##name;
#define GET_CASE_AND_JUMP_WIDE_INSTRUCTION(name, ...) \
- case (static_cast<uchar>(Instr::Type::name##_Wide)): goto op_int_##name;
+ case Instr::Type::name##_Wide: goto op_int_##name;
#define MOTH_DISPATCH() \
- switch (static_cast<uchar>(*code)) { \
+ Instr::Type type = Instr::Type(static_cast<uchar>(*code)); \
+ dispatch: \
+ switch (type) { \
+ case Instr::Type::Nop: \
+ ++code; \
+ type = Instr::Type(static_cast<uchar>(*code)); \
+ goto dispatch; \
+ case Instr::Type::Nop_Wide: /* wide prefix */ \
+ ++code; \
+ type = Instr::Type(0x100 | static_cast<uchar>(*code)); \
+ goto dispatch; \
FOR_EACH_MOTH_INSTR(MOTH_INSTR_CASE_AND_JUMP) \
- FOR_EACH_MOTH_INSTR(MOTH_INSTR_CASE_AND_JUMP_WIDE) \
}
#endif
@@ -502,20 +524,29 @@ inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals,
union Instr
{
enum class Type {
- FOR_EACH_MOTH_INSTR(MOTH_INSTR_ENUM)
+ FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_ENUM)
};
static Type wideInstructionType(Type t) { return Type(int(t) | 1); }
static Type narrowInstructionType(Type t) { return Type(int(t) & ~1); }
static bool isWide(Type t) { return int(t) & 1; }
static bool isNarrow(Type t) { return !(int(t) & 1); }
+ static int encodedLength(Type t) { return int(t) >= 256 ? 2 : 1; }
+
+ static Type unpack(const uchar *c) { if (c[0] == 0x1) return Type(0x100 + c[1]); return Type(c[0]); }
+ static uchar *pack(uchar *c, Type t) {
+ if (uint(t) >= 256) {
+ c[0] = 0x1;
+ c[1] = uint(t) &0xff;
+ return c + 2;
+ }
+ c[0] = uchar(uint(t));
+ return c + 1;
+ }
- static Type unpack(const uchar *c) { return Type(*c); }
- static void pack(uchar *c, Type t) { *c = uchar(uint(t)); }
-
- FOR_EACH_MOTH_INSTR(MOTH_EMIT_STRUCTS)
+ FOR_EACH_MOTH_INSTR_ALL(MOTH_EMIT_STRUCTS)
- FOR_EACH_MOTH_INSTR(MOTH_EMIT_INSTR_MEMBERS)
+ FOR_EACH_MOTH_INSTR_ALL(MOTH_EMIT_INSTR_MEMBERS)
int argumentsAsInts[4];
};
@@ -526,8 +557,6 @@ struct InstrInfo
static int size(Instr::Type type);
};
-Q_STATIC_ASSERT(MOTH_NUM_INSTRUCTIONS() <= 256);
-
template<int N>
struct InstrMeta {
};
@@ -545,7 +574,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
reinterpret_cast<const char *>(&v), \
Size); } \
};
-FOR_EACH_MOTH_INSTR(MOTH_INSTR_META_TEMPLATE);
+FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_META_TEMPLATE);
#undef MOTH_INSTR_META_TEMPLATE
QT_WARNING_POP
@@ -556,7 +585,7 @@ class InstrData : public InstrMeta<InstrType>::DataType
struct Instruction {
#define MOTH_INSTR_DATA_TYPEDEF(I) typedef InstrData<int(Instr::Type::I)> I;
-FOR_EACH_MOTH_INSTR(MOTH_INSTR_DATA_TYPEDEF)
+FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_DATA_TYPEDEF)
#undef MOTH_INSTR_DATA_TYPEDEF
private:
Instruction();
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 6c667110a9..53e5632eff 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -328,7 +328,7 @@ static struct InstrCount {
#ifdef MOTH_COMPUTED_GOTO
#define MOTH_END_INSTR(instr) \
- MOTH_DISPATCH() \
+ MOTH_DISPATCH_SINGLE() \
}
#else // !MOTH_COMPUTED_GOTO
#define MOTH_END_INSTR(instr) \