|
@@ -46,16 +46,16 @@ const char *opcode_name (opcode_t op) {
|
|
|
|
|
|
#define DUMP_VM_RAW(buffer, bindex, ...) bindex += snprintf(&buffer[bindex], balloc-bindex, __VA_ARGS__);
|
|
#define DUMP_VM_RAW(buffer, bindex, ...) bindex += snprintf(&buffer[bindex], balloc-bindex, __VA_ARGS__);
|
|
|
|
|
|
-const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserialize) {
|
|
|
|
|
|
+const char *gravity_disassemble (gravity_vm *vm, gravity_function_t *f, const char *bcode, uint32_t blen, bool deserialize) {
|
|
uint32_t *ip = NULL;
|
|
uint32_t *ip = NULL;
|
|
uint32_t pc = 0, inst = 0, ninsts = 0;
|
|
uint32_t pc = 0, inst = 0, ninsts = 0;
|
|
opcode_t op;
|
|
opcode_t op;
|
|
-
|
|
|
|
|
|
+
|
|
const int rowlen = 256;
|
|
const int rowlen = 256;
|
|
uint32_t bindex = 0;
|
|
uint32_t bindex = 0;
|
|
uint32_t balloc = 0;
|
|
uint32_t balloc = 0;
|
|
char *buffer = NULL;
|
|
char *buffer = NULL;
|
|
-
|
|
|
|
|
|
+
|
|
if (deserialize) {
|
|
if (deserialize) {
|
|
// decode textual buffer to real bytecode
|
|
// decode textual buffer to real bytecode
|
|
ip = gravity_bytecode_deserialize(bcode, blen, &ninsts);
|
|
ip = gravity_bytecode_deserialize(bcode, blen, &ninsts);
|
|
@@ -64,41 +64,57 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
|
|
ip = (uint32_t *)bcode;
|
|
ip = (uint32_t *)bcode;
|
|
ninsts = blen;
|
|
ninsts = blen;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
// allocate a buffer big enought to fit all disassembled bytecode
|
|
// allocate a buffer big enought to fit all disassembled bytecode
|
|
// I assume that each instruction (each row) will be 256 chars long
|
|
// I assume that each instruction (each row) will be 256 chars long
|
|
balloc = ninsts * rowlen;
|
|
balloc = ninsts * rowlen;
|
|
buffer = mem_alloc(NULL, balloc);
|
|
buffer = mem_alloc(NULL, balloc);
|
|
if (!buffer) goto abort_disassemble;
|
|
if (!buffer) goto abort_disassemble;
|
|
-
|
|
|
|
|
|
+
|
|
// conversion loop
|
|
// conversion loop
|
|
while (pc < ninsts) {
|
|
while (pc < ninsts) {
|
|
inst = *ip++;
|
|
inst = *ip++;
|
|
op = (opcode_t)OPCODE_GET_OPCODE(inst);
|
|
op = (opcode_t)OPCODE_GET_OPCODE(inst);
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ // for fixed N spaces in opcode name
|
|
|
|
+ // replace %s with %-Ns
|
|
switch (op) {
|
|
switch (op) {
|
|
case NOP: {
|
|
case NOP: {
|
|
- DUMP_VM(buffer, bindex, "NOP");
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case MOVE: {
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s", opcode_name(op));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ case MOVE:
|
|
|
|
+ case LOADG:
|
|
|
|
+ case LOADU:
|
|
|
|
+ case STOREG:
|
|
|
|
+ case STOREU:
|
|
|
|
+ case JUMPF:
|
|
|
|
+ case MAPNEW:
|
|
|
|
+ case LISTNEW:
|
|
|
|
+ case CLOSURE: {
|
|
OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
- DUMP_VM(buffer, bindex, "MOVE %d %d", r1, r2);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %d", opcode_name(op), r1, r2);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case LOADI: {
|
|
case LOADI: {
|
|
- //OPCODE_GET_ONE8bit_ONE18bit(inst, uint32_t r1, int32_t value); if no support for signed int
|
|
|
|
OPCODE_GET_ONE8bit_SIGN_ONE17bit(inst, const uint32_t r1, const int32_t value);
|
|
OPCODE_GET_ONE8bit_SIGN_ONE17bit(inst, const uint32_t r1, const int32_t value);
|
|
- DUMP_VM(buffer, bindex, "LOADI %d %d", r1, value);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %d", opcode_name(op), r1, value);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
case LOADK: {
|
|
case LOADK: {
|
|
OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t index);
|
|
OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t index);
|
|
if (index < CPOOL_INDEX_MAX) {
|
|
if (index < CPOOL_INDEX_MAX) {
|
|
- DUMP_VM(buffer, bindex, "LOADK %d %d", r1, index);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %d", opcode_name(op), r1, index);
|
|
|
|
+ if (f) {
|
|
|
|
+ char b[2018];
|
|
|
|
+ gravity_value_t constant = gravity_function_cpool_get(f, index);
|
|
|
|
+ gravity_value_dump(vm, constant, b, sizeof(b));
|
|
|
|
+ --bindex; // to replace the \n character
|
|
|
|
+ DUMP_VM_RAW(buffer, bindex, "\t\t;%s\n", b);
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
const char *special;
|
|
const char *special;
|
|
switch (index) {
|
|
switch (index) {
|
|
@@ -111,171 +127,107 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
|
|
case CPOOL_VALUE_FUNC: special = "_FUNC"; break;
|
|
case CPOOL_VALUE_FUNC: special = "_FUNC"; break;
|
|
default: special = "Invalid index in LOADK opcode"; break;
|
|
default: special = "Invalid index in LOADK opcode"; break;
|
|
}
|
|
}
|
|
- DUMP_VM(buffer, bindex, "LOADK %d %s", r1, special);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %s", opcode_name(op), r1, special);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- case LOADG: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, uint32_t r1, int32_t index);
|
|
|
|
- DUMP_VM(buffer, bindex, "LOADG %d %d", r1, index);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+
|
|
case LOAD:
|
|
case LOAD:
|
|
case LOADS:
|
|
case LOADS:
|
|
- case LOADAT: {
|
|
|
|
- OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
|
|
- DUMP_VM(buffer, bindex, "%s %d %d %d", (op == LOAD) ? "LOAD" : "LOADAT", r1, r2, r3);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case LOADU: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
|
|
- DUMP_VM(buffer, bindex, "LOADU %d %d", r1, r2);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case STOREG: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, uint32_t r1, int32_t index);
|
|
|
|
- DUMP_VM(buffer, bindex, "STOREG %d %d", r1, index);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case STOREU: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
|
|
- DUMP_VM(buffer, bindex, "STOREU %d %d", r1, r2);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case STORE:
|
|
|
|
- case STOREAT: {
|
|
|
|
- OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
|
|
- DUMP_VM(buffer, bindex, "%s %d %d %d", (op == STORE) ? "STORE" : "STOREAT", r1, r2, r3);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case EQQ:
|
|
|
|
- case NEQQ:
|
|
|
|
- case ISA:
|
|
|
|
- case MATCH:
|
|
|
|
- case LT:
|
|
|
|
- case GT:
|
|
|
|
- case EQ:
|
|
|
|
- case LEQ:
|
|
|
|
- case GEQ:
|
|
|
|
- case NEQ: {
|
|
|
|
|
|
+ case LOADAT:
|
|
|
|
+ case STORE:
|
|
|
|
+ case STOREAT:
|
|
|
|
+ case EQQ:
|
|
|
|
+ case NEQQ:
|
|
|
|
+ case ISA:
|
|
|
|
+ case MATCH:
|
|
|
|
+ case LT:
|
|
|
|
+ case GT:
|
|
|
|
+ case EQ:
|
|
|
|
+ case LEQ:
|
|
|
|
+ case GEQ:
|
|
|
|
+ case NEQ:
|
|
|
|
+ case LSHIFT:
|
|
|
|
+ case RSHIFT:
|
|
|
|
+ case BAND:
|
|
|
|
+ case BOR:
|
|
|
|
+ case BXOR:
|
|
|
|
+ case ADD:
|
|
|
|
+ case SUB:
|
|
|
|
+ case DIV:
|
|
|
|
+ case MUL:
|
|
|
|
+ case REM:
|
|
|
|
+ case AND:
|
|
|
|
+ case OR: {
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- // binary operators
|
|
|
|
- case LSHIFT:
|
|
|
|
- case RSHIFT:
|
|
|
|
- case BAND:
|
|
|
|
- case BOR:
|
|
|
|
- case BXOR:
|
|
|
|
- case ADD:
|
|
|
|
- case SUB:
|
|
|
|
- case DIV:
|
|
|
|
- case MUL:
|
|
|
|
- case REM:
|
|
|
|
- case AND:
|
|
|
|
- case OR: {
|
|
|
|
- OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
|
|
- DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+
|
|
// unary operators
|
|
// unary operators
|
|
case BNOT:
|
|
case BNOT:
|
|
case NEG:
|
|
case NEG:
|
|
case NOT: {
|
|
case NOT: {
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
#pragma unused(r3)
|
|
#pragma unused(r3)
|
|
- DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %d", opcode_name(op), r1, r2);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case RANGENEW: {
|
|
case RANGENEW: {
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3);
|
|
DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- case JUMPF: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const int32_t value);
|
|
|
|
- DUMP_VM(buffer, bindex, "JUMPF %d %d", r1, value);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+
|
|
case JUMP: {
|
|
case JUMP: {
|
|
OPCODE_GET_ONE26bit(inst, const uint32_t value);
|
|
OPCODE_GET_ONE26bit(inst, const uint32_t value);
|
|
- DUMP_VM(buffer, bindex, "JUMP %d", value);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d", opcode_name(op), value);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case CALL: {
|
|
case CALL: {
|
|
// CALL A B C => R(A) = B(C0... CN)
|
|
// CALL A B C => R(A) = B(C0... CN)
|
|
OPCODE_GET_THREE8bit(inst, const uint32_t r1, const uint32_t r2, uint32_t r3);
|
|
OPCODE_GET_THREE8bit(inst, const uint32_t r1, const uint32_t r2, uint32_t r3);
|
|
- DUMP_VM(buffer, bindex, "CALL %d %d %d", r1, r2, r3);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %d %d", opcode_name(op), r1, r2, r3);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case RET0:
|
|
case RET0:
|
|
case RET: {
|
|
case RET: {
|
|
if (op == RET0) {
|
|
if (op == RET0) {
|
|
- DUMP_VM(buffer, bindex, "RET0");
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s", opcode_name(op));
|
|
} else {
|
|
} else {
|
|
OPCODE_GET_ONE8bit(inst, const uint32_t r1);
|
|
OPCODE_GET_ONE8bit(inst, const uint32_t r1);
|
|
- DUMP_VM(buffer, bindex, "RET %d", r1);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d", opcode_name(op), r1);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case HALT: {
|
|
case HALT: {
|
|
- DUMP_VM(buffer, bindex, "HALT");
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s", opcode_name(op));
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case SWITCH: {
|
|
case SWITCH: {
|
|
DUMP_VM(buffer, bindex, "SWITCH instruction not yet implemented");
|
|
DUMP_VM(buffer, bindex, "SWITCH instruction not yet implemented");
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- case MAPNEW: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t n);
|
|
|
|
- DUMP_VM(buffer, bindex, "MAPNEW %d %d", r1, n);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case LISTNEW: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t n);
|
|
|
|
- DUMP_VM(buffer, bindex, "LISTNEW %d %d", r1, n);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+
|
|
case SETLIST: {
|
|
case SETLIST: {
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, uint32_t r2, const uint32_t r3);
|
|
OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, uint32_t r2, const uint32_t r3);
|
|
#pragma unused(r3)
|
|
#pragma unused(r3)
|
|
- DUMP_VM(buffer, bindex, "SETLIST %d %d", r1, r2);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- case CLOSURE: {
|
|
|
|
- OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
|
|
- DUMP_VM(buffer, bindex, "CLOSURE %d %d", r1, r2);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d %d", opcode_name(op), r1, r2);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case CLOSE: {
|
|
case CLOSE: {
|
|
OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
OPCODE_GET_ONE8bit_ONE18bit(inst, const uint32_t r1, const uint32_t r2);
|
|
#pragma unused(r2)
|
|
#pragma unused(r2)
|
|
- DUMP_VM(buffer, bindex, "CLOSE %d", r1);
|
|
|
|
|
|
+ DUMP_VM(buffer, bindex, "%s %d", opcode_name(op), r1);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
case RESERVED1:
|
|
case RESERVED1:
|
|
case RESERVED2:
|
|
case RESERVED2:
|
|
case RESERVED3:
|
|
case RESERVED3:
|
|
@@ -286,12 +238,12 @@ const char *gravity_disassemble (const char *bcode, uint32_t blen, bool deserial
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
++pc;
|
|
++pc;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
return buffer;
|
|
return buffer;
|
|
-
|
|
|
|
|
|
+
|
|
abort_disassemble:
|
|
abort_disassemble:
|
|
if (ip && deserialize) mem_free(ip);
|
|
if (ip && deserialize) mem_free(ip);
|
|
if (buffer) mem_free(buffer);
|
|
if (buffer) mem_free(buffer);
|