Misc #11276 ยป 0001-compile.c-convert-to-use-ccan-list.patch
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;
|
||
-
|