pike.git / src / program.c

version» Context lines:

pike.git/src/program.c:1:   /*   || 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. - || $Id: program.c,v 1.620 2007/09/25 16:56:53 grubba Exp $ + || $Id: program.c,v 1.621 2007/09/29 15:09:02 grubba Exp $   */      #include "global.h"   #include "program.h"   #include "object.h"   #include "dynamic_buffer.h"   #include "pike_types.h"   #include "stralloc.h"   #include "las.h"   #include "lex.h"
pike.git/src/program.c:3060:    Pike_fatal("Invalid identifier type.\n");    }       if(p->identifiers[e].identifier_flags & ~IDENTIFIER_MASK)    Pike_fatal("Unknown flags in identifier flag field.\n");       if((p->identifiers[e].run_time_type!=T_MIXED) &&    (p->identifiers[e].run_time_type!=PIKE_T_GET_SET))    check_type(p->identifiers[e].run_time_type);    -  if (!IDENTIFIER_IS_EXTERN(p->identifiers[e].identifier_flags)) { +  if (!IDENTIFIER_IS_ALIAS(p->identifiers[e].identifier_flags)) {    if(IDENTIFIER_IS_VARIABLE(p->identifiers[e].identifier_flags))    {    if( (p->identifiers[e].func.offset /* + OFFSETOF(object,storage)*/ ) &    (alignof_variable(p->identifiers[e].run_time_type)-1))    {    Pike_fatal("Variable %s offset is not properly aligned (%ld).\n",    p->identifiers[e].name->str,    PTRDIFF_T_TO_LONG(p->identifiers[e].func.offset));    }    }    } else {    /* FIXME: Check that ext_ref.depth and ext_ref.id are valid and    * have matching identifier_flags.    */ -  if (!(p->flags & PROGRAM_USES_PARENT)) { +  if (p->identifiers[e].func.ext_ref.depth && +  !(p->flags & PROGRAM_USES_PARENT)) {    Pike_fatal("Identifier %d is an external reference, but "    "PROGRAM_USES_PARENT hasn't been set.\n",    e);    }    }    }       for(e=0;e<p->num_identifier_references;e++)    {    struct identifier *i;
pike.git/src/program.c:3106:       if(p->identifier_references[e].identifier_offset >    p->inherits[p->identifier_references[e].inherit_offset].prog->num_identifiers)    Pike_fatal("Identifier offset %d is wrong! %d > %d\n",    e,    p->identifier_references[e].identifier_offset,    p->inherits[p->identifier_references[e].inherit_offset].prog->num_identifiers);       i=ID_FROM_INT(p, e);    -  if(IDENTIFIER_IS_VARIABLE(i->identifier_flags)) +  if(IDENTIFIER_IS_VARIABLE(i->identifier_flags) && +  !IDENTIFIER_IS_ALIAS(i->identifier_flags))    {    size_t q, size;    /* Variable */    ptrdiff_t offset = INHERIT_FROM_INT(p, e)->storage_offset+i->func.offset;    if (i->run_time_type == PIKE_T_GET_SET) {    struct reference *ref = PTR_FROM_INT(p, e);    if (!ref->inherit_offset) {    INT32 *gs_info = (INT32 *)(p->program + i->func.offset);    if ((gs_info + 2) > (INT32 *)(p->program + p->num_program)) {    dump_program_tables(p, 0);
pike.git/src/program.c:4266:    if (!state) {    yyerror("Failed to resolv external constant.\n");    return;    }    p = state->new_program;    numid = n->u.integer.b;    }       continue_inherit:    +  /* FIXME: Support external constants. */    if(numid != IDREF_MAGIC_THIS &&    (IDENTIFIER_IS_CONSTANT((i=ID_FROM_INT(p, numid))->    identifier_flags)) &&    (i->func.offset != -1))    {    struct svalue *s=&PROG_FROM_INT(p, numid)->    constants[i->func.offset].sval;    if(s->type != T_PROGRAM)    {    do_inherit(s,flags,name);
pike.git/src/program.c:4352:   /*    * Return the index of the identifier found, otherwise -1.    */   int isidentifier(struct pike_string *s)   {    return really_low_find_shared_string_identifier(s,    Pike_compiler->new_program,    SEE_STATIC|SEE_PRIVATE);   }    + /* Define an alias for a (possibly extern) identifier. +  * +  * Note that both type and name may be NULL. If they are NULL +  * they will be defaulted to the values from the aliased identifier. +  */ + int low_define_alias(struct pike_string *name, struct pike_type *type, +  int flags, int depth, int refno) + { +  int n; +  int e; +  +  struct program_state *state = Pike_compiler; +  struct identifier dummy, *id; +  struct reference ref; +  + #ifdef PIKE_DEBUG +  if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED)) +  Pike_fatal("Attempting to add variable to fixed program\n"); +  +  if(Pike_compiler->compiler_pass==2) +  Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n" +  "Added identifier: \"%s\"\n", name->str); + #endif +  +  for(e = 0; state && (e < depth); e++) { +  state = state->previous; +  } +  + #ifdef PIKE_DEBUG +  if (!state) { +  Pike_fatal("Internal error: External symbol buried too deep.\n"); +  } +  if (state->new_program->num_identifier_references <= refno) { +  Pike_fatal("Internal error: Reference out of bounds: %d (max: %d).\n", +  refno, state->new_program->num_identifier_references); +  } + #endif +  +  id = ID_FROM_INT(state->new_program, refno); +  +  if (name) { +  copy_shared_string(dummy.name, name); +  } else { +  copy_shared_string(dummy.name, id->name); +  } +  if (type) { +  copy_pike_type(dummy.type, type); +  } else { +  copy_pike_type(dummy.type, id->type); +  } +  dummy.identifier_flags = id->identifier_flags | IDENTIFIER_ALIAS; +  dummy.run_time_type = id->run_time_type; /* Not actually used. */ +  dummy.func.ext_ref.depth = depth; +  dummy.func.ext_ref.id = refno; + #ifdef PROFILING +  dummy.self_time=0; +  dummy.num_calls=0; +  dummy.total_time=0; + #endif +  +  ref.id_flags=flags; +  ref.identifier_offset=Pike_compiler->new_program->num_identifiers; +  ref.inherit_offset=0; +  +  debug_add_to_identifiers(dummy); +  +  n = Pike_compiler->new_program->num_identifier_references; +  add_to_identifier_references(ref); +  +  return n; + } +  + PMOD_EXPORT int define_alias(struct pike_string *name, struct pike_type *type, +  int flags, int depth, int refno) + { +  /* FIXME: Support NULL name and type. */ +  int n = isidentifier(name); +  +  if(Pike_compiler->new_program->flags & PROGRAM_PASS_1_DONE) +  { +  if(n==-1) +  yyerror("Pass2: Alias disappeared!"); +  else { +  struct identifier *id = ID_FROM_INT(Pike_compiler->new_program, n); +  if (!IDENTIFIER_IS_ALIAS(id->identifier_flags)) { +  if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) { +  /* Convert a placeholder constant into an alias. */ +  struct program_state *state = Pike_compiler; +  int e; +  +  for(e = 0; state && (e < depth); e++) { +  state = state->previous; +  } +  + #ifdef PIKE_DEBUG +  if (!state) { +  Pike_fatal("Internal error: External symbol buried too deep.\n"); +  } +  if (state->new_program->num_identifier_references <= refno) { +  Pike_fatal("Internal error: Reference out of bounds: %d (max: %d).\n", +  refno, state->new_program->num_identifier_references); +  } + #endif +  +  id->identifier_flags = IDENTIFIER_ALIAS | +  ID_FROM_INT(state->new_program, refno)->identifier_flags; +  } else { +  Pike_fatal("Replacing non alias with an alias in second pass!\n"); +  } +  } +  +  free_type(id->type); +  copy_pike_type(id->type, type); +  id->func.ext_ref.depth = depth; +  id->func.ext_ref.id = refno; +  return n; +  } +  } +  + #ifdef PIKE_DEBUG +  if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED)) +  Pike_fatal("Attempting to add variable to fixed program\n"); + #endif +  +  if(n != -1) +  { +  /* not inherited */ +  if(Pike_compiler->new_program->identifier_references[n].inherit_offset == 0) +  { +  if (!((IDENTIFIERP(n)->id_flags | flags) & ID_EXTERN)) { +  my_yyerror("Identifier %S defined twice.",name); +  return n; +  } +  if (flags & ID_EXTERN) { +  /* FIXME: Check type */ +  return n; +  } +  } +  +  if (!(IDENTIFIERP(n)->id_flags & ID_EXTERN)) { +  if (IDENTIFIERP(n)->id_flags & ID_NOMASK) +  my_yyerror("Illegal to redefine 'nomask/final' " +  "variable/functions %S", name); +  +  /* FIXME: More. */ +  } +  } +  +  return low_define_alias(name, type, flags, depth, refno); + } +    /* argument must be a shared string */   int low_define_variable(struct pike_string *name,    struct pike_type *type,    INT32 flags,    size_t offset,    INT32 run_time_type)   {    int n;       struct identifier dummy;
pike.git/src/program.c:4375: Inside #if defined(PIKE_DEBUG)
   if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))    Pike_fatal("Attempting to add variable to fixed program\n");       if(Pike_compiler->compiler_pass==2)    Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"    "Added identifier: \"%s\"\n", name->str);   #endif       copy_shared_string(dummy.name, name);    copy_pike_type(dummy.type, type); -  if (flags & ID_ALIAS) { -  dummy.identifier_flags = IDENTIFIER_VARIABLE | IDENTIFIER_ALIAS; -  } else { +     dummy.identifier_flags = IDENTIFIER_VARIABLE; -  } +     dummy.run_time_type=run_time_type;    dummy.func.offset=offset - Pike_compiler->new_program->inherits[0].storage_offset;   #ifdef PROFILING    dummy.self_time=0;    dummy.num_calls=0;    dummy.total_time=0;   #endif       ref.id_flags=flags;    ref.identifier_offset=Pike_compiler->new_program->num_identifiers;
pike.git/src/program.c:4561:       if ((ID_FROM_INT(Pike_compiler->new_program, n)->run_time_type !=    PIKE_T_MIXED) &&    (ID_FROM_INT(Pike_compiler->new_program, n)->run_time_type !=    compile_type_to_runtime_type(type))) {    my_yyerror("Illegal to redefine inherited variable %S "    "with different type.", name);    return n;    }    -  /* Copy the variable reference, so that we can change the -  * compile-time type. */ -  n2 = low_define_variable(name, type, -  (flags | ID_ALIAS) & ~ID_EXTERN, -  ID_FROM_INT(Pike_compiler->new_program, n)-> -  func.offset + -  INHERIT_FROM_INT(Pike_compiler->new_program, -  n)->storage_offset, -  ID_FROM_INT(Pike_compiler->new_program, n)-> -  run_time_type); -  /* Copy IDENTIFIER_NO_THIS_REF state from the old variable. -  */ -  ID_FROM_INT(Pike_compiler->new_program, n2)->identifier_flags |= -  ID_FROM_INT(Pike_compiler->new_program, n)->identifier_flags & -  IDENTIFIER_NO_THIS_REF; -  /* Hide the old variable. */ +  /* Create an alias for the old variable reference, so that we +  * can change the compile-time type. */ +  n2 = define_alias(name, type, flags & ~ID_EXTERN, 0, n); +  +  /* Hide the old variable and make it local. */    Pike_compiler->new_program->identifier_references[n].id_flags |= -  ID_HIDDEN; +  ID_HIDDEN|ID_INLINE;    return n2;    }    }    }       run_time_type=compile_type_to_runtime_type(type);       switch(run_time_type)    {   #ifdef AUTO_BIGNUM
pike.git/src/program.c:4683:    n = isidentifier(name);       if(   #if 1    c &&   #endif    c->type == T_FUNCTION &&    c->subtype != FUNCTION_BUILTIN &&    c->u.object->prog)    { +  struct program_state *state = Pike_compiler;    struct reference *idref = PTR_FROM_INT(c->u.object->prog, c->subtype);    struct program *p = PROG_FROM_PTR(c->u.object->prog, idref);    struct identifier *id = p->identifiers + idref->identifier_offset; -  if(c->u.object->prog == Pike_compiler->new_program) { -  /* Alias for a symbol in the current program. +  int depth = 0; +  while (state && (c->u.object->prog != state->new_program)) { +  depth++; +  state = state->previous; +  } +  if(state) { +  /* Alias for a symbol in the current or surrounding programs.    */    if(IDENTIFIER_IS_CONSTANT(id->identifier_flags) && -  id->func.offset != -1) { +  (id->func.offset != -1) && +  (state == Pike_compiler)) {    c=& p->constants[id->func.offset].sval; -  } -  else if (IDENTIFIER_IS_FUNCTION(id->identifier_flags)) { -  if (!idref->inherit_offset) { -  /* Alias for a function defined in this program. */ -  /* FIXME: Does this work for forward references? */ -  return define_function(name, -  id->type, -  flags, -  id->identifier_flags | IDENTIFIER_ALIAS, -  & id->func, -  id->opt_flags); -  } else if (Pike_compiler->new_program->flags & PROGRAM_PASS_1_DONE) { -  /* Alias for a function defined in an inherited program. */ -  yyerror("Aliasing of inherited functions not supported yet."); -  return define_function(name, -  id->type, -  flags, -  id->identifier_flags | IDENTIFIER_ALIAS, -  NULL, -  id->opt_flags); -  } else { -  /* First pass. -  * Make a prototype for now. -  */ -  return define_function(name, -  id->type, -  flags, -  id->identifier_flags | IDENTIFIER_ALIAS, -  NULL, -  id->opt_flags); -  } -  } else if (IDENTIFIER_IS_VARIABLE(id->identifier_flags)) { +  } else if (IDENTIFIER_IS_VARIABLE(id->identifier_flags) && +  (state == Pike_compiler)) {    my_yyerror("Attempt to make a constant %S of a variable.",    name);    c = NULL; -  +  } else { +  /* Alias for a function or a variable or constant in a surrounding +  * scope. +  */ +  int n = c->subtype; +  struct reference *remote_ref = PTR_FROM_INT(state->new_program, n); +  if (!(remote_ref->id_flags & (ID_INLINE|ID_HIDDEN))) { +  /* We need to get a suitable reference. */ +  n = really_low_reference_inherited_identifier(state, 0, n);    } -  +  return define_alias(name, id->type, flags, depth, n);    }    } -  +  }       if(   #if 1    c &&   #endif    !svalues_are_constant(c,1,BIT_MIXED,0))    my_yyerror("Constant value %S has a reference to this.", name);       if(Pike_compiler->new_program->flags & PROGRAM_PASS_1_DONE)    {
pike.git/src/program.c:5740:    int e;    int n = 0;    struct array *res;    for (e = p->num_identifier_references; e--; ) {    struct identifier *id;    if (p->identifier_references[e].id_flags &    (ID_HIDDEN|ID_STATIC|ID_PRIVATE)) {    continue;    }    id = ID_FROM_INT(p, e); -  if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) { +  if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) { +  /* FIXME! +  */ +  continue; +  } else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {    if (id->func.offset >= 0) {    struct program *p2 = PROG_FROM_INT(p, e);    struct svalue *val = &p2->constants[id->func.offset].sval;    if ((val->type != T_PROGRAM) ||    !(val->u.program->flags & PROGRAM_USES_PARENT)) {    ref_push_string(ID_FROM_INT(p, e)->name);    n++;    }    } else {    /* Prototype constant. */
pike.git/src/program.c:5775:    int e;    int n = 0;    struct array *res;    for(e = p->num_identifier_references; e--; ) {    struct identifier *id;    if (p->identifier_references[e].id_flags &    (ID_HIDDEN|ID_STATIC|ID_PRIVATE)) {    continue;    }    id = ID_FROM_INT(p, e); -  if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) { +  if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) { +  /* FIXME! +  */ +  continue; +  } else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {    if (id->func.offset >= 0) {    struct program *p2 = PROG_FROM_INT(p, e);    struct svalue *val = &p2->constants[id->func.offset].sval;    if ((val->type != T_PROGRAM) ||    !(val->u.program->flags & PROGRAM_USES_PARENT)) {    push_svalue(val);    n++;    }    } else {    /* Prototype constant. */
pike.git/src/program.c:5807:      int program_index_no_free(struct svalue *to, struct svalue *what,    struct svalue *ind)   {    int e;    struct pike_string *s;    struct object *parent = NULL;    struct svalue *sub = NULL;    struct program *p;    struct identifier *id; +  int parent_identifier = -1;       if (what->type == T_PROGRAM) {    p = what->u.program;    } else if ((what->type == T_FUNCTION) &&    (what->subtype != FUNCTION_BUILTIN) &&    ((parent = what->u.object)->prog) &&    IDENTIFIER_IS_CONSTANT((id = ID_FROM_INT(parent->prog,    what->subtype))->identifier_flags) &&    (id->func.offset != -1) &&    ((sub = &PROG_FROM_INT(parent->prog, what->subtype)->constants[id->func.offset].sval)->type == T_PROGRAM)) {    p = sub->u.program; -  +  parent_identifier = what->subtype;    } else {    /* Not a program. */    return 0;    }    if (ind->type != T_STRING) {    Pike_error("Can't index a program with a %s (expected string)\n",    get_name_of_type(ind->type));    }    s = ind->u.string;    e=find_shared_string_identifier(s, p);    if(e!=-1)    {    struct identifier *id;    id=ID_FROM_INT(p, e); -  +  +  if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) { +  struct external_variable_context loc; +  struct object fake_object; +  struct parent_info parent_info; +  int refid; +  +  if (!parent) goto fail; +  +  parent_info.parent = parent; +  parent_info.parent_identifier = parent_identifier; +  fake_object.prog = p; +  fake_object.refs = 1; +  fake_object.next = fake_object.prev = NULL; +  fake_object.storage = ((char *)&parent_info) - p->parent_info_storage; + #ifdef PIKE_DEBUG +  fake_object.program_id = p->id; + #endif +  +  loc.o = &fake_object; +  loc.inherit = INHERIT_FROM_INT(p, e); +  loc.parent_identifier = 0; +  +  do { +  find_external_context(&loc, id->func.ext_ref.depth); +  refid = id->func.ext_ref.id; +  id = ID_FROM_INT(loc.o->prog, refid); +  } while (IDENTIFIER_IS_ALIAS(id->identifier_flags)); +  +  if (fake_object.refs != 1) { +  Pike_fatal("Lost track of fake object! refs: %d\n", +  fake_object.refs); +  } +  +  if (loc.o != &fake_object) { +  low_object_index_no_free(to, loc.o, refid); +  return 1; +  } +  } +     if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {    if (id->func.offset >= 0) {    struct program *p2 = PROG_FROM_INT(p, e);    struct svalue *val = &p2->constants[id->func.offset].sval;    assign_svalue_no_free(to, val);    } else {    /* Prototype constant. */    to->type = T_INT;    to->subtype = 0;    to->u.integer = 0;    }    return 1;    }    } -  +  fail:       to->type=T_INT;    to->subtype=NUMBER_UNDEFINED;    to->u.integer=0;    return 1;   }      /*    * Line number support routines, now also tells what file we are in    */
pike.git/src/program.c:6368:    REF_MAKE_CONST_STRING(not_found, "Line not found");    return not_found;    }    return res;   }      PMOD_EXPORT struct pike_string *low_get_function_line (struct object *o,    int fun, INT32 *linep)   {    if (o->prog) { +  struct program *p; +  struct identifier *id; +  while (1) { +  struct external_variable_context loc;    struct reference *idref = o->prog->identifier_references + fun; -  struct program *p = PROG_FROM_PTR (o->prog, idref); -  struct identifier *id = p->identifiers + idref->identifier_offset; +  p = PROG_FROM_PTR(o->prog, idref); +  id = p->identifiers + idref->identifier_offset; +  if (!IDENTIFIER_IS_ALIAS(id->identifier_flags)) break; +  loc.o = o; +  loc.inherit = INHERIT_FROM_INT(o->prog, fun); +  loc.parent_identifier = fun; +  find_external_context(&loc, id->func.ext_ref.depth); +  fun = id->func.ext_ref.id + loc.inherit->identifier_level; +  o = loc.o; +  }    if (IDENTIFIER_IS_PIKE_FUNCTION(id->identifier_flags))    return low_get_line (p->program + id->func.offset, p, linep);    return low_get_program_line(o->prog, linep);    }    *linep = 0;    return NULL;   }      PMOD_EXPORT void va_yyerror(const char *fmt, va_list args)   {
pike.git/src/program.c:7997: Inside #if defined(_REENTRANT)
     #ifdef _REENTRANT    if(d_flag) CHECK_INTERPRETER_LOCK();   #endif       offset= low_get_storage(o->prog, p);    if(offset == -1) return 0;    return o->storage + offset;   }    - struct program *low_program_from_function(struct program *p, -  INT32 i) + struct program *low_program_from_function(struct object *o, INT32 i)   {    struct svalue *f; -  struct identifier *id=ID_FROM_INT(p, i); +  struct program *p; +  struct identifier *id; +  while(1) { +  struct external_variable_context loc; +  p = o->prog; +  +  if(!p) return 0; +  +  id = ID_FROM_INT(p, i); +  if(!IDENTIFIER_IS_ALIAS(id->identifier_flags)) break; +  +  loc.o = o; +  loc.inherit = INHERIT_FROM_INT(p, i); +  loc.parent_identifier = i; +  find_external_context(&loc, id->func.ext_ref.depth); +  i = id->func.ext_ref.id + loc.inherit->identifier_level; +  o = loc.o; +  }    if(!IDENTIFIER_IS_CONSTANT(id->identifier_flags)) return 0;    if(id->func.offset==-1) return 0; -  f=& PROG_FROM_INT(p,i)->constants[id->func.offset].sval; +  f = &PROG_FROM_INT(p,i)->constants[id->func.offset].sval;    if(f->type!=T_PROGRAM) return 0;    return f->u.program;   }      PMOD_EXPORT struct program *program_from_function(const struct svalue *f)   {    if(f->type != T_FUNCTION) return 0;    if(f->subtype == FUNCTION_BUILTIN) return 0; -  if(!f->u.object->prog) return 0; -  return low_program_from_function(f->u.object->prog, f->subtype); +  return low_program_from_function(f->u.object, f->subtype);   }      /* NOTE: Does not add references to the return value! */   PMOD_EXPORT struct program *program_from_svalue(const struct svalue *s)   {    switch(s->type)    {    case T_OBJECT:    {    struct program *p = s->u.object->prog;
pike.git/src/program.c:8060:    return 0;    }   }      #define FIND_CHILD_HASHSIZE 5003   struct find_child_cache_s   {    INT32 pid,cid,id;   };    + #if 0   static struct find_child_cache_s find_child_cache[FIND_CHILD_HASHSIZE];      int find_child(struct program *parent, struct program *child)   {    unsigned INT32 h=(parent->id * 9248339 + child->id);    h= h % FIND_CHILD_HASHSIZE;   #ifdef PIKE_DEBUG    if(h>=FIND_CHILD_HASHSIZE)    Pike_fatal("find_child failed to hash within boundaries.\n");   #endif
pike.git/src/program.c:8089:    {    find_child_cache[h].pid=parent->id;    find_child_cache[h].cid=child->id;    find_child_cache[h].id=i;    return i;    }    }    }    return -1;   } + #endif /* 0 */      void yywarning(char *fmt, ...)   {    /* If we have parse errors we might get erroneous warnings,    * so don't print them.    * This has the additional benefit of making it easier to    * visually locate the actual error message.    */    if (Pike_compiler->num_parse_error) return;