Project

General

Profile

Misc #11276 ยป 0001-compile.c-convert-to-use-ccan-list.patch

normalperson (Eric Wong), 06/17/2015 11:54 PM

View differences:

compile.c
ISEQ_ELEMENT_INSN,
ISEQ_ELEMENT_ADJUST
} type;
struct iseq_link_element *next;
struct iseq_link_element *prev;
struct list_node iseq_node;
} LINK_ELEMENT;
typedef struct iseq_link_anchor {
LINK_ELEMENT anchor;
LINK_ELEMENT *last;
} LINK_ANCHOR;
typedef struct iseq_label_data {
LINK_ELEMENT link;
int label_no;
......
#define COMPILE_OK 1
#define COMPILE_NG 0
/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
* missing */
#define DECL_ANCHOR(name) \
LINK_ANCHOR *name, name##_body__ = {{0,},}
#define INIT_ANCHOR(name) \
(name##_body__.last = &name##_body__.anchor, name = &name##_body__)
LIST_HEAD(name##_body__); struct list_head *name = &name##_body__
#define hide_obj(obj) do {OBJ_FREEZE(obj); RBASIC_CLEAR_CLASS(obj);} while (0)
......
#define gl_node_level iseq->compile_data->node_level
#endif
static void dump_disasm_list(LINK_ELEMENT *elem);
static void dump_disasm_list(struct list_head *anchor, LINK_ELEMENT *elem);
static int insn_data_length(INSN *iobj);
static int calc_sp_depth(int depth, INSN *iobj);
......
static LABEL *new_label_body(rb_iseq_t *iseq, long line);
static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * n, int);
static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
static int iseq_compile_each(rb_iseq_t *iseq, struct list_head *anchor, NODE * n, int);
static int iseq_setup(rb_iseq_t *iseq, struct list_head *anchor);
static int iseq_optimize(rb_iseq_t *iseq, struct list_head *anchor);
static int iseq_insns_unification(rb_iseq_t *iseq, struct list_head *anchor);
static int iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl);
static int iseq_set_exception_local_table(rb_iseq_t *iseq);
static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * node);
static int iseq_set_arguments(rb_iseq_t *iseq, struct list_head *anchor, NODE * node);
static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, struct list_head *anchor);
static int iseq_set_sequence(rb_iseq_t *iseq, struct list_head *anchor);
static int iseq_set_exception_table(rb_iseq_t *iseq);
static int iseq_set_optargs_table(rb_iseq_t *iseq);
/*
* To make Array to LinkedList, use link_anchor
*/
static void
verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *anchor)
{
#if CPDEBUG
int flag = 0;
LINK_ELEMENT *list, *plist;
if (!compile_debug) return;
list = anchor->anchor.next;
plist = &anchor->anchor;
while (list) {
if (plist != list->prev) {
flag += 1;
}
plist = list;
list = list->next;
}
if (anchor->last != plist && anchor->last != 0) {
flag |= 0x70000;
}
if (flag != 0) {
rb_bug("list verify error: %08x (%s)", flag, info);
}
#endif
}
#if CPDEBUG < 0
#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
#endif
/*
* elem1, elem2 => elem1, elem2, elem
*/
static void
ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem)
ADD_ELEM(ISEQ_ARG_DECLARE struct list_head *anchor, LINK_ELEMENT *elem)
{
elem->prev = anchor->last;
anchor->last->next = elem;
anchor->last = elem;
verify_list("add", anchor);
list_add_tail(anchor, &elem->iseq_node);
}
/*
* elem1, before, elem2 => elem1, before, elem, elem2
*/
static void
APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
APPEND_ELEM(ISEQ_ARG_DECLARE struct list_head *anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
{
elem->prev = before;
elem->next = before->next;
elem->next->prev = elem;
before->next = elem;
if (before == anchor->last) anchor->last = elem;
verify_list("add", anchor);
list_add_after(anchor, &before->iseq_node, &elem->iseq_node);
}
#if CPDEBUG < 0
#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
......
return COMPILE_OK;
}
struct validate_arg {
rb_iseq_t *iseq;
struct list_head *anchor;
};
static int
validate_label(st_data_t name, st_data_t label, st_data_t arg)
{
rb_iseq_t *iseq = (rb_iseq_t *)arg;
struct validate_arg *v = (struct validate_arg *)arg;
rb_iseq_t *iseq = v->iseq;
struct list_head *anchor = v->anchor;
LABEL *lobj = (LABEL *)label;
if (!lobj->link.next) {
if (!list_next(anchor, &lobj->link, iseq_node)) {
do {
int ret;
COMPILE_ERROR((ruby_sourcefile, lobj->position,
......
}
static void
validate_labels(rb_iseq_t *iseq, st_table *labels_table)
validate_labels(struct list_head *anchor, rb_iseq_t *iseq, st_table *labels_table)
{
st_foreach(labels_table, validate_label, (st_data_t)iseq);
struct validate_arg v;
v.iseq = iseq;
v.anchor = anchor;
st_foreach(labels_table, validate_label, (st_data_t)&v);
if (!NIL_P(iseq->compile_data->err_info)) {
rb_exc_raise(iseq->compile_data->err_info);
}
......
{
DECL_ANCHOR(ret);
rb_iseq_t *iseq;
INIT_ANCHOR(ret);
GetISeqPtr(self, iseq);
if (node == 0) {
......
* elem1, elemX => elem1, elem2, elemX
*/
static void
INSERT_ELEM_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
INSERT_ELEM_NEXT(struct list_head *anchor, LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
{
elem2->next = elem1->next;
elem2->prev = elem1;
elem1->next = elem2;
if (elem2->next) {
elem2->next->prev = elem2;
}
list_add_after(anchor, &elem1->iseq_node, &elem2->iseq_node);
}
/*
......
static void
REPLACE_ELEM(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
{
elem2->prev = elem1->prev;
elem2->next = elem1->next;
if (elem1->prev) {
elem1->prev->next = elem2;
}
if (elem1->next) {
elem1->next->prev = elem2;
}
list_swap(&elem1->iseq_node, &elem2->iseq_node);
}
static void
REMOVE_ELEM(LINK_ELEMENT *elem)
{
elem->prev->next = elem->next;
if (elem->next) {
elem->next->prev = elem->prev;
}
list_del(&elem->iseq_node);
}
static LINK_ELEMENT *
FIRST_ELEMENT(LINK_ANCHOR *anchor)
FIRST_ELEMENT(struct list_head *anchor)
{
return anchor->anchor.next;
return list_top(anchor, LINK_ELEMENT, iseq_node);
}
static LINK_ELEMENT *
POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
POP_ELEMENT(ISEQ_ARG_DECLARE struct list_head *anchor)
{
LINK_ELEMENT *elem = anchor->last;
anchor->last = anchor->last->prev;
anchor->last->next = 0;
verify_list("pop", anchor);
/* list_pop in ccan/list removes the first element, not the last */
LINK_ELEMENT *elem = list_tail(anchor, LINK_ELEMENT, iseq_node);
if (elem)
REMOVE_ELEM(elem);
return elem;
}
#if CPDEBUG < 0
#define POP_ELEMENT(anchor) POP_ELEMENT(iseq, (anchor))
#endif
static int
LIST_SIZE_ZERO(LINK_ANCHOR *anchor)
{
if (anchor->anchor.next == 0) {
return 1;
}
else {
return 0;
}
}
/*
* anc1: e1, e2, e3
* anc2: e4, e5
*#=>
* anc1: e1, e2, e3, e4, e5
* anc2: e4, e5 (broken)
* anc2: (empty)
*/
static void
APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
APPEND_LIST(ISEQ_ARG_DECLARE struct list_head *anc1, struct list_head *anc2)
{
if (anc2->anchor.next) {
anc1->last->next = anc2->anchor.next;
anc2->anchor.next->prev = anc1->last;
anc1->last = anc2->last;
}
verify_list("append", anc1);
list_append_list(anc1, anc2);
}
#if CPDEBUG < 0
#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
......
* anc2: e4, e5
*#=>
* anc1: e4, e5, e1, e2, e3
* anc2: e4, e5 (broken)
* anc2: (empty)
*/
static void
INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2)
INSERT_LIST(ISEQ_ARG_DECLARE struct list_head *anc1, struct list_head *anc2)
{
if (anc2->anchor.next) {
LINK_ELEMENT *first = anc1->anchor.next;
anc1->anchor.next = anc2->anchor.next;
anc1->anchor.next->prev = &anc1->anchor;
anc2->last->next = first;
if (first) {
first->prev = anc2->last;
}
else {
anc1->last = anc2->last;
}
}
verify_list("append", anc1);
list_prepend_list(anc1, anc2);
}
#if CPDEBUG < 0
#define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, (anc1), (anc2))
#endif
#if CPDEBUG && 0
static void
debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor)
{
LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
printf("----\n");
printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
anchor->anchor.next, anchor->last);
while (list) {
printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
list->prev, FIX2INT(list->type));
list = list->next;
}
printf("----\n");
dump_disasm_list(anchor->anchor.next);
verify_list("debug list", anchor);
}
#if CPDEBUG < 0
#define debug_list(anc) debug_list(iseq, (anc))
#endif
#endif
static LABEL *
new_label_body(rb_iseq_t *iseq, long line)
{
LABEL *labelobj = compile_data_alloc_label(iseq);
labelobj->link.type = ISEQ_ELEMENT_LABEL;
labelobj->link.next = 0;
labelobj->label_no = iseq->compile_data->label_no++;
labelobj->sc_state = 0;
......
{
ADJUST *adjust = compile_data_alloc_adjust(iseq);
adjust->link.type = ISEQ_ELEMENT_ADJUST;
adjust->link.next = 0;
adjust->label = label;
adjust->line_no = line;
return adjust;
......
/* printf("insn_id: %d, line: %d\n", insn_id, line_no); */
iobj->link.type = ISEQ_ELEMENT_INSN;
iobj->link.next = 0;
iobj->insn_id = insn_id;
iobj->line_no = line_no;
iobj->operands = argv;
......
}
static int
iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
iseq_setup(rb_iseq_t *iseq, struct list_head *anchor)
{
/* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
if (compile_debug > 5)
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(anchor, FIRST_ELEMENT(anchor));
debugs("[compile step 3.1 (iseq_optimize)]\n");
iseq_optimize(iseq, anchor);
if (compile_debug > 5)
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(anchor, FIRST_ELEMENT(anchor));
if (iseq->compile_data->option->instructions_unification) {
debugs("[compile step 3.2 (iseq_insns_unification)]\n");
iseq_insns_unification(iseq, anchor);
if (compile_debug > 5)
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(anchor, FIRST_ELEMENT(anchor));
}
if (iseq->compile_data->option->stack_caching) {
debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
iseq_set_sequence_stackcaching(iseq, anchor);
if (compile_debug > 5)
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(anchor, FIRST_ELEMENT(anchor));
}
debugs("[compile step 4.1 (iseq_set_sequence)]\n");
iseq_set_sequence(iseq, anchor);
if (compile_debug > 5)
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(anchor, FIRST_ELEMENT(anchor));
debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
iseq_set_exception_table(iseq);
......
}
static int
iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
iseq_set_arguments(rb_iseq_t *iseq, struct list_head *optargs, NODE *node_args)
{
debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
......
ruby insn object list -> raw instruction sequence
*/
static int
iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
iseq_set_sequence(rb_iseq_t *iseq, struct list_head *anchor)
{
LABEL *lobj;
INSN *iobj;
......
int k, pos, sp, stack_max = 0, line = 0;
/* set label position */
list = FIRST_ELEMENT(anchor);
k = pos = 0;
while (list) {
list_for_each(anchor, list, iseq_node) {
switch (list->type) {
case ISEQ_ELEMENT_INSN:
{
......
break;
}
default:
dump_disasm_list(FIRST_ELEMENT(anchor));
dump_disasm_list(list);
dump_disasm_list(anchor, FIRST_ELEMENT(anchor));
dump_disasm_list(anchor, list);
rb_compile_error(RSTRING_PTR(iseq->location.path), line,
"error: set_sequence");
break;
}
list = list->next;
}
/* make instruction sequence */
......
iseq->callinfo_entries = ALLOC_N(rb_call_info_t, iseq->callinfo_size);
/* MEMZERO(iseq->callinfo_entries, rb_call_info_t, iseq->callinfo_size); */
list = FIRST_ELEMENT(anchor);
k = pos = sp = 0;
while (list) {
list_for_each(anchor, list, iseq_node) {
switch (list->type) {
case ISEQ_ELEMENT_INSN:
{
......
/* operand check */
if (iobj->operand_size != len - 1) {
/* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
dump_disasm_list(list);
dump_disasm_list(anchor, list);
rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
"operand size miss! (%d for %d)",
iobj->operand_size, len - 1);
......
/* ignore */
break;
}
list = list->next;
}
iseq->iseq_encoded = (void *)generated_iseq;
......
}
static LINK_ELEMENT *
get_destination_insn(INSN *iobj)
get_destination_insn(struct list_head *anchor, INSN *iobj)
{
LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
LINK_ELEMENT *list;
LINK_ELEMENT *list = list_next(anchor, &lobj->link, iseq_node);
list = lobj->link.next;
while (list) {
if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
break;
}
list = list->next;
list = list_next(anchor, list, iseq_node);
}
return list;
}
static LINK_ELEMENT *
get_next_insn(INSN *iobj)
get_next_insn(struct list_head *anchor, INSN *iobj)
{
LINK_ELEMENT *list = iobj->link.next;
LINK_ELEMENT *list = list_next(anchor, &iobj->link, iseq_node);
while (list) {
if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
return list;
}
list = list->next;
list = list_next(anchor, list, iseq_node);
}
return 0;
}
static LINK_ELEMENT *
get_prev_insn(INSN *iobj)
get_prev_insn(struct list_head *anchor, INSN *iobj)
{
LINK_ELEMENT *list = iobj->link.prev;
LINK_ELEMENT *list = list_prev(anchor, &iobj->link, iseq_node);
while (list) {
if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) {
return list;
}
list = list->prev;
list = list_prev(anchor, list, iseq_node);
}
return 0;
}
static int
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
iseq_peephole_optimize(rb_iseq_t *iseq, struct list_head *anchor,
LINK_ELEMENT *list, const int do_tailcallopt)
{
INSN *iobj = (INSN *)list;
again:
......
* => in this case, first jump instruction should jump to
* LABEL2 directly
*/
diobj = (INSN *)get_destination_insn(iobj);
niobj = (INSN *)get_next_insn(iobj);
diobj = (INSN *)get_destination_insn(anchor, iobj);
niobj = (INSN *)get_next_insn(anchor, iobj);
if (diobj == niobj) {
/*
......
BIN(pop), 0, 0);
/* replace */
REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj);
INSERT_ELEM_NEXT((LINK_ELEMENT *)eiobj, (LINK_ELEMENT *)popiobj);
INSERT_ELEM_NEXT(anchor, (LINK_ELEMENT *)eiobj,
(LINK_ELEMENT *)popiobj);
iobj = popiobj;
}
/*
......
* ...
* L2:
*/
else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 &&
else if ((piobj = (INSN *)get_prev_insn(anchor, iobj)) != 0 &&
(piobj->insn_id == BIN(branchif) ||
piobj->insn_id == BIN(branchunless))) {
if (niobj == (INSN *)get_destination_insn(piobj)) {
if (niobj == (INSN *)get_destination_insn(anchor, piobj)) {
piobj->insn_id = (piobj->insn_id == BIN(branchif))
? BIN(branchunless) : BIN(branchif);
OPERAND_AT(piobj, 0) = OPERAND_AT(iobj, 0);
......
* =>
* if L2
*/
INSN *nobj = (INSN *)get_destination_insn(iobj);
INSN *nobj = (INSN *)get_destination_insn(anchor, iobj);
if (nobj->insn_id == BIN(jump)) {
OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
}
......
* send ..., ... | VM_CALL_TAILCALL, ...
* leave # unreachable
*/
INSN *piobj = (INSN *)get_prev_insn((INSN *)list);
INSN *piobj = (INSN *)get_prev_insn(anchor, (INSN *)list);
enum ruby_vminsn_type previ = piobj->insn_id;
if (previ == BIN(send) || previ == BIN(opt_send_without_block) || previ == BIN(invokesuper)) {
......
}
static int
iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
iseq_optimize(rb_iseq_t *iseq, struct list_head *anchor)
{
LINK_ELEMENT *list;
LINK_ELEMENT *list, *next;
const int do_peepholeopt = iseq->compile_data->option->peephole_optimization;
const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization;
const int do_si = iseq->compile_data->option->specialized_instruction;
const int do_ou = iseq->compile_data->option->operands_unification;
list = FIRST_ELEMENT(anchor);
while (list) {
list_for_each_safe(anchor, list, next, iseq_node) {
if (list->type == ISEQ_ELEMENT_INSN) {
if (do_peepholeopt) {
iseq_peephole_optimize(iseq, list, do_tailcallopt);
iseq_peephole_optimize(iseq, anchor, list, do_tailcallopt);
}
if (do_si) {
iseq_specialized_instruction(iseq, (INSN *)list);
......
insn_operands_unification((INSN *)list);
}
}
list = list->next;
}
return COMPILE_OK;
}
#if OPT_INSTRUCTIONS_UNIFICATION
static INSN *
new_unified_insn(rb_iseq_t *iseq,
int insn_id, int size, LINK_ELEMENT *seq_list)
new_unified_insn(rb_iseq_t *iseq, int insn_id, int size,
struct list_head *anchor, LINK_ELEMENT *seq_list)
{
INSN *iobj = 0;
LINK_ELEMENT *list = seq_list;
......
for (i = 0; i < size; i++) {
iobj = (INSN *)list;
argc += iobj->operand_size;
list = list->next;
list = list_next(anchor, list, iseq_node);
}
if (argc > 0) {
......
iobj = (INSN *)list;
MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
ptr += iobj->operand_size;
list = list->next;
list = list_next(anchor, list, iseq_node);
}
return new_insn_core(iseq, iobj->line_no, insn_id, argc, operands);
......
* It's future work (if compile time was bottle neck).
*/
static int
iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
iseq_insns_unification(rb_iseq_t *iseq, struct list_head *anchor)
{
#if OPT_INSTRUCTIONS_UNIFICATION
LINK_ELEMENT *list;
......
const int *const *entry = unified_insns_data[id];
for (j = 1; j < (intptr_t)entry[0]; j++) {
const int *unified = entry[j];
LINK_ELEMENT *li = list->next;
LINK_ELEMENT *li = list_next(anchor, list, iseq_node);
for (k = 2; k < unified[1]; k++) {
if (li->type != ISEQ_ELEMENT_INSN ||
((INSN *)li)->insn_id != unified[k]) {
goto miss;
}
li = li->next;
li = list_next(anchor, li, iseq_node);
}
/* matched */
niobj =
new_unified_insn(iseq, unified[0], unified[1] - 1,
list);
anchor, list);
/* insert to list */
niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
niobj->link.next = li;
APPEND_ELEM(anchor, &iobj->link, &niobj->link);
if (li) {
li->prev = (LINK_ELEMENT *)niobj;
APPEND_ELEM(anchor, &niobj->link, li);
}
list->prev->next = (LINK_ELEMENT *)niobj;
REMOVE_ELEM(&iobj->link);
list = (LINK_ELEMENT *)niobj;
break;
miss:;
}
}
}
list = list->next;
list = list_next(anchor, list, iseq_node);
}
#endif
return COMPILE_OK;
......
#include "opt_sc.inc"
static int
insn_set_sc_state(rb_iseq_t *iseq, INSN *iobj, int state)
insn_set_sc_state(struct list_head *anchor, rb_iseq_t *iseq, INSN *iobj, int state)
{
int nstate;
int insn_id;
......
if (lobj->sc_state != 0) {
if (lobj->sc_state != nstate) {
dump_disasm_list((LINK_ELEMENT *)iobj);
dump_disasm_list((LINK_ELEMENT *)lobj);
dump_disasm_list(anchor, (LINK_ELEMENT *)iobj);
dump_disasm_list(anchor, (LINK_ELEMENT *)lobj);
printf("\n-- %d, %d\n", lobj->sc_state, nstate);
rb_compile_error(RSTRING_PTR(iseq->location.path), iobj->line_no,
"insn_set_sc_state error\n");
......
#endif
static int
iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
iseq_set_sequence_stackcaching(rb_iseq_t *iseq, struct list_head *anchor)
{
#if OPT_STACK_CACHING
LINK_ELEMENT *list;
#if OPT_STACK_CACHING /* FIXME: bitrotten */
LINK_ELEMENT *list, *next;
int state, insn_id;
/* initialize */
state = SCS_XX;
list = FIRST_ELEMENT(anchor);
/* dump_disasm_list(list); */
/* dump_disasm_list(anchor, list); */
/* for each list element */
while (list) {
......
INSN *iobj = (INSN *)list;
insn_id = iobj->insn_id;
/* dump_disasm_list(list); */
/* dump_disasm_list(anchor, list); */
switch (insn_id) {
case BIN(nop):
......
if (state == SCS_AB || state == SCS_BA) {
state = (state == SCS_AB ? SCS_BA : SCS_AB);
next = list_next(anchor, list, iseq_node);
REMOVE_ELEM(list);
list = list->next;
list = next;
goto redo_point;
}
break;
......
"unreachable");
}
/* remove useless pop */
next = list_next(anchor, list, iseq_node);
REMOVE_ELEM(list);
list = list->next;
goto redo_point;
list = next;
continue;
}
default:;
/* none */
} /* end of switch */
normal_insn:
state = insn_set_sc_state(iseq, iobj, state);
state = insn_set_sc_state(anchor, iseq, iobj, state);
break;
}
case ISEQ_ELEMENT_LABEL:
......
default:
break;
}
list = list->next;
list = list_next(anchor, list, iseq_node);
}
#endif
return COMPILE_OK;
}
static int
compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int *cntp)
compile_dstr_fragments(rb_iseq_t *iseq, struct list_head *ret, NODE *node, int *cntp)
{
NODE *list = node->nd_next;
VALUE lit = node->nd_lit;
......
}
static int
compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
compile_dstr(rb_iseq_t *iseq, struct list_head *ret, NODE * node)
{
int cnt;
compile_dstr_fragments(iseq, ret, node, &cnt);
......
}
static int
compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node)
compile_dregx(rb_iseq_t *iseq, struct list_head *ret, NODE * node)
{
int cnt;
compile_dstr_fragments(iseq, ret, node, &cnt);
......
}
static int
compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
compile_branch_condition(rb_iseq_t *iseq, struct list_head *ret, NODE * cond,
LABEL *then_label, LABEL *else_label)
{
switch (nd_type(cond)) {
......
}
static int
compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE * const root_node, rb_call_info_kw_arg_t ** const kw_arg_ptr)
compile_array_keyword_arg(rb_iseq_t *iseq, struct list_head *ret, const NODE * const root_node, rb_call_info_kw_arg_t ** const kw_arg_ptr)
{
if (kw_arg_ptr == NULL) return FALSE;
......
};
static int
compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
compile_array_(rb_iseq_t *iseq, struct list_head *ret, NODE* node_root,
enum compile_array_type_t type, rb_call_info_kw_arg_t **keywords_ptr, int poped)
{
NODE *node = node_root;
......
NODE *kw = 0;
const int max = 0x100;
DECL_ANCHOR(anchor);
INIT_ANCHOR(anchor);
for (i=0; i<max && node; i++, len++, node = node->nd_next) {
if (CPDEBUG > 0 && nd_type(node) != NODE_ARRAY) {
......
}
static VALUE
compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, enum compile_array_type_t type)
compile_array(rb_iseq_t *iseq, struct list_head *ret, NODE* node_root, enum compile_array_type_t type)
{
return compile_array_(iseq, ret, node_root, type, NULL, 0);
}
......
}
static int
when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, int only_special_literals, VALUE literals)
when_vals(rb_iseq_t *iseq, struct list_head *cond_seq, NODE *vals, LABEL *l1, int only_special_literals, VALUE literals)
{
while (vals) {
NODE* val = vals->nd_head;
......
}
static int
compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node)
compile_massign_lhs(rb_iseq_t *iseq, struct list_head *ret, NODE *node)
{
switch (nd_type(node)) {
case NODE_ATTRASGN: {
......
}
case NODE_MASGN: {
DECL_ANCHOR(anchor);
INIT_ANCHOR(anchor);
COMPILE_POPED(anchor, "nest masgn lhs", node);
REMOVE_ELEM(FIRST_ELEMENT(anchor));
ADD_SEQ(ret, anchor);
......
}
default: {
DECL_ANCHOR(anchor);
INIT_ANCHOR(anchor);
COMPILE_POPED(anchor, "masgn lhs", node);
REMOVE_ELEM(FIRST_ELEMENT(anchor));
ADD_SEQ(ret, anchor);
......
}
static void
compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *lhsn)
compile_massign_opt_lhs(rb_iseq_t *iseq, struct list_head *ret, NODE *lhsn)
{
if (lhsn) {
compile_massign_opt_lhs(iseq, ret, lhsn->nd_next);
......
}
static int
compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret,
compile_massign_opt(rb_iseq_t *iseq, struct list_head *ret,
NODE *rhsn, NODE *orig_lhsn)
{
VALUE mem[64];
......
}
static void
adjust_stack(rb_iseq_t *iseq, LINK_ANCHOR *ret, int line, int rlen, int llen)
adjust_stack(rb_iseq_t *iseq, struct list_head *ret, int line, int rlen, int llen)
{
if (rlen < llen) {
do {ADD_INSN(ret, line, putnil);} while (++rlen < llen);
......
}
static int
compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int poped)
compile_massign(rb_iseq_t *iseq, struct list_head *ret, NODE *node, int poped)
{
NODE *rhsn = node->nd_value;
NODE *splatn = node->nd_args;
......
int expand = 1;
DECL_ANCHOR(lhsseq);
INIT_ANCHOR(lhsseq);
while (lhsn) {
compile_massign_lhs(iseq, lhsseq, lhsn->nd_head);
llen += 1;
......
ADD_INSN(ret, nd_line(node), dup);
}
else if (!lhs_splat) {
INSN *last = (INSN*)ret->last;
INSN *last = (INSN *)list_tail(ret, LINK_ELEMENT, iseq_node);
if (last->link.type == ISEQ_ELEMENT_INSN &&
last->insn_id == BIN(newarray) &&
last->operand_size == 1) {
......
static int
compile_colon2(rb_iseq_t *iseq, NODE * node,
LINK_ANCHOR *pref, LINK_ANCHOR *body)
struct list_head *pref, struct list_head *body)
{
switch (nd_type(node)) {
case NODE_CONST:
......
}
static VALUE
compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath)
compile_cpath(struct list_head *ret, rb_iseq_t *iseq, NODE *cpath)
{
if (nd_type(cpath) == NODE_COLON3) {
/* toplevel class ::Foo */
......
#define defined_expr defined_expr0
static int
defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
defined_expr(rb_iseq_t *iseq, struct list_head *ret,
NODE *node, LABEL **lfinish, VALUE needstr)
{
enum defined_type expr_type = 0;
......
#undef defined_expr
static int
defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret,
defined_expr(rb_iseq_t *iseq, struct list_head *ret,
NODE *node, LABEL **lfinish, VALUE needstr)
{
LINK_ELEMENT *lcur = ret->last;
LINK_ELEMENT *lcur = list_tail(ret, LINK_ELEMENT, iseq_node);
int done = defined_expr0(iseq, ret, node, lfinish, needstr);
if (lfinish[1]) {
int line = nd_line(node);
......
}
static void
add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq, int is_return)
add_ensure_iseq(struct list_head *ret, rb_iseq_t *iseq, int is_return)
{
struct iseq_compile_data_ensure_node_stack *enlp =
iseq->compile_data->ensure_node_stack;
struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
DECL_ANCHOR(ensure);
INIT_ANCHOR(ensure);
while (enlp) {
if (enlp->erange != 0) {
DECL_ANCHOR(ensure_part);
LABEL *lstart = NEW_LABEL(0);
LABEL *lend = NEW_LABEL(0);
INIT_ANCHOR(ensure_part);
add_ensure_range(iseq, enlp->erange, lstart, lend);
......
}
static VALUE
setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned int *flag, rb_call_info_kw_arg_t **keywords)
setup_args(rb_iseq_t *iseq, struct list_head *args, NODE *argn, unsigned int *flag, rb_call_info_kw_arg_t **keywords)
{
VALUE argc = INT2FIX(0);
int nsplat = 0;
DECL_ANCHOR(arg_block);
DECL_ANCHOR(args_splat);
INIT_ANCHOR(arg_block);
INIT_ANCHOR(args_splat);
if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
COMPILE(arg_block, "block", argn->nd_body);
*flag |= VM_CALL_ARGS_BLOCKARG;
......
int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY);
DECL_ANCHOR(tmp);
INIT_ANCHOR(tmp);
COMPILE(tmp, "args (cat: splat)", argn->nd_body);
if (nd_type(argn) == NODE_ARGSCAT) {
ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse);
......
}
}
if (!LIST_SIZE_ZERO(args_splat)) {
if (!list_empty(args_splat)) {
ADD_SEQ(args, args_splat);
}
......
}
static VALUE
build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *body)
build_postexe_iseq(rb_iseq_t *iseq, struct list_head *ret, NODE *body)
{
int line = nd_line(body);
VALUE argc = INT2FIX(0);
......
poped: This node will be poped
*/
static int
iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
iseq_compile_each(rb_iseq_t *iseq, struct list_head *ret, NODE * node, int poped)
{
enum node_type type;
LINK_ELEMENT *saved_last_element = 0;
......
if (node->flags & NODE_FL_NEWLINE) {
iseq->compile_data->last_line = line;
ADD_TRACE(ret, line, RUBY_EVENT_LINE);
saved_last_element = ret->last;
saved_last_element = list_tail(ret, LINK_ELEMENT, iseq_node);
}
}
......
DECL_ANCHOR(else_seq);
LABEL *then_label, *else_label, *end_label;
INIT_ANCHOR(cond_seq);
INIT_ANCHOR(then_seq);
INIT_ANCHOR(else_seq);
then_label = NEW_LABEL(line);
else_label = NEW_LABEL(line);
end_label = NEW_LABEL(line);
......
int only_special_literals = 1;
VALUE literals = rb_hash_new();
INIT_ANCHOR(head);
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);
rb_hash_tbl_raw(literals)->type = &cdhash_type;
if (node->nd_head == 0) {
......
LABEL *endlabel;
DECL_ANCHOR(body_seq);
INIT_ANCHOR(body_seq);
endlabel = NEW_LABEL(line);
while (node && nd_type(node) == NODE_WHEN) {
......
struct iseq_compile_data_ensure_node_stack enl;
struct ensure_range *erange;
INIT_ANCHOR(ensr);
COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr);
er.begin = lstart;
......
ADD_LABEL(ret, lstart);
COMPILE_(ret, "ensure head", node->nd_head, poped);
ADD_LABEL(ret, lend);
if (ensr->anchor.next == 0) {
if (list_empty(ensr)) {
ADD_INSN(ret, line, nop);
}
else {
......
case NODE_BLOCK_PASS:
boff = 1;
default:
INIT_ANCHOR(args);
argc = setup_args(iseq, args, node->nd_args->nd_head, &flag, NULL);
ADD_SEQ(ret, args);
}
......
VALUE parent_block = iseq->compile_data->current_block;
iseq->compile_data->current_block = Qfalse;
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
#if SUPPORT_JOKE
if (nd_type(node) == NODE_VCALL) {
ID id_bitblt;
......
rb_call_info_kw_arg_t *keywords = NULL;
VALUE parent_block = iseq->compile_data->current_block;
INIT_ANCHOR(args);
iseq->compile_data->current_block = Qfalse;
if (nd_type(node) == NODE_SUPER) {
VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
......
DECL_ANCHOR(list);
int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY;
INIT_ANCHOR(list);
switch (type) {
case NODE_ARRAY:
compile_array(iseq, list, node->nd_head, COMPILE_ARRAY_TYPE_HASH);
......
unsigned int flag = 0;
rb_call_info_kw_arg_t *keywords = NULL;
INIT_ANCHOR(args);
if (iseq->type == ISEQ_TYPE_TOP) {
COMPILE_ERROR((ERROR_ARGS "Invalid yield"));
}
......
DECL_ANCHOR(recv);
DECL_ANCHOR(val);
INIT_ANCHOR(recv);
INIT_ANCHOR(val);
switch (nd_type(node)) {
case NODE_MATCH:
ADD_INSN1(recv, line, putobject, node->nd_lit);
......
}
if (iseq->compile_data->option->specialized_instruction) {
LINK_ELEMENT *last = list_tail(recv, LINK_ELEMENT, iseq_node);
/* TODO: detect by node */
if (recv->last == recv->anchor.next &&
INSN_OF(recv->last) == BIN(putobject) &&
if (last == list_top(recv, LINK_ELEMENT, iseq_node) &&
INSN_OF(last) == BIN(putobject) &&
nd_type(node) == NODE_MATCH2) {
ADD_SEQ(ret, val);
ADD_INSN1(ret, line, opt_regexpmatch1,
OPERAND_AT(recv->last, 0));
OPERAND_AT(last, 0));
}
else {
ADD_SEQ(ret, recv);
......
DECL_ANCHOR(pref);
DECL_ANCHOR(body);
INIT_ANCHOR(pref);
INIT_ANCHOR(body);
compile_colon2(iseq, node, pref, body);
if (LIST_SIZE_ZERO(pref)) {
if (list_empty(pref)) {
if (iseq->compile_data->option->inline_const_cache) {
ADD_INSN2(ret, line, getinlinecache, lend, INT2FIX(ic_index));
}
......
break;
}
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
flag |= COMPILE_RECV(recv, "recv", node);
......
/* check & remove redundant trace(line) */
if (saved_last_element && ret /* ret can be 0 when error */ &&
ret->last == saved_last_element &&
list_tail(ret, LINK_ELEMENT, iseq_node) == saved_last_element &&
((INSN *)saved_last_element)->insn_id == BIN(trace)) {
POP_ELEMENT(ret);
}
......
}
static void
dump_disasm_list(struct iseq_link_element *link)
dump_disasm_list(struct list_head *anchor, struct iseq_link_element *link)
{
int pos = 0;
INSN *iobj;
......
/* ignore */
rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
}
link = link->next;
link = list_next(anchor, link, iseq_node);
}
printf("---------------------\n");
}
......
return (VALUE)new_callinfo(iseq, mid, orig_argc, block, flag, kw_arg);
}
static int
iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
iseq_build_from_ary_body(rb_iseq_t *iseq, struct list_head *anchor,
VALUE body, struct st_table *labels_table)
{
/* TODO: body should be frozen */
......
rb_raise(rb_eTypeError, "unexpected object for instruction");
}
}
validate_labels(iseq, labels_table);
validate_labels(anchor, iseq, labels_table);
st_free_table(labels_table);
iseq_setup(iseq, anchor);
return COMPILE_OK;
......
VALUE keywords = rb_hash_aref(params, SYM(keyword));
VALUE sym_arg_rest = ID2SYM(rb_intern("#arg_rest"));
DECL_ANCHOR(anchor);
INIT_ANCHOR(anchor);
len = RARRAY_LENINT(locals);
iseq->local_table_size = len;
......
static VALUE
method_for_self(VALUE name, VALUE arg, rb_insn_func_t func,
VALUE (*build)(rb_iseq_t *, LINK_ANCHOR *, VALUE))
VALUE (*build)(rb_iseq_t *, struct list_head *, VALUE))
{
VALUE path, absolute_path;
accessor_args acc;
......
}
static VALUE
for_self_aref(rb_iseq_t *iseq, LINK_ANCHOR *ret, VALUE a)
for_self_aref(rb_iseq_t *iseq, struct list_head *ret, VALUE a)
{
const accessor_args *const args = (void *)a;
const int line = args->line;
......
}
static VALUE
for_self_aset(rb_iseq_t *iseq, LINK_ANCHOR *ret, VALUE a)
for_self_aset(rb_iseq_t *iseq, struct list_head *ret, VALUE a)
{
const accessor_args *const args = (void *)a;
const int line = args->line;
-
    (1-1/1)