|
|
|
|
|
|
|
#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" |
#include "pike_macros.h" |
#include "fsort.h" |
#include "pike_error.h" |
#include "docode.h" |
#include "interpret.h" |
#include "hashtable.h" |
#include "main.h" |
#include "pike_memory.h" |
#include "gc.h" |
#include "threads.h" |
#include "constants.h" |
#include "operators.h" |
#include "builtin_functions.h" |
#include "stuff.h" |
#include "mapping.h" |
#include "cyclic.h" |
#include "pike_security.h" |
#include "pike_types.h" |
#include "opcodes.h" |
#include "version.h" |
#include "block_alloc.h" |
#include "pikecode.h" |
|
#include <errno.h> |
#include <fcntl.h> |
|
#define sp Pike_sp |
|
#undef ATTRIBUTE |
#define ATTRIBUTE(X) |
|
static void exit_program_struct(struct program *); |
static size_t add_xstorage(size_t size, |
size_t alignment, |
ptrdiff_t modulo_orig); |
|
#undef EXIT_BLOCK |
#define EXIT_BLOCK(P) exit_program_struct( (P) ) |
|
#undef COUNT_OTHER |
#define COUNT_OTHER() do{ \ |
struct program *p; \ |
for(p=first_program;p;p=p->next) \ |
{ \ |
size+=p->total_size; \ |
} \ |
}while(0) |
|
BLOCK_ALLOC_FILL_PAGES(program, 4) |
|
|
|
|
|
#ifdef COMPILER_DEBUG |
#define CDFPRINTF(X) fprintf X |
#else /* !COMPILER_DEBUG */ |
#define CDFPRINTF(X) |
#endif /* COMPILER_DEBUG */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define FIND_FUNCTION_HASHSIZE 15013 |
|
|
#define FIND_FUNCTION_HASH_TRESHOLD 9 |
|
|
#define DECLARE |
#include "compilation.h" |
|
struct pike_string *this_program_string, *this_string; |
static struct pike_string *UNDEFINED_string; |
|
const char *const lfun_names[] = { |
"__INIT", |
"create", |
"destroy", |
"`+", |
"`-", |
"`&", |
"`|", |
"`^", |
"`<<", |
"`>>", |
"`*", |
"`/", |
"`%", |
"`~", |
"`==", |
"`<", |
"`>", |
"__hash", |
"cast", |
"`!", |
"`[]", |
"`[]=", |
"`->", |
"`->=", |
"_sizeof", |
"_indices", |
"_values", |
"`()", |
"``+", |
"``-", |
"``&", |
"``|", |
"``^", |
"``<<", |
"``>>", |
"``*", |
"``/", |
"``%", |
"`+=", |
"_is_type", |
"_sprintf", |
"_equal", |
"_m_delete", |
"_get_iterator", |
"`[..]", |
|
"_search", |
}; |
|
struct pike_string *lfun_strings[NELEM(lfun_names)]; |
|
static struct mapping *lfun_ids; |
|
|
static struct mapping *lfun_types; |
|
static const char *const raw_lfun_types[] = { |
tFuncV(tNone,tVoid,tVoid), |
tFuncV(tNone,tZero,tVoid), |
tFuncV(tOr(tVoid,tInt),tVoid,tVoid), |
tFuncV(tZero,tZero,tMix), |
tFunc(tOr(tVoid,tZero),tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tVoid,tMix), |
tFuncV(tMix,tVoid,tInt), |
tFuncV(tMix,tVoid,tInt), |
tFuncV(tMix,tVoid,tInt), |
tFuncV(tNone,tVoid,tInt), |
tFuncV(tString,tVoid,tMix), |
tFuncV(tNone,tVoid,tInt), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tZero tSetvar(0,tZero),tVoid,tVar(0)), |
tFuncV(tStr,tVoid,tMix), |
tFuncV(tStr tSetvar(0,tZero),tVoid,tVar(0)), |
tFuncV(tNone,tVoid,tInt), |
tFuncV(tNone,tVoid,tArray), |
tFuncV(tNone,tVoid,tArray), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tZero,tZero,tMix), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tNone,tZero,tMix), |
tFuncV(tZero,tZero,tMix), |
tFuncV(tStr,tVoid,tInt), |
tFuncV(tInt tOr(tMap(tStr,tInt),tVoid),tVoid,tStr), |
tFuncV(tMix,tVoid,tInt), |
tFuncV(tZero,tVoid,tMix), |
tFuncV(tNone,tVoid,tObj), |
tFuncV(tZero tRangeBound tZero tRangeBound, tVoid, tMix), |
|
tFuncV(tZero tOr(tZero, tVoid), tVoid, tMix), |
}; |
|
|
static struct pike_type *lfun_getter_type_string = NULL; |
static struct pike_type *lfun_setter_type_string = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct program *first_program = 0; |
static int current_program_id = PROG_DYNAMIC_ID_START; |
|
struct program *null_program=0; |
|
struct object *error_handler=0; |
struct object *compat_handler=0; |
|
struct program *gc_internal_program = 0; |
static struct program *gc_mark_program_pos = 0; |
|
int compilation_depth=-1; |
dynamic_buffer used_modules; |
static struct mapping *resolve_cache=0; |
|
#ifdef PIKE_DEBUG |
#define CHECK_FILE_ENTRY(PROG, POS, LEN, SHIFT) \ |
do { \ |
if (SHIFT < 0 || SHIFT > 2 || \ |
POS + (LEN << SHIFT) > PROG->linenumbers + PROG->num_linenumbers) \ |
Pike_fatal ("Invalid file entry in linenumber info.\n"); \ |
} while (0) |
#else |
#define CHECK_FILE_ENTRY(PROG, POS, LEN, SHIFT) do {} while (0) |
#endif |
|
int get_small_number(char **q); |
|
PMOD_EXPORT void do_free_program (struct program *p) |
{ |
if (p) |
free_program(p); |
} |
|
|
|
#ifdef PIKE_DEBUG |
#define CHECK_FOO(NUMTYPE,TYPE,NAME) \ |
if(Pike_compiler->malloc_size_program-> PIKE_CONCAT(num_,NAME) < \ |
Pike_compiler->new_program-> PIKE_CONCAT(num_,NAME)) \ |
Pike_fatal("Pike_compiler->new_program->num_" #NAME " is out of order\n");\ |
if(Pike_compiler->new_program->flags & PROGRAM_OPTIMIZED) \ |
Pike_fatal("Tried to reallocate fixed program.\n") |
|
#else |
#define CHECK_FOO(NUMTYPE,TYPE,NAME) |
#endif |
|
#ifndef RELOCATE_program |
#define RELOCATE_program(ORIG, NEW) |
#endif /* !RELOCATE_program */ |
#define RELOCATE_linenumbers(ORIG,NEW) |
#define RELOCATE_identifier_index(ORIG,NEW) |
#define RELOCATE_variable_index(ORIG,NEW) |
#define RELOCATE_identifier_references(ORIG,NEW) |
#define RELOCATE_strings(ORIG,NEW) |
#define RELOCATE_inherits(ORIG,NEW) |
#define RELOCATE_identifiers(ORIG,NEW) |
#define RELOCATE_constants(ORIG,NEW) |
#define RELOCATE_relocations(ORIG,NEW) |
|
#if SIZEOF_LONG_LONG == 8 |
|
#define MAXVARS(NUMTYPE) \ |
(NUMTYPE)(sizeof(NUMTYPE)==1?254: \ |
(sizeof(NUMTYPE)==2?65534: \ |
(sizeof(NUMTYPE)==4?4294967294U:18446744073709551614ULL))) |
#else |
#define MAXVARS(NUMTYPE) \ |
(NUMTYPE)(sizeof(NUMTYPE)==1?254: (sizeof(NUMTYPE)==2?65534:4294967294U)) |
#endif |
|
#ifdef PIKE_USE_MACHINE_CODE |
|
* many OSes require us to use mmap to allocate memory for our |
* machine code. |
*/ |
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
void PIKE_CONCAT(low_add_to_,NAME) (struct program_state *state, \ |
TYPE ARG) { \ |
NUMTYPE m = state->malloc_size_program->PIKE_CONCAT(num_,NAME); \ |
CHECK_FOO(NUMTYPE,TYPE,NAME); \ |
if(m == state->new_program->PIKE_CONCAT(num_,NAME)) { \ |
TYPE *tmp; \ |
if(m==MAXVARS(NUMTYPE)) { \ |
yyerror("Too many " #NAME "."); \ |
return; \ |
} \ |
m = MINIMUM(m*2+1,MAXVARS(NUMTYPE)); \ |
tmp = mexec_realloc((void *)state->new_program->NAME, \ |
sizeof(TYPE) * m); \ |
if(!tmp) Pike_fatal("Out of memory.\n"); \ |
PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \ |
state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \ |
state->new_program->NAME=tmp; \ |
} \ |
state->new_program-> \ |
NAME[state->new_program->PIKE_CONCAT(num_,NAME)++]=(ARG); \ |
} \ |
void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \ |
PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \ |
} |
#endif /* PIKE_USE_MACHINE_CODE */ |
|
|
|
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
void PIKE_CONCAT(low_add_to_,NAME) (struct program_state *state, \ |
TYPE ARG) { \ |
NUMTYPE m = state->malloc_size_program->PIKE_CONCAT(num_,NAME); \ |
CHECK_FOO(NUMTYPE,TYPE,NAME); \ |
if(m == state->new_program->PIKE_CONCAT(num_,NAME)) { \ |
TYPE *tmp; \ |
if(m==MAXVARS(NUMTYPE)) { \ |
yyerror("Too many " #NAME "."); \ |
return; \ |
} \ |
m = MINIMUM(m*2+1,MAXVARS(NUMTYPE)); \ |
tmp = realloc((void *)state->new_program->NAME, \ |
sizeof(TYPE) * m); \ |
if(!tmp) Pike_fatal("Out of memory.\n"); \ |
PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \ |
state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \ |
state->new_program->NAME=tmp; \ |
} \ |
state->new_program-> \ |
NAME[state->new_program->PIKE_CONCAT(num_,NAME)++]=(ARG); \ |
} \ |
void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \ |
PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \ |
} |
|
|
|
#define PASS1ONLY(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
void PIKE_CONCAT(low_add_to_,NAME) (struct program_state *state, \ |
TYPE ARG) { \ |
NUMTYPE m = state->malloc_size_program->PIKE_CONCAT(num_,NAME); \ |
CHECK_FOO(NUMTYPE,TYPE,NAME); \ |
DO_IF_DEBUG(if (state->compiler_pass != 1) { \ |
Pike_fatal("Adding " TOSTR(NAME) " in pass %d.\n", \ |
state->compiler_pass); \ |
}); \ |
if(m == state->new_program->PIKE_CONCAT(num_,NAME)) { \ |
TYPE *tmp; \ |
if(m==MAXVARS(NUMTYPE)) { \ |
yyerror("Too many " #NAME "."); \ |
return; \ |
} \ |
m = MINIMUM(m*2+1,MAXVARS(NUMTYPE)); \ |
tmp = realloc((void *)state->new_program->NAME, \ |
sizeof(TYPE) * m); \ |
if(!tmp) Pike_fatal("Out of memory.\n"); \ |
PIKE_CONCAT(RELOCATE_,NAME)(state->new_program, tmp); \ |
state->malloc_size_program->PIKE_CONCAT(num_,NAME)=m; \ |
state->new_program->NAME=tmp; \ |
} \ |
state->new_program-> \ |
NAME[state->new_program->PIKE_CONCAT(num_,NAME)++]=(ARG); \ |
} \ |
void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \ |
PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \ |
} |
|
|
#include "program_areas.h" |
|
|
#define add_to_program(ARG) do { \ |
debug_malloc_touch(Pike_compiler->new_program->program); \ |
add_to_program(ARG); \ |
} while(0) |
|
void ins_int(INT32 i, void (*func)(char tmp)) |
{ |
int e; |
unsigned char *p = (unsigned char *)&i; |
for(e=0;e<(long)sizeof(i);e++) { |
func(p[e]); |
} |
} |
|
void ins_short(int i, void (*func)(char tmp)) |
{ |
int e; |
unsigned char *p = (unsigned char *)&i; |
for(e=0;e<(long)sizeof(i);e++) { |
func(p[e]); |
} |
} |
|
#ifdef PIKE_DEBUG |
static void debug_add_to_identifiers (struct identifier id) |
{ |
if (d_flag) { |
int i; |
for (i = 0; i < Pike_compiler->new_program->num_identifiers; i++) |
if (Pike_compiler->new_program->identifiers[i].name == id.name) { |
dump_program_tables (Pike_compiler->new_program, 0); |
Pike_fatal ("Adding identifier twice, old at %d.\n", i); |
} |
} |
add_to_identifiers (id); |
} |
#else |
#define debug_add_to_identifiers(ARG) add_to_identifiers(ARG) |
#endif |
|
void add_relocated_int_to_program(INT32 i) |
{ |
add_to_relocations(Pike_compiler->new_program->num_program); |
ins_int(i, (void (*)(char))add_to_program); |
} |
|
void use_module(struct svalue *s) |
{ |
if( (1<<s->type) & (BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM)) |
{ |
Pike_compiler->num_used_modules++; |
assign_svalue_no_free((struct svalue *) |
low_make_buf_space(sizeof(struct svalue), |
&used_modules), s); |
if(Pike_compiler->module_index_cache) |
{ |
free_mapping(Pike_compiler->module_index_cache); |
Pike_compiler->module_index_cache=0; |
} |
}else{ |
yyerror("Module is neither mapping nor object"); |
} |
} |
|
void unuse_modules(INT32 howmany) |
{ |
if(!howmany) return; |
#ifdef PIKE_DEBUG |
if(howmany *sizeof(struct svalue) > used_modules.s.len) |
Pike_fatal("Unusing too many modules.\n"); |
#endif |
Pike_compiler->num_used_modules-=howmany; |
low_make_buf_space(-sizeof(struct svalue)*howmany, &used_modules); |
free_svalues((struct svalue *)low_make_buf_space(0, &used_modules), |
howmany, |
BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM); |
if(Pike_compiler->module_index_cache) |
{ |
free_mapping(Pike_compiler->module_index_cache); |
Pike_compiler->module_index_cache=0; |
} |
} |
|
int low_find_shared_string_identifier(struct pike_string *name, |
struct program *prog); |
|
|
|
static struct node_s *index_modules(struct pike_string *ident, |
struct mapping **module_index_cache, |
int num_used_modules, |
struct svalue *modules) |
{ |
if(*module_index_cache) |
{ |
struct svalue *tmp=low_mapping_string_lookup(*module_index_cache,ident); |
if(tmp) |
{ |
if(!(SAFE_IS_ZERO(tmp) && tmp->subtype==1)) |
return mksvaluenode(tmp); |
return 0; |
} |
} |
|
|
|
{ |
JMP_BUF tmp; |
|
if(SETJMP(tmp)) |
{ |
if (!ident->size_shift) { |
handle_compile_exception ("Couldn't index a module with '%s'.", ident->str); |
} else { |
handle_compile_exception ("Couldn't index a module."); |
} |
} else { |
int e = num_used_modules; |
struct svalue *m = modules - num_used_modules; |
|
while(--e>=0) |
{ |
push_svalue(m+e); |
ref_push_string(ident); |
f_index(2); |
|
if(!IS_UNDEFINED(Pike_sp-1)) |
{ |
struct node_s *ret; |
UNSETJMP(tmp); |
|
if (Pike_compiler->compiler_pass == 2 && |
((Pike_sp[-1].type == T_OBJECT && |
Pike_sp[-1].u.object == placeholder_object) || |
(Pike_sp[-1].type == T_PROGRAM && |
Pike_sp[-1].u.program == placeholder_program))) { |
my_yyerror("Got placeholder %s (resolver problem) " |
"when indexing a module with %S.", |
get_name_of_type (Pike_sp[-1].type), ident); |
ret = 0; |
} |
else { |
if(!*module_index_cache) |
*module_index_cache = allocate_mapping(10); |
mapping_string_insert(*module_index_cache, ident, Pike_sp-1); |
ret = mksvaluenode(Pike_sp-1); |
} |
pop_stack(); |
return ret; |
} |
pop_stack(); |
} |
} |
UNSETJMP(tmp); |
} |
|
|
|
return 0; |
} |
|
struct node_s *resolve_identifier(struct pike_string *ident); |
|
struct node_s *find_module_identifier(struct pike_string *ident, |
int see_inherit) |
{ |
struct node_s *ret; |
|
struct svalue *modules=(struct svalue *) |
(used_modules.s.str + used_modules.s.len); |
|
{ |
struct program_state *p=Pike_compiler; |
int n; |
for(n=0;n<=compilation_depth;n++,p=p->previous) |
{ |
int i; |
if(see_inherit) |
{ |
i=really_low_find_shared_string_identifier(ident, |
p->new_program, |
SEE_STATIC|SEE_PRIVATE); |
if(i!=-1) |
{ |
return p == Pike_compiler ? |
mkidentifiernode(i) : |
mkexternalnode(p->new_program, i); |
} |
} |
|
if((ret=index_modules(ident, |
&p->module_index_cache, |
p->num_used_modules, |
modules))) return ret; |
modules-=p->num_used_modules; |
#ifdef PIKE_DEBUG |
if( ((char *)modules ) < used_modules.s.str) |
Pike_fatal("Modules out of whack!\n"); |
#endif |
} |
} |
|
return resolve_identifier(ident); |
} |
|
|
|
|
|
|
struct node_s *resolve_identifier(struct pike_string *ident) |
{ |
|
if (ident == UNDEFINED_string) { |
struct svalue s; |
s.type = T_INT; |
s.subtype = NUMBER_UNDEFINED; |
s.u.integer = 0; |
return mkconstantsvaluenode(&s); |
} |
|
if(resolve_cache) |
{ |
struct svalue *tmp=low_mapping_string_lookup(resolve_cache,ident); |
if(tmp) |
{ |
if(!(SAFE_IS_ZERO(tmp) && tmp->subtype==1)) |
return mkconstantsvaluenode(tmp); |
|
return 0; |
} |
} |
|
if(get_master()) |
{ |
DECLARE_CYCLIC(); |
node *ret=0; |
if(BEGIN_CYCLIC(ident, lex.current_file)) |
{ |
my_yyerror("Recursive module dependency in %S.", ident); |
}else{ |
SET_CYCLIC_RET(1); |
|
ref_push_string(ident); |
ref_push_string(lex.current_file); |
if (error_handler) { |
ref_push_object(error_handler); |
} else { |
push_int(0); |
} |
|
if (safe_apply_handler("resolv", error_handler, compat_handler, 3, 0)) { |
if (Pike_compiler->compiler_pass == 2 && |
((Pike_sp[-1].type == T_OBJECT && |
Pike_sp[-1].u.object == placeholder_object) || |
(Pike_sp[-1].type == T_PROGRAM && |
Pike_sp[-1].u.program == placeholder_program))) { |
my_yyerror("Got placeholder %s (resolver problem) " |
"when resolving %S.", |
get_name_of_type (Pike_sp[-1].type), ident->str); |
} |
else { |
if(!resolve_cache) |
resolve_cache=dmalloc_touch(struct mapping *, allocate_mapping(10)); |
mapping_string_insert(resolve_cache,ident,Pike_sp-1); |
|
if(!(SAFE_IS_ZERO(Pike_sp-1) && Pike_sp[-1].subtype==1)) |
{ |
ret=mkconstantsvaluenode(Pike_sp-1); |
} |
} |
pop_stack(); |
} |
else { |
if(Pike_compiler->compiler_pass==2) { |
if (throw_value.type == T_STRING) { |
my_yyerror("%S", throw_value.u.string); |
free_svalue(&throw_value); |
throw_value.type = T_INT; |
} |
else { |
handle_compile_exception ("Error resolving %S.", ident); |
} |
} |
else { |
|
|
struct svalue thrown; |
move_svalue (&thrown, &throw_value); |
throw_value.type = T_INT; |
#ifdef PIKE_DEBUG |
{ |
struct pike_string *msg = format_exception_for_error_msg (&thrown); |
if (msg) { |
yywarning ("Ignoring resolv() exception in pass %d:", |
Pike_compiler->compiler_pass); |
yywarning ("%S", msg); |
free_string (msg); |
} |
else |
yywarning ("Ignoring resolv() exception in pass %d", |
Pike_compiler->compiler_pass); |
} |
#endif |
free_svalue (&thrown); |
} |
} |
} |
END_CYCLIC(); |
|
return ret; |
} |
|
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct node_s *program_magic_identifier (struct program_state *state, |
int state_depth, int inherit_num, |
struct pike_string *ident, |
int colon_colon_ref) |
{ |
#if 0 |
fprintf (stderr, "magic_identifier (state, %d, %d, %s, %d)\n", |
state_depth, inherit_num, ident->str, colon_colon_ref); |
#endif |
|
if (!inherit_num || (!TEST_COMPAT(7,6) && (inherit_num > 0))) { |
if (ident == this_string) { |
|
return mkthisnode(state->new_program, inherit_num); |
} |
|
|
if (ident == this_program_string) { |
node *n = mkefuncallnode("object_program", |
mkthisnode(state->new_program, inherit_num)); |
|
n->node_info &= ~OPT_NOT_CONST; |
n->tree_info &= ~OPT_NOT_CONST; |
return n; |
} |
} |
|
if (colon_colon_ref) { |
|
|
if (inherit_num < 0) inherit_num = 0; |
if(ident == lfun_strings[LFUN_ARROW] || |
ident == lfun_strings[LFUN_INDEX]) { |
return mknode(F_MAGIC_INDEX, mknewintnode(inherit_num), |
mknewintnode(state_depth)); |
} else if(ident == lfun_strings[LFUN_ASSIGN_ARROW] || |
ident == lfun_strings[LFUN_ASSIGN_INDEX]) { |
return mknode(F_MAGIC_SET_INDEX, mknewintnode(inherit_num), |
mknewintnode(state_depth)); |
} else if(ident == lfun_strings[LFUN__INDICES]) { |
return mknode(F_MAGIC_INDICES, mknewintnode(inherit_num), |
mknewintnode(state_depth)); |
} else if(ident == lfun_strings[LFUN__VALUES]) { |
return mknode(F_MAGIC_VALUES, mknewintnode(inherit_num), |
mknewintnode(state_depth)); |
} |
} |
|
return NULL; |
} |
|
|
struct program *parent_compilation(int level) |
{ |
int n; |
struct program_state *p=Pike_compiler->previous; |
for(n=0;n<level;n++) |
{ |
if(n>=compilation_depth) return 0; |
p=p->previous; |
if(!p) return 0; |
} |
return p->new_program; |
} |
|
#define ID_TO_PROGRAM_CACHE_SIZE 512 |
struct program *id_to_program_cache[ID_TO_PROGRAM_CACHE_SIZE]; |
|
struct program *id_to_program(INT32 id) |
{ |
struct program *p; |
INT32 h; |
if(!id) return 0; |
|
|
|
h=id & (ID_TO_PROGRAM_CACHE_SIZE-1); |
|
if((p=id_to_program_cache[h])) |
if(p->id==id) { |
|
return p; |
} |
|
for(p=first_program;p;p=p->next) |
{ |
if(id==p->id) |
{ |
id_to_program_cache[h]=p; |
|
return p; |
} |
} |
|
if ((id > 0) && (id < PROG_DYNAMIC_ID_START)) { |
|
|
|
char *module = NULL; |
|
|
|
switch(id) { |
case PROG_PARSER_HTML_ID: |
module = "Parser._parser"; |
break; |
case PROG_GMP_MPZ_ID: |
module = "Gmp"; |
break; |
case PROG_MODULE_MIME_ID: |
module = "___MIME"; |
break; |
default: |
if ((id >= 100) && (id <= 300)) { |
module = "Image"; |
} else if ((id >= 1000) && (id < 2000)) { |
module = "___GTK"; |
} else if ((id >= 2000) && (id < 3000)) { |
module = "___GTK2"; |
} |
break; |
} |
if (module) { |
|
push_text(module); |
SAFE_APPLY_MASTER("resolv", 1); |
pop_stack(); |
|
|
for(p=first_program;p;p=p->next) |
{ |
if(id==p->id) |
{ |
id_to_program_cache[h]=p; |
|
return p; |
} |
} |
} |
} |
|
return 0; |
} |
|
|
|
|
|
|
|
|
void optimize_program(struct program *p) |
{ |
size_t size=0; |
char *data; |
|
|
if(p->flags & PROGRAM_OPTIMIZED) return; |
|
#ifdef PIKE_USE_MACHINE_CODE |
|
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) |
#endif /* PIKE_USE_MACHINE_CODE */ |
|
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
size=DO_ALIGN(size, ALIGNOF(TYPE)); \ |
size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]); |
#include "program_areas.h" |
|
data=malloc(size); |
if(!data) |
{ |
make_program_executable(p); |
return; |
} |
|
size=0; |
|
#ifdef PIKE_USE_MACHINE_CODE |
|
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) |
#endif /* PIKE_USE_MACHINE_CODE */ |
|
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
size=DO_ALIGN(size, ALIGNOF(TYPE)); \ |
if (p->PIKE_CONCAT (num_, NAME)) \ |
MEMCPY(data+size,p->NAME,p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0])); \ |
PIKE_CONCAT(RELOCATE_,NAME)(p, (TYPE *)(data+size)); \ |
dmfree(p->NAME); \ |
p->NAME=(TYPE *)(data+size); \ |
size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]); |
#include "program_areas.h" |
|
p->total_size=size + sizeof(struct program); |
|
p->flags |= PROGRAM_OPTIMIZED; |
make_program_executable(p); |
} |
|
|
static int program_identifier_index_compare(int a, int b, |
const struct program *p) |
{ |
size_t val_a = PTR_TO_INT (ID_FROM_INT(p, a)->name); |
size_t val_b = PTR_TO_INT (ID_FROM_INT(p, b)->name); |
return val_a < val_b ? -1 : (val_a == val_b ? 0 : 1); |
} |
|
#define CMP(X,Y) program_identifier_index_compare(*(X), *(Y), prog) |
#define EXTRA_ARGS , struct program *prog |
#define XARGS , prog |
#define ID fsort_program_identifier_index |
#define TYPE unsigned short |
#include "fsort_template.h" |
#undef TYPE |
#undef ID |
#undef XARGS |
#undef EXTRA_ARGS |
#undef CMP |
|
#ifdef PIKE_DEBUG |
struct pike_string *find_program_name(struct program *p, INT32 *line) |
{ |
INT32 l; |
if(!line) line=&l; |
|
#ifdef DEBUG_MALLOC |
{ |
char *tmp=dmalloc_find_name(p); |
if (tmp) { |
char *p = STRCHR (tmp, ':'); |
if (p) { |
char *pp; |
while ((pp = STRCHR (p + 1, ':'))) p = pp; |
*line = atoi (p + 1); |
return make_shared_binary_string (tmp, p - tmp); |
} |
else { |
*line=0; |
return make_shared_string(tmp); |
} |
} |
} |
#endif |
|
return get_program_line(p, line); |
} |
#endif |
|
int override_identifier (struct reference *new_ref, struct pike_string *name) |
{ |
int id = -1, cur_id = 0, is_used = 0; |
|
int new_is_variable = |
IDENTIFIER_IS_VARIABLE(ID_FROM_PTR(Pike_compiler->new_program, |
new_ref)->identifier_flags); |
|
|
|
|
|
|
|
for(;cur_id<Pike_compiler->new_program->num_identifier_references;cur_id++) |
{ |
struct reference *ref = |
Pike_compiler->new_program->identifier_references + cur_id; |
struct identifier *i; |
|
|
if (ref == new_ref) continue; |
|
|
if(ref->id_flags & ID_HIDDEN) continue; |
|
|
if((ref->id_flags & (ID_INLINE|ID_INHERITED)) == (ID_INLINE|ID_INHERITED)) |
continue; |
|
|
if((i = ID_FROM_PTR(Pike_compiler->new_program, ref))->name != name) |
continue; |
|
#ifdef PROGRAM_BUILD_DEBUG |
fprintf(stderr, "%.*soverloaded reference %d (id_flags:0x%04x)\n", |
compilation_depth, " ", cur_id, ref->id_flags); |
#endif |
|
if (!new_is_variable && IDENTIFIER_IS_VARIABLE(i->identifier_flags)) { |
|
|
|
ref->id_flags |= ID_INLINE|ID_HIDDEN; |
yywarning("Attempt to override a non local variable %S " |
"with a non-variable.", name); |
continue; |
} |
|
if ((ref->id_flags & (ID_INHERITED|ID_USED)) == (ID_INHERITED|ID_USED)) { |
struct inherit *inh = INHERIT_FROM_PTR(Pike_compiler->new_program, ref); |
struct reference *sub_ref; |
|
|
while (inh->inherit_level > 1) inh--; |
|
#ifdef PIKE_DEBUG |
if (!inh->inherit_level) { |
Pike_fatal("Inherit without intermediate levels.\n"); |
} |
#endif |
|
sub_ref = PTR_FROM_INT(inh->prog, cur_id - inh->identifier_level); |
|
|
if ((lex.pragmas & ID_STRICT_TYPES) && |
(sub_ref->id_flags & ID_USED)) { |
struct identifier *sub_id = ID_FROM_PTR(inh->prog, sub_ref); |
if (IDENTIFIER_IS_FUNCTION(sub_id->identifier_flags)) { |
if ((Pike_compiler->compiler_pass == 2) && |
!pike_types_le(ID_FROM_PTR(Pike_compiler->new_program, |
new_ref)->type, sub_id->type)) { |
yywarning("Type mismatch when overloading function %S.", name); |
yyexplain_nonmatching_types(sub_id->type, |
ID_FROM_PTR(Pike_compiler->new_program, |
new_ref)->type, |
YYTE_IS_WARNING); |
} |
} else { |
|
if (!pike_types_le(sub_id->type, |
ID_FROM_PTR(Pike_compiler->new_program, |
new_ref)->type)) { |
yywarning("Type mismatch when overloading %S.", name); |
yyexplain_nonmatching_types(sub_id->type, |
ID_FROM_PTR(Pike_compiler->new_program, |
new_ref)->type, |
YYTE_IS_WARNING); |
} |
} |
} |
} |
is_used = ref->id_flags & ID_USED; |
|
*ref=*new_ref; |
ref->id_flags |= is_used; |
id = cur_id; |
} |
|
return id; |
} |
|
void fixate_program(void) |
{ |
INT32 i,e,t; |
struct program *p=Pike_compiler->new_program; |
|
if(p->flags & PROGRAM_FIXED) return; |
#ifdef PIKE_DEBUG |
if(p->flags & PROGRAM_OPTIMIZED) |
Pike_fatal("Cannot fixate optimized program\n"); |
#endif |
|
|
|
|
for (i=0; i < p->num_identifiers; i++) { |
if (IDENTIFIER_IS_FUNCTION(p->identifiers[i].identifier_flags) && |
(p->identifiers[i].run_time_type == T_MIXED)) { |
|
|
|
|
p->identifiers[i].run_time_type = T_FUNCTION; |
} |
} |
|
|
for (i = 0; i < p->num_identifier_references; i++) { |
struct reference *ref = p->identifier_references + i; |
if (ref->id_flags & ID_HIDDEN) continue; |
if (ref->inherit_offset != 0) continue; |
override_identifier (ref, ID_FROM_PTR (p, ref)->name); |
|
if ((ref->id_flags & (ID_HIDDEN|ID_PRIVATE|ID_USED)) == ID_PRIVATE) { |
yywarning("%S is private but not used anywhere.", |
ID_FROM_PTR(p, ref)->name); |
} |
} |
|
|
for(e=i=0;i<(int)p->num_identifier_references;i++) |
{ |
struct reference *funp; |
struct identifier *fun; |
funp=p->identifier_references+i; |
if(funp->id_flags & ID_HIDDEN) continue; |
fun=ID_FROM_PTR(p, funp); |
if(funp->id_flags & ID_INHERITED) |
{ |
int found_better=-1; |
int funa_is_prototype; |
|
if(funp->id_flags & ID_PRIVATE) continue; |
funa_is_prototype = fun->func.offset == -1; |
|
|
|
for(t=i+1;t<(int)p->num_identifier_references;t++) |
{ |
struct reference *funpb; |
struct identifier *funb; |
|
funpb=p->identifier_references+t; |
if (funpb->id_flags & ID_HIDDEN) continue; |
funb=ID_FROM_PTR(p,funpb); |
|
|
if(fun->name==funb->name) |
{ |
found_better=t; |
|
|
|
|
|
|
if(funa_is_prototype && (funb->func.offset != -1) && |
!(funp->id_flags & ID_INLINE)) |
{ |
if ((lex.pragmas & ID_STRICT_TYPES) && |
(funp->id_flags & ID_USED)) { |
|
if (!pike_types_le(funb->type, fun->type)) { |
yywarning("Type mismatch when overloading %S.", fun->name); |
yyexplain_nonmatching_types(fun->type, funb->type, |
YYTE_IS_WARNING); |
} |
} |
funp->inherit_offset = funpb->inherit_offset; |
funp->identifier_offset = funpb->identifier_offset; |
} |
if(!funa_is_prototype && funb->func.offset == -1) |
{ |
if ((lex.pragmas & ID_STRICT_TYPES) && |
(funpb->id_flags & ID_USED)) { |
|
if (!pike_types_le(fun->type, funb->type)) { |
yywarning("Type mismatch when overloading %S.", fun->name); |
yyexplain_nonmatching_types(funb->type, fun->type, |
YYTE_IS_WARNING); |
} |
} |
funpb->inherit_offset = funp->inherit_offset; |
funpb->identifier_offset = funp->identifier_offset; |
} |
} |
} |
if(found_better!=-1) |
continue; |
} |
if ((fun->func.offset == -1) && (funp->id_flags & ID_INLINE) && |
IDENTIFIER_IS_PIKE_FUNCTION(fun->identifier_flags)) { |
my_yyerror("Missing definition for local function %S.", |
fun->name); |
} |
if (funp->id_flags & ID_STATIC) continue; |
add_to_identifier_index(i); |
} |
fsort_program_identifier_index(p->identifier_index, |
p->identifier_index + |
p->num_identifier_index - 1, |
p); |
|
|
p->flags |= PROGRAM_FIXED; |
|
|
for(i=1;i<NUM_LFUNS;i++) { |
int id = p->lfuns[i] = low_find_lfun(p, i); |
} |
|
|
|
|
|
if (!(p->flags & PROGRAM_LIVE_OBJ)) { |
int e, destroy = p->lfuns[LFUN_DESTROY]; |
if (destroy > -1) { |
struct identifier *id = ID_FROM_INT (p, destroy); |
if (!IDENTIFIER_IS_PIKE_FUNCTION (id->identifier_flags) || |
id->func.offset != -1) { |
|
p->flags |= PROGRAM_LIVE_OBJ; |
goto program_live_obj_set; |
} |
} |
|
for (e = p->num_inherits - 1; e >= 0; e--) |
if (p->inherits[e].prog->flags & PROGRAM_LIVE_OBJ) { |
p->flags |= PROGRAM_LIVE_OBJ; |
break; |
} |
|
program_live_obj_set:; |
} |
|
if(Pike_compiler->flags & COMPILATION_CHECK_FINAL) |
{ |
for(i=0;i<(int)p->num_identifier_references;i++) |
{ |
if((p->identifier_references[i].id_flags & (ID_NOMASK|ID_HIDDEN)) == |
ID_NOMASK) |
{ |
struct pike_string *name=ID_FROM_INT(p, i)->name; |
|
e=find_shared_string_identifier(name,p); |
if(e == -1) |
e=really_low_find_shared_string_identifier(name, p, |
SEE_STATIC|SEE_PRIVATE); |
|
if((e != i) && (e != -1)) |
{ |
my_yyerror("Illegal to redefine final identifier %S", name); |
} |
} |
} |
} |
|
#ifdef DEBUG_MALLOC |
{ |
#define DBSTR(X) ((X)?(X)->str:"") |
int e,v; |
INT32 line; |
struct pike_string *tmp; |
struct memory_map *m=0;; |
if(lex.current_file && |
lex.current_file->str && |
lex.current_file->len && |
!strcmp(lex.current_file->str,"-")) |
{ |
m=dmalloc_alloc_mmap( DBSTR(lex.current_file), lex.current_line); |
} |
else if( (tmp=find_program_name(Pike_compiler->new_program, &line)) ) |
{ |
m=dmalloc_alloc_mmap( tmp->str, line); |
free_string(tmp); |
}else{ |
m=dmalloc_alloc_mmap( "program id", Pike_compiler->new_program->id); |
} |
|
for(e=0;e<Pike_compiler->new_program->num_inherits;e++) |
{ |
struct inherit *i=Pike_compiler->new_program->inherits+e; |
char *tmp; |
struct pike_string *tmp2 = NULL; |
char buffer[50]; |
|
for(v=0;v<i->prog->num_variable_index;v++) |
{ |
int d=i->prog->variable_index[v]; |
struct identifier *id=i->prog->identifiers+d; |
|
dmalloc_add_mmap_entry(m, |
id->name->str, |
i->storage_offset + id->func.offset, |
sizeof_variable(id->run_time_type), |
1, |
0,0); |
} |
|
if(i->name) |
{ |
tmp=i->name->str; |
} |
else if(!(tmp2 = find_program_name(i->prog, &line))) |
{ |
sprintf(buffer,"inherit[%d]",e); |
tmp=buffer; |
} else { |
tmp = tmp2->str; |
} |
dmalloc_add_mmap_entry(m, |
tmp, |
i->storage_offset, |
i->prog->storage_needed - i->prog->inherits[0].storage_offset, |
1, |
0,0); |
if (tmp2) { |
free_string(tmp2); |
} |
} |
dmalloc_set_mmap_template(Pike_compiler->new_program, m); |
} |
#endif |
} |
|
struct program *low_allocate_program(void) |
{ |
struct program *p=alloc_program(); |
MEMSET(p, 0, sizeof(struct program)); |
p->flags|=PROGRAM_VIRGIN; |
p->alignment_needed=1; |
|
GC_ALLOC(p); |
p->id=++current_program_id; |
INIT_PIKE_MEMOBJ(p); |
|
DOUBLELINK(first_program, p); |
GETTIMEOFDAY(& p->timestamp); |
return p; |
} |
|
|
|
|
void low_start_new_program(struct program *p, |
int pass, |
struct pike_string *name, |
int flags, |
int *idp) |
{ |
int id=0; |
struct svalue tmp; |
|
#ifdef WITH_FACETS |
if(Pike_compiler->compiler_pass == 1 && p) { |
p->facet_class = 0; |
p->facet_index = -1; |
p->facet_group = NULL; |
} |
#endif |
|
#if 0 |
#ifdef SHARED_NODES |
if (!node_hash.table) { |
node_hash.table = malloc(sizeof(node *)*32831); |
if (!node_hash.table) { |
Pike_fatal("Out of memory!\n"); |
} |
MEMSET(node_hash.table, 0, sizeof(node *)*32831); |
node_hash.size = 32831; |
} |
#endif /* SHARED_NODES */ |
#endif /* 0 */ |
|
|
|
|
low_init_threads_disable(); |
|
compilation_depth++; |
|
if (!Pike_compiler->compiler_frame) { |
new_node_s_context(); |
} |
|
tmp.type=T_PROGRAM; |
if(!p) |
{ |
p=low_allocate_program(); |
if(name) |
{ |
tmp.u.program=p; |
id=add_constant(name, &tmp, flags & ~ID_EXTERN); |
#if 0 |
fprintf(stderr,"Compiling class %s, depth=%d\n",name->str,compilation_depth); |
}else{ |
fprintf(stderr,"Compiling file %s, depth=%d\n", |
lex.current_file ? lex.current_file->str : "-", |
compilation_depth); |
#endif |
} |
}else{ |
tmp.u.program=p; |
add_ref(p); |
if((pass == 2) && name) |
{ |
struct identifier *i; |
id=isidentifier(name); |
if (id < 0) |
Pike_fatal("Program constant disappeared in second pass.\n"); |
i=ID_FROM_INT(Pike_compiler->new_program, id); |
free_type(i->type); |
i->type=get_type_of_svalue(&tmp); |
} |
} |
if (pass == 1) { |
if(compilation_depth >= 1) |
add_ref(p->parent = Pike_compiler->new_program); |
} |
p->flags &=~ PROGRAM_VIRGIN; |
Pike_compiler->parent_identifier=id; |
if(idp) *idp=id; |
|
CDFPRINTF((stderr, "th(%ld) %p low_start_new_program() %s " |
"pass=%d: threads_disabled:%d, compilation_depth:%d\n", |
(long)th_self(), p, name ? name->str : "-", |
Pike_compiler->compiler_pass, |
threads_disabled, compilation_depth)); |
|
init_type_stack(); |
|
#define PUSH |
#include "compilation.h" |
|
Pike_compiler->compiler_pass = pass; |
|
Pike_compiler->num_used_modules=0; |
|
if(p->flags & PROGRAM_FINISHED) |
{ |
yyerror("Pass2: Program already done"); |
} |
|
Pike_compiler->malloc_size_program = ALLOC_STRUCT(program); |
Pike_compiler->fake_object=alloc_object(); |
|
#ifdef PIKE_DEBUG |
Pike_compiler->fake_object->storage=(char *)malloc(256 * sizeof(struct svalue)); |
if (Pike_compiler->fake_object->storage) { |
|
MEMSET(Pike_compiler->fake_object->storage,0x55,256*sizeof(struct svalue)); |
} |
#else |
Pike_compiler->fake_object->storage=(char *)malloc(sizeof(struct parent_info)); |
#endif |
if (!Pike_compiler->fake_object->storage) { |
yyerror("Out of memory when allocating object storage."); |
} |
|
|
if (Pike_in_gc) remove_marker(Pike_compiler->fake_object); |
|
Pike_compiler->fake_object->next=Pike_compiler->fake_object; |
Pike_compiler->fake_object->prev=Pike_compiler->fake_object; |
Pike_compiler->fake_object->refs=0; |
add_ref(Pike_compiler->fake_object); |
Pike_compiler->fake_object->prog=p; |
add_ref(p); |
|
#ifdef PIKE_DEBUG |
Pike_compiler->fake_object->program_id=p->id; |
#endif |
|
#ifdef PIKE_SECURITY |
Pike_compiler->fake_object->prot=0; |
#endif |
|
debug_malloc_touch(Pike_compiler->fake_object); |
debug_malloc_touch(Pike_compiler->fake_object->storage); |
|
if (Pike_compiler->fake_object->storage) { |
if(name) |
{ |
|
if((((struct parent_info *)Pike_compiler->fake_object->storage)->parent=Pike_compiler->previous->fake_object)) |
add_ref(Pike_compiler->previous->fake_object); |
((struct parent_info *)Pike_compiler->fake_object->storage)->parent_identifier=id; |
}else{ |
((struct parent_info *)Pike_compiler->fake_object->storage)->parent=0; |
((struct parent_info *)Pike_compiler->fake_object->storage)->parent_identifier=0; |
} |
} |
|
Pike_compiler->new_program=p; |
|
#ifdef PROGRAM_BUILD_DEBUG |
if (name) { |
fprintf (stderr, "%.*sstarting program %d (pass=%d): ", |
compilation_depth, " ", Pike_compiler->new_program->id, Pike_compiler->compiler_pass); |
push_string (name); |
print_svalue (stderr, --Pike_sp); |
putc ('\n', stderr); |
} |
else |
fprintf (stderr, "%.*sstarting program %d (pass=%d)\n", |
compilation_depth, " ", Pike_compiler->new_program->id, Pike_compiler->compiler_pass); |
#endif |
|
if (compilation_depth >= 1) { |
if(TEST_COMPAT(7,2) || (lex.pragmas & ID_SAVE_PARENT)) |
{ |
p->flags |= PROGRAM_USES_PARENT; |
}else if (!(lex.pragmas & ID_DONT_SAVE_PARENT)) { |
struct pike_string *tmp=findstring("__pragma_save_parent__"); |
if(tmp) |
{ |
struct node_s *n=find_module_identifier(tmp, 0); |
if(n) |
{ |
int do_save_parent = !node_is_false(n); |
free_node(n); |
if (do_save_parent) p->flags |= PROGRAM_USES_PARENT; |
} |
} |
} |
} |
|
debug_malloc_touch(Pike_compiler->fake_object); |
debug_malloc_touch(Pike_compiler->fake_object->storage); |
|
if(Pike_compiler->new_program->program) |
{ |
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
Pike_compiler->malloc_size_program->PIKE_CONCAT(num_,NAME) = \ |
Pike_compiler->new_program->PIKE_CONCAT(num_,NAME); |
#include "program_areas.h" |
|
|
{ |
INT32 line=0, off=0; |
size_t len = 0; |
INT32 shift = 0; |
char *file=0; |
char *cnt=Pike_compiler->new_program->linenumbers; |
|
while(cnt < Pike_compiler->new_program->linenumbers + |
Pike_compiler->new_program->num_linenumbers) |
{ |
if(*cnt == 127) |
{ |
cnt++; |
len = get_small_number(&cnt); |
shift = *cnt; |
file = ++cnt; |
CHECK_FILE_ENTRY (Pike_compiler->new_program, cnt, len, shift); |
cnt += len<<shift; |
} |
off+=get_small_number(&cnt); |
line+=get_small_number(&cnt); |
} |
Pike_compiler->last_line=line; |
Pike_compiler->last_pc=off; |
if(file) |
{ |
struct pike_string *str = begin_wide_shared_string(len, shift); |
if(Pike_compiler->last_file) free_string(Pike_compiler->last_file); |
memcpy(str->str, file, len<<shift); |
Pike_compiler->last_file = end_shared_string(str); |
} |
} |
|
}else{ |
static struct pike_string *s; |
struct inherit i; |
|
#define START_SIZE 64 |
#ifdef PIKE_USE_MACHINE_CODE |
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
if (Pike_compiler->new_program->NAME) { \ |
mexec_free(Pike_compiler->new_program->NAME); \ |
Pike_compiler->new_program->PIKE_CONCAT(num_,NAME) = 0; \ |
} \ |
Pike_compiler->malloc_size_program->PIKE_CONCAT(num_,NAME) = \ |
START_SIZE; \ |
Pike_compiler->new_program->NAME = \ |
(TYPE *)mexec_alloc(sizeof(TYPE) * START_SIZE); |
#endif /* PIKE_USE_MACHINE_CODE */ |
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
if (Pike_compiler->new_program->NAME) { \ |
free (Pike_compiler->new_program->NAME); \ |
Pike_compiler->new_program->PIKE_CONCAT(num_,NAME) = 0; \ |
} \ |
Pike_compiler->malloc_size_program->PIKE_CONCAT(num_,NAME) = \ |
START_SIZE; \ |
Pike_compiler->new_program->NAME = \ |
(TYPE *)xalloc(sizeof(TYPE) * START_SIZE); |
#include "program_areas.h" |
|
i.prog=Pike_compiler->new_program; |
i.identifier_level=0; |
i.storage_offset=0; |
i.inherit_level=0; |
i.identifier_ref_offset=0; |
i.parent=0; |
i.parent_identifier=-1; |
i.parent_offset=OBJECT_PARENT; |
i.name=0; |
add_to_inherits(i); |
} |
|
Pike_compiler->init_node=0; |
Pike_compiler->num_parse_error=0; |
|
push_compiler_frame(0); |
copy_pike_type(Pike_compiler->compiler_frame->current_return_type, |
void_type_string); |
|
debug_malloc_touch(Pike_compiler->fake_object); |
debug_malloc_touch(Pike_compiler->fake_object->storage); |
} |
|
PMOD_EXPORT void debug_start_new_program(int line, const char *file) |
{ |
struct pike_string *save_file = |
dmalloc_touch(struct pike_string *, lex.current_file); |
int save_line = lex.current_line; |
|
{ |
const char *p = DEFINETOSTR(PIKE_SRC_ROOT), *f = file; |
while (*p && *p == *f) p++, f++; |
while (*f == '/' || *f == '\\') f++; |
|
lex.current_file = make_shared_string(f); |
lex.current_line = line; |
} |
|
CDFPRINTF((stderr, |
"th(%ld) start_new_program(%d, %s): " |
"threads_disabled:%d, compilation_depth:%d\n", |
(long)th_self(), line, file, threads_disabled, compilation_depth)); |
|
low_start_new_program(0,1,0,0,0); |
store_linenumber(line,lex.current_file); |
debug_malloc_name(Pike_compiler->new_program, file, line); |
|
free_string(lex.current_file); |
lex.current_file = dmalloc_touch(struct pike_string *, save_file); |
lex.current_line = save_line; |
} |
|
|
static void exit_program_struct(struct program *p) |
{ |
unsigned e; |
|
#ifdef PIKE_DEBUG |
if (p->refs) { |
#ifdef DEBUG_MALLOC |
fprintf (stderr, "Program to be freed still got %d references:\n", p->refs); |
describe_something(p, T_PROGRAM, 0,2,0, NULL); |
#endif |
Pike_fatal("Program to be freed still got %d references.\n", p->refs); |
} |
#endif |
|
if(p->parent) |
{ |
|
struct program *parent = p->parent; |
p->parent = NULL; |
free_program(parent); |
} |
|
|
|
if(id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]==p) |
id_to_program_cache[p->id & (ID_TO_PROGRAM_CACHE_SIZE-1)]=0; |
|
if(p->strings) |
for(e=0; e<p->num_strings; e++) |
if(p->strings[e]) |
free_string(p->strings[e]); |
|
if(p->identifiers) |
{ |
for(e=0; e<p->num_identifiers; e++) |
{ |
if(p->identifiers[e].name) |
free_string(p->identifiers[e].name); |
if(p->identifiers[e].type) |
free_type(p->identifiers[e].type); |
} |
} |
|
if(p->constants) |
{ |
for(e=0;e<p->num_constants;e++) |
{ |
free_svalue(& p->constants[e].sval); |
#if 0 |
if(p->constants[e].name) free_string(p->constants[e].name); |
#endif /* 0 */ |
} |
} |
|
if(p->inherits) |
for(e=0; e<p->num_inherits; e++) |
{ |
if(p->inherits[e].name) |
free_string(p->inherits[e].name); |
if(e) |
{ |
if(p->inherits[e].prog) |
free_program(p->inherits[e].prog); |
} |
if(p->inherits[e].parent) |
free_object(p->inherits[e].parent); |
} |
|
DOUBLEUNLINK(first_program, p); |
|
#ifdef WITH_FACETS |
if(p->facet_group) |
{ |
free_object(p->facet_group); |
} |
#endif |
|
if(p->flags & PROGRAM_OPTIMIZED) |
{ |
#ifdef PIKE_USE_MACHINE_CODE |
do { |
|
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
if (p->NAME) mexec_free(p->NAME); |
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
if (p->NAME) { \ |
dmfree(p->NAME); \ |
break; \ |
} |
#include "program_areas.h" |
} while(0); |
#else /* PIKE_USE_MACHINE_CODE */ |
if(p->program) { |
dmfree(p->program); |
} |
#endif /* PIKE_USE_MACHINE_CODE */ |
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) p->NAME=0; |
#include "program_areas.h" |
}else{ |
#ifdef PIKE_USE_MACHINE_CODE |
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
if(p->NAME) { mexec_free((char *)p->NAME); p->NAME=0; } |
#endif /* PIKE_USE_MACHINE_CODE */ |
#define FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \ |
if(p->NAME) { dmfree((char *)p->NAME); p->NAME=0; } |
#include "program_areas.h" |
} |
|
EXIT_PIKE_MEMOBJ(p); |
|
GC_FREE(p); |
} |
|
#ifdef PIKE_DEBUG |
void dump_program_desc(struct program *p) |
{ |
int e,d,q; |
|
|
fprintf(stderr,"$$$$$ dump_program_desc for %p\n", p); |
|
fprintf(stderr,"All inherits:\n"); |
for(e=0;e<p->num_inherits;e++) |
{ |
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"%3d:\n",e); |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"inherited program: %d\n",p->inherits[e].prog->id); |
|
if(p->inherits[e].name) |
{ |
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"name : %s\n",p->inherits[e].name->str); |
} |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"inherit_level: %d\n",p->inherits[e].inherit_level); |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"identifier_level: %d\n",p->inherits[e].identifier_level); |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"parent_identifier: %d\n",p->inherits[e].parent_identifier); |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"parent_offset: %d\n",p->inherits[e].parent_offset); |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"storage_offset: %ld\n", |
DO_NOT_WARN((long)p->inherits[e].storage_offset)); |
|
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"parent: %p\n",p->inherits[e].parent); |
|
if(p->inherits[e].parent && |
p->inherits[e].parent->prog && |
p->inherits[e].parent->prog->num_linenumbers>1) |
{ |
for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"parent: %s\n",p->inherits[e].parent->prog->linenumbers+1); |
} |
} |
|
fprintf(stderr,"All identifier references:\n"); |
for(e=0;e<(int)p->num_identifier_references;e++) |
{ |
struct inherit *inh = INHERIT_FROM_INT(p,e); |
fprintf(stderr,"%3d: ",e); |
for(d=0;d<inh->inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"%-40s flags 0x%x",ID_FROM_INT(p,e)->name->str, |
p->identifier_references[e].id_flags); |
for (q = 0; q < p->num_inherits; q++) |
if (p->inherits + q == inh) { |
fprintf(stderr, |
" inherit %d\n" |
" type: ", |
q); |
simple_describe_type(ID_FROM_INT(p, e)->type); |
fprintf(stderr, "\n"); |
goto inherit_found; |
} |
fprintf (stderr, " inherit not found!\n"); |
inherit_found:; |
} |
fprintf(stderr,"All sorted identifiers:\n"); |
for(q=0;q<(int)p->num_identifier_index;q++) |
{ |
e=p->identifier_index[q]; |
fprintf(stderr,"%3d (%3d):",e,q); |
for(d=0;d<INHERIT_FROM_INT(p,e)->inherit_level;d++) fprintf(stderr," "); |
fprintf(stderr,"%s;\n", ID_FROM_INT(p,e)->name->str); |
} |
|
fprintf(stderr,"$$$$$ dump_program_desc for %p done\n", p); |
} |
#endif |
|
static void toss_compilation_resources(void) |
{ |
if(Pike_compiler->fake_object) |
{ |
if( ((struct parent_info *)Pike_compiler->fake_object->storage)->parent ) |
{ |
free_object(((struct parent_info *)Pike_compiler->fake_object->storage)->parent); |
|
((struct parent_info *)Pike_compiler->fake_object->storage)->parent=0; |
} |
|
free_program(Pike_compiler->fake_object->prog); |
Pike_compiler->fake_object->prog=0; |
free_object(Pike_compiler->fake_object); |
Pike_compiler->fake_object=0; |
} |
|
free_program(Pike_compiler->new_program); |
Pike_compiler->new_program=0; |
|
if(Pike_compiler->malloc_size_program) |
{ |
dmfree((char *)Pike_compiler->malloc_size_program); |
Pike_compiler->malloc_size_program=0; |
} |
|
if(Pike_compiler->module_index_cache) |
{ |
free_mapping(Pike_compiler->module_index_cache); |
Pike_compiler->module_index_cache=0; |
} |
|
while(Pike_compiler->compiler_frame) |
pop_compiler_frame(); |
|
if(Pike_compiler->last_identifier) |
{ |
free_string(Pike_compiler->last_identifier); |
Pike_compiler->last_identifier=0; |
} |
|
if(Pike_compiler->last_file) |
{ |
free_string(Pike_compiler->last_file); |
Pike_compiler->last_file=0; |
} |
|
unuse_modules(Pike_compiler->num_used_modules); |
} |
|
int sizeof_variable(int run_time_type) |
{ |
switch(run_time_type) |
{ |
case T_FUNCTION: |
case T_MIXED: return sizeof(struct svalue); |
case T_FLOAT: return sizeof(FLOAT_TYPE); |
case T_INT: return sizeof(INT_TYPE); |
default: return sizeof(void *); |
} |
} |
|
static ptrdiff_t alignof_variable(int run_time_type) |
{ |
switch(run_time_type) |
{ |
case T_FUNCTION: |
case T_MIXED: return ALIGNOF(struct svalue); |
case T_FLOAT: return ALIGNOF(FLOAT_TYPE); |
case T_INT: return ALIGNOF(INT_TYPE); |
default: return ALIGNOF(void *); |
} |
} |
|
#ifdef PIKE_DEBUG |
|
void dump_program_tables (struct program *p, int indent) |
{ |
int d; |
|
if (!p) { |
fprintf(stderr, "%*sProgram: NULL\n\n", indent, ""); |
return; |
} |
|
fprintf(stderr, |
"%*sProgram flags: 0x%04x\n\n", |
indent, "", p->flags); |
|
fprintf(stderr, |
"%*sReference table:\n" |
"%*s ####: Flags Inherit Identifier\n", |
indent, "", indent, ""); |
for (d=0; d < p->num_identifier_references; d++) { |
struct reference *ref = p->identifier_references + d; |
|
fprintf(stderr, "%*s %4d: %5x %7d %10d %s\n", |
indent, "", |
d, ref->id_flags, ref->inherit_offset, |
ref->identifier_offset, |
ID_FROM_PTR(p,ref)->name->size_shift ? "(wide)" : |
ID_FROM_PTR(p,ref)->name->str); |
if (IDENTIFIER_IS_PIKE_FUNCTION(ID_FROM_PTR(p,ref)->identifier_flags)) { |
INT32 line; |
struct program *inh_p = INHERIT_FROM_PTR(p,ref)->prog; |
struct pike_string *file = |
get_line (ID_FROM_PTR(p,ref)->func.offset + inh_p->program, inh_p, &line); |
if (!file->size_shift) |
fprintf (stderr, "%*s %s:%d\n", |
indent, "", file->str, line); |
free_string (file); |
} |
} |
|
fprintf(stderr, "\n" |
"%*sIdentifier index table:\n" |
"%*s ####: Index\n", |
indent, "", indent, ""); |
for (d = 0; d < p->num_identifier_index; d++) { |
fprintf(stderr, "%*s %4d: %5d\n", |
indent, "", |
d, p->identifier_index[d]); |
} |
|
fprintf(stderr, "\n" |
"%*sInherit table:\n" |
"%*s ####: Level prog_id id_level storage_offs " |
"par_id par_offs par_obj_id id_ref_offs\n", |
indent, "", indent, ""); |
for (d=0; d < p->num_inherits; d++) { |
struct inherit *inh = p->inherits + d; |
|
fprintf(stderr, "%*s %4d: %5d %7d %8d %12"PRINTPTRDIFFT"d %6d %8d %10d %11"PRINTSIZET"d\n", |
indent, "", |
d, inh->inherit_level, |
inh->prog ? inh->prog->id : -1, |
inh->identifier_level, inh->storage_offset, |
inh->parent_identifier, inh->parent_offset, |
inh->parent ? inh->parent->program_id : -1, |
inh->identifier_ref_offset); |
} |
fprintf(stderr, "\n" |
"%*sIdentifier table:\n" |
"%*s ####: Flags Offset Type Name\n", |
indent, "", indent, ""); |
for (d=0; d < p->num_identifiers; d++) { |
struct identifier *id = p->identifiers + d; |
|
fprintf(stderr, "%*s %4d: %5x %6"PRINTPTRDIFFT"d %4d \"%s\"\n", |
indent, "", |
d, id->identifier_flags, id->func.offset, |
id->run_time_type, id->name->str); |
} |
|
fprintf(stderr, "\n" |
"%*sVariable table:\n" |
"%*s ####: Index\n", |
indent, "", indent, ""); |
for (d = 0; d < p->num_variable_index; d++) { |
fprintf(stderr, "%*s %4d: %5d\n", |
indent, "", |
d, p->variable_index[d]); |
} |
fprintf(stderr, "\n" |
"%*sConstant table:\n" |
"%*s ####: Type Name\n", |
indent, "", indent, ""); |
for (d = 0; d < p->num_constants; d++) { |
struct program_constant *c = p->constants + d; |
#if 0 |
fprintf(stderr, "%*s %4d: %-15s %s%s%s\n", |
indent, "", |
d, get_name_of_type (c->sval.type), |
c->name?"\"":"",c->name?c->name->str:"NULL",c->name?"\"":""); |
#else /* !0 */ |
fprintf(stderr, "%*s %4d: %-15s %"PRINTPTRDIFFT"d\n", |
indent, "", |
d, get_name_of_type (c->sval.type), |
c->offset); |
#endif /* 0 */ |
} |
|
fprintf(stderr, "\n" |
"%*sLinenumber table:\n", |
indent, ""); |
{ |
INT32 off = 0, line = 0; |
char *cnt = p->linenumbers; |
|
while (cnt < p->linenumbers + p->num_linenumbers) { |
if (*cnt == 127) { |
int len, shift; |
char *file; |
cnt++; |
len = get_small_number(&cnt); |
shift = *cnt; |
file = ++cnt; |
CHECK_FILE_ENTRY (p, cnt, len, shift); |
cnt += len << shift; |
if (!shift) { |
fprintf(stderr, "%*s Filename: \"%s\"\n", indent, "", file); |
} else { |
fprintf(stderr, "%*s Filename: len:%d, shift:%d\n", indent, "", len, shift); |
} |
} |
off += get_small_number(&cnt); |
line += get_small_number(&cnt); |
fprintf(stderr, "%*s %8d:%8d\n", indent, "", off, line); |
} |
} |
|
fprintf(stderr, "\n"); |
} |
|
void check_program(struct program *p) |
{ |
INT32 size; |
unsigned INT32 checksum, e; |
int variable_positions[1024]; |
|
if(p->flags & PROGRAM_AVOID_CHECK) return; |
|
for(e=0;e<NELEM(variable_positions);e++) |
variable_positions[e]=-1; |
|
if(p->id > current_program_id) |
Pike_fatal("Program id is out of sync! (p->id=%d, current_program_id=%d)\n",p->id,current_program_id); |
|
if(p->refs <=0) |
Pike_fatal("Program has zero refs.\n"); |
|
if(p->next && p->next->prev != p) |
Pike_fatal("Program ->next->prev != program.\n"); |
|
if(p->prev) |
{ |
if(p->prev->next != p) |
Pike_fatal("Program ->prev->next != program.\n"); |
}else{ |
if(first_program != p) |
Pike_fatal("Program ->prev == 0 but first_program != program.\n"); |
} |
|
if(p->id > current_program_id || p->id <= 0) |
Pike_fatal("Program id is wrong.\n"); |
|
if(p->storage_needed < 0) |
Pike_fatal("Program->storage_needed < 0.\n"); |
|
if(p->num_identifier_index > p->num_identifier_references) |
Pike_fatal("Too many identifier index entries in program!\n"); |
|
for(e=0;e<p->num_constants;e++) |
{ |
struct svalue *s = & p->constants[e].sval; |
check_svalue(s); |
if (p->flags & PROGRAM_FINISHED && s->type == T_OBJECT && |
s->u.object->next == s->u.object) |
Pike_fatal ("Got fake object in constant in finished program.\n"); |
#if 0 |
if(p->constants[e].name) check_string(p->constants[e].name); |
|