mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 07:15:19 +00:00
Estimated hours taken: 200
Major changes to bytecode interpreter.
Beginnings of native code integration
bytecode/bytecode.c:
bytecode/bytecode.h:
bytecode/dict.c:
bytecode/dict.h:
bytecode/disasm.c:
bytecode/disasm.h:
bytecode/machine.c:
bytecode/machine.h:
bytecode/mbi_main.c:
bytecode/mdb.m:
bytecode/mem.c:
bytecode/mem.h:
bytecode/slist.c:
bytecode/slist.h:
bytecode/template.c:
bytecode/template.h:
bytecode/util.c:
bytecode/util.h:
Removed. These are all the old bytecode files from
before I started. Any parts that were useful have already
been salvaged and used in the new interpreter.
bytecode/*:
Added MB_Bytecode_Addr and MB_Native_Addr types to remove abiguity
as to what type of code an instruction pointer points to, and
provide compiler help for erroneously mixing pointer types.
bytecode/Mmakefile:
bytecode/Mmake.params:
Makefile for test bytecode program. Note that any library
functions that are called from bytecode must be compiled
with trace information. (So their entry labels can be
looked up)
bytecode/mb_basetypes.h:
Added. Contains basic type definitions.
bytecode/mb_bytecode.c:
bytecode/mb_bytecode.h:
Better error messages.
Changed var_lists to direct pointers rather than
lookups through data stacks (much simpler but stop you
using realloc() on the bytecode argument data)
Label addresses are computed at module load time rather
than being looked up each jump
Added endof_negation_goal
Temporary stack slot numbers are translated to variable
numbers (now there is no distinction between temps & vars)
MB_read_cstring return value convention changed (see comments
for how to now free the returned memory)
Added distinction between functions and predicates
Added enter_else
Code addresses are all pointers rather than simple ints
Added MB_Code_Addr type for pred_const and call instructions
bytecode/mb_disasm.c:
bytecode/mb_disasm.h:
Added endof_negation_goal & enter_else
Output strings are now easier to read
MB_listing does not display anything for invalid addresses
MB_listing takes line length argument
bytecode/mb_interface.c:
bytecode/mb_interface.h:
bytecode/mb_interface_stub.m:
Interfacing between native/bytecode
bytecode/mb_machine.c:
bytecode/mb_machine.h:
bytecode/mb_machine_def.h:
Large sections of code branched off into mb_module.?
Most instructions completed, but not integrated with native
code.
Most of mb_machine_def has been removed as the native
code functions provide the same functionality.
bytecode/mb_machine_show.c:
bytecode/mb_machine_show.h:
Completely changed. Less information now as a lot of what
was being displayed before cannot be determined as easily
now that it is stored in the mercury runtime.
bytecode/mb_mem.c:
bytecode/mb_mem.h:
Added routines for garbage collected memory
bytecode/mb_module.c:
bytecode/mb_module.h:
Loading & accessing bytecode. Argument data indexes & id are now
stored in a single word. (see MB_BCID_xxx macros).
Call & label addresses are now calculated at load time.
bytecode/mb_stack.c:
bytecode/mb_stack.h:
Added options for garbage collection of MB_Stack memory
bytecode/mb_util.c:
bytecode/mb_util.h:
Miscellaneous string functions added and SAY() for debugging
bytecode/simple01.m:
Added. Simple test program. (replace with whatever
program is being tested at the time).
1130 lines
23 KiB
C
1130 lines
23 KiB
C
|
|
/*
|
|
** Copyright (C) 1997,2000-2001 The University of Melbourne.
|
|
** This file may only be copied under the terms of the GNU Library General
|
|
** Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
**
|
|
** Contains functions for disassembling bytecodes into human readable form
|
|
**
|
|
*/
|
|
|
|
/* Imports */
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "mb_disasm.h"
|
|
#include "mb_module.h"
|
|
#include "mb_util.h"
|
|
|
|
#include "mb_machine_def.h"
|
|
|
|
/* Exported definitions */
|
|
|
|
int MB_str_bytecode(MB_Machine_State *ms, MB_Bytecode_Addr addr,
|
|
char *buffer, int buffer_len, int indent_level);
|
|
|
|
void MB_listing(MB_Machine_State *ms, FILE *fp, MB_Bytecode_Addr start,
|
|
MB_Bytecode_Addr end, MB_Word line_len);
|
|
|
|
/* Local declarations */
|
|
|
|
/* Fills a c string buffer with to the name of a constructor id */
|
|
static void str_cons_id(MB_Cons_id cons_id, char *buffer, int buffer_len);
|
|
|
|
/* Fills a c string buffer with to the name of a tag */
|
|
static void str_tag(MB_Tag tag, char *buffer, int buffer_len);
|
|
|
|
/* Returns a string corresponding to the name of a bytecode type */
|
|
static MB_CString_Const str_bytecode_name(MB_Byte bytecode_id);
|
|
|
|
/* Returns a string corresponding to the name of a determinism type */
|
|
static MB_CString_Const str_determinism_name(MB_Byte determinism_id);
|
|
|
|
/* Returns a string corresponding to the name of a unary operation */
|
|
static MB_CString_Const str_unop_name(MB_Byte unop);
|
|
|
|
/* Returns a string corresponding to the name of a binary operation */
|
|
static MB_CString_Const str_binop_name(MB_Byte binop);
|
|
|
|
/* Fills a buffer with a string transformed into a source-style c string
|
|
* (includes double quotes around string) */
|
|
static void quote_cstring(MB_CString str, char *buffer, int buffer_len);
|
|
|
|
/* Fills a c string buffer with a variable list */
|
|
static void str_var_dir(MB_Var_dir var_dir, char *buffer, int buffer_len);
|
|
|
|
/* Fills a c string buffer with an operation argument */
|
|
static void str_op_arg(MB_Op_arg op_arg, char *buffer, int buffer_len);
|
|
|
|
/* Implementation */
|
|
|
|
|
|
/*
|
|
** Macros for printing:
|
|
** Expects buffer, buffer_len & last_len to be defined.
|
|
** Wraps calls to snprintf, checks if the buffer is full and
|
|
** if it is, returns from the function
|
|
*/
|
|
|
|
#define PRINT() if (buffer_len > 1) { \
|
|
int last_len; \
|
|
assert(buffer_len > 0); \
|
|
last_len = snprintf(buffer, buffer_len,
|
|
|
|
/* printf arguments get sandwiched between these macros */
|
|
#define ENDPRINT() ); \
|
|
if (last_len >= buffer_len) {\
|
|
last_len = buffer_len-1; \
|
|
} \
|
|
buffer += last_len; \
|
|
buffer_len -= last_len; \
|
|
assert(buffer_len > 0); \
|
|
} else { \
|
|
assert(buffer_len >= 0); \
|
|
if (buffer_len == 0) { \
|
|
buffer--; \
|
|
buffer_len++; \
|
|
} \
|
|
}
|
|
|
|
|
|
/*
|
|
** Call this after calling a function that has added characters to the buffer
|
|
** Requires that if the function filled the buffer, it must have at least
|
|
** put a null terminator at the end
|
|
*/
|
|
#define PRINTFILLCHECK() { \
|
|
int str_len = strlen(buffer); \
|
|
buffer += str_len; \
|
|
buffer_len -= str_len; \
|
|
assert(buffer_len > 0); \
|
|
}
|
|
|
|
/*
|
|
** Macro to call a function of the format f(arg, buffer, buffer_len)
|
|
** where the function fills all or part of the buffer
|
|
*/
|
|
#define PRINTCALL(x, y) (x)((y), buffer, buffer_len); \
|
|
PRINTFILLCHECK()
|
|
|
|
/*
|
|
** Fills a string corresponding to a bytecode
|
|
** Returns indent level for subsequent instructions
|
|
**
|
|
** If buffer is NULL or buffer_len is <= 0 then only returns
|
|
** new indent level
|
|
**
|
|
** The general convention is for arguments to be in square brackets and
|
|
** calculated arguments (ie not in the bytecode file) in round brackets
|
|
*/
|
|
|
|
int
|
|
MB_str_bytecode(MB_Machine_State *ms, MB_Bytecode_Addr addr, char *buffer,
|
|
int buffer_len, int indent_level)
|
|
{
|
|
MB_Byte bc_id = MB_code_get_id(addr);
|
|
MB_Bytecode_Arg *bca = MB_code_get_arg(addr);
|
|
|
|
/* calculate indent changes */
|
|
int this_indent = indent_level;
|
|
int next_indent = indent_level;
|
|
|
|
switch (bc_id) {
|
|
case MB_BC_enter_pred:
|
|
case MB_BC_enter_proc:
|
|
case MB_BC_enter_disjunction:
|
|
case MB_BC_enter_disjunct:
|
|
case MB_BC_enter_switch:
|
|
case MB_BC_enter_switch_arm:
|
|
case MB_BC_enter_if:
|
|
case MB_BC_enter_negation:
|
|
case MB_BC_enter_commit:
|
|
next_indent++;
|
|
break;
|
|
case MB_BC_label:
|
|
case MB_BC_enter_then:
|
|
case MB_BC_endof_then:
|
|
case MB_BC_enter_else:
|
|
case MB_BC_endof_negation_goal:
|
|
this_indent--;
|
|
break;
|
|
case MB_BC_endof_pred:
|
|
case MB_BC_endof_proc:
|
|
case MB_BC_endof_disjunction:
|
|
case MB_BC_endof_disjunct:
|
|
case MB_BC_endof_switch:
|
|
case MB_BC_endof_switch_arm:
|
|
case MB_BC_endof_if:
|
|
case MB_BC_endof_negation:
|
|
case MB_BC_endof_commit:
|
|
this_indent--;
|
|
next_indent--;
|
|
break;
|
|
case MB_BC_assign:
|
|
case MB_BC_test:
|
|
case MB_BC_construct:
|
|
case MB_BC_deconstruct:
|
|
case MB_BC_complex_construct:
|
|
case MB_BC_complex_deconstruct:
|
|
case MB_BC_place_arg:
|
|
case MB_BC_pickup_arg:
|
|
case MB_BC_call:
|
|
case MB_BC_higher_order_call:
|
|
case MB_BC_builtin_binop:
|
|
case MB_BC_builtin_unop:
|
|
case MB_BC_builtin_bintest:
|
|
case MB_BC_builtin_untest:
|
|
case MB_BC_semidet_succeed:
|
|
case MB_BC_semidet_success_check:
|
|
case MB_BC_fail:
|
|
case MB_BC_context:
|
|
case MB_BC_not_supported:
|
|
break;
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
|
|
if (next_indent < 0) next_indent = 0;
|
|
|
|
|
|
/* if we only wanted to calculate the indents, return now */
|
|
if (buffer == NULL || buffer_len <= 0) return next_indent;
|
|
|
|
|
|
/* indicate det/nondet code */
|
|
/*
|
|
PRINT()
|
|
"%c",
|
|
(MB_code_get_det(addr) ? '+' : '-')
|
|
ENDPRINT()
|
|
*/
|
|
|
|
|
|
/* print the indents */
|
|
while (this_indent > 0) {
|
|
PRINT()
|
|
" "
|
|
ENDPRINT()
|
|
this_indent--;
|
|
}
|
|
|
|
PRINT()
|
|
"%s",
|
|
str_bytecode_name(bc_id)
|
|
ENDPRINT()
|
|
|
|
switch (bc_id) {
|
|
case MB_BC_enter_pred:
|
|
PRINT()
|
|
" %s %s/%d (%d procs)",
|
|
bca->enter_pred.is_func ? "func" : "pred",
|
|
bca->enter_pred.pred_name,
|
|
(int) bca->enter_pred.pred_arity,
|
|
(int) bca->enter_pred.proc_count
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_pred:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_enter_proc: {
|
|
MB_Short i;
|
|
MB_Short len;
|
|
|
|
PRINT()
|
|
" mode %d: [%s] [%d labels] [endlabel %p]"
|
|
" [%d temps] [%d vars]",
|
|
(int) bca->enter_proc.mode_num,
|
|
str_determinism_name(bca->enter_proc.det),
|
|
bca->enter_proc.label_count,
|
|
bca->enter_proc.end_label.addr,
|
|
bca->enter_proc.temp_count,
|
|
bca->enter_proc.list_length
|
|
ENDPRINT()
|
|
|
|
len = bca->enter_proc.list_length;
|
|
for (i = 0; i < len; i++) {
|
|
PRINT()
|
|
" %s",
|
|
bca->enter_proc.var_info[i]
|
|
|
|
ENDPRINT()
|
|
}
|
|
break;
|
|
}
|
|
case MB_BC_endof_proc:
|
|
PRINT()
|
|
" (%p)",
|
|
bca->endof_proc.proc_start
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_label:
|
|
PRINT()
|
|
" %d",
|
|
(int) bca->label.label
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_enter_disjunction:
|
|
PRINT()
|
|
" [endlabel %p]",
|
|
bca->enter_disjunction.end_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_disjunction:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_enter_disjunct:
|
|
PRINT()
|
|
" [nextlabel %p]",
|
|
bca->enter_disjunct.next_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_disjunct:
|
|
PRINT()
|
|
" [endlabel %p]",
|
|
bca->endof_disjunct.end_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_enter_switch:
|
|
PRINT()
|
|
" [var %d] [endlabel %p]",
|
|
(int) bca->enter_switch.var,
|
|
bca->enter_switch.end_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_switch:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_enter_switch_arm:
|
|
PRINT()
|
|
" (on var %d) ",
|
|
(int) bca->enter_switch_arm.var
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_cons_id, bca->enter_switch_arm.cons_id)
|
|
|
|
PRINT()
|
|
" [nextlabel %p]",
|
|
bca->enter_switch_arm.next_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_switch_arm:
|
|
PRINT()
|
|
" [endlabel %p]",
|
|
bca->endof_switch_arm.end_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_enter_if:
|
|
PRINT()
|
|
" [else %p] [end %p] [frame %d]",
|
|
bca->enter_if.else_label.addr,
|
|
bca->enter_if.end_label.addr,
|
|
(int) bca->enter_if.frame_ptr_tmp
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_enter_then:
|
|
PRINT()
|
|
" [frame %d]",
|
|
(int) bca->enter_then.frame_ptr_tmp
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_then:
|
|
PRINT()
|
|
" [follow %p]",
|
|
bca->endof_then.follow_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_enter_else:
|
|
PRINT()
|
|
" [frame %d]",
|
|
(int) bca->enter_else.frame_ptr_tmp
|
|
ENDPRINT()
|
|
break;
|
|
|
|
|
|
case MB_BC_endof_if:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_enter_negation:
|
|
PRINT()
|
|
" [frame %d] [endlabel %p]",
|
|
(int) bca->enter_negation.frame_ptr_tmp,
|
|
bca->enter_negation.end_label.addr
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_negation_goal:
|
|
PRINT()
|
|
" [frame %d]",
|
|
(int) bca->endof_negation_goal.frame_ptr_tmp
|
|
ENDPRINT()
|
|
|
|
case MB_BC_endof_negation:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_enter_commit:
|
|
PRINT()
|
|
" [frame %d]",
|
|
(int) bca->enter_commit.frame_ptr_tmp
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_endof_commit:
|
|
PRINT()
|
|
" [frame %d]",
|
|
(int) bca->endof_commit.frame_ptr_tmp
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_assign:
|
|
PRINT()
|
|
" [var %d] <= [var %d]",
|
|
(int) bca->assign.to_var,
|
|
(int) bca->assign.from_var
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_test:
|
|
PRINT()
|
|
" [var %d] == [var %d]",
|
|
(int) bca->test.var1,
|
|
(int) bca->test.var2
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_construct: {
|
|
MB_Short len;
|
|
MB_Short i;
|
|
|
|
PRINT()
|
|
" [var %d] <= ",
|
|
(int) bca->construct.to_var
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_cons_id,bca->construct.consid)
|
|
|
|
len = bca->construct.list_length;
|
|
PRINT()
|
|
" [%d var%s%s",
|
|
(int) len,
|
|
(len != 0) ? "s" : "",
|
|
(len > 0) ? ":" : ""
|
|
ENDPRINT()
|
|
for (i = 0; i < len; i++) {
|
|
PRINT()
|
|
" %d",
|
|
(int) bca->construct.var_list[i]
|
|
ENDPRINT()
|
|
|
|
}
|
|
PRINT()
|
|
"]"
|
|
ENDPRINT()
|
|
break;
|
|
}
|
|
case MB_BC_deconstruct: {
|
|
MB_Short len;
|
|
MB_Short i;
|
|
|
|
PRINT()
|
|
" [var %d] ",
|
|
(int) bca->deconstruct.from_var
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_cons_id,bca->deconstruct.consid)
|
|
|
|
len = bca->deconstruct.list_length;
|
|
PRINT()
|
|
" [%d var%s%s",
|
|
(int) len,
|
|
(len != 0) ? "s" : "",
|
|
(len > 0) ? ":" : ""
|
|
ENDPRINT()
|
|
|
|
for (i = 0; i < len; i++) {
|
|
PRINT()
|
|
" %d",
|
|
(int) bca->deconstruct.var_list[i]
|
|
ENDPRINT()
|
|
|
|
}
|
|
PRINT()
|
|
"]"
|
|
ENDPRINT()
|
|
break;
|
|
}
|
|
case MB_BC_complex_construct: {
|
|
MB_Short len;
|
|
MB_Short i;
|
|
|
|
PRINT()
|
|
" %d ",
|
|
(int) bca->complex_construct.to_var
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_cons_id,bca->complex_construct.consid);
|
|
|
|
len = bca->complex_construct.list_length;
|
|
|
|
PRINT()
|
|
" %d", (int) len
|
|
ENDPRINT()
|
|
|
|
for (i = 0; i < len; i++) {
|
|
PRINT()
|
|
" "
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_var_dir,
|
|
bca->complex_construct.var_dir[i])
|
|
}
|
|
break;
|
|
}
|
|
case MB_BC_complex_deconstruct: {
|
|
MB_Short len;
|
|
MB_Short i;
|
|
|
|
PRINT()
|
|
" %d ",
|
|
(int) bca->complex_deconstruct.from_var
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_cons_id,bca->complex_deconstruct.consid)
|
|
|
|
len = bca->complex_deconstruct.list_length;
|
|
PRINT()
|
|
" %d",
|
|
(int) len
|
|
ENDPRINT()
|
|
|
|
for (i = 0; i < len; i++) {
|
|
PRINT()
|
|
" "
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_var_dir,
|
|
bca->complex_deconstruct.var_dir[i])
|
|
}
|
|
break;
|
|
}
|
|
case MB_BC_place_arg:
|
|
PRINT()
|
|
" [r%d] <= [var %d]",
|
|
(int) bca->place_arg.to_reg,
|
|
(int) bca->place_arg.from_var
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_pickup_arg:
|
|
PRINT()
|
|
" [r%d] => [var %d]",
|
|
(int) bca->pickup_arg.from_reg,
|
|
(int) bca->pickup_arg.to_var
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_call:
|
|
PRINT()
|
|
" [%s %s__%s/%d mode %d (%s %p)]",
|
|
bca->call.is_func ? "func" : "pred",
|
|
bca->call.module_name,
|
|
bca->call.pred_name,
|
|
(int) bca->call.arity,
|
|
(int) bca->call.mode_num,
|
|
bca->call.addr.is_native ? "natv" : "byte",
|
|
bca->call.addr.is_native ?
|
|
(MB_Word *) bca->call.addr.addr.native :
|
|
(MB_Word *) bca->call.addr.addr.bc
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_higher_order_call:
|
|
PRINT()
|
|
" [var %d] [invars %d] [outvars %d] [%s]",
|
|
(int) bca->higher_order_call.pred_var,
|
|
(int) bca->higher_order_call.in_var_count,
|
|
(int) bca->higher_order_call.out_var_count,
|
|
str_determinism_name(bca->higher_order_call.det)
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_builtin_binop:
|
|
PRINT()
|
|
": "
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_op_arg,bca->builtin_binop.arg1)
|
|
|
|
PRINT()
|
|
" %s ",
|
|
str_binop_name(bca->builtin_binop.binop)
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_op_arg,bca->builtin_binop.arg2)
|
|
|
|
PRINT()
|
|
" => [var %d]",
|
|
(int) bca->builtin_binop.to_var
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_builtin_unop:
|
|
PRINT()
|
|
" %s ",
|
|
str_unop_name(bca->builtin_unop.unop)
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_op_arg,bca->builtin_unop.arg)
|
|
|
|
PRINT()
|
|
" %d",
|
|
(int) bca->builtin_unop.to_var
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_builtin_bintest:
|
|
|
|
PRINT()
|
|
" "
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_op_arg,bca->builtin_binop.arg1)
|
|
|
|
PRINT()
|
|
" %s ",
|
|
str_binop_name(bca->builtin_bintest.binop)
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(str_op_arg,bca->builtin_binop.arg2)
|
|
break;
|
|
|
|
case MB_BC_builtin_untest:
|
|
PRINT()
|
|
" %s ",
|
|
str_unop_name(bca->builtin_untest.unop)
|
|
ENDPRINT()
|
|
PRINTCALL(str_op_arg,bca->builtin_unop.arg)
|
|
break;
|
|
|
|
case MB_BC_semidet_succeed:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_semidet_success_check:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_fail:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
case MB_BC_context:
|
|
PRINT()
|
|
" %d",
|
|
bca->context.line_number
|
|
ENDPRINT()
|
|
break;
|
|
|
|
case MB_BC_not_supported:
|
|
/* No args */
|
|
buffer[0] = 0;
|
|
break;
|
|
|
|
default:
|
|
MB_fatal("Attempt to disassemble unknown bytecode");
|
|
break;
|
|
} /* end switch */
|
|
|
|
return next_indent;
|
|
|
|
} /* end print_bytecode() */
|
|
|
|
static void
|
|
str_cons_id(MB_Cons_id cons_id, char *buffer, int buffer_len)
|
|
{
|
|
PRINT()
|
|
"["
|
|
ENDPRINT()
|
|
switch (cons_id.id) {
|
|
case MB_CONSID_CONS: {
|
|
PRINT()
|
|
"functor %s__%s/%d ",
|
|
cons_id.opt.cons.module_name,
|
|
cons_id.opt.cons.string,
|
|
(int) cons_id.opt.cons.arity
|
|
ENDPRINT()
|
|
PRINTCALL(str_tag, cons_id.opt.cons.tag)
|
|
break;
|
|
}
|
|
case MB_CONSID_INT_CONST:
|
|
PRINT()
|
|
"int_const " MB_FMT_INT " (" MB_FMT_HEX ")",
|
|
cons_id.opt.int_const,
|
|
cons_id.opt.int_const
|
|
ENDPRINT()
|
|
break;
|
|
case MB_CONSID_STRING_CONST: {
|
|
PRINT()
|
|
"string_const"
|
|
ENDPRINT()
|
|
|
|
PRINTCALL(quote_cstring, cons_id.opt.string_const);
|
|
break;
|
|
}
|
|
case MB_CONSID_FLOAT_CONST:
|
|
PRINT()
|
|
"float_const %.15g",
|
|
cons_id.opt.float_const
|
|
ENDPRINT()
|
|
break;
|
|
case MB_CONSID_PRED_CONST:
|
|
PRINT()
|
|
"%s %s %s__%s/%d mode %d (%s %p)",
|
|
"pred_const",
|
|
cons_id.opt.pred_const.is_func ?"func":"pred",
|
|
cons_id.opt.pred_const.module_name,
|
|
cons_id.opt.pred_const.pred_name,
|
|
(int) cons_id.opt.pred_const.arity,
|
|
(int) cons_id.opt.pred_const.mode_num,
|
|
cons_id.opt.pred_const.addr.is_native
|
|
? "natv" : "byte",
|
|
cons_id.opt.pred_const.addr.is_native
|
|
? (MB_Word *) cons_id.opt.pred_const
|
|
.addr.addr.native
|
|
: (MB_Word *) cons_id.opt.pred_const
|
|
.addr.addr.bc
|
|
ENDPRINT()
|
|
break;
|
|
case MB_CONSID_CODE_ADDR_CONST:
|
|
PRINT()
|
|
"%s %s %s %d %d",
|
|
"code_addr_const",
|
|
cons_id.opt.code_addr_const.module_name,
|
|
cons_id.opt.code_addr_const.pred_name,
|
|
(int) cons_id.opt.code_addr_const.arity,
|
|
(int) cons_id.opt.code_addr_const.mode_num
|
|
ENDPRINT()
|
|
break;
|
|
case MB_CONSID_BASE_TYPE_INFO_CONST:
|
|
PRINT()
|
|
"%s %s__%s/%d",
|
|
"base_type_info_const",
|
|
cons_id.opt.base_type_info_const.module_name,
|
|
cons_id.opt.base_type_info_const.type_name,
|
|
(int) cons_id.opt.base_type_info_const
|
|
.type_arity
|
|
ENDPRINT()
|
|
break;
|
|
case MB_CONSID_CHAR_CONST:
|
|
if (isprint(cons_id.opt.char_const.ch)) {
|
|
PRINT()
|
|
"%s '%c'",
|
|
"char_const",
|
|
cons_id.opt.char_const.ch
|
|
ENDPRINT()
|
|
} else {
|
|
PRINT()
|
|
"%s %d (0x%02X)",
|
|
"char_const",
|
|
(int) cons_id.opt.char_const.ch,
|
|
(int) cons_id.opt.char_const.ch
|
|
ENDPRINT()
|
|
}
|
|
break;
|
|
default:
|
|
MB_fatal("Attempt to disassemble unknown cons");
|
|
break;
|
|
} /* end switch */
|
|
PRINT()
|
|
"]"
|
|
ENDPRINT()
|
|
|
|
buffer[buffer_len-1] = 0; /* snprintf may not do it if a long string */
|
|
} /* end print_cons_id() */
|
|
|
|
static void
|
|
str_tag(MB_Tag tag, char *buffer, int buffer_len)
|
|
{
|
|
|
|
switch (tag.id) {
|
|
case MB_TAG_SIMPLE:
|
|
snprintf(buffer, buffer_len,
|
|
"%s %d",
|
|
"simple_tag",
|
|
(int) tag.opt.primary);
|
|
break;
|
|
case MB_TAG_COMPLICATED:
|
|
snprintf(buffer, buffer_len,
|
|
"%s %d %ld",
|
|
"complicated_tag",
|
|
(int) tag.opt.pair.primary,
|
|
(long int) tag.opt.pair.secondary);
|
|
break;
|
|
case MB_TAG_COMPLICATED_CONSTANT:
|
|
snprintf(buffer, buffer_len,
|
|
"%s %d %ld",
|
|
"complicated_constant_tag",
|
|
(int) tag.opt.pair.primary,
|
|
(long int) tag.opt.pair.secondary);
|
|
break;
|
|
case MB_TAG_ENUM:
|
|
snprintf(buffer, buffer_len,
|
|
"%s %d",
|
|
"enum_tag",
|
|
(int) tag.opt.enum_tag);
|
|
break;
|
|
case MB_TAG_NONE:
|
|
snprintf(buffer, buffer_len,
|
|
"%s",
|
|
"no_tag");
|
|
break;
|
|
default:
|
|
MB_util_error("Invalid tag: %d\n", tag.id);
|
|
assert(FALSE); /* XXX */
|
|
break;
|
|
} /* end switch */
|
|
|
|
/* snprintf may not append a null character */
|
|
buffer[buffer_len-1] = 0;
|
|
} /* end print_tag() */
|
|
|
|
/*
|
|
** XXX ORDER: Currently we depend on the order of elements in the table.
|
|
*/
|
|
static const char *
|
|
bytecode_table[] = {
|
|
"enter_pred",
|
|
"endof_pred",
|
|
"enter_proc",
|
|
"endof_proc",
|
|
"label",
|
|
"enter_disjunction",
|
|
"endof_disjunction",
|
|
"enter_disjunct",
|
|
"endof_disjunct",
|
|
"enter_switch",
|
|
"endof_switch",
|
|
"enter_switch_arm",
|
|
"endof_switch_arm",
|
|
"enter_if",
|
|
"enter_then",
|
|
"endof_then",
|
|
"endof_if",
|
|
"enter_negation",
|
|
"endof_negation",
|
|
"enter_commit",
|
|
"endof_commit",
|
|
"assign",
|
|
"test",
|
|
"construct",
|
|
"deconstruct",
|
|
"complex_construct",
|
|
"complex_deconstruct",
|
|
"place_arg ",
|
|
"pickup_arg",
|
|
"call",
|
|
"higher_order_call",
|
|
"builtin_binop",
|
|
"builtin_unop",
|
|
"builtin_bintest",
|
|
"builtin_untest",
|
|
"semidet_succeed",
|
|
"semidet_success_check",
|
|
"fail",
|
|
"context",
|
|
"not_supported",
|
|
"enter_else",
|
|
"endof_negation_goal"
|
|
};
|
|
|
|
static MB_CString_Const
|
|
str_bytecode_name(MB_Byte bytecode_id)
|
|
{
|
|
if (bytecode_id >= sizeof(bytecode_table) / sizeof(*bytecode_table)) {
|
|
return (MB_CString_Const) "<<unknown bytecode>>"; /* XXX */
|
|
} else {
|
|
return (MB_CString_Const) bytecode_table[bytecode_id];
|
|
}
|
|
}
|
|
|
|
/*
|
|
** XXX ORDER: Currently we depend on the order of elements in the table.
|
|
*/
|
|
static const char *
|
|
determinism_table[] = {
|
|
"det",
|
|
"semidet",
|
|
"multidet",
|
|
"nondet",
|
|
"cc_multidet",
|
|
"cc_nondet",
|
|
"erroneous",
|
|
"failure"
|
|
};
|
|
|
|
/* Returns a string corresponding to the name of a determinism type */
|
|
static MB_CString_Const
|
|
str_determinism_name(MB_Byte determinism_id)
|
|
{
|
|
if (determinism_id >=
|
|
sizeof(determinism_table) / sizeof(*determinism_table))
|
|
{
|
|
return (MB_CString_Const) "<<unknown determinism>>"; /* XXX */
|
|
} else {
|
|
return (MB_CString_Const) determinism_table[determinism_id];
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** XXX ORDER: Currently we depend on the order of elements in the table.
|
|
*/
|
|
static const char *
|
|
unop_table[] = {
|
|
"mktag",
|
|
"tag",
|
|
"unmktag",
|
|
"mkbody",
|
|
"unmkbody",
|
|
"cast_to_unsigned",
|
|
"hash_string",
|
|
"bitwise_complement",
|
|
"not"
|
|
};
|
|
|
|
/* Return a string corresponding to the name of a unary operation */
|
|
static MB_CString_Const
|
|
str_unop_name(MB_Byte unop)
|
|
{
|
|
/* bounds check */
|
|
|
|
if (unop >= sizeof(unop_table) / sizeof(*unop_table)) {
|
|
return (MB_CString_Const) "<<unknown unop>>"; /* XXX */
|
|
} else {
|
|
return (MB_CString_Const) unop_table[unop];
|
|
}
|
|
}
|
|
|
|
/*
|
|
** XXX ORDER: Currently we depend on the order of elements in the table.
|
|
*/
|
|
static const char *
|
|
binop_table[] = {
|
|
"+",
|
|
"-",
|
|
"*",
|
|
"/",
|
|
"mod",
|
|
"<<",
|
|
">>",
|
|
"&",
|
|
"|",
|
|
"^",
|
|
"and",
|
|
"or",
|
|
"eq",
|
|
"ne",
|
|
"array_index",
|
|
"str_eq",
|
|
"str_ne",
|
|
"str_lt",
|
|
"str_gt",
|
|
"str_le",
|
|
"str_ge",
|
|
"<",
|
|
">",
|
|
"<=",
|
|
">=",
|
|
"float_plus",
|
|
"float_minus",
|
|
"float_times",
|
|
"float_divide",
|
|
"float_eq",
|
|
"float_ne",
|
|
"float_lt",
|
|
"float_gt",
|
|
"float_le",
|
|
"float_ge",
|
|
"body"
|
|
};
|
|
|
|
static MB_CString_Const
|
|
str_binop_name(MB_Byte binop)
|
|
{
|
|
/* bounds check */
|
|
if (binop >= sizeof(binop_table) / sizeof(*binop_table)) {
|
|
return (MB_CString_Const) "<<unknown binop>>"; /* XXX */
|
|
} else {
|
|
return (MB_CString_Const) binop_table[binop];
|
|
}
|
|
} /* end str_binop_name() */
|
|
|
|
|
|
/* Fills a buffer with a string transformed into a source-style c string
|
|
* (includes double quotes around string) */
|
|
static void
|
|
quote_cstring(MB_CString str, char * buffer, int buffer_len)
|
|
{
|
|
int i; /* index into str */
|
|
int j; /* index into buffer */
|
|
|
|
i = j = 0;
|
|
if (j < buffer_len) {
|
|
buffer[j] = '"';
|
|
j++;
|
|
}
|
|
while (buffer_len-1 > j) {
|
|
/*
|
|
** According to K&R 2nd ed, page 194, string literals
|
|
** may not contain newline or double-quote; they must be
|
|
** escaped. (And of course the backslash must also be
|
|
** escaped.) There is no mention of other limitations
|
|
** on what characters may be within a string literal.
|
|
*/
|
|
switch(str[i]) {
|
|
/* following two cases are identical */
|
|
case '\\':
|
|
case '\"':
|
|
buffer[j] = '\\';
|
|
buffer[j+1] = str[i];
|
|
j += 2;
|
|
i++;
|
|
break;
|
|
case '\n':
|
|
buffer[j] = '\\';
|
|
buffer[j+1] = 'n';
|
|
j += 2;
|
|
i++;
|
|
break;
|
|
case '\0': {
|
|
buffer[j] = '"';
|
|
buffer[j+1] = 0;
|
|
return;
|
|
}
|
|
default:
|
|
buffer[j] = str[i];
|
|
j++;
|
|
i++;
|
|
break;
|
|
} /* end switch */
|
|
} /* end for */
|
|
buffer[buffer_len-1] = 0;
|
|
} /* end quote_cstring() */
|
|
|
|
static void
|
|
str_var_dir(MB_Var_dir var_dir, char *buffer, int buffer_len)
|
|
{
|
|
PRINT()
|
|
"<<var_dir>>"
|
|
ENDPRINT()
|
|
return;
|
|
} /* end str_var_dir() */
|
|
|
|
static void
|
|
str_op_arg(MB_Op_arg op_arg, char *buffer, int buffer_len)
|
|
{
|
|
switch (op_arg.id) {
|
|
case MB_ARG_VAR:
|
|
PRINT()
|
|
"[var %d]",
|
|
op_arg.opt.var
|
|
ENDPRINT()
|
|
break;
|
|
case MB_ARG_INT_CONST:
|
|
PRINT()
|
|
/*
|
|
** XXX: int_const has type Integer which could
|
|
** be int, long or long long. Correct solution
|
|
** is to define a format string in conf.h, but
|
|
** for now assume long is enough
|
|
*/
|
|
"[int " MB_FMT_INT " (" MB_FMT_HEX ")]",
|
|
op_arg.opt.int_const,
|
|
op_arg.opt.int_const
|
|
ENDPRINT()
|
|
break;
|
|
case MB_ARG_FLOAT_CONST:
|
|
PRINT()
|
|
"[float %f]",
|
|
op_arg.opt.float_const
|
|
ENDPRINT()
|
|
break;
|
|
default:
|
|
assert(FALSE); /* XXX */
|
|
break;
|
|
} /* end switch */
|
|
} /* end str_op_arg() */
|
|
|
|
/*
|
|
** displays a code listing from address start to end
|
|
*/
|
|
|
|
void
|
|
MB_listing(MB_Machine_State *ms, FILE *fp, MB_Bytecode_Addr start, MB_Bytecode_Addr end,
|
|
MB_Word line_len)
|
|
{
|
|
char buffer[256];
|
|
MB_Bytecode_Addr i;
|
|
MB_Word indent = 0;
|
|
MB_Bytecode_Addr ip = MB_ip_get(ms);
|
|
|
|
MB_SAY("linelen: %d\n", line_len);
|
|
|
|
start = MB_code_range_clamp(start);
|
|
end = MB_code_range_clamp(end);
|
|
|
|
if (sizeof(buffer) < line_len) line_len = sizeof(buffer);
|
|
|
|
/*
|
|
** backtrack to the previous predicate
|
|
** and assume that it is at indent level 0
|
|
*/
|
|
i = MB_code_get_pred_addr(start);
|
|
|
|
if (i != MB_CODE_INVALID_ADR) {
|
|
/* work out the indent level at the start */
|
|
while (i != start) {
|
|
indent = MB_str_bytecode(ms,
|
|
i, NULL, 0, indent);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* Show the code */
|
|
for (; i != end+1; i++) {
|
|
indent = MB_str_bytecode(ms, i,
|
|
buffer, line_len, indent);
|
|
fprintf(fp, "%s%p %s\n",
|
|
(i == ip) ? "-> " : " ",
|
|
i,
|
|
buffer);
|
|
}
|
|
}
|
|
|