pike.git / src / interpret.c

version» Context lines:

pike.git/src/interpret.c:2079:    return C.ptr;    }    /* This is only needed for pike functions right now:    * callsite_prepare(&C); */    callsite_execute(&C);    callsite_return(&C);    callsite_free(&C);    return NULL;   }    - void* lower_mega_apply_tailcall(INT32 args, struct object *o, ptrdiff_t fun) { -  struct pike_frame *frame = Pike_fp; -  void *ret; -  -  if (frame->flags & PIKE_FRAME_NO_REUSE) { -  /* We cannot reuse this frame. So we simply call mega_apply_low and are done. */ -  mega_apply_low(args, o, fun); -  return NULL; -  } -  -  ret = lower_mega_apply(args, o, fun); -  -  if (ret) { - #ifdef PIKE_DEBUG -  frame->pc = 0; - #endif -  unlink_previous_frame(); -  } -  -  return ret; - } -  +    /* Apply a function.    *    * Application types:    *    * APPLY_STACK: Apply Pike_sp[-args] with args-1 arguments.    *    * APPLY_SVALUE: Apply the svalue at arg1, and adjust the stack    * to leave a return value.    *    * APPLY_SVALUE_STRICT: Apply the svalue at arg1, and don't adjust the
pike.git/src/interpret.c:2158:    return C.ptr;    }       callsite_execute(&C);    callsite_return(&C);    callsite_free(&C);       return NULL;   }    + /* TAILCALL optimization variants. They try to reuse the current frame */   void* low_mega_apply_tailcall(enum apply_type type, INT32 args, void *arg1, void *arg2) {    struct pike_frame *frame = Pike_fp; -  void *ret; +  struct pike_callsite C;    -  if (frame->flags & PIKE_FRAME_NO_REUSE) { -  /* We cannot reuse this frame. So we simply call mega_apply and are done. */ -  mega_apply(type, args, arg1, arg2); +  callsite_init(&C); +  callsite_set_args(&C, args); +  +  /* We can reuse the current frame, so we set it into C here +  * to allow callsite_resolve_* to pick it up +  */ +  if (!(frame->flags & PIKE_FRAME_NO_REUSE) && frame->refs == 1) { +  C.frame = Pike_fp; +  } +  +  switch (type) { +  case APPLY_STACK: +  C.args--; +  callsite_resolve_svalue(&C, Pike_sp - args); +  break; +  case APPLY_SVALUE_STRICT: +  C.flags |= CALL_NEED_NO_RETVAL; +  case APPLY_SVALUE: +  callsite_resolve_svalue(&C, arg1); +  break; +  case APPLY_LOW: +  Pike_fatal("Deprecated. Use lower_mega_apply instead.\n"); +  break; +  } +  +  /* If the same frame is still set, either +  * - this is a pike function and we can just return +  * the jmp target +  * - or this is some other calltype which does not +  * use a frame at all, so we just set it to NULL +  */ +  if (C.frame == frame) { +  if (C.type == CALLTYPE_PIKEFUN) { +  FAST_CHECK_THREADS_ON_CALL(); +  return C.ptr; +  } else C.frame = NULL; +  } +  +  callsite_prepare(&C); +  callsite_execute(&C); +  callsite_return(&C); +  callsite_free(&C); +     return NULL;   }    -  ret = low_mega_apply(type, args, arg1, arg2); + /* NOTE: see comments in low_mega_apply_tailcall() */ + void* lower_mega_apply_tailcall(INT32 args, struct object *o, ptrdiff_t fun) { +  struct pike_frame *frame = Pike_fp; +  struct pike_callsite C;    -  if (ret) { - #ifdef PIKE_DEBUG -  frame->pc = 0; - #endif -  unlink_previous_frame(); +  callsite_init(&C); +  callsite_set_args(&C, args); +  +  if (!(frame->flags & PIKE_FRAME_NO_REUSE) && frame->refs == 1) { +  C.frame = Pike_fp;    }    -  +  callsite_resolve_fun(&C, o, fun);    -  return ret; +  if (C.frame == frame) { +  if (C.type == CALLTYPE_PIKEFUN) { +  FAST_CHECK_THREADS_ON_CALL(); +  return C.ptr; +  } else C.frame = NULL;    }    -  +  callsite_prepare(&C); +  callsite_execute(&C); +  callsite_return(&C); +  callsite_free(&C); +  +  return NULL; + } +    void low_return(void)   {    struct svalue *save_sp = frame_get_save_sp(Pike_fp);    struct object *o = Pike_fp->current_object;    int fun = Pike_fp->fun;    int pop = Pike_fp->flags & PIKE_FRAME_RETURN_POP;       if (PIKE_FN_DONE_ENABLED()) {    /* DTrace leave probe    arg0: function name
pike.git/src/interpret.c:2245:   #endif       if(UNLIKELY(Pike_interpreter.trace_level>1))    do_trace_func_return (o, fun, 1);      #if defined (PIKE_USE_MACHINE_CODE) && defined (OPCODE_RETURN_JUMPADDR)    free_object (o);   #endif   }    - void unlink_previous_frame(void) - { -  struct pike_frame *current, *prev; -  -  current=Pike_interpreter.frame_pointer; -  prev=current->next; - #ifdef PIKE_DEBUG -  { -  JMP_BUF *rec; -  -  /* Check if any recoveries belong to the frame we're -  * about to unlink. -  */ -  if((rec=Pike_interpreter.recoveries)) -  { -  while(rec->frame_pointer == current) rec=rec->previous; -  /* FIXME: Wouldn't a simple return be ok? */ -  if(rec->frame_pointer == current->next) -  Pike_fatal("You can't touch this!\n"); -  } -  } - #endif -  /* Save various fields from the previous frame. -  */ -  frame_set_save_sp(current, frame_get_save_sp(prev)); -  current->save_mark_sp=prev->save_mark_sp; -  current->flags = prev->flags; -  -  /* Unlink the top frame temporarily. */ -  Pike_interpreter.frame_pointer=prev; -  - #ifdef PROFILING -  { -  /* We must update the profiling info of the previous frame -  * to account for that the current frame has gone away. -  */ -  cpu_time_t total_time = -  get_cpu_time() - (Pike_interpreter.unlocked_time + current->start_time); -  cpu_time_t child_time = -  Pike_interpreter.accounted_time - current->children_base; -  struct identifier *function = -  current->context->prog->identifiers + current->ident; -  if (!function->recur_depth) -  function->total_time += total_time; -  total_time -= child_time; -  function->self_time += total_time; -  Pike_interpreter.accounted_time += total_time; - #ifdef PROFILING_DEBUG -  fprintf(stderr, "%p: Unlinking previous frame.\n" -  "Previous: %" PRINT_CPU_TIME " %" PRINT_CPU_TIME "\n" -  "Current: %" PRINT_CPU_TIME " %" PRINT_CPU_TIME "\n", -  Pike_interpreter.thread_state, -  prev->start_time, prev->children_base, -  current->start_time, current->children_base); - #endif /* PROFILING_DEBUG */ -  } - #endif /* PROFILING */ -  -  /* Unlink the frame. */ -  POP_PIKE_FRAME(); -  -  /* Hook our frame again. */ -  current->next=Pike_interpreter.frame_pointer; -  Pike_interpreter.frame_pointer=current; -  - #ifdef PROFILING -  current->children_base = Pike_interpreter.accounted_time; -  current->start_time = get_cpu_time() - Pike_interpreter.unlocked_time; - #endif /* PROFILING */ - } -  +    static void restore_catching_eval_jmpbuf (LOW_JMP_BUF *p)   {    Pike_interpreter.catching_eval_jmpbuf = p;   }      PMOD_EXPORT void mega_apply(enum apply_type type, INT32 args, void *arg1, void *arg2)   {    /* Save and clear Pike_interpreter.catching_eval_jmpbuf so that the    * following eval_instruction will install a LOW_JMP_BUF of its    * own to handle catches. */
pike.git/src/interpret.c:3416: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    Pike_fatal("Unknown identifier type.\n");   #endif    UNREACHABLE(break);    }    /*    * The cases which do _not_ return, have a frame created. These are:    * CALLTYPE_CFUN, CALLTYPE_PIKEFUN and CALLTYPE_PARENT_CLONE.    */    +  +  struct pike_frame *frame = c->frame; +  +  if (!frame || c->type != CALLTYPE_PIKEFUN) {    add_ref(o);    add_ref(p); -  +  frame = alloc_pike_frame();    -  struct pike_frame *frame = alloc_pike_frame(); -  -  frame->next = Pike_fp; +  c->frame = frame;    frame->current_object = o;    frame->current_program = p; -  +  frame->save_mark_sp=Pike_mark_sp; +  frame->locals = Pike_sp - args; +  frame_set_save_sp(frame, c->retval); +  +  /* link new frame */ +  frame->next = Pike_fp; +  Pike_fp = frame; +  } else { +  if (o != frame->current_object) { +  free_object(frame->current_object); +  add_ref(frame->current_object = o); +  +  if (p != frame->current_program) { +  free_program(frame->current_program); +  add_ref(frame->current_program = p); +  } +  } +  struct svalue *save_sp = frame_get_save_sp(frame); +  frame->locals = Pike_sp - args; +  frame_set_save_sp(frame, save_sp); +  } +     frame->context = context;    frame->fun = fun;    frame->locals = Pike_sp - args;    if (c->type == CALLTYPE_PIKEFUN)    frame->pc = c->ptr;    else    frame->pc = NULL;    frame->current_storage = o->storage + context->storage_offset;    frame->expendible_offset = 0;    frame->args = args;    frame->num_locals = 0;    frame->num_args = 0;    frame->scope = scope; -  frame->save_mark_sp=Pike_mark_sp; +     frame->return_addr = NULL; -  frame_set_save_sp(frame, c->retval); +     -  Pike_fp = frame; -  c->frame = frame; -  +     check_stack(256);    check_mark_stack(256);       if (PIKE_NEEDS_TRACE())    callsite_trace_call_fun(c);   }      PMOD_EXPORT void callsite_resolve_lfun(struct pike_callsite *c, struct object *o, int lfun) {    struct program *p = o->prog;   
pike.git/src/interpret.c:3534:    * execution of Pike code. We can probably    * make most of these PIKE_DEBUG stuff */    frame->pc = c->ptr;    frame->num_locals = 0;    frame->num_args = 0;    frame->return_addr = NULL;    if (UNLIKELY(frame->save_locals_bitmask)) {    free(frame->save_locals_bitmask);    frame->save_locals_bitmask = NULL;    } -  frame->flags = 0; +  frame->flags &= PIKE_FRAME_NO_REUSE;    return;    }       struct pike_frame *n = alloc_pike_frame();       *n = *frame;    n->refs = 1; -  n->flags = 0; +  n->flags = frame->flags & PIKE_FRAME_NO_REUSE;    n->pc = c->ptr;    n->num_locals = 0;    n->num_args = 0;    n->return_addr = NULL;    if (n->scope) add_ref(n->scope);    add_ref(n->current_object);    add_ref(n->current_program);       LOW_POP_PIKE_FRAME(frame);   
pike.git/src/interpret.c:3645:      PMOD_EXPORT void callsite_return_slowpath(struct pike_callsite *c) {    const struct svalue *sp = Pike_sp;    struct svalue *retval = c->retval;    struct pike_frame *frame = c->frame;    int got_retval = 1;    int pop = 0;       /* NOTE: this is necessary because of recursion */    if (c->type == CALLTYPE_PIKEFUN) { -  c->frame = frame = Pike_fp; +     pop = frame->flags & PIKE_FRAME_RETURN_POP;    }      #ifdef PIKE_DEBUG    if(Pike_mark_sp < Pike_fp->save_mark_sp)    Pike_fatal("Popped below save_mark_sp!\n");    if(Pike_sp<Pike_interpreter.evaluator_stack)    Pike_fatal("Stack error (also simple).\n");   #endif