pike.git/
src/
docode.c
Branch:
Tag:
Non-build tags
All tags
No tags
2019-08-27
2019-08-27 10:03:13 by Henrik Grubbström (Grubba) <grubba@grubba.org>
3e80aad094b685f09caa5cf3eebccb2ac9f4f8ff (
203
lines) (+
173
/-
30
)
[
Show
|
Annotate
]
Branch:
master
Compiler: First go at generating code for generators.
444:
} }
+
static INT32 count_continue_returns(node *n)
+
{
+
INT32 ret = 0;
+
if(!n) return 0;
+
switch(n->token)
+
{
+
case F_RETURN:
+
/* FIXME: continue returns in expressions are likely to be broken. */
+
if (CDR(n) && CDR(n)->u.sval.u.integer) ret = 1;
+
+
/* FALLTHRU */
+
default:
+
if(car_is_node(n)) ret += count_continue_returns(CAR(n));
+
if(cdr_is_node(n)) ret += count_continue_returns(CDR(n));
+
return ret;
+
}
+
}
+
static int has_automap(node *n) { if(!n) return 0;
2135:
* So far all switches are implemented with a binsearch lookup. * It stores the case values in the programs area for constants. * It also has a jump-table in the program itself, for every index in
-
* the array of cases, there
is
2
indexes
in the jumptable, and one extra.
+
* the array of cases, there
are
2
indices
in the jumptable, and one extra.
* The first entry in the jumptable is used if you call switch with * a value that is ranked lower than all the indexes in the array of * cases. (Ranked by the binsearch that is) The second is used if it
2462:
case F_RETURN: { struct statement_label *p; int in_catch = 0;
+
int continue_label = -1;
do_docode(CAR(n),0); /* Insert the appropriate number of F_ESCAPE_CATCH. The rest of
2490:
} }
+
if (Pike_compiler->compiler_frame->generator_local != -1) {
+
if (CDR(n) && CDR(n)->u.sval.u.integer) {
+
/* Continue return. */
+
continue_label = alloc_label();
+
/* NB: Subtract 1 to compensate for starting cases at -1. */
+
emit1(F_NUMBER,
+
Pike_compiler->compiler_frame->generator_index-1);
+
} else {
+
emit1(F_NUMBER, -1);
+
}
+
emit1(F_ASSIGN_LOCAL_AND_POP,
+
Pike_compiler->compiler_frame->generator_local);
+
}
+
emit0(in_catch ? F_VOLATILE_RETURN : F_RETURN);
-
+
+
if (continue_label != -1) {
+
Pike_compiler->compiler_frame->generator_jumptable[
+
Pike_compiler->compiler_frame->generator_index++] =
+
ins_label(continue_label);
+
}
return 0; }
2789:
return 1; }
+
case F_GENERATOR:
+
{
+
tmp1 = do_docode(CAR(n), 0);
+
if ((tmp1 != 1) || !CAR(n) || (CAR(n)->token != F_TRAMPOLINE)) {
+
emit0(F_UNDEFINED);
+
return 1;
+
}
+
emit1(F_GENERATOR, CAR(n)->u.trampoline.ident);
+
return 1;
+
}
+
case F_VAL_LVAL: case F_FOREACH_VAL_LVAL: ret = do_docode(CAR(n),flags);
2878:
struct compilation *c = THIS_COMPILATION; struct reference *id = NULL; INT32 entry_point;
+
INT32 generator_switch = -1, *generator_jumptable = NULL;
int aggregate_cnum = -1; int save_stack_depth = current_stack_depth; int save_label_no = label_no;
2896:
emit0(F_ENTRY); emit0(F_START_FUNCTION);
+
if (Pike_compiler->compiler_frame->generator_local != -1) {
+
INT32 e, states;
+
/* Emit the state-machine switch for the generator. */
+
emit1(F_LOCAL, Pike_compiler->compiler_frame->generator_local);
+
generator_switch = emit1(F_SWITCH, 0);
+
emit1(F_ALIGN, sizeof(INT32));
+
+
/* NB: Three implicit states:
+
* -1: return UNDEFINED; // Termination state.
+
* 0: code // Code start.
+
* ...
+
* *: return UNDEFINED; // Termination state (again).
+
*
+
* Jumptable:
+
*
+
* jmp_index case_index case_value label
+
* 0 - - Terminate
+
* 1 0 0 Start
+
* 2 - 1 Cont #0
+
* ...
+
* n+2 (n+2)>>1 n+1 Cont #n
+
* n+3 - - Terminate
+
*
+
* Note that the above requires an even number of continuation states.
+
* We therefore add an extra termination state if we have an odd
+
* number of continuation states.
+
*/
+
states = count_continue_returns(n);
+
+
Pike_compiler->compiler_frame->generator_index = 0;
+
Pike_compiler->compiler_frame->generator_jumptable =
+
xalloc(sizeof(INT32) * (states + (states & 1) + 3));
+
generator_jumptable = xalloc(sizeof(INT32) * (states + (states & 1) + 3));
+
+
for (e = 0; e < states + (states & 1) + 3; e++) {
+
generator_jumptable[e] = (INT32)emit1(F_POINTER, 0);
+
Pike_compiler->compiler_frame->generator_jumptable[e] = -1;
+
}
+
emit0(F_NOTREACHED);
+
+
/* Termination state. (-1, default) */
+
Pike_compiler->compiler_frame->generator_jumptable[
+
Pike_compiler->compiler_frame->generator_index++] = ins_label(-1);
+
emit0(F_UNDEFINED);
+
emit0(F_RETURN);
+
+
/* Start. (0) */
+
Pike_compiler->compiler_frame->generator_jumptable[
+
Pike_compiler->compiler_frame->generator_index++] = ins_label(-1);
+
} else {
if (Pike_compiler->compiler_frame->num_args) { emit2(F_FILL_STACK, Pike_compiler->compiler_frame->num_args, 1); }
2928:
if (Pike_compiler->compiler_frame->lexical_scope & SCOPE_SCOPE_USED) { emit_save_locals(Pike_compiler->compiler_frame); }
+
}
if(id && (id->id_flags & ID_INLINE)) {
2937:
DO_CODE_BLOCK(n);
-
if(Pike_compiler->compiler_frame->recur_label > 0)
+
if
(
generator_switch != -1) {
+
INT32 e;
+
struct svalue *save_sp =
Pike_
sp;
+
+
/* Termination state. (-1, default) */
+
if (Pike_
compiler->compiler_frame->
generator_index & 1) {
+
Pike_compiler->compiler_frame->generator_jumptable[
+
Pike_compiler->compiler_frame->generator_index++] =
+
Pike_compiler->compiler_frame->generator_jumptable[0];
+
}
+
Pike_compiler->compiler_frame->generator_jumptable[
+
Pike_compiler->compiler_frame->generator_index++] =
+
Pike_compiler->compiler_frame->generator_jumptable[0];
+
+
for (e = 0; e < Pike_compiler->compiler_frame->generator_index; e++) {
+
INT32 jmp = Pike_compiler->compiler_frame->generator_jumptable[e];
+
if (jmp < 0) {
+
yywarning("Lost track of continue return #%d.\n", e - 2);
+
jmp = Pike_compiler->compiler_frame->generator_jumptable[0];
+
}
+
if (!generator_jumptable[e]) {
+
my_yyerror("Lost address for switch pointer #%d.\n", e);
+
} else {
+
update_arg(generator_jumptable[e], jmp);
+
}
+
}
+
+
/* NB: For eg 5 entries (-1, 0, 1, 2, (3)), we need 2 entries in the array
+
* ({ 0, 2 }).
+
*/
+
for (e = 0; e < Pike_compiler->compiler_frame->generator_index-1; e += 2) {
+
push_int(e);
+
}
+
f_aggregate(Pike_sp - save_sp);
+
+
update_arg(generator_switch, store_constant(Pike_sp - 1, 1, 0));
+
pop_stack();
+
} else if(Pike_compiler->compiler_frame->
recur_label > 0)
{ #ifdef PIKE_DEBUG if(l_flag)
2994:
{ INT32 entry_point; int label_no_save = label_no;
+
int generator_local_save = Pike_compiler->compiler_frame->generator_local;
struct byte_buffer instrbuf_save = instrbuf; int stack_depth_save = current_stack_depth; struct statement_label *label_save = current_label;
3003:
current_stack_depth = 0; current_label = &top_statement_label_dummy; /* Fix these two to */ top_statement_label_dummy.cleanups = 0; /* please F_PUSH_ARRAY. */
+
Pike_compiler->compiler_frame->generator_local = -1;
init_bytecode(); insert_opcode0(F_ENTRY, n->line_number, n->current_file);
3012:
entry_point = assemble(0); /* Don't store linenumbers. */ instrbuf=instrbuf_save;
+
Pike_compiler->compiler_frame->generator_local = generator_local_save;
label_no = label_no_save; current_stack_depth = stack_depth_save; current_label = label_save; top_statement_label_dummy.cleanups = top_cleanups_save; return entry_point; }