pike.git / src / interpret_functions.h

version» Context lines:

pike.git/src/interpret_functions.h:1:   /* -  * $Id: interpret_functions.h,v 1.39 2001/01/12 01:58:40 mast Exp $ -  * + || This file is part of Pike. For copyright information see COPYRIGHT. + || Pike is distributed under GPL, LGPL and MPL. See the file COPYING + || for more information. + */ +  + /*    * Opcode definitions for the interpreter.    */    - OPCODE0(F_UNDEFINED,"push UNDEFINED") + #include "global.h" +  + #undef CJUMP + #undef LOOP + #undef COMPARISON + #undef MKAPPLY + #undef DO_CALL_BUILTIN +  + #undef DO_IF_ELSE_COMPUTED_GOTO + #ifdef HAVE_COMPUTED_GOTO + #define DO_IF_ELSE_COMPUTED_GOTO(A, B) (A) + #else /* !HAVE_COMPUTED_GOTO */ + #define DO_IF_ELSE_COMPUTED_GOTO(A, B) (B) + #endif /* HAVE_COMPUTED_GOTO */ +  + #ifdef GEN_PROTOS + /* Used to generate the interpret_protos.h file. */ + #define OPCODE0(A, B, F, C) OPCODE0(A, B, F) --- C + #define OPCODE1(A, B, F, C) OPCODE1(A, B, F) --- C + #define OPCODE2(A, B, F, C) OPCODE2(A, B, F) --- C + #define OPCODE0_TAIL(A, B, F, C) OPCODE0_TAIL(A, B, F) --- C + #define OPCODE1_TAIL(A, B, F, C) OPCODE1_TAIL(A, B, F) --- C + #define OPCODE2_TAIL(A, B, F, C) OPCODE2_TAIL(A, B, F) --- C + #define OPCODE0_JUMP(A, B, F, C) OPCODE0_JUMP(A, B, F) --- C + #define OPCODE1_JUMP(A, B, F, C) OPCODE1_JUMP(A, B, F) --- C + #define OPCODE2_JUMP(A, B, F, C) OPCODE2_JUMP(A, B, F) --- C + #define OPCODE0_TAILJUMP(A, B, F, C) OPCODE0_TAILJUMP(A, B, F) --- C + #define OPCODE1_TAILJUMP(A, B, F, C) OPCODE1_TAILJUMP(A, B, F) --- C + #define OPCODE2_TAILJUMP(A, B, F, C) OPCODE2_TAILJUMP(A, B, F) --- C + #define OPCODE0_PTRJUMP(A, B, F, C) OPCODE0_PTRJUMP(A, B, F) --- C + #define OPCODE1_PTRJUMP(A, B, F, C) OPCODE1_PTRJUMP(A, B, F) --- C + #define OPCODE2_PTRJUMP(A, B, F, C) OPCODE2_PTRJUMP(A, B, F) --- C + #define OPCODE0_TAILPTRJUMP(A, B, F, C) OPCODE0_TAILPTRJUMP(A, B, F) --- C + #define OPCODE1_TAILPTRJUMP(A, B, F, C) OPCODE1_TAILPTRJUMP(A, B, F) --- C + #define OPCODE2_TAILPTRJUMP(A, B, F, C) OPCODE2_TAILPTRJUMP(A, B, F) --- C + #define OPCODE0_RETURN(A, B, F, C) OPCODE0_RETURN(A, B, F) --- C + #define OPCODE1_RETURN(A, B, F, C) OPCODE1_RETURN(A, B, F) --- C + #define OPCODE2_RETURN(A, B, F, C) OPCODE2_RETURN(A, B, F) --- C + #define OPCODE0_TAILRETURN(A, B, F, C) OPCODE0_TAILRETURN(A, B, F) --- C + #define OPCODE1_TAILRETURN(A, B, F, C) OPCODE1_TAILRETURN(A, B, F) --- C + #define OPCODE2_TAILRETURN(A, B, F, C) OPCODE2_TAILRETURN(A, B, F) --- C + #define OPCODE0_BRANCH(A, B, F, C) OPCODE0_BRANCH(A, B, F) --- C + #define OPCODE1_BRANCH(A, B, F, C) OPCODE1_BRANCH(A, B, F) --- C + #define OPCODE2_BRANCH(A, B, F, C) OPCODE2_BRANCH(A, B, F) --- C + #define OPCODE0_TAILBRANCH(A, B, F, C) OPCODE0_TAILBRANCH(A, B, F) --- C + #define OPCODE1_TAILBRANCH(A, B, F, C) OPCODE1_TAILBRANCH(A, B, F) --- C + #define OPCODE2_TAILBRANCH(A, B, F, C) OPCODE2_TAILBRANCH(A, B, F) --- C + #define OPCODE0_ALIAS(A, B, F, C) OPCODE0_ALIAS(A, B, F, C) --- FOO + #define OPCODE1_ALIAS(A, B, F, C) OPCODE1_ALIAS(A, B, F, C) --- FOO + #define OPCODE2_ALIAS(A, B, F, C) OPCODE2_ALIAS(A, B, F, C) --- FOO + #endif /* GEN_PROTOS */ +  + #ifndef OPCODE0_ALIAS + #define OPCODE0_ALIAS(A,B,C,D) OPCODE0(A,B,C,{D();}) + #endif /* !OPCODE0_ALIAS */ + #ifndef OPCODE1_ALIAS + #define OPCODE1_ALIAS(A,B,C,D) OPCODE1(A,B,C,{D();}) + #endif /* !OPCODE1_ALIAS */ + #ifndef OPCODE2_ALIAS + #define OPCODE2_ALIAS(A,B,C,D) OPCODE2(A,B,C,{D();}) + #endif /* !OPCODE2_ALIAS */ +  +  + /* + #ifndef PROG_COUNTER + #define PROG_COUNTER pc + #endif + */ +  + #ifndef INTER_RETURN + #define INTER_RETURN return -1 + #endif +  + /* BRANCH opcodes use these two to indicate whether the +  * branch should be taken or not. +  */ + #ifndef DO_BRANCH + #define DO_BRANCH DOJUMP + #endif + #ifndef DONT_BRANCH + #define DONT_BRANCH SKIPJUMP + #endif +  + #ifndef LOCAL_VAR + #define LOCAL_VAR(X) X + #endif +  + #ifndef OVERRIDE_JUMPS +  + #undef GET_JUMP + #undef SKIPJUMP + #undef DOJUMP +  + #ifdef PIKE_DEBUG +  + #define GET_JUMP() (backlog[backlogp].arg=( \ +  (Pike_interpreter.trace_level>3 ? \ +  sprintf(trace_buffer, "- Target = %+ld\n", \ +  (long)LOW_GET_JUMP()), \ +  write_to_stderr(trace_buffer,strlen(trace_buffer)) : 0), \ +  LOW_GET_JUMP())) +  + #define SKIPJUMP() (GET_JUMP(), LOW_SKIPJUMP()) +  + #else /* !PIKE_DEBUG */ +  + #define GET_JUMP() (/*write_to_stderr("GET_JUMP\n", 9),*/ LOW_GET_JUMP()) + #define SKIPJUMP() (/*write_to_stderr("SKIPJUMP\n", 9),*/ LOW_SKIPJUMP()) +  + #endif /* PIKE_DEBUG */ +  + #define DOJUMP() do { \ +  PIKE_OPCODE_T *addr; \ +  INT32 tmp; \ +  JUMP_SET_TO_PC_AT_NEXT (addr); \ +  tmp = GET_JUMP(); \ +  SET_PROG_COUNTER(addr + tmp); \ +  FETCH; \ +  if(tmp < 0) \ +  FAST_CHECK_THREADS_ON_BRANCH(); \ +  } while(0) +  + #endif /* OVERRIDE_JUMPS */ +  +  + /* WARNING: +  * The surgeon general has stated that define code blocks +  * without do{}while() can be hazardous to your health. +  * However, in these cases it is required to handle break +  * properly. -Hubbe +  */ + #undef DO_JUMP_TO + #define DO_JUMP_TO(NEWPC) { \ +  SET_PROG_COUNTER(NEWPC); \ +  FETCH; \ +  JUMP_DONE; \ + } +  + #undef DO_DUMB_RETURN + #define DO_DUMB_RETURN { \ +  if(Pike_fp -> flags & PIKE_FRAME_RETURN_INTERNAL) \ +  { \ +  int f=Pike_fp->flags; \ +  if(f & PIKE_FRAME_RETURN_POP) \ +  low_return_pop(); \ +  else \ +  low_return(); \ +  \ +  DO_IF_DEBUG(if (Pike_interpreter.trace_level > 5) \ +  fprintf(stderr, "Returning to 0x%p\n", \ +  Pike_fp->return_addr)); \ +  DO_JUMP_TO(Pike_fp->return_addr); \ +  } \ +  DO_IF_DEBUG(if (Pike_interpreter.trace_level > 5) \ +  fprintf(stderr, "Inter return\n")); \ +  INTER_RETURN; \ + } +  + #undef DO_RETURN + #ifndef PIKE_DEBUG + #define DO_RETURN DO_DUMB_RETURN + #else + #define DO_RETURN { \ +  if(d_flag>3) do_gc(NULL, 0); \ +  if(d_flag>4) do_debug(); \ +  DO_DUMB_RETURN; \ + } + #endif +  + #ifdef OPCODE_RETURN_JUMPADDR + #define DO_JUMP_TO_NEXT do { \ +  PIKE_OPCODE_T *next_addr; \ +  JUMP_SET_TO_PC_AT_NEXT (next_addr); \ +  SET_PROG_COUNTER (next_addr); \ +  FETCH; \ +  JUMP_DONE; \ +  } while (0) + #else /* !OPCODE_RETURN_JUMPADDR */ + #define JUMP_SET_TO_PC_AT_NEXT(PC) ((PC) = PROG_COUNTER) + #define DO_JUMP_TO_NEXT JUMP_DONE + #endif /* !OPCODE_RETURN_JUMPADDR */ +  + #undef DO_INDEX + #define DO_INDEX do { \ +  LOCAL_VAR(struct svalue tmp); \ +  index_no_free(&tmp,Pike_sp-2,Pike_sp-1); \ +  pop_2_elems(); \ +  move_svalue (Pike_sp, &tmp); \ +  Pike_sp++; \ +  print_return_value(); \ +  }while(0) +  +  + OPCODE0(F_UNDEFINED, "push UNDEFINED", I_UPDATE_SP, { +  push_undefined(); + }); +  + OPCODE0(F_CONST0, "push 0", I_UPDATE_SP, {    push_int(0); -  Pike_sp[-1].subtype=NUMBER_UNDEFINED; - BREAK; + });    - OPCODE0(F_CONST0, "push 0") + OPCODE0(F_CONST1, "push 1", I_UPDATE_SP, { +  push_int(1); + }); +  +  + OPCODE0(F_MARK_AND_CONST0, "mark & 0", I_UPDATE_SP|I_UPDATE_M_SP, { +  *(Pike_mark_sp++)=Pike_sp;    push_int(0); - BREAK; + });    - OPCODE0(F_CONST1, "push 1") + OPCODE0(F_MARK_AND_CONST1, "mark & 1", I_UPDATE_SP|I_UPDATE_M_SP, { +  *(Pike_mark_sp++)=Pike_sp;    push_int(1); - BREAK; + });    - OPCODE0(F_CONST_1,"push -1") + OPCODE0(F_CONST_1,"push -1", I_UPDATE_SP, {    push_int(-1); - BREAK; + });    - OPCODE0(F_BIGNUM, "push 0x7fffffff") + OPCODE0(F_BIGNUM, "push 0x7fffffff", I_UPDATE_SP, {    push_int(0x7fffffff); - BREAK; + });    - OPCODE1(F_NUMBER, "push int") + OPCODE1(F_NUMBER, "push int", I_UPDATE_SP, {    push_int(arg1); - BREAK; + });    - OPCODE1(F_NEG_NUMBER,"push -int") + /* always need to declare this opcode to make working dists */ + #if SIZEOF_INT_TYPE > 4 + OPCODE2(F_NUMBER64, "push 64-bit int", I_UPDATE_SP, { +  push_int( (INT_TYPE) +  (( ((unsigned INT_TYPE)arg1) << 32) +  | ((unsigned INT32)arg2)) ); + }); + #else + OPCODE2(F_NUMBER64, "push 64-bit int", I_UPDATE_SP, { +  Pike_error("F_NUMBER64: this opcode should never be used in your system\n"); + }); + #endif +  + OPCODE1(F_NEG_NUMBER, "push -int", I_UPDATE_SP, {    push_int(-arg1); - BREAK; + });    - OPCODE1(F_CONSTANT,"constant") -  assign_svalue_no_free(Pike_sp++,& Pike_fp->context.prog->constants[arg1].sval); + OPCODE1(F_CONSTANT, "constant", I_UPDATE_SP, { +  push_svalue(& Pike_fp->context->prog->constants[arg1].sval);    print_return_value(); - BREAK; + });    -  +  + /* Generic swap instruction: +  * swaps the arg1 top values with the arg2 values beneath +  */ + OPCODE2(F_REARRANGE,"rearrange",0,{ +  check_stack(arg2); +  MEMCPY(Pike_sp,Pike_sp-arg1-arg2,sizeof(struct svalue)*arg2); +  MEMMOVE(Pike_sp-arg1-arg2,Pike_sp-arg1,sizeof(struct svalue)*arg1); +  MEMCPY(Pike_sp-arg2,Pike_sp,sizeof(struct svalue)*arg2); + }); +    /* The rest of the basic 'push value' instructions */    - OPCODE1_TAIL(F_MARK_AND_STRING,"mark & string") + OPCODE1_TAIL(F_MARK_AND_STRING, "mark & string", I_UPDATE_SP|I_UPDATE_M_SP, {    *(Pike_mark_sp++)=Pike_sp;    - OPCODE1(F_STRING,"string") -  copy_shared_string(Pike_sp->u.string,Pike_fp->context.prog->strings[arg1]); -  Pike_sp->type=PIKE_T_STRING; -  Pike_sp->subtype=0; -  Pike_sp++; +  OPCODE1(F_STRING, "string", I_UPDATE_SP, { +  ref_push_string(Pike_fp->context->prog->strings[arg1]);    print_return_value(); - BREAK; +  }); + });       - OPCODE1(F_ARROW_STRING,"->string") -  copy_shared_string(Pike_sp->u.string,Pike_fp->context.prog->strings[arg1]); -  Pike_sp->type=PIKE_T_STRING; -  Pike_sp->subtype=1; /* Magic */ -  Pike_sp++; + OPCODE1(F_ARROW_STRING, "->string", I_UPDATE_SP, { +  ref_push_string(Pike_fp->context->prog->strings[arg1]); +  SET_SVAL_SUBTYPE(Pike_sp[-1], 1); /* Magic */    print_return_value(); - BREAK; + });    - OPCODE0(F_FLOAT,"push float") -  /* FIXME, this opcode uses 'pc' which is not allowed.. */ -  Pike_sp->type=PIKE_T_FLOAT; -  MEMCPY((void *)&Pike_sp->u.float_number, pc, sizeof(FLOAT_TYPE)); -  pc+=sizeof(FLOAT_TYPE); -  Pike_sp++; - BREAK; + OPCODE1(F_LOOKUP_LFUN, "->lfun", 0, { +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct svalue tmp); +  LOCAL_VAR(struct program *p);    - OPCODE1(F_LFUN, "local function") -  Pike_sp->u.object=Pike_fp->current_object; -  add_ref(Pike_fp->current_object); -  Pike_sp->subtype=arg1+Pike_fp->context.identifier_level; -  Pike_sp->type=PIKE_T_FUNCTION; -  Pike_sp++; +  if ((TYPEOF(Pike_sp[-1]) == T_OBJECT) && +  (p = (o = Pike_sp[-1].u.object)->prog) && +  (FIND_LFUN(p = p->inherits[SUBTYPEOF(Pike_sp[-1])].prog, +  LFUN_ARROW) == -1)) { +  int id = FIND_LFUN(p, arg1); +  if ((id != -1) && +  (!(p->identifier_references[id].id_flags & +  (ID_PROTECTED|ID_PRIVATE|ID_HIDDEN)))) { +  id += o->prog->inherits[SUBTYPEOF(Pike_sp[-1])].identifier_level; +  low_object_index_no_free(&tmp, o, id); +  } else { +  /* Not found. */ +  SET_SVAL(tmp, T_INT, NUMBER_UNDEFINED, integer, 0); +  } +  } else { +  LOCAL_VAR(struct svalue tmp2); +  SET_SVAL(tmp2, PIKE_T_STRING, 1, string, lfun_strings[arg1]); +  index_no_free(&tmp, Pike_sp-1, &tmp2); +  } +  free_svalue(Pike_sp-1); +  move_svalue (Pike_sp - 1, &tmp);    print_return_value(); - BREAK; + });    - OPCODE1(F_TRAMPOLINE, "trampoline") - { -  struct object *o=low_clone(pike_trampoline_program); -  add_ref( ((struct pike_trampoline *)(o->storage))->frame=Pike_fp ); -  ((struct pike_trampoline *)(o->storage))->func=arg1+Pike_fp->context.identifier_level; -  push_object(o); -  /* Make it look like a function. */ -  Pike_sp[-1].subtype = pike_trampoline_program->lfuns[LFUN_CALL]; -  Pike_sp[-1].type = T_FUNCTION; + OPCODE1(F_LFUN, "local function", I_UPDATE_SP, { +  ref_push_function (Pike_fp->current_object, +  arg1+Pike_fp->context->identifier_level);    print_return_value(); -  + }); +  + OPCODE2(F_TRAMPOLINE, "trampoline", I_UPDATE_SP, { +  struct pike_frame *f=Pike_fp; +  DO_IF_DEBUG(INT32 arg2_ = arg2;) +  LOCAL_VAR(struct object *o); +  o = low_clone(pike_trampoline_program); +  +  while(arg2--) { +  DO_IF_DEBUG({ +  if (!f->scope) { +  Pike_fatal("F_TRAMPOLINE %d, %d: Missing %d levels of scope!\n", +  arg1, arg2_, arg2+1);    } - BREAK; +  }); +  f=f->scope; +  } +  add_ref( ((struct pike_trampoline *)(o->storage))->frame=f ); +  ((struct pike_trampoline *)(o->storage))->func=arg1+Pike_fp->context->identifier_level; +  push_function(o, pike_trampoline_program->lfuns[LFUN_CALL]); +  print_return_value(); + });      /* The not so basic 'push value' instructions */    - OPCODE1(F_GLOBAL,"global") -  low_object_index_no_free(Pike_sp, -  Pike_fp->current_object, -  arg1 + Pike_fp->context.identifier_level); + OPCODE1_TAIL(F_MARK_AND_GLOBAL, "mark & global", I_UPDATE_SP|I_UPDATE_M_SP, { +  *(Pike_mark_sp++)=Pike_sp; +  +  OPCODE1(F_GLOBAL, "global", I_UPDATE_SP, { +  low_index_current_object_no_free(Pike_sp, arg1);    Pike_sp++;    print_return_value(); - BREAK; +  }); + });    - OPCODE2(F_EXTERNAL,"external") - { -  struct external_variable_context loc; + OPCODE2_TAIL(F_MARK_AND_EXTERNAL, "mark & external", I_UPDATE_SP|I_UPDATE_M_SP, { +  *(Pike_mark_sp++)=Pike_sp;    -  loc.o=Pike_fp->current_object; -  if(!loc.o->prog) -  Pike_error("Cannot access parent of destructed object.\n"); +  OPCODE2(F_EXTERNAL,"external", I_UPDATE_SP, { +  LOCAL_VAR(struct external_variable_context loc);    -  +  loc.o=Pike_fp->current_object;    loc.parent_identifier=Pike_fp->fun; -  loc.inherit=INHERIT_FROM_INT(loc.o->prog, Pike_fp->fun); -  +  loc.inherit=Pike_fp->context;    find_external_context(&loc, arg2);    - #ifdef PIKE_DEBUG +  DO_IF_DEBUG({    TRACE((5,"- Identifier=%d Offset=%d\n",    arg1,    loc.inherit->identifier_level)); - #endif +  });    -  +  if (arg1 == IDREF_MAGIC_THIS) +  /* Special treatment to allow doing Foo::this on destructed +  * parent objects. */ +  ref_push_object (loc.o); +  else {    low_object_index_no_free(Pike_sp,    loc.o,    arg1 + loc.inherit->identifier_level);    Pike_sp++; -  print_return_value(); +     } - BREAK; +  print_return_value(); +  }); + });    - OPCODE2(F_EXTERNAL_LVALUE,"& external") - { -  struct external_variable_context loc; + OPCODE2(F_EXTERNAL_LVALUE, "& external", I_UPDATE_SP, { +  LOCAL_VAR(struct external_variable_context loc);       loc.o=Pike_fp->current_object; -  if(!loc.o->prog) -  Pike_error("Cannot access parent of destructed object.\n"); -  +     loc.parent_identifier=Pike_fp->fun; -  loc.inherit=INHERIT_FROM_INT(loc.o->prog, Pike_fp->fun); -  +  loc.inherit=Pike_fp->context;    find_external_context(&loc, arg2);    - #ifdef PIKE_DEBUG +  if (!loc.o->prog) +  Pike_error ("Cannot access variable in destructed parent object.\n"); +  +  DO_IF_DEBUG({    TRACE((5,"- Identifier=%d Offset=%d\n",    arg1,    loc.inherit->identifier_level)); - #endif +  });    -  +     ref_push_object(loc.o); -  Pike_sp->type=T_LVALUE; -  Pike_sp->u.integer=arg1 + loc.inherit->identifier_level; -  Pike_sp++; - } - BREAK; +  push_obj_index(arg1 + loc.inherit->identifier_level); + });    - OPCODE1(F_MARK_AND_LOCAL, "mark & local") + OPCODE1(F_MARK_AND_LOCAL, "mark & local", I_UPDATE_SP|I_UPDATE_M_SP, {    *(Pike_mark_sp++) = Pike_sp; -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); +  push_svalue( Pike_fp->locals + arg1);    print_return_value(); - BREAK; + });    - OPCODE1(F_LOCAL, "local") -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); + OPCODE1(F_LOCAL, "local", I_UPDATE_SP, { +  push_svalue( Pike_fp->locals + arg1);    print_return_value(); - BREAK; + });    - OPCODE2(F_2_LOCALS, "2 locals") -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); + OPCODE2(F_2_LOCALS, "2 locals", I_UPDATE_SP, { +  push_svalue( Pike_fp->locals + arg1);    print_return_value(); -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg2); +  push_svalue( Pike_fp->locals + arg2);    print_return_value(); - BREAK; + });    - OPCODE2(F_LOCAL_2_LOCAL, "local = local") + OPCODE2(F_LOCAL_2_LOCAL, "local = local", 0, {    assign_svalue(Pike_fp->locals + arg1, Pike_fp->locals + arg2); - BREAK; + });    - OPCODE2(F_LOCAL_2_GLOBAL, "global = local") - { -  INT32 tmp = arg1 + Pike_fp->context.identifier_level; -  struct identifier *i; -  -  if(!Pike_fp->current_object->prog) -  Pike_error("Cannot access global variables in destructed object.\n"); -  -  i = ID_FROM_INT(Pike_fp->current_object->prog, tmp); -  if(!IDENTIFIER_IS_VARIABLE(i->identifier_flags)) -  Pike_error("Cannot assign functions or constants.\n"); -  if(i->run_time_type == PIKE_T_MIXED) -  { -  assign_svalue((struct svalue *)GLOBAL_FROM_INT(tmp), + OPCODE2(F_LOCAL_2_GLOBAL, "global = local", 0, { +  object_low_set_index(Pike_fp->current_object, +  arg1 + Pike_fp->context->identifier_level,    Pike_fp->locals + arg2); -  }else{ -  assign_to_short_svalue((union anything *)GLOBAL_FROM_INT(tmp), -  i->run_time_type, -  Pike_fp->locals + arg2); -  } - } - BREAK; + });    - OPCODE2(F_GLOBAL_2_LOCAL,"local = global") - { -  INT32 tmp = arg1 + Pike_fp->context.identifier_level; + OPCODE2(F_GLOBAL_2_LOCAL, "local = global", 0, {    free_svalue(Pike_fp->locals + arg2); -  low_object_index_no_free(Pike_fp->locals + arg2, -  Pike_fp->current_object, -  tmp); - } - BREAK; +  mark_free_svalue (Pike_fp->locals + arg2); +  low_index_current_object_no_free(Pike_fp->locals + arg2, arg1); + });    - OPCODE1(F_LOCAL_LVALUE, "& local") -  Pike_sp[0].type = T_LVALUE; -  Pike_sp[0].u.lval = Pike_fp->locals + arg1; -  Pike_sp[1].type = T_VOID; + OPCODE1(F_LOCAL_LVALUE, "& local", I_UPDATE_SP, { +  SET_SVAL(Pike_sp[0], T_SVALUE_PTR, 0, lval, Pike_fp->locals + arg1); +  SET_SVAL_TYPE(Pike_sp[1], T_VOID);    Pike_sp += 2; - BREAK; + });    - OPCODE2(F_LEXICAL_LOCAL,"lexical local") - { + OPCODE2(F_LEXICAL_LOCAL, "lexical local", I_UPDATE_SP, {    struct pike_frame *f=Pike_fp;    while(arg2--)    {    f=f->scope;    if(!f) Pike_error("Lexical scope error.\n");    }    push_svalue(f->locals + arg1);    print_return_value(); - } - BREAK; + });    - OPCODE2(F_LEXICAL_LOCAL_LVALUE,"&lexical local") - { + OPCODE2(F_LEXICAL_LOCAL_LVALUE, "&lexical local", I_UPDATE_SP, {    struct pike_frame *f=Pike_fp;    while(arg2--)    {    f=f->scope;    if(!f) Pike_error("Lexical scope error.\n");    } -  Pike_sp[0].type=T_LVALUE; -  Pike_sp[0].u.lval=f->locals+arg1; -  Pike_sp[1].type=T_VOID; +  SET_SVAL(Pike_sp[0], T_SVALUE_PTR, 0, lval, f->locals+arg1); +  SET_SVAL_TYPE(Pike_sp[1], T_VOID);    Pike_sp+=2; - } - BREAK; + });    - OPCODE1(F_ARRAY_LVALUE, "[ lvalues ]") + OPCODE1(F_ARRAY_LVALUE, "[ lvalues ]", I_UPDATE_SP, {    f_aggregate(arg1*2);    Pike_sp[-1].u.array->flags |= ARRAY_LVALUE;    Pike_sp[-1].u.array->type_field |= BIT_UNFINISHED | BIT_MIXED;    /* FIXME: Shouldn't a ref be added here? */ -  Pike_sp[0] = Pike_sp[-1]; -  Pike_sp[-1].type = T_ARRAY_LVALUE; -  dmalloc_touch_svalue(Pike_sp); +  move_svalue (Pike_sp, Pike_sp - 1); +  SET_SVAL_TYPE(Pike_sp[-1], T_ARRAY_LVALUE);    Pike_sp++; - BREAK; + });    - OPCODE1(F_CLEAR_2_LOCAL, "clear 2 local") -  free_svalues(Pike_fp->locals + arg1, 2, -1); -  Pike_fp->locals[arg1].type = PIKE_T_INT; -  Pike_fp->locals[arg1].subtype = 0; -  Pike_fp->locals[arg1].u.integer = 0; -  Pike_fp->locals[arg1+1].type = PIKE_T_INT; -  Pike_fp->locals[arg1+1].subtype = 0; -  Pike_fp->locals[arg1+1].u.integer = 0; - BREAK; + OPCODE1(F_CLEAR_2_LOCAL, "clear 2 local", 0, { +  free_mixed_svalues(Pike_fp->locals + arg1, 2); +  SET_SVAL(Pike_fp->locals[arg1], PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  SET_SVAL(Pike_fp->locals[arg1+1], PIKE_T_INT, NUMBER_NUMBER, integer, 0); + });    - OPCODE1(F_CLEAR_4_LOCAL, "clear 4 local") - { + OPCODE1(F_CLEAR_4_LOCAL, "clear 4 local", 0, { +  struct svalue *locals = Pike_fp->locals;    int e; -  free_svalues(Pike_fp->locals + arg1, 4, -1); +  free_mixed_svalues(locals + arg1, 4);    for(e = 0; e < 4; e++)    { -  Pike_fp->locals[arg1+e].type = PIKE_T_INT; -  Pike_fp->locals[arg1+e].subtype = 0; -  Pike_fp->locals[arg1+e].u.integer = 0; +  SET_SVAL(locals[arg1+e], PIKE_T_INT, NUMBER_NUMBER, integer, 0);    } - } - BREAK; + });    - OPCODE1(F_CLEAR_LOCAL, "clear local") + OPCODE1(F_CLEAR_LOCAL, "clear local", 0, {    free_svalue(Pike_fp->locals + arg1); -  Pike_fp->locals[arg1].type = PIKE_T_INT; -  Pike_fp->locals[arg1].subtype = 0; -  Pike_fp->locals[arg1].u.integer = 0; - BREAK; +  SET_SVAL(Pike_fp->locals[arg1], PIKE_T_INT, NUMBER_NUMBER, integer, 0); + });    - OPCODE1(F_INC_LOCAL, "++local") -  if( (Pike_fp->locals[arg1].type == PIKE_T_INT) - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_ADD_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1)) - #endif /* AUTO_BIGNUM */ -  ) + OPCODE2(F_ADD_LOCALS_AND_POP, "local += local", 0,   { -  Pike_fp->locals[arg1].u.integer++; -  assign_svalue_no_free(Pike_sp++,Pike_fp->locals+arg1); +  struct svalue *dst = Pike_fp->locals+arg1; +  struct svalue *src = Pike_fp->locals+arg2; +  if( (dst->type|src->type) == PIKE_T_INT +  && !INT_TYPE_ADD_OVERFLOW(src->u.integer,dst->u.integer) ) +  { +  SET_SVAL_SUBTYPE(*dst,NUMBER_NUMBER); +  dst->u.integer += src->u.integer; +  } +  else if( dst->type == src->type && dst->type == PIKE_T_STRING ) +  { +  struct pike_string *srcs = src->u.string; +  struct pike_string *dsts = dst->u.string; +  if( dsts->len && srcs->len ) +  { +  size_t tmp = dsts->len; +  size_t tmp2 = srcs->len; +  /* +  * in case srcs==dsts +  * pike_string_cpy(MKPCHARP_STR_OFF(dsts,tmp), srcs); +  * does bad stuff +  */ +  dsts = new_realloc_shared_string( dsts, tmp+srcs->len, MAXIMUM(srcs->size_shift,dsts->size_shift) ); +  update_flags_for_add( dsts, srcs ); +  generic_memcpy(MKPCHARP_STR_OFF(dsts,tmp), MKPCHARP_STR(srcs), tmp2); +  dst->u.string = low_end_shared_string( dsts ); +  } +  else if( !dsts->len ) +  { +  free_string( dsts ); +  dst->u.string = srcs; +  srcs->refs++; +  } +  } +  else +  { +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT); +  push_svalue( src ); +  f_add(2); +  *dst = *--Pike_sp; +  } + }); +  + OPCODE2(F_ADD_LOCAL_INT_AND_POP, "local += number", 0,{ +  struct svalue *dst = Pike_fp->locals+arg1; +  if( dst->type == PIKE_T_INT +  && !INT_TYPE_ADD_OVERFLOW(dst->u.integer,arg2) ) +  { +  SET_SVAL_SUBTYPE(*dst,NUMBER_NUMBER); +  dst->u.integer += arg2; +  } +  else +  { +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT); +  push_int( arg2 ); +  f_add(2); +  *dst = *--Pike_sp; +  } + }); +  + OPCODE2(F_ADD_LOCAL_INT, "local += number local", 0,{ +  struct svalue *dst = Pike_fp->locals+arg1; +  if( dst->type == PIKE_T_INT +  && !INT_TYPE_ADD_OVERFLOW(dst->u.integer,arg2) ) +  { +  SET_SVAL_SUBTYPE(*dst,NUMBER_NUMBER); +  dst->u.integer += arg2; +  push_int( dst->u.integer ); +  } +  else +  { +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT); +  push_int( arg2 ); +  f_add(2); +  *dst = *--Pike_sp; +  } + }); +  + OPCODE1(F_INC_LOCAL, "++local", I_UPDATE_SP, { +  struct svalue *dst = Pike_fp->locals+arg1; +  if( (TYPEOF(*dst) == PIKE_T_INT) +  && !INT_TYPE_ADD_OVERFLOW(dst->u.integer, 1) ) +  { +  push_int(++dst->u.integer); +  SET_SVAL_SUBTYPE(*dst, NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } else { -  assign_svalue_no_free(Pike_sp++,Pike_fp->locals+arg1); +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT);    push_int(1);    f_add(2); -  assign_svalue(Pike_fp->locals+arg1,Pike_sp-1); +  assign_svalue(dst, Pike_sp-1);    } - BREAK; + });    - OPCODE1(F_POST_INC_LOCAL, "local++") -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); -  if( (Pike_fp->locals[arg1].type == PIKE_T_INT) - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_ADD_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1)) - #endif /* AUTO_BIGNUM */ -  ) + OPCODE1(F_POST_INC_LOCAL, "local++", I_UPDATE_SP, { +  struct svalue *dst = Pike_fp->locals+arg1; +  if( (TYPEOF(*dst) == PIKE_T_INT) +  && !INT_TYPE_ADD_OVERFLOW(dst->u.integer, 1) )    { -  Pike_fp->locals[arg1].u.integer++; +  push_int( dst->u.integer++ ); +  SET_SVAL_SUBTYPE(*dst, NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } else { -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); +  push_svalue( dst ); +  push_svalue( dst );    push_int(1);    f_add(2); -  assign_svalue(Pike_fp->locals + arg1, Pike_sp-1); -  pop_stack(); +  stack_pop_to(dst);    } - BREAK; + });    - OPCODE1(F_INC_LOCAL_AND_POP, "++local and pop") -  if( (Pike_fp->locals[arg1].type == PIKE_T_INT) - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_ADD_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1)) - #endif /* AUTO_BIGNUM */ -  ) + OPCODE1(F_INC_LOCAL_AND_POP, "++local and pop", 0, { +  struct svalue *dst = Pike_fp->locals+arg1; +  if( (TYPEOF(*dst) == PIKE_T_INT) +  && !INT_TYPE_ADD_OVERFLOW(dst->u.integer, 1) )    { -  Pike_fp->locals[arg1].u.integer++; +  dst->u.integer++; +  SET_SVAL_SUBTYPE(*dst, NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } else { -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT);    push_int(1);    f_add(2); -  assign_svalue(Pike_fp->locals + arg1, Pike_sp-1); -  pop_stack(); +  *dst = *--Pike_sp;    } - BREAK; + });    - OPCODE1(F_DEC_LOCAL, "--local") -  if( (Pike_fp->locals[arg1].type == PIKE_T_INT) - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_SUB_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1)) - #endif /* AUTO_BIGNUM */ -  ) + OPCODE1(F_DEC_LOCAL, "--local", I_UPDATE_SP, { +  struct svalue *dst = Pike_fp->locals+arg1; +  if( (TYPEOF(*dst) == PIKE_T_INT) +  && !INT_TYPE_SUB_OVERFLOW(dst->u.integer, 1) )    { -  Pike_fp->locals[arg1].u.integer--; -  assign_svalue_no_free(Pike_sp++,Pike_fp->locals+arg1); +  push_int(--(dst->u.integer)); +  SET_SVAL_SUBTYPE(*dst, NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } else { -  assign_svalue_no_free(Pike_sp++,Pike_fp->locals+arg1); +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT);    push_int(1);    o_subtract(); -  assign_svalue(Pike_fp->locals+arg1,Pike_sp-1); +  assign_svalue(dst,Pike_sp-1);    } - BREAK; + });    - OPCODE1(F_POST_DEC_LOCAL, "local--") -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); -  if( (Pike_fp->locals[arg1].type == PIKE_T_INT) - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_SUB_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1)) - #endif /* AUTO_BIGNUM */ -  ) + OPCODE1(F_POST_DEC_LOCAL, "local--", I_UPDATE_SP, { +  push_svalue( Pike_fp->locals + arg1); +  +  if( (TYPEOF(Pike_fp->locals[arg1]) == PIKE_T_INT) +  && !INT_TYPE_SUB_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1) )    {    Pike_fp->locals[arg1].u.integer--; -  +  SET_SVAL_SUBTYPE(Pike_fp->locals[arg1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } else { -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); +  push_svalue(Pike_fp->locals + arg1);    push_int(1);    o_subtract(); -  assign_svalue(Pike_fp->locals + arg1, Pike_sp-1); -  pop_stack(); +  stack_pop_to(Pike_fp->locals + arg1);    } -  /* Pike_fp->locals[instr].u.integer--; */ - BREAK; + });    - OPCODE1(F_DEC_LOCAL_AND_POP, "--local and pop") -  if( (Pike_fp->locals[arg1].type == PIKE_T_INT) - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_SUB_OVERFLOW(Pike_fp->locals[arg1].u.integer, 1)) - #endif /* AUTO_BIGNUM */ -  ) + OPCODE1(F_DEC_LOCAL_AND_POP, "--local and pop", 0, { +  struct svalue *dst = Pike_fp->locals+arg1; +  if( (TYPEOF(*dst) == PIKE_T_INT) +  && !INT_TYPE_SUB_OVERFLOW(dst->u.integer, 1) )    { -  Pike_fp->locals[arg1].u.integer--; +  --dst->u.integer; +  SET_SVAL_SUBTYPE(*dst, NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } else { -  assign_svalue_no_free(Pike_sp++, Pike_fp->locals + arg1); +  *Pike_sp++ = *dst; +  SET_SVAL_TYPE(*dst,PIKE_T_INT);    push_int(1);    o_subtract(); -  assign_svalue(Pike_fp->locals + arg1, Pike_sp-1); -  pop_stack(); +  *dst = *--Pike_sp;    } - BREAK; + });    - OPCODE0(F_LTOSVAL, "lvalue to svalue") + /* lval[0], lval[1], *Pike_sp +  * -> +  * lval[0], lval[1], result, *Pike_sp +  */ + OPCODE0(F_LTOSVAL, "lvalue to svalue", I_UPDATE_SP, { +  dmalloc_touch_svalue(Pike_sp-2); +  dmalloc_touch_svalue(Pike_sp-1);    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2);    Pike_sp++; - BREAK; +  print_return_value(); + });    - OPCODE0(F_LTOSVAL2, "ltosval2") -  Pike_sp[0] = Pike_sp[-1]; -  Pike_sp[-1].type = PIKE_T_INT; + /* The F_LTOSVAL*_AND_FREE opcodes are used to optimize foo+=bar and +  * similar things. The optimization is to free the old reference to +  * foo after it has been pushed on the stack. That way we make it +  * possible for foo to have only 1 reference, and then the low +  * array/multiset/mapping manipulation routines can be destructive if +  * they like. +  * +  * Warning: We must not release the interpreter lock while foo is +  * zeroed, or else other threads might read the zero in cases where +  * there's supposed to be none. +  * +  * FIXME: The next opcode must not throw, because then the zeroing +  * becomes permanent and can cause lasting side effects if it's a +  * global variable. F_ADD and most other opcodes currently break this. +  * +  * (Another way to handle both problems above is to restrict this +  * optimization to local variables.) +  */ +  + /* lval[0], lval[1], x, *Pike_sp +  * -> +  * lval[0], lval[1], result, x, *Pike_sp +  */ + OPCODE0(F_LTOSVAL2_AND_FREE, "ltosval2 and free", I_UPDATE_SP, { +  dmalloc_touch_svalue(Pike_sp-3); +  dmalloc_touch_svalue(Pike_sp-2); +  dmalloc_touch_svalue(Pike_sp-1); +  +  move_svalue (Pike_sp, Pike_sp - 1); +  mark_free_svalue (Pike_sp - 1);    Pike_sp++;    lvalue_to_svalue_no_free(Pike_sp-2, Pike_sp-4);    -  /* this is so that foo+=bar (and similar things) will be faster, this -  * is done by freeing the old reference to foo after it has been pushed -  * on the stack. That way foo can have only 1 reference if we are lucky, -  * and then the low array/multiset/mapping manipulation routines can be -  * destructive if they like -  */ -  if( (1 << Pike_sp[-2].type) & +  if( (1 << TYPEOF(Pike_sp[-2])) &    (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) )    { -  struct svalue s; -  s.type = PIKE_T_INT; -  s.subtype = 0; -  s.u.integer = 0; -  assign_lvalue(Pike_sp-4, &s); +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-4, &tmp);    } - BREAK; + });    - OPCODE0(F_ADD_TO_AND_POP, "+= and pop") -  Pike_sp[0]=Pike_sp[-1]; -  Pike_sp[-1].type=PIKE_T_INT; + /* lval[0], lval[1], x, y, *Pike_sp +  * -> +  * lval[0], lval[1], result, x, y, *Pike_sp +  */ + OPCODE0(F_LTOSVAL3_AND_FREE, "ltosval3 and free", I_UPDATE_SP, { +  dmalloc_touch_svalue(Pike_sp-4); +  dmalloc_touch_svalue(Pike_sp-3); +  dmalloc_touch_svalue(Pike_sp-2); +  dmalloc_touch_svalue(Pike_sp-1); +  +  move_svalue (Pike_sp, Pike_sp - 1); +  move_svalue (Pike_sp - 1, Pike_sp - 2); +  mark_free_svalue (Pike_sp - 2);    Pike_sp++; -  lvalue_to_svalue_no_free(Pike_sp-2,Pike_sp-4); +  lvalue_to_svalue_no_free(Pike_sp-3, Pike_sp-5);    -  /* this is so that foo+=bar (and similar things) will be faster, this -  * is done by freeing the old reference to foo after it has been pushed -  * on the stack. That way foo can have only 1 reference if we are lucky, -  * and then the low array/multiset/mapping manipulation routines can be -  * destructive if they like +  /* This is so that foo=foo[x..y] (and similar things) will be faster. +  * It's done by freeing the old reference to foo after it has been +  * pushed on the stack. That way foo can have only 1 reference if we +  * are lucky, and then the low array/multiset/mapping manipulation +  * routines can be destructive if they like.    */ -  if( (1 << Pike_sp[-2].type) & +  if( (1 << TYPEOF(Pike_sp[-3])) &    (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) )    { -  struct svalue s; -  s.type=PIKE_T_INT; -  s.subtype=0; -  s.u.integer=0; -  assign_lvalue(Pike_sp-4,&s); +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-5, &tmp);    } -  f_add(2); -  assign_lvalue(Pike_sp-3,Pike_sp-1); -  pop_n_elems(3); - BREAK; + });    - OPCODE1(F_GLOBAL_LVALUE, "& global") + /* lval[0], lval[1], *Pike_sp +  * -> +  * lval[0], lval[1], result, *Pike_sp +  */ + OPCODE0(F_LTOSVAL_AND_FREE, "ltosval and free", I_UPDATE_SP, { +  dmalloc_touch_svalue(Pike_sp-2); +  dmalloc_touch_svalue(Pike_sp-1); +  +  lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); +  Pike_sp++; +  +  /* See ltosval3. This opcode is used e.g. in foo = foo[..] where no +  * bound arguments are pushed on the stack. */ +  if( (1 << TYPEOF(Pike_sp[-1])) & +  (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) )    { -  struct identifier *i; -  INT32 tmp=arg1 + Pike_fp->context.identifier_level; -  if(!Pike_fp->current_object->prog) -  Pike_error("Cannot access global variables in destructed object.\n"); -  i=ID_FROM_INT(Pike_fp->current_object->prog, tmp); +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-3, &tmp); +  } + });    -  if(!IDENTIFIER_IS_VARIABLE(i->identifier_flags)) -  Pike_error("Cannot re-assign functions or constants.\n"); + OPCODE0(F_ADD_TO, "+=", I_UPDATE_SP, { +  ONERROR uwp; +  move_svalue (Pike_sp, Pike_sp - 1); +  mark_free_svalue (Pike_sp - 1); +  Pike_sp++; +  lvalue_to_svalue_no_free(Pike_sp-2,Pike_sp-4);    -  if(i->run_time_type == PIKE_T_MIXED) +  if( TYPEOF(Pike_sp[-1]) == PIKE_T_INT && +  TYPEOF(Pike_sp[-2]) == PIKE_T_INT )    { -  Pike_sp[0].type=T_LVALUE; -  Pike_sp[0].u.lval=(struct svalue *)GLOBAL_FROM_INT(tmp); -  }else{ -  Pike_sp[0].type=T_SHORT_LVALUE; -  Pike_sp[0].u.short_lval= (union anything *)GLOBAL_FROM_INT(tmp); -  Pike_sp[0].subtype=i->run_time_type; +  if(!INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, Pike_sp[-2].u.integer)) +  { +  /* Optimization for a rather common case. Makes it 30% faster. */ +  INT_TYPE val = (Pike_sp[-1].u.integer += Pike_sp[-2].u.integer); +  SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */ +  assign_lvalue(Pike_sp-4,Pike_sp-1); +  Pike_sp-=2; +  pop_2_elems(); +  push_int(val); +  goto add_to_done;    } -  Pike_sp[1].type=T_VOID; -  Pike_sp+=2; +     } - BREAK; +  /* This is so that foo+=bar (and similar things) will be faster. +  * It's done by freeing the old reference to foo after it has been +  * pushed on the stack. That way foo can have only 1 reference if we +  * are lucky, and then the low array/multiset/mapping manipulation +  * routines can be destructive if they like. +  */ +  if( (1 << TYPEOF(Pike_sp[-2])) & +  (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) ) +  { +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-4, &tmp); +  } else if (TYPEOF(Pike_sp[-2]) == T_OBJECT) { +  /* One ref in the lvalue, and one on the stack. */ +  int i; +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct program *p); +  if((o = Pike_sp[-2].u.object)->refs <= 2 && +  (p = o->prog) && +  (i = FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-2])].prog, +  LFUN_ADD_EQ)) != -1) +  { +  apply_low(o, i + p->inherits[SUBTYPEOF(Pike_sp[-2])].identifier_level, 1); +  /* NB: The lvalue already contains the object, so +  * no need to reassign it. +  */ +  pop_stack(); +  stack_pop_2_elems_keep_top(); +  goto add_to_done; +  } +  } +  /* NOTE: Pike_sp-4 is the lvalue, Pike_sp-2 is the original value. +  * If an error gets thrown, the original value will thus be restored. +  * If f_add() succeeds, Pike_sp-2 will hold the result. +  */ +  SET_ONERROR(uwp, o_assign_lvalue, Pike_sp-4); +  f_add(2); +  CALL_AND_UNSET_ONERROR(uwp); /* assign_lvalue(Pike_sp-3,Pike_sp-1); */ +  stack_pop_2_elems_keep_top(); +  add_to_done: +  ; /* make gcc happy */ + });    - OPCODE0(F_INC, "++x") + OPCODE0(F_ADD_TO_AND_POP, "+= and pop", I_UPDATE_SP, { +  ONERROR uwp; +  move_svalue (Pike_sp, Pike_sp - 1); +  mark_free_svalue (Pike_sp - 1); +  Pike_sp++; +  lvalue_to_svalue_no_free(Pike_sp-2,Pike_sp-4); +  +  if( TYPEOF(Pike_sp[-1]) == PIKE_T_INT && +  TYPEOF(Pike_sp[-2]) == PIKE_T_INT )    { -  +  if(!INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, Pike_sp[-2].u.integer)) +  { +  /* Optimization for a rather common case. Makes it 30% faster. */ +  Pike_sp[-1].u.integer += Pike_sp[-2].u.integer; +  SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */ +  assign_lvalue(Pike_sp-4,Pike_sp-1); +  Pike_sp-=2; +  pop_2_elems(); +  goto add_to_and_pop_done; +  } +  } +  /* This is so that foo+=bar (and similar things) will be faster. +  * It's done by freeing the old reference to foo after it has been +  * pushed on the stack. That way foo can have only 1 reference if we +  * are lucky, and then the low array/multiset/mapping manipulation +  * routines can be destructive if they like. +  */ +  if( (1 << TYPEOF(Pike_sp[-2])) & +  (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) ) +  { +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-4, &tmp); +  } else if (TYPEOF(Pike_sp[-2]) == PIKE_T_OBJECT) { +  /* One ref in the lvalue, and one on the stack. */ +  int i; +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct program *p); +  if((o = Pike_sp[-2].u.object)->refs <= 2 && +  (p = o->prog) && +  (i = FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-2])].prog, +  LFUN_ADD_EQ)) != -1) +  { +  apply_low(o, i + p->inherits[SUBTYPEOF(Pike_sp[-2])].identifier_level, 1); +  /* NB: The lvalue already contains the object, so +  * no need to reassign it. +  */ +  pop_n_elems(4); +  goto add_to_and_pop_done; +  } +  } +  /* NOTE: Pike_sp-4 is the lvalue, Pike_sp-2 is the original value. +  * If an error gets thrown, the original value will thus be restored. +  * If f_add() succeeds, Pike_sp-2 will hold the result. +  */ +  SET_ONERROR(uwp, o_assign_lvalue, Pike_sp-4); +  f_add(2); +  CALL_AND_UNSET_ONERROR(uwp); /* assign_lvalue(Pike_sp-3,Pike_sp-1); */ +  pop_n_elems(3); +  add_to_and_pop_done: +  ; /* make gcc happy */ + }); +  + OPCODE1(F_GLOBAL_LVALUE, "& global", I_UPDATE_SP, { +  ref_push_object(Pike_fp->current_object); +  push_obj_index(arg1 + Pike_fp->context->identifier_level); + }); +  + OPCODE0(F_INC, "++x", I_UPDATE_SP, {    union anything *u=get_pointer_if_this_type(Pike_sp-2, PIKE_T_INT); -  if(u - #ifdef AUTO_BIGNUM -  && !INT_TYPE_ADD_OVERFLOW(u->integer, 1) - #endif -  ) +  if(u && !INT_TYPE_ADD_OVERFLOW(u->integer, 1))    { -  instr=++ u->integer; -  pop_n_elems(2); -  push_int(u->integer); +  INT_TYPE val = ++u->integer; +  pop_2_elems(); +  push_int(val);    } else {    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); Pike_sp++;    push_int(1);    f_add(2);    assign_lvalue(Pike_sp-3, Pike_sp-1); -  assign_svalue(Pike_sp-3, Pike_sp-1); -  pop_n_elems(2); +  stack_pop_2_elems_keep_top();    } - } - BREAK; + });    - OPCODE0(F_DEC, "--x") - { + OPCODE0(F_DEC, "--x", I_UPDATE_SP, {    union anything *u=get_pointer_if_this_type(Pike_sp-2, PIKE_T_INT); -  if(u - #ifdef AUTO_BIGNUM -  && !INT_TYPE_SUB_OVERFLOW(u->integer, 1) - #endif -  ) +  if(u && !INT_TYPE_SUB_OVERFLOW(u->integer, 1))    { -  instr=-- u->integer; -  pop_n_elems(2); -  push_int(u->integer); +  INT_TYPE val = --u->integer; +  pop_2_elems(); +  push_int(val);    } else {    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); Pike_sp++;    push_int(1);    o_subtract();    assign_lvalue(Pike_sp-3, Pike_sp-1); -  assign_svalue(Pike_sp-3, Pike_sp-1); -  pop_n_elems(2); +  stack_pop_2_elems_keep_top();    } - } - BREAK; + });    - OPCODE0(F_DEC_AND_POP, "x-- and pop") - { + OPCODE0(F_DEC_AND_POP, "x-- and pop", I_UPDATE_SP, {    union anything *u=get_pointer_if_this_type(Pike_sp-2, PIKE_T_INT); -  if(u - #ifdef AUTO_BIGNUM -  && !INT_TYPE_SUB_OVERFLOW(u->integer, 1) - #endif - ) +  if(u && !INT_TYPE_SUB_OVERFLOW(u->integer, 1))    { -  instr=-- u->integer; -  pop_n_elems(2); +  --u->integer; +  pop_2_elems();    }else{    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); Pike_sp++;    push_int(1);    o_subtract();    assign_lvalue(Pike_sp-3, Pike_sp-1);    pop_n_elems(3);    } - } - BREAK; + });    - OPCODE0(F_INC_AND_POP, "x++ and pop") - { + OPCODE0(F_INC_AND_POP, "x++ and pop", I_UPDATE_SP, {    union anything *u=get_pointer_if_this_type(Pike_sp-2, PIKE_T_INT); -  if(u - #ifdef AUTO_BIGNUM -  && !INT_TYPE_ADD_OVERFLOW(u->integer, 1) - #endif -  ) +  if(u && !INT_TYPE_ADD_OVERFLOW(u->integer, 1))    { -  instr=++ u->integer; -  pop_n_elems(2); +  ++u->integer; +  pop_2_elems();    } else {    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); Pike_sp++;    push_int(1);    f_add(2);    assign_lvalue(Pike_sp-3, Pike_sp-1);    pop_n_elems(3);    } - } - BREAK; + });    - OPCODE0(F_POST_INC, "x++") - { + OPCODE0(F_POST_INC, "x++", I_UPDATE_SP, {    union anything *u=get_pointer_if_this_type(Pike_sp-2, PIKE_T_INT); -  if(u - #ifdef AUTO_BIGNUM -  && !INT_TYPE_ADD_OVERFLOW(u->integer, 1) - #endif -  ) +  if(u && !INT_TYPE_ADD_OVERFLOW(u->integer, 1))    { -  instr=u->integer ++; -  pop_n_elems(2); -  push_int(instr); +  INT_TYPE val = u->integer++; +  pop_2_elems(); +  push_int(val);    } else {    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); Pike_sp++; -  assign_svalue_no_free(Pike_sp,Pike_sp-1); Pike_sp++; +  stack_dup();    push_int(1);    f_add(2);    assign_lvalue(Pike_sp-4, Pike_sp-1); -  assign_svalue(Pike_sp-4, Pike_sp-2); -  pop_n_elems(3); +  pop_stack(); +  stack_pop_2_elems_keep_top(); +  print_return_value();    } - } - BREAK; + });    - OPCODE0(F_POST_DEC, "x--") - { + OPCODE0(F_POST_DEC, "x--", I_UPDATE_SP, {    union anything *u=get_pointer_if_this_type(Pike_sp-2, PIKE_T_INT); -  if(u - #ifdef AUTO_BIGNUM -  && !INT_TYPE_SUB_OVERFLOW(u->integer, 1) - #endif -  ) +  if(u && !INT_TYPE_SUB_OVERFLOW(u->integer, 1))    { -  instr=u->integer --; -  pop_n_elems(2); -  push_int(instr); +  INT_TYPE val = u->integer--; +  pop_2_elems(); +  push_int(val);    } else {    lvalue_to_svalue_no_free(Pike_sp, Pike_sp-2); Pike_sp++; -  assign_svalue_no_free(Pike_sp,Pike_sp-1); Pike_sp++; +  stack_dup();    push_int(1);    o_subtract();    assign_lvalue(Pike_sp-4, Pike_sp-1); -  assign_svalue(Pike_sp-4, Pike_sp-2); -  pop_n_elems(3); +  pop_stack(); +  stack_pop_2_elems_keep_top(); +  print_return_value();    } - } - BREAK; + });    - OPCODE1(F_ASSIGN_LOCAL,"assign local") + OPCODE1(F_ASSIGN_LOCAL, "assign local", 0, {    assign_svalue(Pike_fp->locals+arg1,Pike_sp-1); - BREAK; + });    - OPCODE0(F_ASSIGN, "assign") + OPCODE0(F_ASSIGN, "assign", I_UPDATE_SP, {    assign_lvalue(Pike_sp-3,Pike_sp-1);    free_svalue(Pike_sp-3);    free_svalue(Pike_sp-2); -  Pike_sp[-3]=Pike_sp[-1]; +  move_svalue (Pike_sp - 3, Pike_sp - 1);    Pike_sp-=2; - BREAK; + });    - OPCODE2(F_APPLY_ASSIGN_LOCAL_AND_POP,"apply, assign local and pop") -  strict_apply_svalue(&((Pike_fp->context.prog->constants + arg1)->sval), -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp)); + OPCODE2(F_APPLY_ASSIGN_LOCAL_AND_POP, "apply, assign local and pop", I_UPDATE_SP|I_UPDATE_M_SP, { +  apply_svalue(&((Pike_fp->context->prog->constants + arg1)->sval), +  DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)));    free_svalue(Pike_fp->locals+arg2); -  Pike_fp->locals[arg2]=Pike_sp[-1]; +  move_svalue (Pike_fp->locals + arg2, Pike_sp - 1);    Pike_sp--; - BREAK; + });    - OPCODE2(F_APPLY_ASSIGN_LOCAL,"apply, assign local") -  strict_apply_svalue(&((Pike_fp->context.prog->constants + arg1)->sval), -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp)); + OPCODE2(F_APPLY_ASSIGN_LOCAL, "apply, assign local", I_UPDATE_ALL, { +  apply_svalue(&((Pike_fp->context->prog->constants + arg1)->sval), +  DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)));    assign_svalue(Pike_fp->locals+arg2, Pike_sp-1); - BREAK; + });    - OPCODE0(F_ASSIGN_AND_POP, "assign and pop") + OPCODE0(F_ASSIGN_AND_POP, "assign and pop", I_UPDATE_SP, {    assign_lvalue(Pike_sp-3, Pike_sp-1);    pop_n_elems(3); - BREAK; + });    - OPCODE1(F_ASSIGN_LOCAL_AND_POP, "assign local and pop") + OPCODE1(F_ASSIGN_LOCAL_AND_POP, "assign local and pop", I_UPDATE_SP, {    free_svalue(Pike_fp->locals + arg1); -  Pike_fp->locals[arg1] = Pike_sp[-1]; +  move_svalue (Pike_fp->locals + arg1, Pike_sp - 1);    Pike_sp--; - BREAK; + });    - OPCODE1(F_ASSIGN_GLOBAL, "assign global") - { -  struct identifier *i; -  INT32 tmp=arg1 + Pike_fp->context.identifier_level; -  if(!Pike_fp->current_object->prog) -  Pike_error("Cannot access global variables in destructed object.\n"); + OPCODE2(F_ASSIGN_LOCAL_NUMBER_AND_POP, "assign local number and pop", 0, { +  free_svalue(Pike_fp->locals + arg1); +  SET_SVAL(Pike_fp->locals[arg1], PIKE_T_INT, 0, integer, arg2); + });    -  i=ID_FROM_INT(Pike_fp->current_object->prog, tmp); -  if(!IDENTIFIER_IS_VARIABLE(i->identifier_flags)) -  Pike_error("Cannot assign functions or constants.\n"); -  if(i->run_time_type == PIKE_T_MIXED) -  { -  assign_svalue((struct svalue *)GLOBAL_FROM_INT(tmp), Pike_sp-1); -  }else{ -  assign_to_short_svalue((union anything *)GLOBAL_FROM_INT(tmp), -  i->run_time_type, + OPCODE1(F_ASSIGN_GLOBAL, "assign global", 0, { +  object_low_set_index(Pike_fp->current_object, +  arg1 + Pike_fp->context->identifier_level,    Pike_sp-1); -  } - } - BREAK; + });    - OPCODE1(F_ASSIGN_GLOBAL_AND_POP, "assign global and pop") - { -  struct identifier *i; -  INT32 tmp=arg1 + Pike_fp->context.identifier_level; -  if(!Pike_fp->current_object->prog) -  Pike_error("Cannot access global variables in destructed object.\n"); -  -  i=ID_FROM_INT(Pike_fp->current_object->prog, tmp); -  if(!IDENTIFIER_IS_VARIABLE(i->identifier_flags)) -  Pike_error("Cannot assign functions or constants.\n"); -  -  if(i->run_time_type == PIKE_T_MIXED) -  { -  struct svalue *s=(struct svalue *)GLOBAL_FROM_INT(tmp); -  free_svalue(s); -  Pike_sp--; -  *s=*Pike_sp; -  }else{ -  assign_to_short_svalue((union anything *)GLOBAL_FROM_INT(tmp), -  i->run_time_type, + OPCODE1(F_ASSIGN_GLOBAL_AND_POP, "assign global and pop", I_UPDATE_SP, { +  object_low_set_index(Pike_fp->current_object, +  arg1 + Pike_fp->context->identifier_level,    Pike_sp-1);    pop_stack(); -  } - } - BREAK; + });    -  + OPCODE2(F_ASSIGN_GLOBAL_NUMBER_AND_POP, "assign global number and pop", 0, { +  struct svalue tmp; +  SET_SVAL(tmp,PIKE_T_INT,0,integer,arg2); +  object_low_set_index(Pike_fp->current_object, +  arg1 + Pike_fp->context->identifier_level, +  &tmp); + });    -  +    /* Stack machine stuff */    - OPCODE0(F_POP_VALUE, "pop") + OPCODE0(F_POP_VALUE, "pop", I_UPDATE_SP, {    pop_stack(); - BREAK; + });    - OPCODE1(F_POP_N_ELEMS, "pop_n_elems") + OPCODE1(F_POP_N_ELEMS, "pop_n_elems", I_UPDATE_SP, {    pop_n_elems(arg1); - BREAK; + });    - OPCODE0_TAIL(F_MARK2,"mark mark") + OPCODE0_TAIL(F_MARK2, "mark mark", I_UPDATE_M_SP, {    *(Pike_mark_sp++)=Pike_sp; - OPCODE0(F_MARK,"mark") +  + /* This opcode is only used when running with -d. Identical to F_MARK, +  * but with a different name to make the debug printouts more clear. */ +  OPCODE0_TAIL(F_SYNCH_MARK, "synch mark", I_UPDATE_M_SP, { +  +  OPCODE0(F_MARK, "mark", I_UPDATE_M_SP, {    *(Pike_mark_sp++)=Pike_sp; - BREAK; +  }); +  }); + });    - OPCODE1(F_MARK_X, "mark Pike_sp-X") + OPCODE1(F_MARK_X, "mark Pike_sp-X", I_UPDATE_M_SP, {    *(Pike_mark_sp++)=Pike_sp-arg1; - BREAK; + });    - OPCODE0(F_POP_MARK, "pop mark") + OPCODE0(F_POP_MARK, "pop mark", I_UPDATE_M_SP, {    --Pike_mark_sp; - BREAK; + });    - OPCODE0(F_CLEAR_STRING_SUBTYPE, "clear string subtype") -  if(Pike_sp[-1].type==PIKE_T_STRING) Pike_sp[-1].subtype=0; - BREAK; + OPCODE0(F_POP_TO_MARK, "pop to mark", I_UPDATE_SP|I_UPDATE_M_SP, { +  pop_n_elems(Pike_sp - *--Pike_mark_sp); + });    -  + /* These opcodes are only used when running with -d. The reason for +  * the two aliases is mainly to keep the indentation in asm debug +  * output. */ + OPCODE0_TAIL(F_CLEANUP_SYNCH_MARK, "cleanup synch mark", I_UPDATE_SP|I_UPDATE_M_SP, { +  OPCODE0(F_POP_SYNCH_MARK, "pop synch mark", I_UPDATE_SP|I_UPDATE_M_SP, { +  if (d_flag) { +  if (Pike_mark_sp <= Pike_interpreter.mark_stack) { +  Pike_fatal("Mark stack out of synch - %p <= %p.\n", +  Pike_mark_sp, Pike_interpreter.mark_stack); +  } else if (*--Pike_mark_sp != Pike_sp) { +  ptrdiff_t should = *Pike_mark_sp - Pike_interpreter.evaluator_stack; +  ptrdiff_t is = Pike_sp - Pike_interpreter.evaluator_stack; +  if (Pike_sp - *Pike_mark_sp > 0) /* not always same as Pike_sp > *Pike_mark_sp */ +  /* Some attempt to recover, just to be able to report the backtrace. */ +  pop_n_elems(Pike_sp - *Pike_mark_sp); +  Pike_fatal("Stack out of synch - " +  "should be %"PRINTPTRDIFFT"d, is %"PRINTPTRDIFFT"d.\n", +  should, is); +  } +  } +  }); + }); +  + OPCODE0(F_CLEAR_STRING_SUBTYPE, "clear string subtype", 0, { +  if(TYPEOF(Pike_sp[-1]) == PIKE_T_STRING) SET_SVAL_SUBTYPE(Pike_sp[-1], 0); + }); +     /* Jumps */ - OPCODE0_JUMP(F_BRANCH,"branch") -  DOJUMP(); - BREAK; + OPCODE0_BRANCH(F_BRANCH, "branch", 0, { +  DO_BRANCH(); + });    - OPCODE2(F_BRANCH_IF_NOT_LOCAL_ARROW,"branch if !local->x") - { -  struct svalue tmp; -  tmp.type=PIKE_T_STRING; -  tmp.u.string=Pike_fp->context.prog->strings[arg1]; -  tmp.subtype=1; -  Pike_sp->type=PIKE_T_INT; + OPCODE2_BRANCH(F_BRANCH_IF_NOT_LOCAL_ARROW, "branch if !local->x", 0, { +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_STRING, 1, string, +  Pike_fp->context->prog->strings[arg1]); +  mark_free_svalue (Pike_sp);    Pike_sp++;    index_no_free(Pike_sp-1,Pike_fp->locals+arg2, &tmp);    print_return_value(); - } +        /* Fall through */    - OPCODE0_TAILJUMP(F_BRANCH_WHEN_ZERO,"branch if zero") -  if(!IS_ZERO(Pike_sp-1)) +  OPCODE0_TAILBRANCH(F_BRANCH_WHEN_ZERO, "branch if zero", I_UPDATE_SP, { +  if(!UNSAFE_IS_ZERO(Pike_sp-1))    { -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    }else{ -  DOJUMP(); +  DO_BRANCH();    }    pop_stack(); - BREAK; +  }); + });    -  + OPCODE0_BRANCH(F_QUICK_BRANCH_WHEN_ZERO, "(Q) branch if zero", I_UPDATE_SP, { +  if(Pike_sp[-1].u.integer) +  { +  DONT_BRANCH(); +  }else{ +  DO_BRANCH(); +  } +  pop_stack(); +  });    - OPCODE0_JUMP(F_BRANCH_WHEN_NON_ZERO,"branch if not zero") -  if(IS_ZERO(Pike_sp-1)) + OPCODE0_BRANCH(F_QUICK_BRANCH_WHEN_NON_ZERO, "(Q) branch if not zero", I_UPDATE_SP, { +  if(Pike_sp[-1].u.integer)    { -  SKIPJUMP(); +  DO_BRANCH();    }else{ -  DOJUMP(); +  DONT_BRANCH();    }    pop_stack(); - BREAK + });    - OPCODE1_JUMP(F_BRANCH_IF_LOCAL,"branch if local") -  if(IS_ZERO(Pike_fp->locals + arg1)) + OPCODE0_BRANCH(F_BRANCH_WHEN_NON_ZERO, "branch if not zero", I_UPDATE_SP, { +  if(UNSAFE_IS_ZERO(Pike_sp-1))    { -  SKIPJUMP(); +  DONT_BRANCH();    }else{ -  DOJUMP(); +  DO_BRANCH();    } - BREAK; +  pop_stack(); + });    -  CASE(F_BRANCH_IF_NOT_LOCAL); -  instr=GET_ARG(); -  if(!IS_ZERO(Pike_fp->locals + instr)) + OPCODE1_BRANCH(F_BRANCH_IF_TYPE_IS_NOT, "branch if type is !=", I_UPDATE_SP, { + /* fprintf(stderr,"******BRANCH IF TYPE IS NOT***** %s\n",get_name_of_type(arg1)); */ +  LOCAL_VAR(struct object *o); +  if(TYPEOF(Pike_sp[-1]) == T_OBJECT && +  (o = Pike_sp[-1].u.object)->prog)    { -  SKIPJUMP(); +  int fun = FIND_LFUN(o->prog->inherits[SUBTYPEOF(Pike_sp[-1])].prog, +  LFUN__IS_TYPE); +  if(fun != -1) +  { + /* fprintf(stderr,"******OBJECT OVERLOAD IN TYPEP***** %s\n",get_name_of_type(arg1)); */ +  push_text(get_name_of_type(arg1)); +  apply_low(o, fun + +  o->prog->inherits[SUBTYPEOF(Pike_sp[-2])].identifier_level, 1); +  arg1=UNSAFE_IS_ZERO(Pike_sp-1) ? T_FLOAT : T_OBJECT ; +  pop_stack(); +  } +  } +  if(TYPEOF(Pike_sp[-1]) == arg1) +  { +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    }else{ -  DOJUMP(); +  DO_BRANCH();    } -  break; +  pop_stack(); + });    -  CJUMP(F_BRANCH_WHEN_EQ, is_eq); -  CJUMP(F_BRANCH_WHEN_NE,!is_eq); -  CJUMP(F_BRANCH_WHEN_LT, is_lt); -  CJUMP(F_BRANCH_WHEN_LE,!is_gt); -  CJUMP(F_BRANCH_WHEN_GT, is_gt); -  CJUMP(F_BRANCH_WHEN_GE,!is_lt); + OPCODE1_BRANCH(F_BRANCH_IF_LOCAL, "branch if local", 0, { +  if(UNSAFE_IS_ZERO(Pike_fp->locals + arg1)) +  { +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH(); +  }else{ +  DO_BRANCH(); +  } + });    -  CASE(F_BRANCH_AND_POP_WHEN_ZERO); -  if(!IS_ZERO(Pike_sp-1)) + OPCODE1_BRANCH(F_BRANCH_IF_NOT_LOCAL, "branch if !local", 0, { +  if(!UNSAFE_IS_ZERO(Pike_fp->locals + arg1))    { -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    }else{ -  DOJUMP(); +  DO_BRANCH(); +  } + }); +  + #define CJUMP(X, DESC, Y) \ +  OPCODE0_BRANCH(X, DESC, I_UPDATE_SP, { \ +  if(Y(Pike_sp-2,Pike_sp-1)) { \ +  DO_BRANCH(); \ +  }else{ \ +  /* write_to_stderr("foreach\n", 8); */ \ +  DONT_BRANCH(); \ +  } \ +  pop_2_elems(); \ +  }) +  + CJUMP(F_BRANCH_WHEN_EQ, "branch if ==", is_eq); + CJUMP(F_BRANCH_WHEN_NE, "branch if !=", !is_eq); + CJUMP(F_BRANCH_WHEN_LT, "branch if <", is_lt); + CJUMP(F_BRANCH_WHEN_LE, "branch if <=", is_le); + CJUMP(F_BRANCH_WHEN_GT, "branch if >", is_gt); + CJUMP(F_BRANCH_WHEN_GE, "branch if >=", is_ge); +  + OPCODE0_BRANCH(F_BRANCH_AND_POP_WHEN_ZERO, "branch & pop if zero", 0, { +  if(!UNSAFE_IS_ZERO(Pike_sp-1)) +  { +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH(); +  }else{ +  DO_BRANCH();    pop_stack();    } -  break; + });    -  CASE(F_BRANCH_AND_POP_WHEN_NON_ZERO); -  if(IS_ZERO(Pike_sp-1)) + OPCODE0_BRANCH(F_BRANCH_AND_POP_WHEN_NON_ZERO, "branch & pop if !zero", 0, { +  if(UNSAFE_IS_ZERO(Pike_sp-1))    { -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    }else{ -  DOJUMP(); +  DO_BRANCH();    pop_stack();    } -  break; + });    -  CASE(F_LAND); -  if(!IS_ZERO(Pike_sp-1)) + OPCODE0_BRANCH(F_LAND, "&&", I_UPDATE_SP, { +  if(!UNSAFE_IS_ZERO(Pike_sp-1))    { -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    pop_stack();    }else{ -  DOJUMP(); +  DO_BRANCH();    } -  break; + });    -  CASE(F_LOR); -  if(IS_ZERO(Pike_sp-1)) + OPCODE0_BRANCH(F_LOR, "||", I_UPDATE_SP, { +  if(UNSAFE_IS_ZERO(Pike_sp-1))    { -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    pop_stack();    }else{ -  DOJUMP(); +  DO_BRANCH();    } -  break; + });    -  CASE(F_EQ_OR); + OPCODE0_BRANCH(F_EQ_OR, "==||", I_UPDATE_SP, {    if(!is_eq(Pike_sp-2,Pike_sp-1))    { -  pop_n_elems(2); -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH(); +  pop_2_elems();    }else{ -  pop_n_elems(2); +  DO_BRANCH(); +  pop_2_elems();    push_int(1); -  DOJUMP(); +     } -  break; + });    -  CASE(F_EQ_AND); + OPCODE0_BRANCH(F_EQ_AND, "==&&", I_UPDATE_SP, {    if(is_eq(Pike_sp-2,Pike_sp-1))    { -  pop_n_elems(2); -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH(); +  pop_2_elems();    }else{ -  pop_n_elems(2); +  DO_BRANCH(); +  pop_2_elems();    push_int(0); -  DOJUMP(); +     } -  break; + });    -  CASE(F_CATCH); -  switch (o_catch(pc+sizeof(INT32))) { -  case 1: -  return -1; /* There was a return inside the evaluated code */ -  case 2: -  pc = Pike_fp->pc; -  break; -  default: -  pc+=EXTRACT_INT(pc); + #ifndef ENTRY_PROLOGUE_SIZE + #define ENTRY_PROLOGUE_SIZE 0 + #endif +  + /* Ideally this ought to be an OPCODE0_PTRRETURN but I don't fancy +  * adding that variety to this macro hell. At the end of the day there +  * wouldn't be any difference anyway afaics. /mast */ + OPCODE0_PTRJUMP(F_CATCH, "catch", I_UPDATE_ALL|I_RETURN, { +  PIKE_OPCODE_T *addr; +  +  { +  struct catch_context *new_catch_ctx = alloc_catch_context(); +  DO_IF_REAL_DEBUG ( +  new_catch_ctx->frame = Pike_fp; +  init_recovery (&new_catch_ctx->recovery, 0, 0, PERR_LOCATION()); +  ); +  DO_IF_NOT_REAL_DEBUG ( +  init_recovery (&new_catch_ctx->recovery, 0); +  ); +  new_catch_ctx->save_expendible = Pike_fp->expendible; +  JUMP_SET_TO_PC_AT_NEXT (addr); +  new_catch_ctx->continue_reladdr = GET_JUMP() +  /* We need to run the entry prologue... */ +  - ENTRY_PROLOGUE_SIZE; +  +  new_catch_ctx->next_addr = addr; +  new_catch_ctx->prev = Pike_interpreter.catch_ctx; +  Pike_interpreter.catch_ctx = new_catch_ctx; +  DO_IF_DEBUG({ +  TRACE((3,"- Pushed catch context %p\n", new_catch_ctx)); +  });    } -  +  +  Pike_fp->expendible = Pike_fp->locals + Pike_fp->num_locals; +  +  /* Need to adjust next_addr by sizeof(INT32) to skip past the jump +  * address to the continue position after the catch block. */ +  addr = (PIKE_OPCODE_T *) ((INT32 *) addr + 1); +  +  if (Pike_interpreter.catching_eval_jmpbuf) { +  /* There's already a catching_eval_instruction around our +  * eval_instruction, so we can just continue. */ +  debug_malloc_touch_named (Pike_interpreter.catch_ctx, "(1)"); +  /* Skip past the entry prologue... */ +  addr += ENTRY_PROLOGUE_SIZE; +  SET_PROG_COUNTER(addr); +  FETCH; +  DO_IF_DEBUG({ +  TRACE((3,"- In active catch; continuing at %p\n", addr)); +  }); +  JUMP_DONE; +  } +  +  else { +  debug_malloc_touch_named (Pike_interpreter.catch_ctx, "(2)"); +  +  while (1) { +  /* Loop here every time an exception is caught. Once we've +  * gotten here and set things up to run eval_instruction from +  * inside catching_eval_instruction, we keep doing it until it's +  * time to return. */ +  +  int res; +  +  DO_IF_DEBUG({ +  TRACE((3,"- Activating catch; calling %p in context %p\n", +  addr, Pike_interpreter.catch_ctx)); +  }); +  +  res = catching_eval_instruction (addr); +  +  DO_IF_DEBUG({ +  TRACE((3,"- catching_eval_instruction(%p) returned %d\n", +  addr, res)); +  }); +  +  if (res != -3) { +  /* There was an inter return inside the evaluated code. Just +  * propagate it. */ +  DO_IF_DEBUG ({ +  TRACE((3,"- Returning from catch.\n")); +  if (res != -1) Pike_fatal ("Unexpected return value from " +  "catching_eval_instruction: %d\n", res); +  });    break; -  +  }    - OPCODE0(F_ESCAPE_CATCH, "escape catch") - { -  Pike_fp->pc = pc; -  return -2; +  else { +  /* Caught an exception. */ +  struct catch_context *cc = Pike_interpreter.catch_ctx; +  +  DO_IF_DEBUG ({ +  TRACE((3,"- Caught exception. catch context: %p\n", cc)); +  if (!cc) Pike_fatal ("Catch context dropoff.\n"); +  if (cc->frame != Pike_fp) +  Pike_fatal ("Catch context doesn't belong to this frame.\n"); +  }); +  +  debug_malloc_touch_named (cc, "(3)"); +  UNSETJMP (cc->recovery); +  Pike_fp->expendible = cc->save_expendible; +  move_svalue (Pike_sp++, &throw_value); +  mark_free_svalue (&throw_value); +  low_destruct_objects_to_destruct(); +  +  if (cc->continue_reladdr < 0) +  FAST_CHECK_THREADS_ON_BRANCH(); +  addr = cc->next_addr + cc->continue_reladdr; +  +  DO_IF_DEBUG({ +  TRACE((3,"- Popping catch context %p ==> %p\n", +  cc, cc->prev)); +  if (!addr) Pike_fatal ("Unexpected null continue addr.\n"); +  }); +  +  Pike_interpreter.catch_ctx = cc->prev; +  really_free_catch_context (cc);    } - BREAK; +  }    - OPCODE0(F_THROW_ZERO, "throw(0)") -  push_int(0); -  f_throw(1); - BREAK; +  INTER_RETURN; +  } + });    - OPCODE1(F_SWITCH, "switch") - { + OPCODE0(F_ESCAPE_CATCH, "escape catch", 0, { +  POP_CATCH_CONTEXT; + }); +  + OPCODE0(F_EXIT_CATCH, "exit catch", I_UPDATE_SP, { +  push_undefined(); +  POP_CATCH_CONTEXT; + }); +  + OPCODE1_JUMP(F_SWITCH, "switch", I_UPDATE_ALL, {    INT32 tmp; -  tmp=switch_lookup(Pike_fp->context.prog-> +  PIKE_OPCODE_T *addr; +  JUMP_SET_TO_PC_AT_NEXT (addr); +  tmp=switch_lookup(Pike_fp->context->prog->    constants[arg1].sval.u.array,Pike_sp-1); -  pc=(unsigned char *)DO_ALIGN(pc,sizeof(INT32)); -  pc+=(tmp>=0 ? 1+tmp*2 : 2*~tmp) * sizeof(INT32); -  if(*(INT32*)pc < 0) fast_check_threads_etc(7); -  pc+=*(INT32*)pc; +  addr = DO_IF_ELSE_COMPUTED_GOTO(addr, (PIKE_OPCODE_T *) +  DO_ALIGN(PTR_TO_INT(addr), +  ((ptrdiff_t)sizeof(INT32)))); +  addr = (PIKE_OPCODE_T *)(((INT32 *)addr) + (tmp>=0 ? 1+tmp*2 : 2*~tmp)); +  if(*(INT32*)addr < 0) FAST_CHECK_THREADS_ON_BRANCH();    pop_stack(); - } - BREAK; +  DO_JUMP_TO(addr + *(INT32*)addr); + });    - OPCODE1(F_SWITCH_ON_INDEX, "switch on index") - { + OPCODE1_JUMP(F_SWITCH_ON_INDEX, "switch on index", I_UPDATE_ALL, {    INT32 tmp; -  struct svalue s; -  index_no_free(&s,Pike_sp-2,Pike_sp-1); -  Pike_sp++[0]=s; +  PIKE_OPCODE_T *addr; +  LOCAL_VAR(struct svalue tmp2); +  JUMP_SET_TO_PC_AT_NEXT (addr); +  index_no_free(&tmp2, Pike_sp-2, Pike_sp-1); +  move_svalue (Pike_sp++, &tmp2);    -  tmp=switch_lookup(Pike_fp->context.prog-> +  tmp=switch_lookup(Pike_fp->context->prog->    constants[arg1].sval.u.array,Pike_sp-1);    pop_n_elems(3); -  pc=(unsigned char *)DO_ALIGN(pc,sizeof(INT32)); -  pc+=(tmp>=0 ? 1+tmp*2 : 2*~tmp) * sizeof(INT32); -  if(*(INT32*)pc < 0) fast_check_threads_etc(7); -  pc+=*(INT32*)pc; - } - BREAK; +  addr = DO_IF_ELSE_COMPUTED_GOTO(addr, (PIKE_OPCODE_T *) +  DO_ALIGN(PTR_TO_INT(addr), +  ((ptrdiff_t)sizeof(INT32)))); +  addr = (PIKE_OPCODE_T *)(((INT32 *)addr) + (tmp>=0 ? 1+tmp*2 : 2*~tmp)); +  if(*(INT32*)addr < 0) FAST_CHECK_THREADS_ON_BRANCH(); +  DO_JUMP_TO(addr + *(INT32*)addr); + });    - OPCODE2(F_SWITCH_ON_LOCAL, "switch on local") - { + OPCODE2_JUMP(F_SWITCH_ON_LOCAL, "switch on local", 0, {    INT32 tmp; -  tmp=switch_lookup(Pike_fp->context.prog-> +  PIKE_OPCODE_T *addr; +  JUMP_SET_TO_PC_AT_NEXT (addr); +  tmp=switch_lookup(Pike_fp->context->prog->    constants[arg2].sval.u.array,Pike_fp->locals + arg1); -  pc=(unsigned char *)DO_ALIGN(pc,sizeof(INT32)); -  pc+=(tmp>=0 ? 1+tmp*2 : 2*~tmp) * sizeof(INT32); -  if(*(INT32*)pc < 0) fast_check_threads_etc(7); -  pc+=*(INT32*)pc; - } - BREAK; +  addr = DO_IF_ELSE_COMPUTED_GOTO(addr, (PIKE_OPCODE_T *) +  DO_ALIGN(PTR_TO_INT(addr), +  ((ptrdiff_t)sizeof(INT32)))); +  addr = (PIKE_OPCODE_T *)(((INT32 *)addr) + (tmp>=0 ? 1+tmp*2 : 2*~tmp)); +  if(*(INT32*)addr < 0) FAST_CHECK_THREADS_ON_BRANCH(); +  DO_JUMP_TO(addr + *(INT32*)addr); + });       -  /* FIXME: Does this need bignum tests? /Fixed - Hubbe */ -  LOOP(F_INC_LOOP, 1, <, is_lt); -  LOOP(F_DEC_LOOP, -1, >, is_gt); -  LOOP(F_INC_NEQ_LOOP, 1, !=, !is_eq); -  LOOP(F_DEC_NEQ_LOOP, -1, !=, !is_eq); +  /* LOOP(OPCODE, INCREMENT, OPERATOR, IS_OPERATOR) */ + #define LOOP(ID, DESC, INC, OP2, OP4) \ +  OPCODE0_BRANCH(ID, DESC, 0, { \ +  union anything *i=get_pointer_if_this_type(Pike_sp-2, T_INT); \ +  if(i && !INT_TYPE_ADD_OVERFLOW(i->integer,INC) && \ +  TYPEOF(Pike_sp[-3]) == T_INT) \ +  { \ +  i->integer += INC; \ +  if(i->integer OP2 Pike_sp[-3].u.integer) \ +  { \ +  DO_BRANCH(); \ +  }else{ \ +  /* write_to_stderr("loop\n", 8); */ \ +  DONT_BRANCH(); \ +  } \ +  }else{ \ +  lvalue_to_svalue_no_free(Pike_sp,Pike_sp-2); Pike_sp++; \ +  push_int(INC); \ +  f_add(2); \ +  assign_lvalue(Pike_sp-3,Pike_sp-1); \ +  if(OP4 ( Pike_sp-1, Pike_sp-4 )) \ +  { \ +  DO_BRANCH(); \ +  }else{ \ +  /* write_to_stderr("loop\n", 8); */ \ +  DONT_BRANCH(); \ +  } \ +  pop_stack(); \ +  } \ +  })    -  CASE(F_FOREACH) /* array, lvalue, X, i */ -  { -  if(Pike_sp[-4].type != PIKE_T_ARRAY) + LOOP(F_INC_LOOP, "++Loop", 1, <, is_lt); + LOOP(F_DEC_LOOP, "--Loop", -1, >, is_gt); + LOOP(F_INC_NEQ_LOOP, "++Loop!=", 1, !=, !is_eq); + LOOP(F_DEC_NEQ_LOOP, "--Loop!=", -1, !=, !is_eq); +  + /* Use like: +  * +  * push(loopcnt) +  * branch(l2) +  * l1: +  * sync_mark +  * code +  * pop_sync_mark +  * l2: +  * loop(l1) +  */ + OPCODE0_BRANCH(F_LOOP, "loop", I_UPDATE_SP, { /* loopcnt */ +  /* Use >= and 1 to be able to reuse the 1 for the subtraction. */ +  push_int(1); +  if (!is_lt(Pike_sp-2, Pike_sp-1)) { +  o_subtract(); +  DO_BRANCH(); +  } else { +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH(); +  pop_2_elems(); +  } + }); +  + OPCODE0_BRANCH(F_FOREACH, "foreach", 0, { /* array, lvalue, i */ +  if(TYPEOF(Pike_sp[-4]) != PIKE_T_ARRAY)    PIKE_ERROR("foreach", "Bad argument 1.\n", Pike_sp-3, 1);    if(Pike_sp[-1].u.integer < Pike_sp[-4].u.array->size)    { -  fast_check_threads_etc(10); -  index_no_free(Pike_sp,Pike_sp-4,Pike_sp-1); -  Pike_sp++; -  assign_lvalue(Pike_sp-4, Pike_sp-1); -  free_svalue(Pike_sp-1); -  Pike_sp--; -  pc+=EXTRACT_INT(pc); +  DO_IF_DEBUG(if(Pike_sp[-1].u.integer < 0) +  /* Isn't this an internal compiler error? /mast */ +  Pike_error("Foreach loop variable is negative!\n")); +  assign_lvalue(Pike_sp-3, Pike_sp[-4].u.array->item + Pike_sp[-1].u.integer); +  DO_BRANCH();    Pike_sp[-1].u.integer++; -  +  DO_IF_DEBUG ( +  if (SUBTYPEOF(Pike_sp[-1])) +  Pike_fatal ("Got unexpected subtype in loop variable.\n"); +  );    }else{ -  SKIPJUMP(); +  /* write_to_stderr("foreach\n", 8); */ +  DONT_BRANCH();    } -  break; -  } + });    -  CASE(F_APPLY_AND_RETURN); -  { -  INT32 args = DO_NOT_WARN(Pike_sp - *--Pike_mark_sp); - /* fprintf(stderr,"%p >= %p\n",Pike_fp->expendible,Pike_sp-args); */ -  if(Pike_fp->expendible >= Pike_sp-args) -  { - /* fprintf(stderr,"NOT EXPENDIBLE!\n"); */ -  MEMMOVE(Pike_sp-args+1,Pike_sp-args,args*sizeof(struct svalue)); -  Pike_sp++; -  Pike_sp[-args-1].type=PIKE_T_INT; + OPCODE0(F_MAKE_ITERATOR, "get_iterator", 0, { +  f_get_iterator(1); + }); +  + /* Stack is: iterator, index lvalue, value lvalue. */ + OPCODE0_BRANCH (F_FOREACH_START, "foreach start", 0, { +  DO_IF_DEBUG ( +  if(TYPEOF(Pike_sp[-5]) != PIKE_T_OBJECT) +  Pike_fatal ("Iterator gone from stack.\n"); +  ); +  /* FIXME: object subtype. */ +  if (foreach_iterate (Pike_sp[-5].u.object, 0)) +  DONT_BRANCH(); +  else { +  DO_BRANCH();    } -  /* We sabotage the stack here */ -  assign_svalue(Pike_sp-args-1,&Pike_fp->context.prog->constants[GET_ARG()].sval); -  return args+1; -  } + });    - OPCODE1(F_CALL_LFUN_AND_RETURN,"call lfun & return") + /* Stack is: iterator, index lvalue, value lvalue. */ + OPCODE0_BRANCH(F_FOREACH_LOOP, "foreach loop", 0, { +  DO_IF_DEBUG ( +  if(TYPEOF(Pike_sp[-5]) != PIKE_T_OBJECT) +  Pike_fatal ("Iterator gone from stack.\n"); +  ); +  /* FIXME: object subtype. */ +  if(foreach_iterate(Pike_sp[-5].u.object, 1))    { -  INT32 args = DO_NOT_WARN(Pike_sp - *--Pike_mark_sp); -  -  if(Pike_fp->expendible >= Pike_sp-args) -  { -  MEMMOVE(Pike_sp-args+1,Pike_sp-args,args*sizeof(struct svalue)); -  Pike_sp++; -  Pike_sp[-args-1].type=PIKE_T_INT; +  DO_BRANCH();    }else{ -  free_svalue(Pike_sp-args-1); +  DONT_BRANCH();    } -  /* More stack sabotage */ -  Pike_sp[-args-1].u.object=Pike_fp->current_object; -  Pike_sp[-args-1].subtype=arg1+Pike_fp->context.identifier_level; - #ifdef PIKE_DEBUG -  if(t_flag > 9) -  fprintf(stderr,"- IDENTIFIER_LEVEL: %d\n",Pike_fp->context.identifier_level); - #endif -  Pike_sp[-args-1].type=PIKE_T_FUNCTION; -  add_ref(Pike_fp->current_object); + });    -  return args+1; - } - BREAK +     -  CASE(F_RETURN_LOCAL); -  instr=GET_ARG(); - #if defined(PIKE_DEBUG) && defined(GC2) + OPCODE1_RETURN(F_RETURN_LOCAL,"return local", I_UPDATE_SP|I_UPDATE_FP, { +  DO_IF_DEBUG(    /* special case! Pike_interpreter.mark_stack may be invalid at the time we    * call return -1, so we must call the callbacks here to    * prevent false alarms! /Hubbe    */ -  if(d_flag>3) do_gc(); +  if(d_flag>3) do_gc(NULL, 0);    if(d_flag>4) do_debug(); -  check_threads_etc(); - #endif -  if(Pike_fp->expendible <= Pike_fp->locals+instr) +  ); +  if(Pike_fp->expendible <= Pike_fp->locals + arg1)    { -  pop_n_elems(Pike_sp-1 - (Pike_fp->locals+instr)); +  pop_n_elems(Pike_sp-1 - (Pike_fp->locals + arg1)); +  DO_IF_DEBUG(Pike_fp->num_locals = arg1);    }else{ -  push_svalue(Pike_fp->locals+instr); +  push_svalue(Pike_fp->locals + arg1);    } -  print_return_value(); -  return -1; +  DO_DUMB_RETURN; + });    -  CASE(F_RETURN_IF_TRUE); -  if(!IS_ZERO(Pike_sp-1)) goto do_return; +  + OPCODE0_RETURN(F_RETURN_IF_TRUE,"return if true", I_UPDATE_SP|I_UPDATE_FP, { +  if(!UNSAFE_IS_ZERO(Pike_sp-1)) DO_RETURN;    pop_stack(); -  break; +  DO_JUMP_TO_NEXT; + });    -  CASE(F_RETURN_1); + OPCODE0_RETURN(F_RETURN_1,"return 1", I_UPDATE_SP|I_UPDATE_FP, {    push_int(1); -  goto do_return; +  DO_RETURN; + });    -  CASE(F_RETURN_0); + OPCODE0_RETURN(F_RETURN_0,"return 0", I_UPDATE_SP|I_UPDATE_FP, {    push_int(0); -  goto do_return; +  DO_RETURN; + });    -  CASE(F_RETURN); -  do_return: - #if defined(PIKE_DEBUG) && defined(GC2) -  if(d_flag>3) do_gc(); -  if(d_flag>4) do_debug(); -  check_threads_etc(); - #endif + OPCODE0_RETURN(F_RETURN, "return", I_UPDATE_FP, { +  DO_RETURN; + });    -  /* fall through */ + OPCODE0_RETURN(F_DUMB_RETURN,"dumb return", I_UPDATE_FP, { +  DO_DUMB_RETURN; + });    -  CASE(F_DUMB_RETURN); -  return -1; -  - OPCODE0(F_NEGATE, "unary minus") -  if(Pike_sp[-1].type == PIKE_T_INT) + OPCODE0(F_NEGATE, "unary minus", 0, { +  if(TYPEOF(Pike_sp[-1]) == PIKE_T_INT)    { - #ifdef AUTO_BIGNUM +     if(INT_TYPE_NEG_OVERFLOW(Pike_sp[-1].u.integer))    {    convert_stack_top_to_bignum();    o_negate();    }    else - #endif /* AUTO_BIGNUM */ +  {    Pike_sp[-1].u.integer =- Pike_sp[-1].u.integer; -  +  SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */    } -  else if(Pike_sp[-1].type == PIKE_T_FLOAT) +  } +  else if(TYPEOF(Pike_sp[-1]) == PIKE_T_FLOAT)    {    Pike_sp[-1].u.float_number =- Pike_sp[-1].u.float_number;    }else{    o_negate();    } - BREAK; + });    - OPCODE0(F_COMPL, "~") -  o_compl(); - BREAK; + OPCODE0_ALIAS(F_COMPL, "~", 0, o_compl);    - OPCODE0(F_NOT, "!") -  switch(Pike_sp[-1].type) + OPCODE0(F_NOT, "!", 0, { +  switch(TYPEOF(Pike_sp[-1]))    {    case PIKE_T_INT:    Pike_sp[-1].u.integer =! Pike_sp[-1].u.integer; -  +  SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */    break;       case PIKE_T_FUNCTION:    case PIKE_T_OBJECT: -  if(IS_ZERO(Pike_sp-1)) +  if(UNSAFE_IS_ZERO(Pike_sp-1))    {    pop_stack();    push_int(1);    }else{    pop_stack();    push_int(0);    }    break;       default:    free_svalue(Pike_sp-1); -  Pike_sp[-1].type=PIKE_T_INT; -  Pike_sp[-1].u.integer=0; +  SET_SVAL(Pike_sp[-1], PIKE_T_INT, NUMBER_NUMBER, integer, 0);    } - BREAK; + });    - OPCODE0(F_LSH, "<<") -  o_lsh(); - BREAK; + /* Used with F_LTOSVAL*_AND_FREE - must not release interpreter lock. */ + OPCODE0_ALIAS(F_LSH, "<<", I_UPDATE_SP, o_lsh); + OPCODE0_ALIAS(F_RSH, ">>", I_UPDATE_SP, o_rsh);    - OPCODE0(F_RSH, ">>") -  o_rsh(); - BREAK; + #define COMPARISON(ID,DESC,EXPR) \ +  OPCODE0(ID, DESC, I_UPDATE_SP, { \ +  INT32 val = EXPR; \ +  pop_2_elems(); \ +  push_int(val); \ +  })    -  COMPARISMENT(F_EQ, is_eq(Pike_sp-2,Pike_sp-1)); -  COMPARISMENT(F_NE,!is_eq(Pike_sp-2,Pike_sp-1)); -  COMPARISMENT(F_GT, is_gt(Pike_sp-2,Pike_sp-1)); -  COMPARISMENT(F_GE,!is_lt(Pike_sp-2,Pike_sp-1)); -  COMPARISMENT(F_LT, is_lt(Pike_sp-2,Pike_sp-1)); -  COMPARISMENT(F_LE,!is_gt(Pike_sp-2,Pike_sp-1)); + COMPARISON(F_EQ, "==", is_eq(Pike_sp-2,Pike_sp-1)); + COMPARISON(F_NE, "!=", !is_eq(Pike_sp-2,Pike_sp-1)); + COMPARISON(F_GT, ">", is_gt(Pike_sp-2,Pike_sp-1)); + COMPARISON(F_GE, ">=", is_ge(Pike_sp-2,Pike_sp-1)); + COMPARISON(F_LT, "<", is_lt(Pike_sp-2,Pike_sp-1)); + COMPARISON(F_LE, "<=", is_le(Pike_sp-2,Pike_sp-1));    - OPCODE0(F_ADD, "+") + /* Used with F_LTOSVAL*_AND_FREE - must not release interpreter lock. */ + OPCODE0(F_ADD, "+", I_UPDATE_SP, {    f_add(2); - BREAK; + });    - OPCODE0(F_ADD_INTS, "int+int") -  if(Pike_sp[-1].type == T_INT && Pike_sp[-2].type == T_INT - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, Pike_sp[-2].u.integer)) - #endif -  ) + /* Used with F_LTOSVAL*_AND_FREE - must not release interpreter lock. */ + OPCODE0(F_ADD_INTS, "int+int", I_UPDATE_SP, { +  if(TYPEOF(Pike_sp[-1]) == T_INT && TYPEOF(Pike_sp[-2]) == T_INT +  && !INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, Pike_sp[-2].u.integer))    {    Pike_sp[-2].u.integer+=Pike_sp[-1].u.integer; -  +  SET_SVAL_SUBTYPE(Pike_sp[-2], NUMBER_NUMBER); /* Could have UNDEFINED there before. */ +  dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;    }else{    f_add(2);    } - BREAK; + });    - OPCODE0(F_ADD_FLOATS, "float+float") -  if(Pike_sp[-1].type == T_FLOAT && Pike_sp[-2].type == T_FLOAT) + /* Used with F_LTOSVAL*_AND_FREE - must not release interpreter lock. */ + OPCODE0(F_ADD_FLOATS, "float+float", I_UPDATE_SP, { +  if(TYPEOF(Pike_sp[-1]) == T_FLOAT && TYPEOF(Pike_sp[-2]) == T_FLOAT)    {    Pike_sp[-2].u.float_number+=Pike_sp[-1].u.float_number; -  +  dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;    }else{    f_add(2);    } - BREAK; + });    - OPCODE0(F_SUBTRACT, "-") -  o_subtract(); - BREAK; + /* Used with F_LTOSVAL*_AND_FREE - must not release interpreter lock. */ + OPCODE0_ALIAS(F_SUBTRACT, "-", I_UPDATE_SP, o_subtract); + OPCODE0_ALIAS(F_AND, "&", I_UPDATE_SP, o_and); + OPCODE0_ALIAS(F_OR, "|", I_UPDATE_SP, o_or); + OPCODE0_ALIAS(F_XOR, "^", I_UPDATE_SP, o_xor); + OPCODE0_ALIAS(F_MULTIPLY, "*", I_UPDATE_SP, o_multiply); + OPCODE0_ALIAS(F_DIVIDE, "/", I_UPDATE_SP, o_divide); + OPCODE0_ALIAS(F_MOD, "%", I_UPDATE_SP, o_mod);    - OPCODE0(F_AND, "&") -  o_and(); - BREAK; -  - OPCODE0(F_OR, "|") -  o_or(); - BREAK; -  - OPCODE0(F_XOR, "^") -  o_xor(); - BREAK; -  - OPCODE0(F_MULTIPLY, "*") -  o_multiply(); - BREAK; -  - OPCODE0(F_DIVIDE, "/") -  o_divide(); - BREAK; -  - OPCODE0(F_MOD, "%") -  o_mod(); - BREAK; -  - OPCODE1(F_ADD_INT, "add integer") -  if(Pike_sp[-1].type == T_INT - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, arg1)) - #endif -  ) + OPCODE1(F_ADD_INT, "add integer", 0, { +  if(TYPEOF(Pike_sp[-1]) == T_INT +  && !INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, arg1))    {    Pike_sp[-1].u.integer+=arg1; -  +  SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */    }else{    push_int(arg1);    f_add(2);    } - BREAK; + });    - OPCODE1(F_ADD_NEG_INT, "add -integer") -  if(Pike_sp[-1].type == T_INT - #ifdef AUTO_BIGNUM -  && (!INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, -arg1)) - #endif -  ) + OPCODE1(F_ADD_NEG_INT, "add -integer", 0, { +  if(TYPEOF(Pike_sp[-1]) == T_INT +  && !INT_TYPE_ADD_OVERFLOW(Pike_sp[-1].u.integer, -arg1))    {    Pike_sp[-1].u.integer-=arg1; -  +  SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); /* Could have UNDEFINED there before. */    }else{    push_int(-arg1);    f_add(2);    } - BREAK; + });    - OPCODE0(F_PUSH_ARRAY, "@") -  switch(Pike_sp[-1].type) + OPCODE0(F_PUSH_ARRAY, "@", I_UPDATE_SP, { +  int i; +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct program *p); +  +  switch(TYPEOF(Pike_sp[-1]))    {    default:    PIKE_ERROR("@", "Bad argument.\n", Pike_sp, 1);       case PIKE_T_OBJECT: -  if(!Pike_sp[-1].u.object->prog || -  FIND_LFUN(Pike_sp[-1].u.object->prog,LFUN__VALUES) == -1) +  if(!(p = (o = Pike_sp[-1].u.object)->prog) || +  (i = FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-1])].prog, +  LFUN__VALUES)) == -1)    PIKE_ERROR("@", "Bad argument.\n", Pike_sp, 1);    -  apply_lfun(Pike_sp[-1].u.object, LFUN__VALUES, 0); -  if(Pike_sp[-1].type != PIKE_T_ARRAY) +  apply_low(o, i + p->inherits[SUBTYPEOF(Pike_sp[-1])].identifier_level, 0); +  if(TYPEOF(Pike_sp[-1]) != PIKE_T_ARRAY)    Pike_error("Bad return type from o->_values() in @\n");    free_svalue(Pike_sp-2); -  Pike_sp[-2]=Pike_sp[-1]; +  move_svalue (Pike_sp - 2, Pike_sp - 1);    Pike_sp--;    break;       case PIKE_T_ARRAY: break;    } -  +  dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;    push_array_items(Pike_sp->u.array); - BREAK; + });    - OPCODE2(F_LOCAL_LOCAL_INDEX, "local[local]") - { -  struct svalue *s=Pike_fp->locals+arg1; -  if(s->type == PIKE_T_STRING) s->subtype=0; -  Pike_sp++->type=PIKE_T_INT; + OPCODE0(F_APPEND_ARRAY, "append array", I_UPDATE_SP|I_UPDATE_M_SP, { +  o_append_array(Pike_sp - *(--Pike_mark_sp)); +  }); +  + OPCODE2(F_LOCAL_LOCAL_INDEX, "local[local]", I_UPDATE_SP, { +  LOCAL_VAR(struct svalue *s); +  s = Pike_fp->locals + arg1; +  if(TYPEOF(*s) == PIKE_T_STRING) SET_SVAL_SUBTYPE(*s, 0); +  mark_free_svalue (Pike_sp++);    index_no_free(Pike_sp-1,Pike_fp->locals+arg2,s); - } - BREAK; + });    - OPCODE1(F_LOCAL_INDEX, "local index") - { -  struct svalue tmp,*s=Pike_fp->locals+arg1; -  if(s->type == PIKE_T_STRING) s->subtype=0; + OPCODE1(F_LOCAL_INDEX, "local index", 0, { +  LOCAL_VAR(struct svalue *s); +  LOCAL_VAR(struct svalue tmp); +  s = Pike_fp->locals + arg1; +  if(TYPEOF(*s) == PIKE_T_STRING) SET_SVAL_SUBTYPE(*s, 0);    index_no_free(&tmp,Pike_sp-1,s);    free_svalue(Pike_sp-1); -  Pike_sp[-1]=tmp; - } - BREAK; +  move_svalue (Pike_sp - 1, &tmp); + });    - OPCODE2(F_GLOBAL_LOCAL_INDEX, "global[local]") - { -  struct svalue tmp,*s; -  low_object_index_no_free(Pike_sp, -  Pike_fp->current_object, -  arg1 + Pike_fp->context.identifier_level); + OPCODE2(F_GLOBAL_LOCAL_INDEX, "global[local]", I_UPDATE_SP, { +  LOCAL_VAR(struct svalue *s); +  LOCAL_VAR(struct svalue tmp); +  low_index_current_object_no_free(Pike_sp, arg1);    Pike_sp++;    s=Pike_fp->locals+arg2; -  if(s->type == PIKE_T_STRING) s->subtype=0; +  if(TYPEOF(*s) == PIKE_T_STRING) SET_SVAL_SUBTYPE(*s, 0);    index_no_free(&tmp,Pike_sp-1,s);    free_svalue(Pike_sp-1); -  Pike_sp[-1]=tmp; - } - BREAK; +  move_svalue (Pike_sp - 1, &tmp); + });    - OPCODE2(F_LOCAL_ARROW, "local->x") - { -  struct svalue tmp; -  tmp.type=PIKE_T_STRING; -  tmp.u.string=Pike_fp->context.prog->strings[arg1]; -  tmp.subtype=1; -  Pike_sp->type=PIKE_T_INT; -  Pike_sp++; -  index_no_free(Pike_sp-1,Pike_fp->locals+arg2, &tmp); + OPCODE2(F_LOCAL_ARROW, "local->x", I_UPDATE_SP, { +  struct pike_frame *fp = Pike_fp; +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_STRING, 1, string, +  fp->context->prog->strings[arg1]); +  mark_free_svalue (Pike_sp++); +  index_no_free(Pike_sp-1,fp->locals+arg2, &tmp);    print_return_value(); - } - BREAK; + });    - OPCODE1(F_ARROW, "->x") - { -  struct svalue tmp,tmp2; -  tmp.type=PIKE_T_STRING; -  tmp.u.string=Pike_fp->context.prog->strings[arg1]; -  tmp.subtype=1; + OPCODE1(F_ARROW, "->x", 0, { +  LOCAL_VAR(struct svalue tmp); +  LOCAL_VAR(struct svalue tmp2); +  SET_SVAL(tmp, PIKE_T_STRING, 1, string, +  Pike_fp->context->prog->strings[arg1]);    index_no_free(&tmp2, Pike_sp-1, &tmp);    free_svalue(Pike_sp-1); -  Pike_sp[-1]=tmp2; +  move_svalue (Pike_sp - 1, &tmp2);    print_return_value(); - } - BREAK; + });    - OPCODE1(F_STRING_INDEX, "string index") - { -  struct svalue tmp,tmp2; -  tmp.type=PIKE_T_STRING; -  tmp.u.string=Pike_fp->context.prog->strings[arg1]; -  tmp.subtype=0; + OPCODE1(F_STRING_INDEX, "string index", 0, { +  LOCAL_VAR(struct svalue tmp); +  LOCAL_VAR(struct svalue tmp2); +  SET_SVAL(tmp, PIKE_T_STRING, 0, string, +  Pike_fp->context->prog->strings[arg1]);    index_no_free(&tmp2, Pike_sp-1, &tmp);    free_svalue(Pike_sp-1); -  Pike_sp[-1]=tmp2; +  move_svalue (Pike_sp - 1, &tmp2);    print_return_value(); - } - BREAK; + });    -  CASE(F_POS_INT_INDEX); -  push_int(GET_ARG()); + OPCODE1(F_POS_INT_INDEX, "int index", 0, { +  push_int((ptrdiff_t)(int)arg1);    print_return_value(); -  goto do_index; +  DO_INDEX; + });    -  CASE(F_NEG_INT_INDEX); -  push_int(-GET_ARG()); + OPCODE1(F_NEG_INT_INDEX, "-int index", 0, { +  push_int(-(ptrdiff_t)arg1);    print_return_value(); -  +  DO_INDEX; + });    -  CASE(F_INDEX); -  do_index: -  { -  struct svalue s; -  index_no_free(&s,Pike_sp-2,Pike_sp-1); -  pop_n_elems(2); -  *Pike_sp=s; -  Pike_sp++; -  } -  print_return_value(); -  break; + OPCODE0(F_INDEX, "index", I_UPDATE_SP, { +  DO_INDEX; + });    - OPCODE2(F_MAGIC_INDEX, "::`[]") + OPCODE2(F_MAGIC_INDEX, "::`[]", I_UPDATE_SP, {    push_magic_index(magic_index_program, arg2, arg1); - BREAK; + });    - OPCODE2(F_MAGIC_SET_INDEX, "::`[]=") + OPCODE2(F_MAGIC_SET_INDEX, "::`[]=", I_UPDATE_SP, {    push_magic_index(magic_set_index_program, arg2, arg1); - BREAK; + });    - OPCODE0(F_CAST, "cast") -  f_cast(); - BREAK; + OPCODE2(F_MAGIC_INDICES, "::_indices", I_UPDATE_SP, { +  push_magic_index(magic_indices_program, arg2, arg1); + });    - OPCODE0(F_SOFT_CAST, "soft cast") -  /* Stack: type_string, value */ - #ifdef PIKE_DEBUG -  if (Pike_sp[-2].type != T_STRING) { -  /* FIXME: The type should really be T_TYPE... */ -  fatal("Argument 1 to soft_cast isn't a string!\n"); -  } - #endif /* PIKE_DEBUG */ -  if (runtime_options & RUNTIME_CHECK_TYPES) { -  struct pike_string *sval_type = get_type_of_svalue(Pike_sp-1); -  if (!pike_types_le(sval_type, Pike_sp[-2].u.string)) { -  /* get_type_from_svalue() doesn't return a fully specified type -  * for array, mapping and multiset, so we perform a more lenient -  * check for them. -  */ -  if (!pike_types_le(sval_type, weak_type_string) || -  !match_types(sval_type, Pike_sp[-2].u.string)) { -  struct pike_string *t1; -  struct pike_string *t2; -  char *fname = "__soft-cast"; -  ONERROR tmp1; -  ONERROR tmp2; + OPCODE2(F_MAGIC_VALUES, "::_values", I_UPDATE_SP, { +  push_magic_index(magic_values_program, arg2, arg1); + });    -  if (Pike_fp->current_object && Pike_fp->context.prog && -  Pike_fp->current_object->prog) { -  /* Look up the function-name */ -  struct pike_string *name = -  ID_FROM_INT(Pike_fp->current_object->prog, Pike_fp->fun)->name; -  if ((!name->size_shift) && (name->len < 100)) -  fname = name->str; -  } + OPCODE0_ALIAS(F_CAST, "cast", I_UPDATE_SP, f_cast); + OPCODE0_ALIAS(F_CAST_TO_INT, "cast_to_int", 0, o_cast_to_int); + OPCODE0_ALIAS(F_CAST_TO_STRING, "cast_to_string", 0, o_cast_to_string);    -  t1 = describe_type(Pike_sp[-2].u.string); -  SET_ONERROR(tmp1, do_free_string, t1); -  -  t2 = describe_type(sval_type); -  SET_ONERROR(tmp2, do_free_string, t2); -  -  free_string(sval_type); -  -  bad_arg_error(NULL, Pike_sp-1, 1, 1, t1->str, Pike_sp-1, -  "%s(): Soft cast failed. Expected %s, got %s\n", -  fname, t1->str, t2->str); -  /* NOT_REACHED */ -  UNSET_ONERROR(tmp2); -  UNSET_ONERROR(tmp1); -  free_string(t2); -  free_string(t1); + OPCODE0(F_SOFT_CAST, "soft cast", I_UPDATE_SP, { +  /* Stack: type_string, value */ +  DO_IF_DEBUG({ +  if (TYPEOF(Pike_sp[-2]) != T_TYPE) { +  Pike_fatal("Argument 1 to soft_cast isn't a type!\n");    } -  } -  free_string(sval_type); - #ifdef PIKE_DEBUG +  }); +  if (runtime_options & RUNTIME_CHECK_TYPES) { +  o_check_soft_cast(Pike_sp-1, Pike_sp[-2].u.type); +  DO_IF_DEBUG({    if (d_flag > 2) { -  struct pike_string *t = describe_type(Pike_sp[-2].u.string); +  struct pike_string *t = describe_type(Pike_sp[-2].u.type);    fprintf(stderr, "Soft cast to %s\n", t->str);    free_string(t);    } - #endif /* PIKE_DEBUG */ +  });    }    stack_swap();    pop_stack(); - BREAK; + });    - OPCODE0(F_RANGE, "range") -  o_range(); - BREAK; + /* Used with F_LTOSVAL*_AND_FREE - must not release interpreter lock. */ + OPCODE1_ALIAS(F_RANGE, "range", I_UPDATE_SP, o_range2);    - OPCODE0(F_COPY_VALUE, "copy_value") - { -  struct svalue tmp; + OPCODE0(F_COPY_VALUE, "copy_value", 0, { +  LOCAL_VAR(struct svalue tmp);    copy_svalues_recursively_no_free(&tmp,Pike_sp-1,1,0);    free_svalue(Pike_sp-1); -  Pike_sp[-1]=tmp; - } - BREAK; +  move_svalue (Pike_sp - 1, &tmp); +  print_return_value(); + });    - OPCODE0(F_INDIRECT, "indirect") + OPCODE0(F_INDIRECT, "indirect", I_UPDATE_SP, { +  LOCAL_VAR(struct svalue tmp); +  lvalue_to_svalue_no_free(&tmp, Pike_sp-2); +  if(TYPEOF(tmp) != PIKE_T_STRING)    { -  struct svalue s; -  lvalue_to_svalue_no_free(&s,Pike_sp-2); -  if(s.type != PIKE_T_STRING) -  { -  pop_n_elems(2); -  *Pike_sp=s; +  pop_2_elems(); +  move_svalue (Pike_sp, &tmp);    Pike_sp++;    }else{ -  struct object *o; +  struct string_assignment_storage *s; +  LOCAL_VAR(struct object *o);    o=low_clone(string_assignment_program); -  ((struct string_assignment_storage *)o->storage)->lval[0]=Pike_sp[-2]; -  ((struct string_assignment_storage *)o->storage)->lval[1]=Pike_sp[-1]; -  ((struct string_assignment_storage *)o->storage)->s=s.u.string; +  s = (struct string_assignment_storage *)o->storage; +  move_svalue (s->lval, Pike_sp - 2); +  move_svalue (s->lval + 1, Pike_sp - 1); +  s->s=tmp.u.string;    Pike_sp-=2;    push_object(o);    } - } +     print_return_value(); - BREAK; + });    - OPCODE0(F_SIZEOF, "sizeof") -  instr=pike_sizeof(Pike_sp-1); + OPCODE0(F_SIZEOF, "sizeof", 0, { +  INT_TYPE val = pike_sizeof(Pike_sp-1);    pop_stack(); -  push_int(instr); - BREAK; +  push_int(val); + });    - OPCODE1(F_SIZEOF_LOCAL, "sizeof local") + OPCODE1(F_SIZEOF_LOCAL, "sizeof local", I_UPDATE_SP, {    push_int(pike_sizeof(Pike_fp->locals+arg1)); - BREAK; + });    - OPCODE1(F_SSCANF, "sscanf") -  o_sscanf(arg1); - BREAK; + OPCODE2_ALIAS(F_SSCANF, "sscanf", I_UPDATE_SP, o_sscanf);    - OPCODE1(F_CALL_LFUN,"call lfun") -  apply_low(Pike_fp->current_object, -  arg1+Pike_fp->context.identifier_level, -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp)); - BREAK; + #define MKAPPLY(OP,OPCODE,NAME,TYPE, ARG2, ARG3) \ +  PIKE_CONCAT(OP,_JUMP)(PIKE_CONCAT(F_,OPCODE),NAME, \ +  I_UPDATE_ALL, { \ +  LOCAL_VAR(PIKE_OPCODE_T *pc); \ + JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); \ + if((pc=low_mega_apply(TYPE,DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)), \ +  ARG2, ARG3))) \ + { \ +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; \ +  DO_JUMP_TO(pc); \ + } \ + else { \ +  DO_JUMP_TO_NEXT; \ + } \ + }); \ +  \ +  PIKE_CONCAT(OP,_JUMP)(PIKE_CONCAT3(F_,OPCODE,_AND_POP),NAME " & pop", \ +  I_UPDATE_ALL, { \ +  LOCAL_VAR(PIKE_OPCODE_T *pc); \ +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); \ +  if((pc=low_mega_apply(TYPE, DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)), \ +  ARG2, ARG3))) \ +  { \ +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL | PIKE_FRAME_RETURN_POP; \ +  DO_JUMP_TO(pc); \ +  }else{ \ +  pop_stack(); \ +  DO_JUMP_TO_NEXT; \ +  } \ + }); \ +  \ + PIKE_CONCAT(OP,_RETURN)(PIKE_CONCAT3(F_,OPCODE,_AND_RETURN), \ +  NAME " & return", \ +  I_UPDATE_ALL, { \ +  LOCAL_VAR(PIKE_OPCODE_T *pc); \ +  if((pc = low_mega_apply(TYPE,DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)), \ +  ARG2,ARG3))) \ +  { \ +  DO_IF_DEBUG(Pike_fp->next->pc=0); \ +  unlink_previous_frame(); \ +  DO_JUMP_TO(pc); \ +  }else{ \ +  DO_DUMB_RETURN; \ +  } \ + })    - OPCODE1(F_CALL_LFUN_AND_POP,"call lfun & pop") -  apply_low(Pike_fp->current_object, -  arg1+Pike_fp->context.identifier_level, -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp)); -  pop_stack(); - BREAK; +     - OPCODE1(F_MARK_APPLY,"mark apply") -  strict_apply_svalue(&((Pike_fp->context.prog->constants + arg1)->sval), 0); - BREAK; + #define MKAPPLY2(OP,OPCODE,NAME,TYPE, ARG2, ARG3) \ +  \ + MKAPPLY(OP,OPCODE,NAME,TYPE, ARG2, ARG3); \ +  \ + PIKE_CONCAT(OP,_JUMP)(PIKE_CONCAT(F_MARK_,OPCODE),"mark, " NAME, \ +  I_UPDATE_ALL, { \ +  LOCAL_VAR(PIKE_OPCODE_T *pc); \ +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); \ +  if((pc=low_mega_apply(TYPE, 0, \ +  ARG2, ARG3))) \ +  { \ +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; \ +  DO_JUMP_TO(pc); \ +  } \ +  else { \ +  DO_JUMP_TO_NEXT; \ +  } \ + }); \ +  \ + PIKE_CONCAT(OP,_JUMP)(PIKE_CONCAT3(F_MARK_,OPCODE,_AND_POP), \ +  "mark, " NAME " & pop", \ +  I_UPDATE_ALL, { \ +  LOCAL_VAR(PIKE_OPCODE_T *pc); \ +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); \ +  if((pc=low_mega_apply(TYPE, 0, \ +  ARG2, ARG3))) \ +  { \ +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL | PIKE_FRAME_RETURN_POP; \ +  DO_JUMP_TO(pc); \ +  }else{ \ +  pop_stack(); \ +  DO_JUMP_TO_NEXT; \ +  } \ + }); \ +  \ + PIKE_CONCAT(OP,_RETURN)(PIKE_CONCAT3(F_MARK_,OPCODE,_AND_RETURN), \ +  "mark, " NAME " & return", \ +  I_UPDATE_ALL, { \ +  LOCAL_VAR(PIKE_OPCODE_T *pc); \ +  if((pc=low_mega_apply(TYPE, 0, \ +  ARG2,ARG3))) \ +  { \ +  DO_IF_DEBUG(Pike_fp->next->pc=0); \ +  unlink_previous_frame(); \ +  DO_JUMP_TO(pc); \ +  }else{ \ +  DO_DUMB_RETURN; \ +  } \ + })    - OPCODE1(F_MARK_APPLY_POP,"mark, apply & pop") -  strict_apply_svalue(&((Pike_fp->context.prog->constants + arg1)->sval), 0); +  + OPCODE1_JUMP(F_CALL_LFUN , "call lfun", I_UPDATE_ALL, { +  LOCAL_VAR(PIKE_OPCODE_T *addr); +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); +  if((addr = lower_mega_apply(DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)), +  Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level) ))) +  { +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; +  DO_JUMP_TO(addr); +  } +  else +  { +  DO_JUMP_TO_NEXT; +  } +  }); +  + OPCODE1_JUMP(F_CALL_LFUN_AND_POP, "call lfun & pop", I_UPDATE_ALL, { +  LOCAL_VAR(PIKE_OPCODE_T *addr); +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); +  if((addr = lower_mega_apply(DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)), +  Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level)))) +  { +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL | PIKE_FRAME_RETURN_POP; +  DO_JUMP_TO(addr); +  } +  else +  {    pop_stack(); - BREAK; +  DO_JUMP_TO_NEXT; +  } +  });    -  CASE(F_APPLY); -  strict_apply_svalue(&((Pike_fp->context.prog->constants + GET_ARG())->sval), -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp )); -  break; + OPCODE1_RETURN(F_CALL_LFUN_AND_RETURN , "call lfun & return", I_UPDATE_ALL, { +  LOCAL_VAR(PIKE_OPCODE_T *addr); +  if((addr = lower_mega_apply(DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)), +  Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level)))) +  { +  DO_IF_DEBUG(Pike_fp->next->pc=0); +  unlink_previous_frame(); +  DO_JUMP_TO(addr); +  }else{ +  DO_DUMB_RETURN; +  } +  });    -  CASE(F_APPLY_AND_POP); -  strict_apply_svalue(&((Pike_fp->context.prog->constants + GET_ARG())->sval), -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp )); + OPCODE1_JUMP(F_MARK_CALL_LFUN, "mark, call lfun" , I_UPDATE_ALL, { +  LOCAL_VAR(PIKE_OPCODE_T *p); +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); +  if((p = lower_mega_apply(0, Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level)))) { +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; +  DO_JUMP_TO(p); +  } else { +  DO_JUMP_TO_NEXT; +  } +  }); +  + OPCODE1_JUMP( F_MARK_CALL_LFUN_AND_POP , "mark, call lfun & pop", I_UPDATE_ALL, { +  LOCAL_VAR(PIKE_OPCODE_T *p); +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); +  if((p = lower_mega_apply(0, Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level) ))) +  { +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL | PIKE_FRAME_RETURN_POP; +  DO_JUMP_TO(p); +  } +  else +  {    pop_stack(); -  break; +  DO_JUMP_TO_NEXT; +  } +  });    -  CASE(F_CALL_FUNCTION); -  mega_apply(APPLY_STACK, -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp), -  0,0); -  break; + OPCODE1_RETURN(F_MARK_CALL_LFUN_AND_RETURN , "mark, call lfun & return", I_UPDATE_ALL, { +  LOCAL_VAR(PIKE_OPCODE_T *addr); +  if((addr = lower_mega_apply(0, Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level)))) +  { +  DO_IF_DEBUG(Pike_fp->next->pc=0); +  unlink_previous_frame(); +  DO_JUMP_TO(addr); +  } +  else +  { +  DO_DUMB_RETURN; +  } +  });    -  CASE(F_CALL_FUNCTION_AND_RETURN); + MKAPPLY2(OPCODE1,APPLY,"apply",APPLY_SVALUE_STRICT, +  &((Pike_fp->context->prog->constants + arg1)->sval),0); +  + MKAPPLY(OPCODE0,CALL_FUNCTION,"call function",APPLY_STACK, 0,0); +  + OPCODE1_JUMP(F_CALL_OTHER,"call other", I_UPDATE_ALL, { +  INT32 args=DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  LOCAL_VAR(struct svalue *s); +  s = Pike_sp-args; +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); +  if(TYPEOF(*s) == T_OBJECT)    { -  INT32 args = DO_NOT_WARN(Pike_sp - *--Pike_mark_sp); -  if(!args) -  PIKE_ERROR("`()", "Too few arguments (call&return).\n", Pike_sp, 0); -  switch(Pike_sp[-args].type) +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct program *p); +  o = s->u.object; +  if((p=o->prog))    { -  case PIKE_T_INT: -  if (!Pike_sp[-args].u.integer) { -  PIKE_ERROR("`()", "Attempt to call the NULL-value\n", -  Pike_sp, args); +  p = p->inherits[SUBTYPEOF(*s)].prog; +  if(FIND_LFUN(p, LFUN_ARROW) == -1) +  { +  PIKE_OPCODE_T *addr; +  int fun; +  fun=find_shared_string_identifier(Pike_fp->context->prog->strings[arg1], +  p); +  if(fun >= 0) +  { +  fun += o->prog->inherits[SUBTYPEOF(*s)].identifier_level; +  if((addr = lower_mega_apply(args-1, o, fun))) +  { +  Pike_fp->save_sp--; +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; +  DO_JUMP_TO(addr);    } -  case PIKE_T_STRING: -  case PIKE_T_FLOAT: -  case PIKE_T_MAPPING: -  case PIKE_T_MULTISET: -  PIKE_ERROR("`()", "Attempt to call a non-function value.\n", -  Pike_sp, args); +  stack_pop_keep_top(); +  DO_JUMP_TO_NEXT;    } -  return args; +     } -  +  } +  }    -  +  { +  LOCAL_VAR(struct svalue tmp); +  LOCAL_VAR(struct svalue tmp2); +  LOCAL_VAR(PIKE_OPCODE_T *p); +  SET_SVAL(tmp, PIKE_T_STRING, 1, string, +  Pike_fp->context->prog->strings[arg1]);    - /* Assume that the number of arguments is correct */ - OPCODE1_JUMP(F_COND_RECUR,"recur if not overloaded") +  index_no_free(&tmp2, s, &tmp); +  free_svalue(s); +  move_svalue (s, &tmp2); +  print_return_value(); +  +  if((p = low_mega_apply(APPLY_STACK, args, 0, 0)))    { -  /* FIXME: -  * this test should actually test if this function is -  * overloaded or not. Currently it only tests if -  * this context is inherited or not. -  */ -  if(Pike_fp->current_object->prog != Pike_fp->context.prog) +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; +  DO_JUMP_TO(p); +  } +  else { +  DO_JUMP_TO_NEXT; +  } +  } + }); +  + OPCODE1_JUMP(F_CALL_OTHER_AND_POP,"call other & pop", I_UPDATE_ALL, { +  INT32 args=DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  LOCAL_VAR(struct svalue *s); +  s = Pike_sp-args; +  JUMP_SET_TO_PC_AT_NEXT (Pike_fp->return_addr); +  if(TYPEOF(*s) == T_OBJECT)    { -  apply_low(Pike_fp->current_object, -  arg1+Pike_fp->context.identifier_level, -  DO_NOT_WARN(Pike_sp - *--Pike_mark_sp)); -  pc+=sizeof(INT32); -  DONE; +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct program *p); +  o = s->u.object; +  if((p=o->prog)) +  { +  p = p->inherits[SUBTYPEOF(*s)].prog; +  if(FIND_LFUN(p, LFUN_ARROW) == -1) +  { +  int fun; +  PIKE_OPCODE_T *addr; +  fun=find_shared_string_identifier(Pike_fp->context->prog->strings[arg1], +  p); +  if(fun >= 0) +  { +  fun += o->prog->inherits[SUBTYPEOF(*s)].identifier_level; +  if((addr = lower_mega_apply(args-1, o, fun))) +  { +  Pike_fp->save_sp--; +  Pike_fp->flags |= +  PIKE_FRAME_RETURN_INTERNAL | +  PIKE_FRAME_RETURN_POP; +  DO_JUMP_TO(addr);    } -  +  pop_2_elems(); +  DO_JUMP_TO_NEXT;    } - /* FALL THROUGH */ +  } +  } +  }    - /* Assume that the number of arguments is correct */ - OPCODE0_TAILJUMP(F_RECUR,"recur") +     { -  int x; -  INT32 num_locals, args; -  char *addr; -  struct light_frame_info info; -  struct svalue *save_sp, **save_mark_sp; -  ONERROR uwp; +  LOCAL_VAR(struct svalue tmp); +  LOCAL_VAR(struct svalue tmp2); +  LOCAL_VAR(PIKE_OPCODE_T *p);    -  fast_check_threads_etc(6); -  check_c_stack(8192); -  check_stack(256); +  SET_SVAL(tmp, PIKE_T_STRING, 1, string, +  Pike_fp->context->prog->strings[arg1]);    -  info.saved_fp = Pike_fp; -  info.expendible = Pike_fp->expendible; -  info.locals = Pike_fp->locals; -  SET_ONERROR(uwp, restore_light_frame_info, &info); +  index_no_free(&tmp2, s, &tmp); +  free_svalue(s); +  move_svalue (s, &tmp2); +  print_return_value();    -  save_sp = Pike_fp->expendible = Pike_fp->locals = *--Pike_mark_sp; -  args = DO_NOT_WARN(Pike_sp - Pike_fp->locals); -  save_mark_sp = Pike_mark_sp; +  if((p = low_mega_apply(APPLY_STACK, args, 0, 0))) +  { +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL | PIKE_FRAME_RETURN_POP; +  DO_JUMP_TO(p); +  } +  else { +  pop_stack(); +  DO_JUMP_TO_NEXT; +  } +  } + });    -  addr=pc+EXTRACT_INT(pc); -  num_locals=EXTRACT_UCHAR(addr-2); + OPCODE1_RETURN(F_CALL_OTHER_AND_RETURN,"call other & return", I_UPDATE_ALL, { +  INT32 args=DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  LOCAL_VAR(struct svalue *s); +  s = Pike_sp - args; +  if(TYPEOF(*s) == T_OBJECT) +  { +  LOCAL_VAR(struct object *o); +  LOCAL_VAR(struct program *p); +  o = s->u.object; +  if((p=o->prog)) +  { +  p = p->inherits[SUBTYPEOF(*s)].prog; +  if(FIND_LFUN(p, LFUN_ARROW) == -1) +  { +  int fun; +  PIKE_OPCODE_T *addr; +  fun=find_shared_string_identifier(Pike_fp->context->prog->strings[arg1], +  p); +  if(fun >= 0) +  { +  fun += o->prog->inherits[SUBTYPEOF(*s)].identifier_level; +  if((addr = lower_mega_apply(args-1, o, fun))) +  { +  Pike_fp->save_sp--; +  DO_IF_DEBUG(Pike_fp->next->pc=0); +  unlink_previous_frame(); +  DO_JUMP_TO(addr); +  } +  stack_pop_keep_top(); +  DO_DUMB_RETURN; +  } +  } +  } +  }    - #ifdef PIKE_DEBUG -  if(args != EXTRACT_UCHAR(addr-1)) -  fatal("Wrong number of arguments in F_RECUR %d!=%d\n", -  args, EXTRACT_UCHAR(addr-1)); - #endif +  { +  LOCAL_VAR(struct svalue tmp); +  LOCAL_VAR(struct svalue tmp2); +  LOCAL_VAR(PIKE_OPCODE_T *p); +  SET_SVAL(tmp, PIKE_T_STRING, 1, string, +  Pike_fp->context->prog->strings[arg1]);    -  clear_svalues(Pike_sp, num_locals - args); -  Pike_sp += num_locals - args; +  index_no_free(&tmp2, s, &tmp); +  free_svalue(s); +  move_svalue (s, &tmp2); +  print_return_value();    -  x=eval_instruction(addr); -  EVAL_INSTR_RET_CHECK(x); +  if((p = low_mega_apply(APPLY_STACK, args, 0, 0))) +  { +  DO_IF_DEBUG(Pike_fp->next->pc=0); +  unlink_previous_frame(); +  DO_JUMP_TO(p); +  } +  DO_DUMB_RETURN; +  } + }); +  + #undef DO_CALL_BUILTIN   #ifdef PIKE_DEBUG -  if(Pike_mark_sp < save_mark_sp) -  fatal("mark Pike_sp underflow in F_RECUR.\n"); + #define DO_CALL_BUILTIN(ARGS) do { \ +  int args_=(ARGS); \ +  struct svalue *expected_stack=Pike_sp-args_; \ +  LOCAL_VAR(struct svalue *s); \ +  s = &Pike_fp->context->prog->constants[arg1].sval; \ +  if(Pike_interpreter.trace_level) \ +  { \ +  LOCAL_VAR(dynamic_buffer save_buf); \ +  init_buf(&save_buf); \ +  if (s->u.efun->name->size_shift) \ +  my_strcat ("[widestring function name]"); \ +  else \ +  my_strcat (s->u.efun->name->str); \ +  do_trace_call(args_, &save_buf); \ +  } \ +  if (PIKE_FN_START_ENABLED()) { \ +  /* DTrace enter probe \ +  arg0: function name \ +  arg1: object \ +  */ \ +  PIKE_FN_START(s->u.efun->name->size_shift == 0 ? \ +  s->u.efun->name->str : "[widestring fn name]", \ +  ""); \ +  } \ +  (*(s->u.efun->function))(args_); \ +  DO_IF_PROFILING (s->u.efun->runs++); \ +  if(Pike_sp != expected_stack + !s->u.efun->may_return_void) \ +  { \ +  if(Pike_sp < expected_stack) \ +  Pike_fatal("Function popped too many arguments: %s\n", \ +  s->u.efun->name->str); \ +  if(Pike_sp>expected_stack+1) \ +  Pike_fatal("Function left %"PRINTPTRDIFFT"d droppings on stack: %s\n", \ +  Pike_sp-(expected_stack+1), \ +  s->u.efun->name->str); \ +  if(Pike_sp == expected_stack && !s->u.efun->may_return_void) \ +  Pike_fatal("Non-void function returned without return value " \ +  "on stack: %s %d\n", \ +  s->u.efun->name->str,s->u.efun->may_return_void); \ +  if(Pike_sp==expected_stack+1 && s->u.efun->may_return_void) \ +  Pike_fatal("Void function returned with a value on the stack: %s %d\n", \ +  s->u.efun->name->str, s->u.efun->may_return_void); \ +  } \ +  if(Pike_interpreter.trace_level>1) { \ +  LOCAL_VAR(dynamic_buffer save_buf); \ +  init_buf(&save_buf); \ +  if (s->u.efun->name->size_shift) \ +  my_strcat ("[widestring function name]"); \ +  else \ +  my_strcat (s->u.efun->name->str); \ +  my_strcat ("() "); \ +  do_trace_return (Pike_sp>expected_stack, &save_buf); \ +  } \ +  if (PIKE_FN_DONE_ENABLED()) { \ +  /* DTrace leave probe \ +  arg0: function name \ +  */ \ +  PIKE_FN_DONE(s->u.efun->name->size_shift == 0 ? \ +  s->u.efun->name->str : "[widestring fn name]"); \ +  } \ + }while(0) + #else + #define DO_CALL_BUILTIN(ARGS) do { \ +  (*(Pike_fp->context->prog->constants[arg1].sval.u.efun->function))(ARGS); \ +  } while (0)   #endif -  Pike_mark_sp=save_mark_sp; -  if(x>=0) mega_apply(APPLY_STACK, x, 0,0); -  pc+=sizeof(INT32); -  if(save_sp+1 < Pike_sp) +  + OPCODE1(F_CALL_BUILTIN, "call builtin", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp))); + }); +  + OPCODE1(F_CALL_BUILTIN_AND_POP,"call builtin & pop", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp))); +  pop_stack(); + }); +  + OPCODE1_RETURN(F_CALL_BUILTIN_AND_RETURN,"call builtin & return", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp))); +  DO_DUMB_RETURN; + }); +  +  + OPCODE1(F_MARK_CALL_BUILTIN, "mark, call builtin", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(0); + }); +  + OPCODE1(F_MARK_CALL_BUILTIN_AND_POP, "mark, call builtin & pop", 0, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(0); +  pop_stack(); + }); +  + OPCODE1_RETURN(F_MARK_CALL_BUILTIN_AND_RETURN, "mark, call builtin & return", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(0); +  DO_DUMB_RETURN; + }); +  +  + OPCODE1(F_CALL_BUILTIN1, "call builtin 1", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(1); + }); +  + OPCODE1(F_CALL_BUILTIN1_AND_POP, "call builtin1 & pop", I_UPDATE_ALL, { +  FAST_CHECK_THREADS_ON_CALL(); +  DO_CALL_BUILTIN(1); +  pop_stack(); + }); +  + OPCODE1(F_LTOSVAL_CALL_BUILTIN_AND_ASSIGN, "ltosval, call builtin & assign", +  I_UPDATE_ALL, { +  INT32 args = DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  ONERROR uwp; +  +  /* Give other threads a chance to run now, before we temporarily +  * clear the svalue, in case another thread looks at it. */ +  FAST_CHECK_THREADS_ON_CALL(); +  +  /* FIXME: Assert that args > 0 */ +  +  STACK_LEVEL_START(args+2); +  +  free_svalue(Pike_sp-args); +  mark_free_svalue (Pike_sp - args); +  lvalue_to_svalue_no_free(Pike_sp-args, Pike_sp-args-2); +  /* This is so that foo = efun(foo,...) (and similar things) will be faster. +  * It's done by freeing the old reference to foo after it has been +  * pushed on the stack. That way foo can have only 1 reference if we +  * are lucky, and then the low array/multiset/mapping manipulation +  * routines can be destructive if they like. +  */ +  if( (1 << TYPEOF(Pike_sp[-args])) & +  (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) )    { -  assign_svalue(save_sp,Pike_sp-1); -  pop_n_elems(Pike_sp-save_sp-1); +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-args-2, &tmp);    } -  +  /* NOTE: Pike_sp-args-2 is the lvalue, Pike_sp-args is the original value. +  * If an error gets thrown, the original value will thus be restored. +  * If the efun succeeds, Pike_sp-args will hold the result. +  */ +  SET_ONERROR(uwp, o_assign_lvalue, Pike_sp-args-2); +  DO_CALL_BUILTIN(args); +  STACK_LEVEL_CHECK(3);    CALL_AND_UNSET_ONERROR(uwp); -  print_return_value(); - #ifdef PIKE_DEBUG -  if(Pike_sp != save_sp+1) -  fatal("Stack whack in F_RECUR Pike_sp=%p, expected=%p\n",Pike_sp,save_sp+1); - #endif +  +  STACK_LEVEL_CHECK(3); +  free_svalue(Pike_sp-3); +  free_svalue(Pike_sp-2); +  move_svalue(Pike_sp - 3, Pike_sp - 1); +  Pike_sp-=2; +  STACK_LEVEL_DONE(1); + }); +  + OPCODE1(F_LTOSVAL_CALL_BUILTIN_AND_ASSIGN_POP, +  "ltosval, call builtin, assign & pop", I_UPDATE_ALL, { +  INT32 args = DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  ONERROR uwp; +  +  /* Give other threads a chance to run now, before we temporarily +  * clear the svalue, in case another thread looks at it. */ +  FAST_CHECK_THREADS_ON_CALL(); +  +  /* FIXME: Assert that args > 0 */ +  +  STACK_LEVEL_START(args+2); +  +  free_svalue(Pike_sp-args); +  mark_free_svalue (Pike_sp - args); +  lvalue_to_svalue_no_free(Pike_sp-args, Pike_sp-args-2); +  /* This is so that foo = efun(foo,...) (and similar things) will be faster. +  * It's done by freeing the old reference to foo after it has been +  * pushed on the stack. That way foo can have only 1 reference if we +  * are lucky, and then the low array/multiset/mapping manipulation +  * routines can be destructive if they like. +  */ +  if( (1 << TYPEOF(Pike_sp[-args])) & +  (BIT_ARRAY | BIT_MULTISET | BIT_MAPPING | BIT_STRING) ) +  { +  LOCAL_VAR(struct svalue tmp); +  SET_SVAL(tmp, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  assign_lvalue(Pike_sp-args-2, &tmp);    } - BREAK +  /* NOTE: Pike_sp-args-2 is the lvalue, Pike_sp-args is the original value. +  * If an error gets thrown, the original value will thus be restored. +  * If the efun succeeds, Pike_sp-args will hold the result. +  */ +  SET_ONERROR(uwp, o_assign_lvalue, Pike_sp-args-2); +  DO_CALL_BUILTIN(args); +  STACK_LEVEL_CHECK(3); +  CALL_AND_UNSET_ONERROR(uwp);    -  +  pop_n_elems (3); +  STACK_LEVEL_DONE (0); + }); +  + #ifndef ENTRY_PROLOGUE_SIZE + #define ENTRY_PROLOGUE_SIZE 0 + #endif /* !ENTRY_PROLOGUE_SIZE */ +  + #define DO_RECUR(XFLAGS) do{ \ +  PIKE_OPCODE_T *addr; \ +  register struct pike_frame *new_frame; \ +  INT32 args = DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); \ +  \ +  DO_IF_SECURITY(CHECK_DATA_SECURITY_OR_ERROR(Pike_fp->current_object, \ +  SECURITY_BIT_CALL, \ +  ("Function call permission denied.\n"))); \ +  \ +  FAST_CHECK_THREADS_ON_CALL(); \ +  check_stack(256); \ +  \ +  new_frame=alloc_pike_frame(); \ +  new_frame->next=Pike_fp; \ +  \ +  JUMP_SET_TO_PC_AT_NEXT (addr); \ +  Pike_fp->return_addr = (PIKE_OPCODE_T *)(((INT32 *) addr) + 1); \ +  addr += GET_JUMP(); \ +  \ +  addr += ENTRY_PROLOGUE_SIZE; \ +  \ +  new_frame->args = args; \ +  new_frame->locals=new_frame->save_sp=new_frame->expendible=Pike_sp-args; \ +  new_frame->save_mark_sp = new_frame->mark_sp_base = Pike_mark_sp; \ +  DO_IF_DEBUG(new_frame->num_args=0;new_frame->num_locals=0;); \ +  SET_PROG_COUNTER(addr); \ +  new_frame->fun=Pike_fp->fun; \ +  DO_IF_PROFILING( new_frame->ident=Pike_fp->ident ); \ +  new_frame->current_storage=Pike_fp->current_storage; \ +  if(Pike_fp->scope) add_ref(new_frame->scope=Pike_fp->scope); \ +  add_ref(new_frame->current_object = Pike_fp->current_object); \ +  add_ref(new_frame->current_program = Pike_fp->current_program); \ +  new_frame->context = Pike_fp->context; \ +  \ +  DO_IF_PROFILING({ \ +  struct identifier *func; \ +  new_frame->start_time = \ +  get_cpu_time() - Pike_interpreter.unlocked_time; \ +  new_frame->ident = Pike_fp->ident; \ +  new_frame->children_base = Pike_interpreter.accounted_time; \ +  func = new_frame->context->prog->identifiers + new_frame->ident; \ +  func->num_calls++; \ +  func->recur_depth++; \ +  DO_IF_PROFILING_DEBUG({ \ +  fprintf(stderr, "%p{: Push at %" PRINT_CPU_TIME \ +  " %" PRINT_CPU_TIME "\n", \ +  Pike_interpreter.thread_state, new_frame->start_time, \ +  new_frame->children_base); \ +  }); \ +  }); \ +  \ +  Pike_fp=new_frame; \ +  new_frame->flags=PIKE_FRAME_RETURN_INTERNAL | XFLAGS; \ +  \ +  DO_IF_SECURITY(if(!CHECK_DATA_SECURITY(Pike_fp->current_object, \ +  SECURITY_BIT_NOT_SETUID)) \ +  SET_CURRENT_CREDS(Pike_fp->current_object->prot)); \ +  \ +  \ +  if (UNLIKELY(Pike_interpreter.trace_level > 3)) { \ +  fprintf(stderr, "- Addr = 0x%lx\n", (unsigned long) addr); \ +  } \ +  \ +  FETCH; \ +  JUMP_DONE; \ + }while(0) +    /* Assume that the number of arguments is correct */ - /* FIXME: adjust Pike_mark_sp */ - OPCODE0_JUMP(F_TAIL_RECUR,"tail recursion") + OPCODE1_PTRJUMP(F_COND_RECUR, "recur if not overloaded", I_UPDATE_ALL, { +  PIKE_OPCODE_T *addr; +  LOCAL_VAR(struct program *p); +  p = Pike_fp->current_program; +  JUMP_SET_TO_PC_AT_NEXT (addr); +  Pike_fp->return_addr = (PIKE_OPCODE_T *)(((INT32 *)addr) + 1); +  +  /* Test if the function is overloaded. +  * +  * Note: The second part of the test is sufficient, but +  * since the first case is much simpler to test and +  * is common, it should offer a speed improvement. +  * +  * /grubba 2002-11-14 +  * +  * Also test if the function uses scoping. DO_RECUR() doesn't +  * adjust fp->expendible which will make eg RETURN_LOCAL fail. +  * +  * /grubba 2003-03-25 +  */ +  if(((p != Pike_fp->context->prog) || +  (Pike_fp->context != +  &p->inherits[p->identifier_references[Pike_fp->context->identifier_level + +  arg1].inherit_offset])) || +  (ID_FROM_INT(p, arg1+Pike_fp->context->identifier_level)-> +  identifier_flags & IDENTIFIER_SCOPE_USED))    { -  int x; -  INT32 num_locals; -  char *addr; -  int args = DO_NOT_WARN(Pike_sp - *--Pike_mark_sp); +  ptrdiff_t num_locals; +  PIKE_OPCODE_T *faddr; +  PIKE_OPCODE_T *addr2; +  INT32 args = DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  JUMP_SET_TO_PC_AT_NEXT (faddr); +  faddr += GET_JUMP();    -  fast_check_threads_etc(6); +  if((addr2 = lower_mega_apply(args, +  Pike_fp->current_object, +  (arg1+Pike_fp->context->identifier_level)))) +  { +  Pike_fp->flags |= PIKE_FRAME_RETURN_INTERNAL; +  addr = addr2; +  } +  DO_JUMP_TO(addr); +  }    -  addr=pc+EXTRACT_INT(pc); -  num_locals=EXTRACT_UCHAR(addr-2); +  /* FALL THROUGH */    -  +  /* Assume that the number of arguments is correct */    - #ifdef PIKE_DEBUG -  if(args != EXTRACT_UCHAR(addr-1)) -  fatal("Wrong number of arguments in F_TAIL_RECUR %d != %d\n", -  args, EXTRACT_UCHAR(addr-1)); - #endif +  OPCODE0_TAILPTRJUMP(F_RECUR, "recur", I_UPDATE_ALL, { +  DO_RECUR(0); +  }); + });    -  + /* Ugly code duplication */ + OPCODE0_PTRJUMP(F_RECUR_AND_POP, "recur & pop", I_UPDATE_ALL, { +  DO_RECUR(PIKE_FRAME_RETURN_POP); + }); +  +  + /* Assume that the number of arguments is correct */ + /* FIXME: adjust Pike_mark_sp */ + OPCODE0_PTRJUMP(F_TAIL_RECUR, "tail recursion", I_UPDATE_ALL, { +  PIKE_OPCODE_T *addr; +  INT32 args = DO_NOT_WARN((INT32)(Pike_sp - *--Pike_mark_sp)); +  +  FAST_CHECK_THREADS_ON_CALL(); +  +  JUMP_SET_TO_PC_AT_NEXT (addr); +  addr += GET_JUMP(); +  addr += ENTRY_PROLOGUE_SIZE; +  SET_PROG_COUNTER(addr); +     if(Pike_sp-args != Pike_fp->locals)    { - #ifdef PIKE_DEBUG +  DO_IF_DEBUG({    if (Pike_sp < Pike_fp->locals + args) -  fatal("Pike_sp (%p) < Pike_fp->locals (%p) + args (%d)\n", +  Pike_fatal("Pike_sp (%p) < Pike_fp->locals (%p) + args (%d)\n",    Pike_sp, Pike_fp->locals, args); - #endif +  });    assign_svalues(Pike_fp->locals, Pike_sp-args, args, BIT_MIXED);    pop_n_elems(Pike_sp - (Pike_fp->locals + args));    }    -  clear_svalues(Pike_sp, num_locals - args); -  Pike_sp += num_locals - args; +  FETCH; +  JUMP_DONE; + });    - #ifdef PIKE_DEBUG -  if(Pike_sp != Pike_fp->locals + Pike_fp->num_locals) -  fatal("Sp whacked!\n"); + #if 0 + /* This opcode needs mending if it is to work with machine code. */ + OPCODE0_JUMP(F_BREAKPOINT, "breakpoint", 0, { +  extern void o_breakpoint(void); +  o_breakpoint(); +  DO_JUMP_TO(PROG_COUNTER-1); + });   #endif    -  pc=addr; + OPCODE1(F_THIS_OBJECT, "this_object", I_UPDATE_SP, { +  int level; +  LOCAL_VAR(struct object *o); +  o = Pike_fp->current_object; +  for (level = 0; level < arg1; level++) { +  LOCAL_VAR(struct program *p); +  p = o->prog; +  if (!p) +  Pike_error ("Object %d level(s) up is destructed - cannot get the parent.\n", +  level); +  if (!(p->flags & PROGRAM_USES_PARENT)) +  /* FIXME: Ought to write out the object here. */ +  Pike_error ("Object %d level(s) up lacks parent reference.\n", level); +  o = PARENT_INFO(o)->parent;    } - BREAK +  ref_push_object(o); +  }); +  + OPCODE0(F_ZERO_TYPE, "zero_type", 0, { +  if(TYPEOF(Pike_sp[-1]) != T_INT) +  { +  if((TYPEOF(Pike_sp[-1]) == T_OBJECT || TYPEOF(Pike_sp[-1]) == T_FUNCTION) +  && !Pike_sp[-1].u.object->prog) +  { +  pop_stack(); +  push_int(NUMBER_DESTRUCTED); +  }else{ +  pop_stack(); +  push_int(0); +  } +  }else{ +  SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, +  SUBTYPEOF(Pike_sp[-1])); +  } + }); +  + OPCODE0(F_SWAP,"swap",0,{ +  stack_swap(); + }); +  + OPCODE0(F_DUP,"dup",I_UPDATE_SP,{ +  stack_dup(); + }); +  + OPCODE2(F_THIS, "this", I_UPDATE_SP, { +  LOCAL_VAR(struct external_variable_context loc); +  +  loc.o = Pike_fp->current_object; +  loc.parent_identifier = Pike_fp->fun; +  loc.inherit = Pike_fp->context; +  find_external_context(&loc, arg1); +  +  DO_IF_DEBUG({ +  TRACE((5,"- Identifier=%d Offset=%d\n", +  arg1, +  loc.inherit->identifier_level)); +  }); +  if ((arg2 < 0) || !loc.o->prog) { +  ref_push_object(loc.o); +  } else { +  ref_push_object_inherit(loc.o, +  (loc.inherit - loc.o->prog->inherits) + arg2); +  } +  print_return_value(); + }); +  + OPCODE2(F_MAGIC_TYPES, "::_types", I_UPDATE_SP, { +  push_magic_index(magic_types_program, arg2, arg1); + }); +  + OPCODE2(F_INIT_FRAME, "init_frame", 0, { +  Pike_fp->num_args = arg1; +  Pike_fp->num_locals = arg2; +  }); +  + OPCODE1(F_PROTECT_STACK, "protect_stack", 0, { +  Pike_fp->expendible = Pike_fp->locals + arg1; +  }); +  + OPCODE2(F_FILL_STACK, "fill_stack", I_UPDATE_SP, { +  INT32 tmp = (Pike_fp->locals + arg1) - Pike_sp; +  if (tmp > 0) { +  if (arg2) { +  push_undefines(tmp); +  } else { +  push_zeroes(tmp); +  } +  } +  }); +  + OPCODE1(F_MARK_AT, "mark_at", I_UPDATE_SP, { +  *(Pike_mark_sp++) = Pike_fp->locals + arg1; +  }); +  + /* + #undef PROG_COUNTER + */