pike.git / src / docode.c

version» Context lines:

pike.git/src/docode.c:437:    return !!CAR(n)+!!CDR(n);       default:    ret=0;    if(car_is_node(n)) ret += count_cases(CAR(n));    if(cdr_is_node(n)) ret += count_cases(CDR(n));    return ret;    }   }    + 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;    switch(n->token)    {    case F_AUTO_MAP_MARKER:    case F_AUTO_MAP:    return 1;       default:
pike.git/src/docode.c:2128:    /* Restore root->parent. */    root->parent = parent;    }    return (INT32)tmp1;          /* Switch:    * 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    * is equal to the first index. The third if it is greater than the    * first, but lesser than the second. The fourth if it is equal to    * the second.... etc. etc.    */       case F_SWITCH:    {
pike.git/src/docode.c:2455:    "Label %S not used.", name.str);    }    POP_STATEMENT_LABEL;    BLOCK_END;    return 0;    }       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    * the cleanup is handled wholesale in low_return et al.    * Alternatively we could handle this too in low_return and    * then allow tail recursion of these kind of returns too. */    for (p = current_label; p; p = p->prev) {    struct cleanup_frame *q;    for (q = p->cleanups; q; q = q->prev) {    if (q->cleanup == (cleanup_func) do_escape_catch) {
pike.git/src/docode.c:2483: Inside #if defined(PIKE_DEBUG)
   q->cleanup == (cleanup_func) do_cleanup_synch_mark) {    /* Use the ordinary pop mark instruction here since we know    * the stack isn't in synch and we don't want debug checks    * for that. */    do_pop_mark (NULL);    }   #endif    }    }    +  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;    }       case F_SSCANF:    tmp1=do_docode(CAR(n),DO_NOT_COPY);    tmp2=do_docode(CDR(n),DO_NOT_COPY | DO_LVALUE);    emit1(F_SSCANF, (INT32)(tmp1+tmp2));    return 1;       case F_CATCH: {
pike.git/src/docode.c:2782:    struct compiler_frame *f;    int depth=0;    for(f=Pike_compiler->compiler_frame;    f!=n->u.trampoline.frame;f=f->previous)    depth++;       emit2(F_TRAMPOLINE,n->u.trampoline.ident,depth);    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);    return ret + do_docode(CDR(n), flags | DO_LVALUE);       case F_AUTO_MAP:    emit0(F_MARK);    PUSH_CLEANUP_FRAME(do_pop_mark, 0);    code_expression(CAR(n), 0, "automap function");    do_encode_automap_arg_list(CDR(n),0);
pike.git/src/docode.c:2871:    }    }   }      /* Used to generate code for functions. */   INT32 do_code_block(node *n, int identifier_flags)   {    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;    current_stack_depth = 0;       if (Pike_compiler->compiler_frame->current_function_number >= 0) {    id = Pike_compiler->new_program->identifier_references +    Pike_compiler->compiler_frame->current_function_number;    }       init_bytecode();    label_no=1;       /* NOTE: This is no ordinary label... */    low_insert_label(0);    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);    }    emit1(F_MARK_AT, Pike_compiler->compiler_frame->num_args);    if (identifier_flags & IDENTIFIER_VARARGS) {    struct svalue *sval =    simple_mapping_string_lookup(get_builtin_constants(), "aggregate");    if (!sval) {    yyerror("predef::aggregate() is missing.\n");    Pike_fatal("No aggregate!\n");
pike.git/src/docode.c:2921:    Pike_compiler->compiler_frame->num_args) {    emit2(F_FILL_STACK,    Pike_compiler->compiler_frame->max_number_of_locals, 0);    }    }    emit2(F_INIT_FRAME, Pike_compiler->compiler_frame->num_args,    Pike_compiler->compiler_frame->max_number_of_locals);    if (Pike_compiler->compiler_frame->lexical_scope & SCOPE_SCOPE_USED) {    emit_save_locals(Pike_compiler->compiler_frame);    } +  }       if(id && (id->id_flags & ID_INLINE))    {    Pike_compiler->compiler_frame->recur_label=0;    Pike_compiler->compiler_frame->is_inline=1;    }       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)    {    fprintf(stderr,"Generating inline recursive function.\n");    }   #endif    /* generate code again, but this time it is inline */    Pike_compiler->compiler_frame->is_inline=1;   
pike.git/src/docode.c:2987:    current_stack_depth = save_stack_depth;    label_no = save_label_no;    return entry_point;   }      /* Used by eval_low() to build code for constant expressions. */   INT32 docode(node *n)   {    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;    struct cleanup_frame *top_cleanups_save = top_statement_label_dummy.cleanups;       label_no=1;    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);    /* FIXME: Should we check that do_docode() returns 1? */    do_docode(n,0);    insert_opcode0(F_DUMB_RETURN, n->line_number, n->current_file);    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;   }