2017-04-18 02:40:39 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Calvin Rose
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2017-03-16 00:56:37 +00:00
|
|
|
#include <gst/disasm.h>
|
2017-02-11 19:01:06 +00:00
|
|
|
|
|
|
|
/* Width of padded opcode names */
|
|
|
|
#define OP_WIDTH 20
|
|
|
|
|
|
|
|
/* Print various register and arguments to instructions */
|
2017-02-16 02:02:00 +00:00
|
|
|
static void dasm_print_slot(FILE * out, uint16_t index) { fprintf(out, "%d ", index); }
|
|
|
|
static void dasm_print_i16(FILE * out, int16_t number) { fprintf(out, "#%d ", number); }
|
|
|
|
static void dasm_print_i32(FILE * out, int32_t number) { fprintf(out, "#%d ", number); }
|
|
|
|
static void dasm_print_f64(FILE * out, double number) { fprintf(out, "#%f ", number); }
|
|
|
|
static void dasm_print_literal(FILE * out, uint16_t index) { fprintf(out, "(%d) ", index); }
|
|
|
|
static void dasm_print_upvalue(FILE * out, uint16_t level, uint16_t index) {
|
2017-03-01 01:20:29 +00:00
|
|
|
fprintf(out, "<%d, %d> ", level, index);
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print the name of the argument but pad it */
|
2017-02-16 02:02:00 +00:00
|
|
|
static void dasm_print_arg(FILE * out, const char * name) {
|
2017-03-01 01:20:29 +00:00
|
|
|
uint32_t i = 0;
|
|
|
|
char c;
|
|
|
|
while ((c = *name++)) {
|
|
|
|
putc(c, out);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
for (; i < OP_WIDTH; ++i)
|
|
|
|
fputc(' ', out);
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print instructions that take a fixed number of arguments */
|
2017-02-16 02:02:00 +00:00
|
|
|
static uint32_t dasm_fixed_op(FILE * out, const uint16_t * current,
|
2017-03-01 01:20:29 +00:00
|
|
|
const char * name, uint32_t size) {
|
|
|
|
uint32_t i;
|
|
|
|
dasm_print_arg(out, name);
|
|
|
|
for (i = 1; i <= size; ++i)
|
|
|
|
dasm_print_slot(out, current[i]);
|
|
|
|
return size + 1;
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print instructions that take a variable number of arguments */
|
2017-02-16 02:02:00 +00:00
|
|
|
static uint32_t dasm_varg_op(FILE * out, const uint16_t * current,
|
2017-03-01 01:20:29 +00:00
|
|
|
const char * name, uint32_t extra) {
|
|
|
|
uint32_t i, argCount;
|
|
|
|
dasm_print_arg(out, name);
|
|
|
|
for (i = 0; i < extra; ++i) {
|
|
|
|
dasm_print_slot(out, current[i + 1]);
|
|
|
|
}
|
|
|
|
argCount = current[extra + 1];
|
|
|
|
fprintf(out, ": "); /* Argument separator */
|
|
|
|
for (i = 0; i < argCount; ++i) {
|
|
|
|
dasm_print_slot(out, current[i + extra + 2]);
|
|
|
|
}
|
|
|
|
return argCount + extra + 2;
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print the disassembly for a function definition */
|
2017-02-16 02:02:00 +00:00
|
|
|
void gst_dasm_funcdef(FILE * out, GstFuncDef * def) {
|
2017-03-01 01:20:29 +00:00
|
|
|
gst_dasm(out, def->byteCode, def->byteCodeLen);
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print the disassembly for a function */
|
2017-02-16 02:02:00 +00:00
|
|
|
void gst_dasm_function(FILE * out, GstFunction * f) {
|
2017-03-01 01:20:29 +00:00
|
|
|
gst_dasm(out, f->def->byteCode, f->def->byteCodeLen);
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Disassemble some bytecode and display it as opcode + arguments assembly */
|
2017-02-16 02:02:00 +00:00
|
|
|
void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
|
2017-03-01 01:20:29 +00:00
|
|
|
uint16_t *current = byteCode;
|
|
|
|
uint16_t *end = byteCode + len;
|
2017-02-11 19:01:06 +00:00
|
|
|
|
2017-03-01 01:20:29 +00:00
|
|
|
while (current < end) {
|
|
|
|
switch (*current) {
|
|
|
|
default:
|
|
|
|
current += dasm_fixed_op(out, current, "unknown", 0);
|
|
|
|
break;
|
|
|
|
case GST_OP_ADD:
|
|
|
|
current += dasm_fixed_op(out, current, "add", 3);
|
|
|
|
break;
|
|
|
|
case GST_OP_SUB:
|
|
|
|
current += dasm_fixed_op(out, current, "sub", 3);
|
2017-03-10 05:17:34 +00:00
|
|
|
break;
|
2017-03-01 01:20:29 +00:00
|
|
|
case GST_OP_MUL:
|
|
|
|
current += dasm_fixed_op(out, current, "mul", 3);
|
2017-03-10 05:17:34 +00:00
|
|
|
break;
|
2017-03-01 01:20:29 +00:00
|
|
|
case GST_OP_DIV:
|
|
|
|
current += dasm_fixed_op(out, current, "div", 3);
|
|
|
|
break;
|
|
|
|
case GST_OP_NOT:
|
|
|
|
current += dasm_fixed_op(out, current, "not", 2);
|
|
|
|
break;
|
|
|
|
case GST_OP_FLS:
|
|
|
|
current += dasm_fixed_op(out, current, "loadFalse", 1);
|
|
|
|
break;
|
|
|
|
case GST_OP_TRU:
|
|
|
|
current += dasm_fixed_op(out, current, "loadTrue", 1);
|
|
|
|
break;
|
|
|
|
case GST_OP_NIL:
|
|
|
|
current += dasm_fixed_op(out, current, "loadNil", 1);
|
|
|
|
break;
|
|
|
|
case GST_OP_I16:
|
|
|
|
dasm_print_arg(out, "loadInt16");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_i16(out, ((int16_t *)current)[2]);
|
|
|
|
current += 3;
|
|
|
|
break;
|
|
|
|
case GST_OP_UPV:
|
|
|
|
dasm_print_arg(out, "loadUpValue");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_upvalue(out, current[2], current[3]);
|
|
|
|
current += 4;
|
|
|
|
break;
|
|
|
|
case GST_OP_JIF:
|
|
|
|
dasm_print_arg(out, "jumpIf");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_i32(out, ((int32_t *)(current + 2))[0]);
|
|
|
|
current += 4;
|
|
|
|
break;
|
|
|
|
case GST_OP_JMP:
|
|
|
|
dasm_print_arg(out, "jump");
|
|
|
|
dasm_print_i32(out, ((int32_t *)(current + 1))[0]);
|
|
|
|
current += 3;
|
|
|
|
break;
|
|
|
|
case GST_OP_SUV:
|
|
|
|
dasm_print_arg(out, "setUpValue");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_upvalue(out, current[2], current[3]);
|
|
|
|
current += 4;
|
|
|
|
break;
|
|
|
|
case GST_OP_CST:
|
|
|
|
dasm_print_arg(out, "loadLiteral");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_literal(out, current[2]);
|
|
|
|
current += 3;
|
|
|
|
break;
|
|
|
|
case GST_OP_I32:
|
|
|
|
dasm_print_arg(out, "loadInt32");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_i32(out, ((int32_t *)(current + 2))[0]);
|
|
|
|
current += 4;
|
|
|
|
break;
|
|
|
|
case GST_OP_F64:
|
|
|
|
dasm_print_arg(out, "loadFloat64");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_f64(out, ((double *)(current + 2))[0]);
|
|
|
|
current += 6;
|
|
|
|
break;
|
|
|
|
case GST_OP_MOV:
|
|
|
|
current += dasm_fixed_op(out, current, "move", 2);
|
|
|
|
break;
|
|
|
|
case GST_OP_CLN:
|
|
|
|
dasm_print_arg(out, "makeClosure");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_literal(out, current[2]);
|
|
|
|
current += 3;
|
|
|
|
break;
|
|
|
|
case GST_OP_EQL:
|
|
|
|
current += dasm_fixed_op(out, current, "equals", 3);
|
|
|
|
break;
|
|
|
|
case GST_OP_LTN:
|
|
|
|
current += dasm_fixed_op(out, current, "lessThan", 3);
|
|
|
|
break;
|
|
|
|
case GST_OP_LTE:
|
|
|
|
current += dasm_fixed_op(out, current, "lessThanEquals", 3);
|
|
|
|
break;
|
|
|
|
case GST_OP_ARR:
|
|
|
|
current += dasm_varg_op(out, current, "array", 1);
|
|
|
|
break;
|
|
|
|
case GST_OP_DIC:
|
|
|
|
current += dasm_varg_op(out, current, "object", 1);
|
|
|
|
break;
|
2017-03-07 20:29:40 +00:00
|
|
|
case GST_OP_TUP:
|
|
|
|
current += dasm_varg_op(out, current, "tuple", 1);
|
|
|
|
break;
|
2017-03-01 01:20:29 +00:00
|
|
|
case GST_OP_ERR:
|
|
|
|
current += dasm_fixed_op(out, current, "error", 1);
|
|
|
|
break;
|
|
|
|
case GST_OP_TRY:
|
|
|
|
dasm_print_arg(out, "try");
|
|
|
|
dasm_print_slot(out, current[1]);
|
|
|
|
dasm_print_i32(out, *(int32_t *)(current + 2));
|
|
|
|
current += 4;
|
|
|
|
break;
|
|
|
|
case GST_OP_UTY:
|
|
|
|
current += dasm_fixed_op(out, current, "untry", 0);
|
|
|
|
break;
|
2017-03-10 05:09:42 +00:00
|
|
|
case GST_OP_RET:
|
|
|
|
current += dasm_fixed_op(out, current, "return", 1);
|
|
|
|
break;
|
|
|
|
case GST_OP_RTN:
|
|
|
|
current += dasm_fixed_op(out, current, "returnNil", 0);
|
|
|
|
break;
|
|
|
|
case GST_OP_CAL:
|
2017-03-12 22:23:27 +00:00
|
|
|
current += dasm_varg_op(out, current, "call", 2);
|
2017-03-10 05:09:42 +00:00
|
|
|
break;
|
|
|
|
case GST_OP_TCL:
|
2017-03-12 22:23:27 +00:00
|
|
|
current += dasm_varg_op(out, current, "tailCall", 1);
|
2017-03-10 05:09:42 +00:00
|
|
|
break;
|
2017-03-01 01:20:29 +00:00
|
|
|
}
|
|
|
|
fprintf(out, "\n");
|
2017-02-26 16:47:50 +00:00
|
|
|
}
|
2017-02-11 19:01:06 +00:00
|
|
|
}
|