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.
*/
#include "global.h"
#include "program.h"
#include "object.h"
- #include "dynamic_buffer.h"
+ #include "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_allocator.h"
#include "block_alloc.h"
#include "pikecode.h"
#include "pike_compiler.h"
#include "module_support.h"
-
+ #include "bitvector.h"
+ #include "sprintf.h"
#include <errno.h>
#include <fcntl.h>
- #define sp Pike_sp
-
- #undef ATTRIBUTE
- #define ATTRIBUTE(X)
-
- static void low_enter_compiler(struct object *ce, int inherit);
+
static void exit_program_struct(struct program *);
static size_t add_xstorage(size_t size,
size_t alignment,
ptrdiff_t modulo_orig);
-
+ /* mapping(int:string) */
+ static struct mapping *reverse_symbol_table = NULL;
+
static struct block_allocator program_allocator = BA_INIT_PAGES(sizeof(struct program), 4);
ATTRIBUTE((malloc))
- struct program * alloc_program() {
+ struct program * alloc_program(void) {
return ba_alloc(&program_allocator);
}
void really_free_program(struct program * p) {
exit_program_struct(p);
ba_free(&program_allocator, p);
}
void count_memory_in_programs(size_t *num, size_t *_size) {
size_t size;
struct program *p;
ba_count_all(&program_allocator, num, &size);
for(p=first_program;p;p=p->next) {
size+=p->total_size - sizeof (struct program);
}
*_size = size;
}
- void free_all_program_blocks() {
+ void free_all_program_blocks(void) {
ba_destroy(&program_allocator);
}
/* #define COMPILER_DEBUG */
/* #define PROGRAM_BUILD_DEBUG */
#ifdef COMPILER_DEBUG
- #define CDFPRINTF(X) fprintf X
+ #define CDFPRINTF(...) fprintf(stderr, __VA_ARGS__)
#ifndef PIKE_THREADS
- /* The CDFPRINTF lines wants to print threads_disabled, so fake on of those */
- static const int threads_disabled = 1;
+ /* The CDFPRINTF lines wants to print lock_depth, so fake one of those */
+ static const int lock_depth = 1;
#endif
#else /* !COMPILER_DEBUG */
- #define CDFPRINTF(X)
+ #define CDFPRINTF(...)
#endif /* COMPILER_DEBUG */
/*
* These two values should probably be fine-tuned, but doing so
* more or less requires running a predictable 'typical' application
* and testing different hashsizes and tresholds. I tried to do it
* mathematically by measuring the extremes (no cache hits, 100%
* cache hits etc.) but it seems that the processor cache becomes
* exhausted in some of my measurements, which renders my mathematical
* model useless.
*
* Further measurements seems to indicate that this cache can slow
* things down a bit if the hit/miss rate is not fairly high.
* For normal applications, the hitrate is most likely well over 90%,
* but that should be verified.
- * - Holistiska Centralbyrån (Hubbe)
+ * - Hubbe
*/
/* Define the size of the cache that is used for method lookup. */
/* A value of zero disables this cache */
#define FIND_FUNCTION_HASHSIZE 16384
/* Programs with less methods will not use the cache for method lookups.. */
#define FIND_FUNCTION_HASH_TRESHOLD 0
#define DECLARE
#include "compilation.h"
- struct pike_string *this_program_string;
- static struct pike_string *this_string, *this_function_string;
+ struct pike_string *this_program_string, *this_string, *args_string;
+ static struct pike_string *this_function_string;
static struct pike_string *UNDEFINED_string;
/* Common compiler subsystems */
struct pike_string *parser_system_string;
struct pike_string *type_check_system_string;
-
+ struct pike_string *compat_lfun_destroy_string;
+
+ /* NOTE: There is a corresponding list to this one in
+ Tools.AutoDoc.PikeObjects
+
+ If new lfuns are added it might be beneficial to also add them to
+ that list.
+ */
const char *const lfun_names[] = {
"__INIT",
"create",
- "destroy",
+ "_destruct",
"`+",
"`-",
"`&",
"`|",
"`^",
"`<<",
"`>>",
"`*",
"`/",
"`%",
pike.git/src/program.c:172:
"_m_delete",
"_get_iterator",
"`[..]",
/* NOTE: After this point there are only fake lfuns. */
"_search",
"_types",
"_serialize",
"_deserialize",
"_size_object",
"_random",
+ "`**",
+ "``**",
+ "_sqrt",
};
struct pike_string *lfun_strings[NELEM(lfun_names)];
static struct mapping *lfun_ids;
/* mapping(string:type) */
static struct mapping *lfun_types;
static const char *const raw_lfun_types[] = {
tFuncV(tNone,tVoid,tVoid), /* "__INIT", */
tFuncV(tNone,tZero,tVoid), /* "create", */
- tFuncV(tOr(tVoid,tInt),tVoid,tVoid), /* "destroy", */
+ tFuncV(tOr(tVoid,tInt),tVoid,tVoid), /* "_destruct", */
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), /* "`%", */
pike.git/src/program.c:228:
tFuncV(tNone,tZero,tMix), /* "``/", */
tFuncV(tNone,tZero,tMix), /* "``%", */
tFuncV(tZero,tZero,tMix), /* "`+=", */
tFuncV(tStr,tVoid,tInt), /* "_is_type", */
tFuncV(tInt tOr(tMap(tStr,tInt),tVoid),tVoid,tStr), /* "_sprintf", */
tFuncV(tMix,tVoid,tInt), /* "_equal", */
tFuncV(tZero,tVoid,tMix), /* "_m_delete", */
tFuncV(tNone,tVoid,tObj), /* "_get_iterator", */
tFuncV(tZero tRangeBound tZero tRangeBound, tVoid, tMix), /* "`[..]" */
/* NOTE: After this point there are only fake lfuns. */
- tFuncV(tZero tOr(tZero, tVoid), tVoid, tMix), /* "_search", */
+ tFuncV(tZero tOr(tZero, tVoid), tZero, tMix), /* "_search", */
tFuncV(tNone,tVoid,tArray), /* "_types", */
tFuncV(tObj tZero, tVoid, tVoid), /* "_serialize", */
tFuncV(tObj tZero, tVoid, tVoid), /* "_deserialize", */
- tFuncV(tZero, tVoid, tInt), /* "_size_object", */
- tFuncV(tNone, tVoid, tMix), /* "_random", */
+ tFuncV(tNone, tVoid, tInt), /* "_size_object", */
+ tFuncV(tFunction tFunction, tVoid, tMix), /* "_random", */
+ tFuncV(tOr3(tInt,tFloat,tObj),tVoid,tOr3(tObj,tInt,tFloat)), /* "pow", */
+ tFuncV(tOr3(tInt,tFloat,tObj),tVoid,tOr3(tObj,tInt,tFloat)), /* "rpow", */
+ tFunc(tVoid,tMix),/* "_sqrt* */
};
/* These two are not true LFUNs! */
static struct pike_type *lfun_getter_type_string = NULL;
static struct pike_type *lfun_setter_type_string = NULL;
/*! @namespace lfun::
*!
*! Callback functions used to overload various builtin functions.
*!
*! The functions can be grouped into a few sets:
*!
*! @ul
*! @item
*! Object initialization and destruction.
*!
- *! @[__INIT()], @[create()], @[destroy()]
+ *! @[__INIT()], @[create()], @[_destruct()]
*!
*! @item
*! Unary operator overloading.
*!
*! @[`~()], @[`!()],
*! @[_values()], @[cast()],
*! @[_sizeof()], @[_indices()],
*! @[__hash()]
*!
*! @item
pike.git/src/program.c:335:
/*! @decl void lfun::create(zero ... args)
*!
*! Object creation callback.
*!
*! This function is called right after @[lfun::__INIT()].
*!
*! @[args] are the arguments passed when the program was called.
*!
*! @note
- *! In Pike 7.2 and later this function can be created implicitly
- *! by the compiler using the new syntax:
+ *! This function can be created implicitly
+ *! by the compiler using the syntax:
*! @code
*! class Foo(int foo) {
*! int bar;
*! }
*! @endcode
*! In the above case an implicit @[lfun::create()] is created, and
- *! it's equvivalent to:
+ *! it's equivalent to:
*! @code
*! class Foo {
*! int foo;
*! int bar;
*! protected void create(int foo)
*! {
- *! local::foo = foo;
+ *! this::foo = foo;
*! }
*! }
*! @endcode
*!
*! @seealso
- *! @[lfun::__INIT()], @[lfun::destroy()]
+ *! @[lfun::__INIT()], @[lfun::_destruct()]
*/
- /*! @decl void lfun::destroy (void|int reason)
+ /*! @decl void lfun::_destruct (void|int reason)
*!
*! Object destruction callback.
*!
*! This function is called right before the object is destructed.
*! That can happen either through a call to @[predef::destruct()],
*! when there are no more references to the object, or when the
*! garbage collector discovers that it's part of a cyclic data
*! structure that has become garbage.
*!
*! @param reason
pike.git/src/program.c:388:
*! Destructed by the garbage collector.
*! @value Object.DESTRUCT_CLEANUP
*! Destructed as part of the cleanup when the pike process
*! exits. Occurs only if Pike has been compiled with the
*! configure option @tt{--with-cleanup-on-exit@}. See note
*! below.
*! @endint
*!
*! @note
*! Objects are normally not destructed when a process exits, so
- *! @expr{destroy@} functions aren't called then. Use @[atexit] to get
+ *! @expr{_destruct@} functions aren't called then. Use @[atexit] to get
*! called when the process exits.
*!
*! @note
*! Regarding destruction order during garbage collection:
*!
*! If an object is destructed by the garbage collector, it's part of
*! a reference cycle with other things but with no external
- *! references. If there are other objects with @expr{destroy@}
+ *! references. If there are other objects with @expr{_destruct@}
*! functions in the same cycle, it becomes a problem which to call
*! first.
*!
*! E.g. if this object has a variable with another object which
*! (directly or indirectly) points back to this one, you might find
*! that the other object already has been destructed and the variable
*! thus contains zero.
*!
*! The garbage collector tries to minimize such problems by defining
*! an order as far as possible:
*!
*! @ul
*! @item
- *! If an object A contains an @[lfun::destroy] and an object B does
+ *! If an object A contains an @[lfun::_destruct] and an object B does
*! not, then A is destructed before B.
*! @item
*! If A references B single way, then A is destructed before B.
*! @item
*! If A and B are in a cycle, and there is a reference somewhere
*! from B to A that is weaker than any reference from A to B, then
*! A is destructed before B.
*! @item
*! If a cycle is resolved according to the rule above by ignoring a
*! weaker reference, and there is another ambiguous cycle that
pike.git/src/program.c:441:
*! destructs a parent object before all children have been
*! destructed.)
*! @endul
*!
*! An example with well defined destruct order due to strong
*! references:
*!
*! @code
*! class Super {
*! class Sub {
- *! protected void destroy() {
+ *! protected void _destruct() {
*! if (!Super::this)
*! error ("My parent has been destructed!\n");
*! }
*! }
*! Sub sub = Sub();
- *! protected void destroy() {
+ *! protected void _destruct() {
*! if (!sub)
*! werror ("sub already destructed.\n");
*! }
*! }
*! @endcode
*!
*! The garbage collector ensures that these objects are destructed in
*! an order so that @expr{werror@} in @expr{Super@} is called and not
*! @expr{error@} in @expr{Sub@}.
*!
*! @note
- *! When the garbage collector calls @[lfun::destroy], all accessible
- *! non-objects and objects without @expr{destroy@} functions are
- *! still intact. They are not freed if the @expr{destroy@} function
+ *! When the garbage collector calls @[lfun::_destruct], all accessible
+ *! non-objects and objects without @expr{_destruct@} functions are
+ *! still intact. They are not freed if the @expr{_destruct@} function
*! adds external references to them. However, all objects with
- *! @[lfun::destroy] in the cycle are already scheduled for
+ *! @[lfun::_destruct] in the cycle are already scheduled for
*! destruction and will therefore be destroyed even if external
*! references are added to them.
*!
- *! @note
- *! The garbage collector had completely random destruct order in
- *! versions prior to 7.2.
- *!
+
*! @seealso
*! @[lfun::create()], @[predef::destruct()]
*/
/*! @decl mixed lfun::`+(zero arg, zero ... rest)
*!
*! Left side addition/concatenation callback.
*!
*! This is used by @[predef::`+]. It's called with any arguments
*! that follow this object in the argument list of the call to
pike.git/src/program.c:771:
*!
*! @note
*! It's assumed that this function is side-effect free.
*!
*! @seealso
*! @[predef::`~()]
*/
/*! @decl int(0..1) lfun::`==(mixed arg)
*!
- *! Equality test callback.
+ *! Equivalence test callback.
*!
-
+ *! @returns
+ *! Is expected to return @expr{1@} if the current object is
+ *! equivalent to @[arg] (ie may be replaced with @[arg], with
+ *! no semantic differences (disregarding the effects of @[destruct()])),
+ *! and @expr{0@} (zero) otherwise.
+ *!
*! @note
- *! If this is implemented it might be necessary to implement
- *! @[lfun::__hash] too. Otherwise mappings might hold several
+ *! If this is implemented it may be necessary to implement
+ *! @[lfun::__hash] too. Otherwise mappings may hold several
*! objects as indices which are duplicates according to this
- *! function. Various other functions that use hashing also might
- *! not work correctly, e.g. @[predef::Array.uniq].
+ *! function. This may also affect various other functions
+ *! that use hashing internally, e.g. @[predef::Array.uniq].
*!
*! @note
*! It's assumed that this function is side-effect free.
*!
-
+ *! @note
+ *! It's recommended to only implement this function for
+ *! immutable objects, as otherwise stuff may get confusing
+ *! when things that once were equivalent no longer are so,
+ *! or the reverse.
+ *!
*! @seealso
*! @[predef::`==()], @[lfun::__hash]
*/
/*! @decl int(0..1) lfun::`<(mixed arg)
*!
*! Less than test callback.
*!
*! @note
*! It's assumed that this function is side-effect free.
pike.git/src/program.c:814:
*!
*! @seealso
*! @[predef::`>()]
*/
/*! @decl int lfun::__hash()
*!
*! Hashing callback.
*!
*! The main caller of this function is @[predef::hash_value()]
- *! or the low-level equvivalent, which get called by various
+ *! or the low-level equivalent, which get called by various
*! mapping operations when the object is used as index in a mapping.
*!
*! @returns
*! It should return an integer that corresponds to the object
*! in such a way that all values which @[lfun::`==] considers
*! equal to the object get the same hash value.
*!
*! @note
*! The function @[predef::hash] does not return hash values that
*! are compatible with this one.
pike.git/src/program.c:874:
*! there is a @[`[..]] in the class. See @[predef::`[..]] for
*! details.
*!
*! @note
*! It's assumed that this function is side-effect free.
*!
*! @seealso
*! @[predef::`[]()], @[predef::`[..]]
*/
- /*! @decl mixed lfun::`[]=(zero arg1, zero arg2)
+ /*! @decl void lfun::`[]=(zero index, zero value, @
+ *! object|void context, int|void access)
*!
*! Index assignment callback.
*!
-
+ *! @param index
+ *! Index to change the value of.
+ *!
+ *! @param value
+ *! The new value.
+ *!
+ *! @param context
+ *! Context in the current object to index.
+ *!
+ *! If @expr{UNDEFINED@} or left out, @expr{this_program::this@}
+ *! is to be used (ie start at the current context and ignore
+ *! any overloaded symbols).
+ *!
+ *! @param access
+ *! Access permission override. One of the following:
+ *! @int
+ *! @value 0
+ *! @value UNDEFINED
+ *! See only public symbols.
+ *! @value 1
+ *! See protected symbols as well.
+ *! @endint
+ *!
+ *! This function is to set the value at index @[index] of the current
+ *! object to @[value].
+ *!
*! @seealso
*! @[predef::`[]=()], @[lfun::`->=()]
*/
/*! @decl mixed lfun::`->(string index, object|void context, int|void access)
*!
*! Arrow index callback.
*!
*! @param index
*! Symbol in @[context] to access.
pike.git/src/program.c:916:
*! Returns the value at @[index] if it exists, and
*! @expr{UNDEFINED@} otherwise.
*!
*! @note
*! It's assumed that this function is side-effect free.
*!
*! @seealso
*! @[predef::`->()], @[::`->()]
*/
- /*! @decl mixed lfun::`->=(string index, zero value, @
+ /*! @decl void lfun::`->=(string index, zero value, @
*! object|void context, int|void access)
*!
*! Arrow index assignment callback.
*!
*! @param index
*! Symbol in @[context] to change the value of.
*!
*! @param value
*! The new value.
*!
*! @param context
- *! Context in the current object to start the search from.
+ *! Context in the current object to index.
+ *!
*! If @expr{UNDEFINED@} or left out, @expr{this_program::this@}
*! is to be used (ie start at the current context and ignore
*! any overloaded symbols).
*!
*! @param access
*! Access permission override. One of the following:
*! @int
*! @value 0
*! @value UNDEFINED
*! See only public symbols.
*! @value 1
*! See protected symbols as well.
*! @endint
*!
- *! This function is to index the current object with the string @[index],
- *! and set it to @[value].
+ *! This function is to set the value at symbol @[index] of the current
+ *! object to @[value].
*!
- *! @returns
- *! Returns the set @[value].
- *!
+
*! @seealso
*! @[predef::`->=()], @[::`->=()], @[lfun::`[]=()]
*/
/*! @decl int lfun::_sizeof()
*!
*! Size query callback.
*!
*! Called by @[predef::sizeof()] to determine the number of elements
*! in an object. If this function is not present, the number
pike.git/src/program.c:1146:
*! It's assumed that this function is side-effect free.
*!
*! @seealso
*! @[predef::sprintf()]
*/
/*! @decl int lfun::_equal(mixed arg)
*!
*! Recursive equality callback.
*!
+ *! @returns
+ *! Is expected to return @expr{1@} if the current object is
+ *! equal to @[arg], and @expr{0@} (zero) otherwise.
+ *!
*! @note
*! It's assumed that this function is side-effect free.
*!
-
+ *! @note
+ *! Note that this function may return different values at different
+ *! times for the same argument due to the mutability of the object.
+ *!
*! @seealso
*! @[predef::equal()], @[lfun::`==()]
*/
/*! @decl mixed lfun::_m_delete(mixed arg)
*!
*! Delete index callback.
*!
*! @seealso
*! @[predef::m_delete()]
pike.git/src/program.c:1191:
*! @note
*! It's assumed that this function is side-effect free.
*!
*! @seealso
*! @[predef::`[..]]
*/
/**** END TRUE LFUNS ****/
/**** BEGIN FAKE LFUNS ****/
- /*! @decl mixed lfun::_search(mixed needle, mixed|void start)
+ /*! @decl mixed lfun::_search(mixed needle, mixed|void start, @
+ *! mixed ... extra_args)
*!
*! Search callback.
*!
-
+ *! The arguments are sent straight from @[search()], and are
+ *! as follows:
+ *!
+ *! @param needle
+ *! Value to search for.
+ *!
+ *! @param start
+ *! The first position to search.
+ *!
+ *! @param extra_args
+ *! Optional extra arguments as passed to @[search()].
+ *!
*! @seealso
*! @[predef::search()]
*/
/*! @decl array lfun::_types(object|void context, int|void access)
*!
*! List types callback.
*!
*! This callback is typically called via @[predef::types()].
*!
pike.git/src/program.c:1294:
*!
*! @[Debug.size_object()] callback.
*!
*! @returns
*! Returns an approximation of the memory use in bytes for the object.
*!
*! @seealso
*! @[Debug.size_object()], @[lfun::_sizeof()]
*/
- /*! @decl mixed lfun::_random()
+ /*! @decl mixed lfun::_random(function(int(0..):string(8bit)) random_string, @
+ *! function(mixed:mixed) random)
*! Called by @[random()]. Typical use is when the object implements
*! a ADT, when a call to this lfun should return a random member of
*! the ADT or range implied by the ADT.
*!
-
+ *! @param random_string
+ *! A @[RandomInterface()->random_string] function that returns
+ *! a string(8bit) of the specified length.
+ *!
+ *! @param random
+ *! A @[RandomInterface()->random] function.
+ *!
*! @seealso
- *! @[predef::random()]
+ *! @[predef::random()], @[RandomInterface]
*/
/**** END FAKE LFUNS ****/
/**** BEGIN MAGIC LFUNS ****/
/*! @decl mixed lfun::`symbol()
*! @decl mixed lfun::`->symbol()
*!
*! Variable retrieval callback (aka "getter").
*!
pike.git/src/program.c:1408:
*! @seealso
*! @[compile_error()]
*/
/*! @endclass
*/
struct program *first_program = 0;
static int current_program_id = PROG_DYNAMIC_ID_START;
- struct program *null_program=0;
-
- static struct program *reporter_program = NULL;
- struct program *compilation_program = 0;
- struct program *compilation_env_program = 0;
- struct object *compilation_environment = NULL;
-
+
struct program *gc_internal_program = 0;
static struct program *gc_mark_program_pos = 0;
- #ifdef PIKE_DEBUG
+
#define CHECK_FILE_ENTRY(PROG, STRNO) \
do { \
if ((STRNO < 0) || (STRNO >= PROG->num_strings)) \
Pike_fatal ("Invalid file entry in linenumber info.\n"); \
} while (0)
- #else
- #define CHECK_FILE_ENTRY(PROG, STRNO) do {} while (0)
- #endif
+
INT_TYPE get_small_number(char **q);
PMOD_EXPORT void do_free_program (struct program *p)
{
if (p)
free_program(p);
}
/* So what if we don't have templates? / Hubbe */
pike.git/src/program.c:1493:
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); \
+ tmp = mexec_realloc(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(low_add_many_to_,NAME) (struct program_state *state, \
TYPE *ARG, NUMTYPE cnt) { \
pike.git/src/program.c:1518:
TYPE *tmp; \
NUMTYPE n = m; \
do { \
if(n==MAXVARS(NUMTYPE)) { \
yyerror("Too many " #NAME "."); \
return; \
} \
n = MINIMUM(n*2+1,MAXVARS(NUMTYPE)); \
} while (m + cnt > n); \
m = n; \
- tmp = mexec_realloc((void *)state->new_program->NAME, \
- sizeof(TYPE) * m); \
+ tmp = mexec_realloc(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; \
} \
- MEMCPY(state->new_program->NAME + \
+ memcpy(state->new_program->NAME + \
state->new_program->PIKE_CONCAT(num_,NAME), \
ARG, sizeof(TYPE) * cnt); \
state->new_program->PIKE_CONCAT(num_,NAME) += cnt; \
} \
void PIKE_CONCAT(add_to_,NAME) (ARGTYPE ARG) { \
PIKE_CONCAT(low_add_to_,NAME) ( Pike_compiler, ARG ); \
}
#else /* !PIKE_USE_MACHINE_CODE */
#define BAR(NUMTYPE,TYPE,ARGTYPE,NAME) \
FOO(NUMTYPE,TYPE,ARGTYPE,NAME) \
pike.git/src/program.c:1551:
TYPE *tmp; \
NUMTYPE n = m; \
do { \
if(n==MAXVARS(NUMTYPE)) { \
yyerror("Too many " #NAME "."); \
return; \
} \
n = MINIMUM(n*2+1,MAXVARS(NUMTYPE)); \
} while (m + cnt > n); \
m = n; \
- tmp = realloc((void *)state->new_program->NAME, \
- sizeof(TYPE) * m); \
+ tmp = realloc(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; \
} \
- MEMCPY(state->new_program->NAME + \
+ memcpy(state->new_program->NAME + \
state->new_program->PIKE_CONCAT(num_,NAME), \
ARG, sizeof(TYPE) * cnt); \
state->new_program->PIKE_CONCAT(num_,NAME) += cnt; \
}
#endif /* PIKE_USE_MACHINE_CODE */
/* Funny guys use the uppermost value for nonexistant variables and
the like. Hence -2 and not -1. Y2K. */
#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); \
+ tmp = realloc(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 ); \
}
/* Funny guys use the uppermost value for nonexistant variables and
the like. Hence -2 and not -1. Y2K. */
#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) { \
+ DO_IF_DEBUG(if (state->compiler_pass != COMPILER_PASS_FIRST) { \
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); \
+ tmp = realloc(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 ); \
pike.git/src/program.c:1643:
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]);
- }
- }
+
#if 0
/* This check is not possible to do since the identifier is added
* before checking for duplicates in add_constant. */
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) {
pike.git/src/program.c:1675: Inside #if 0
Pike_compiler->new_program->identifiers[i].linenumber,
i);
}
}
add_to_identifiers (id);
}
#else
#define debug_add_to_identifiers(ARG) add_to_identifiers(ARG)
#endif
+ static int low_add_identifier(struct compilation *c,
+ struct pike_type *type,
+ struct pike_string *name,
+ unsigned int identifier_flags,
+ unsigned int opt_flags,
+ union idptr func,
+ int run_time_type)
+ {
+ struct identifier dummy;
+ int n = Pike_compiler->new_program->num_identifiers;
+
+ copy_shared_string(dummy.name, name);
+ copy_pike_type(dummy.type, type);
+ dummy.filename_strno = store_prog_string(c->lex.current_file);
+ dummy.linenumber = c->lex.current_line;
+ dummy.identifier_flags = identifier_flags;
+ dummy.run_time_type = run_time_type;
+ dummy.func = func;
+ dummy.opt_flags = opt_flags;
+ #ifdef PROFILING
+ dummy.self_time=0;
+ dummy.num_calls=0;
+ dummy.recur_depth=0;
+ dummy.total_time=0;
+ #endif
+ debug_add_to_identifiers(dummy);
+
+ return n;
+ }
+
+ static int add_identifier(struct compilation *c,
+ struct pike_type *type,
+ struct pike_string *name,
+ unsigned int modifier_flags,
+ unsigned int identifier_flags,
+ unsigned int opt_flags,
+ union idptr func,
+ int run_time_type)
+ {
+ struct reference ref;
+ struct identifier dummy;
+ int n;
+
+ if (modifier_flags & ID_PRIVATE) modifier_flags |= ID_LOCAL|ID_PROTECTED;
+
+ if (((identifier_flags & (IDENTIFIER_VARIABLE|IDENTIFIER_ALIAS)) ==
+ IDENTIFIER_VARIABLE) &&
+ (modifier_flags & ID_WEAK)) {
+ identifier_flags |= IDENTIFIER_WEAK;
+ }
+
+ ref.id_flags = modifier_flags;
+ ref.identifier_offset =
+ low_add_identifier(c, type, name,
+ identifier_flags, opt_flags,
+ func, run_time_type);
+ ref.inherit_offset = 0;
+ ref.run_time_type = PIKE_T_UNKNOWN;
+
+ if ((identifier_flags & (IDENTIFIER_VARIABLE|IDENTIFIER_ALIAS)) ==
+ IDENTIFIER_VARIABLE) {
+ add_to_variable_index(ref.identifier_offset);
+ }
+
+ n = Pike_compiler->new_program->num_identifier_references;
+ add_to_identifier_references(ref);
+
+ return n;
+ }
+
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)
{
struct compilation *c = THIS_COMPILATION;
if( (1<<TYPEOF(*s)) & (BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM))
{
c->num_used_modules++;
Pike_compiler->num_used_modules++;
assign_svalue_no_free((struct svalue *)
- low_make_buf_space(sizeof(struct svalue),
- &c->used_modules), s);
+ buffer_alloc(&c->used_modules, sizeof(struct svalue)), s);
if(Pike_compiler->module_index_cache)
{
free_mapping(Pike_compiler->module_index_cache);
Pike_compiler->module_index_cache=0;
}
if(c->resolve_cache)
{
free_mapping(c->resolve_cache);
c->resolve_cache=0;
}
}else{
yyerror("Module is neither mapping nor object");
}
}
void unuse_modules(INT32 howmany)
{
struct compilation *c = THIS_COMPILATION;
-
+ struct svalue *s = buffer_dst(&c->used_modules);
if(!howmany) return;
-
+ s -= howmany;
#ifdef PIKE_DEBUG
- if(howmany *sizeof(struct svalue) > c->used_modules.s.len)
+ if(howmany *sizeof(struct svalue) > buffer_content_length(&c->used_modules))
Pike_fatal("Unusing too many modules.\n");
#endif
c->num_used_modules -= howmany;
Pike_compiler->num_used_modules-=howmany;
- low_make_buf_space((ptrdiff_t) sizeof(struct svalue) * -howmany,
- &c->used_modules);
- free_svalues((struct svalue *)low_make_buf_space(0, &c->used_modules),
- howmany,
- BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM);
+ free_svalues(s, howmany, BIT_MAPPING | BIT_OBJECT | BIT_PROGRAM);
+ buffer_remove(&c->used_modules, howmany*sizeof(struct svalue));
+ #ifdef PIKE_DEBUG
+ if (s != buffer_dst(&c->used_modules))
+ Pike_fatal("buffer_remove is broken.\n");
+ #endif
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,
+ const int num_used_modules,
struct svalue *modules)
-
+ /* num_used_modules is declared const here to convince the compiler that it is not
+ * modified in between setjmp() and longjmp(). This prevents -Wclobbered warnings.
+ */
{
if(*module_index_cache)
{
struct svalue *tmp=low_mapping_string_lookup(*module_index_cache,ident);
if(tmp)
{
if(!(SAFE_IS_ZERO(tmp) && SUBTYPEOF(*tmp)==1))
return mksvaluenode(tmp);
return 0;
}
pike.git/src/program.c:1771:
{
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 &&
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST &&
((TYPEOF(Pike_sp[-1]) == T_OBJECT &&
Pike_sp[-1].u.object == placeholder_object) ||
(TYPEOF(Pike_sp[-1]) == 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 (TYPEOF(Pike_sp[-1])), 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);
- #if 0 && defined (COMPILER_DEBUG)
- safe_pike_fprintf (stderr, "Index %S: %O\n", ident, Pike_sp - 1);
- #endif
+
}
pop_stack();
return ret;
}
pop_stack();
}
}
UNSETJMP(tmp);
}
- #if 0 && defined (COMPILER_DEBUG)
- safe_pike_fprintf (stderr, "Index %S: undefined\n", ident);
- #endif
+
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 compilation *c = THIS_COMPILATION;
struct node_s *ret;
- struct svalue *modules=(struct svalue *)
- (c->used_modules.s.str + c->used_modules.s.len);
+ struct svalue *modules=(struct svalue *)buffer_dst(&c->used_modules);
{
struct program_state *p=Pike_compiler;
int n;
for(n=0;n<=c->compilation_depth;n++,p=p->previous)
{
int i;
if(see_inherit)
{
i=really_low_find_shared_string_identifier(ident,
p->new_program,
SEE_PROTECTED|SEE_PRIVATE);
if(i!=-1)
{
if ((p->flags & COMPILATION_FORCE_RESOLVE) &&
- (p->compiler_pass == 2) &&
+ (p->compiler_pass == COMPILER_PASS_LAST) &&
((p->num_inherits + 1) < p->new_program->num_inherits) &&
(PTR_FROM_INT(p->new_program, i)->inherit_offset >
p->num_inherits)) {
/* Don't look up symbols inherited later, since we need to get
* the same symbol in both passes in the force_resolve mode.
*/
continue;
}
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 ) < c->used_modules.s.str)
+ if( ((char *)modules ) < (char*)buffer_ptr(&c->used_modules))
Pike_fatal("Modules out of whack!\n");
#endif
}
}
return resolve_identifier(ident);
}
-
+ /* Look up a predefined identifier. */
+ struct node_s *find_predef_identifier(struct pike_string *ident)
+ {
+ struct compilation *c = THIS_COMPILATION;
+ node *tmp = mkconstantsvaluenode(&c->default_module);
+ node *ret = index_node(tmp, "predef", ident);
+ if(ret && !ret->name)
+ add_ref(ret->name = ident);
+ free_node(tmp);
+ return ret;
+ }
+
/*! @decl constant UNDEFINED
*!
*! The undefined value; ie a zero for which @[zero_type()] returns 1.
*/
- struct node_s *resolve_identifier(struct pike_string *ident)
+ int low_resolve_identifier(struct pike_string *ident)
{
struct compilation *c = THIS_COMPILATION;
node *ret = NULL;
/* Handle UNDEFINED */
if (ident == UNDEFINED_string) {
- return mkconstantsvaluenode(&svalue_undefined);
+ push_undefined();
+ return 1;
}
if(c->resolve_cache)
{
struct svalue *tmp=low_mapping_string_lookup(c->resolve_cache,ident);
if(tmp)
{
- if(!IS_UNDEFINED (tmp))
- return mkconstantsvaluenode(tmp);
-
+ if(IS_UNDEFINED (tmp)) {
return 0;
}
-
+
+ push_svalue(tmp);
+ return 1;
}
-
+ }
CHECK_COMPILER();
ref_push_string(ident);
- ref_push_string(c->lex.current_file);
- if (c->handler) {
- ref_push_object(c->handler);
- } else {
- push_int(0);
- }
- if (!safe_apply_current2(PC_RESOLV_FUN_NUM, 3, NULL))
+ if (!safe_apply_current2(PC_RESOLV_FUN_NUM, 1, NULL))
handle_compile_exception ("Error resolving '%S'.", ident);
- if (Pike_compiler->compiler_pass != 2) {
+ if (Pike_compiler->compiler_pass != COMPILER_PASS_LAST) {
/* If we get a program that hasn't gone through pass 1 yet then we
* have to register a dependency now in our pass 1 so that our
* pass 2 gets delayed. Otherwise the other program might still be
* just as unfinished when we come back here in pass 2. */
struct program *p = NULL;
if (TYPEOF(Pike_sp[-1]) == T_PROGRAM)
p = Pike_sp[-1].u.program;
else if (TYPEOF(Pike_sp[-1]) == T_OBJECT ||
(TYPEOF(Pike_sp[-1]) == T_FUNCTION &&
SUBTYPEOF(Pike_sp[-1]) != FUNCTION_BUILTIN))
p = Pike_sp[-1].u.object->prog;
if (p && !(p->flags & PROGRAM_PASS_1_DONE))
report_compiler_dependency (p);
}
- if (Pike_compiler->compiler_pass == 2 &&
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST &&
((TYPEOF(Pike_sp[-1]) == T_OBJECT &&
Pike_sp[-1].u.object == placeholder_object) ||
(TYPEOF(Pike_sp[-1]) == T_PROGRAM &&
Pike_sp[-1].u.program == placeholder_program))) {
my_yyerror("Got placeholder %s (resolver problem) "
"when resolving '%S'.",
get_name_of_type (TYPEOF(Pike_sp[-1])), ident);
} else {
if(!c->resolve_cache)
c->resolve_cache=dmalloc_touch(struct mapping *, allocate_mapping(10));
mapping_string_insert(c->resolve_cache,ident,Pike_sp-1);
if(!IS_UNDEFINED (Pike_sp-1))
{
- ret=mkconstantsvaluenode(Pike_sp-1);
+ return 1;
}
}
pop_stack();
-
+ return 0;
+ }
+
+ struct node_s *resolve_identifier(struct pike_string *ident)
+ {
+ node *ret = NULL;
+
+ if (low_resolve_identifier(ident)) {
+ ret = mkconstantsvaluenode(Pike_sp-1);
+ pop_stack();
+ }
return ret;
}
- /* This function is intended to simplify resolving of
+ /**
+ * This function is intended to simplify resolving of
* program symbols during compile-time for C-modules.
*
* A typical use-case is for a C-module inheriting
* code written in Pike.
*/
PMOD_EXPORT struct program *resolve_program(struct pike_string *ident)
{
struct program *ret = NULL;
- struct node_s *n = resolve_identifier(ident);
- if (n) {
- if ((n->token == F_CONSTANT) && (TYPEOF(n->u.sval) == T_PROGRAM) &&
- (ret = n->u.sval.u.program)) {
+ if (low_resolve_identifier(ident)) {
+ if ((ret = program_from_svalue(Pike_sp-1))) {
add_ref(ret);
- } else {
+ }
+ pop_stack();
+ }
+ if (!ret) {
my_yyerror("Invalid program identifier '%S'.", ident);
}
- free_node(n);
+ return ret;
+ }
+
+ /**
+ * Find the identifier named ident in inherit #inh in the lexical scope
+ * given by inherit_state and inherit_depth.
+ *
+ * @param inherit_state
+ * The program state for the program where the inherit is found.
+ *
+ * @param inherit_depth
+ * The number of lexical levels from the currently compiling program
+ * (ie Pike_compiler) to the one in inherit_state.
+ *
+ * @param inh
+ * >0 Specified inherit.
+ * =0 this_program:: or this::.
+ * -1 local::
+ * -2 global::
+ * -3 ::
+ */
+ struct node_s *find_inherited_identifier(struct program_state *inherit_state,
+ int inherit_depth, int inh,
+ struct pike_string *ident)
+ {
+ int id;
+ struct program *p = inherit_state->new_program;
+
+ #if 0
+ fprintf(stderr, "find_inherited_identifier(%p, %d, %d, \"%s\")\n",
+ inherit_state, inherit_depth, inh, ident->str);
+ #endif /* 0 */
+ if (inh == INHERIT_ALL) {
+ /* Unspecified inherit, but not inherit #0. */
+ struct node_s *res = NULL;
+ for (inh = 1; inh < p->num_inherits; inh++) {
+ struct node_s *n;
+ if (p->inherits[inh].inherit_level != 1) continue;
+ /* NB: We can't recurse here, as that would resolve the magic
+ * identifiers multiple times on multiple inherit.
+ */
+ id = low_reference_inherited_identifier(inherit_state, inh, ident,
+ SEE_PROTECTED);
+ if (id == -1) continue;
+ if (inherit_depth) {
+ n = mkexternalnode(inherit_state->new_program, id);
} else {
- my_yyerror("Unknown program identifier '%S'.", ident);
+ n = mkidentifiernode(id);
}
- return ret;
+ if (res) {
+ res = mknode(F_ARG_LIST, res, n);
+ } else {
+ res = n;
}
-
+ }
+ if (res) {
+ if (res->token == F_ARG_LIST) res = mkefuncallnode("aggregate", res);
+ return res;
+ }
+ inh = -1;
+ } else {
+ if (inh > 0) {
+ /* Specified inherit. */
+ id = low_reference_inherited_identifier(inherit_state, inh, ident,
+ SEE_PROTECTED);
+ } else {
+ /* this_program:: (0), local:: (-1) or global:: (-2). */
+ id = really_low_find_shared_string_identifier(ident,
+ inherit_state->new_program,
+ SEE_PROTECTED|SEE_PRIVATE);
+ }
-
+ if (id != -1) {
+ if (inh == INHERIT_LOCAL) {
+ /* local:: */
+ struct reference *ref = p->identifier_references + id;
+ if (IDENTIFIER_IS_VARIABLE(ID_FROM_PTR(p, ref)->identifier_flags)) {
+ /* Allowing local:: on variables would lead to pathological
+ * behavior: If a non-local variable in a class is referenced
+ * both with and without local::, both references would
+ * address the same variable in all cases except where an
+ * inheriting program overrides it (c.f. [bug 1252]).
+ *
+ * Furthermore, that's not how it works currently; if this
+ * error is removed then local:: will do nothing on variables
+ * except forcing a lookup in the closest surrounding class
+ * scope. */
+ yyerror ("Cannot make local references to variables.");
+ return NULL;
+ }
+ if (!(ref->id_flags & ID_LOCAL)) {
+ /* We need to generate a new reference. */
+ int d;
+ struct reference funp = *ref;
+ funp.id_flags = (funp.id_flags & ~ID_INHERITED) | ID_INLINE|ID_HIDDEN;
+ id = -1;
+ for(d = 0; d < (int)p->num_identifier_references; d++) {
+ struct reference *refp;
+ refp = p->identifier_references + d;
+
+ if (!(refp->id_flags & ID_LOCAL)) continue;
+
+ if((refp->inherit_offset == funp.inherit_offset) &&
+ (refp->identifier_offset == funp.identifier_offset)) {
+ id = d;
+ break;
+ }
+ }
+ if (id < 0) {
+ low_add_to_identifier_references(inherit_state, funp);
+ id = p->num_identifier_references - 1;
+ }
+ }
+ }
+ if (inherit_depth > 0) {
+ return mkexternalnode(inherit_state->new_program, id);
+ }
+ return mkidentifiernode(id);
+ }
+ if (inh < 0) inh = -1;
+ }
+
+ return program_magic_identifier(inherit_state, inherit_depth, inh, ident, 1);
+ }
+
/*! @decl constant this
*!
*! Builtin read only variable that evaluates to the current object.
*!
*! @seealso
*! @[this_program], @[this_object()]
*/
/*! @decl constant this_program
*!
*! Builtin constant that evaluates to the current program.
*!
*! @seealso
*! @[this], @[this_object()]
*/
- /* If the identifier is recognized as one of the magic identifiers,
+ /*! @decl constant this_function
+ *!
+ *! Builtin constant that evaluates to the current function.
+ *!
+ *! @seealso
+ *! @[this], @[this_object()]
+ */
+
+ /**
+ * If the identifier is recognized as one of the magic identifiers,
* like "this", "this_program" or "`->" when preceded by ::, then a
* suitable node is returned, NULL otherwise.
*
- * inherit_num is -1 when no specific inherit has been specified; ie
- * either when the identifier has no prefix (colon_colon_ref == 0) or
- * when the identifier has the prefix :: without any preceding identifier
- * (colon_colon_ref == 1).
+ * @param state
+ * Program state containing the inherit (if any), otherwise the
+ * current program state.
*
-
+ * @param state_depth
+ * Number of lexical scopes to the inherit state.
+ *
+ * @param inherit_num
+ * Inherit number in state->new_program that the identifier has been
+ * qualified with. -1 when no specific inherit has been specified; ie
+ * either when the identifier has no prefix (colon_colon_ref == 0) or
+ * when the identifier has the prefix :: without any preceding identifier
+ * (colon_colon_ref == 1).
+ *
+ * @param ident
+ * Identifier to look up.
+ *
+ * @param colon_colon_ref
+ * Boolean indicating whether state, state_depth and inherit_num
+ * should be regarded (1) or not (0).
+ *
* New in Pike 7.9.5 and later:
*
* If colon_colon_ref is 1 and the selected inherit defines the
* `->() lfun, code calling the lfun will be generated as follows:
*
* inh::`->(ident, inh::this, 1)
-
+ *
+ * New in Pike 8.1.4 and later:
+ *
+ * The symbol this_function may be prefixed with a selected inherit.
+ * It will then refer to the symbol with the same name as the
+ * current function from the selected inherit.
+ *
*/
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",
+ 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)) {
- /* Pike 7.6 and earlier couldn't refer to the current inherit. */
- inherit_num = -1;
- }
-
- if ((inherit_num == -1) || (!TEST_COMPAT(7,6) && (inherit_num >= 0))) {
+
if (ident == this_string) {
/* Handle this. */
return mkthisnode(state->new_program, inherit_num);
}
/* Handle this_program */
if (ident == this_program_string) {
node *n;
if (!state_depth && (inherit_num == -1) && colon_colon_ref &&
!TEST_COMPAT(7,8) &&
pike.git/src/program.c:2067:
/* Found! */
name = id->name;
break;
}
if (!name) {
yyerror("Failed to find current class in its parent.");
return NULL;
}
/* Find ::name in the parent. */
- i = reference_inherited_identifier(state->previous, NULL, name);
- if (i == -1) {
+ n = find_inherited_identifier(state->previous, state_depth+1,
+ INHERIT_ALL, name);
+ if (!n) {
my_yyerror("Failed to find previous inherited definition of %S "
"in parent.", name);
return NULL;
}
- n = mkexternalnode(parent, i);
+
} else {
n = mkefuncallnode("object_program",
mkthisnode(state->new_program, inherit_num));
}
/* We know this expression is constant. */
n->node_info &= ~OPT_NOT_CONST;
n->tree_info &= ~OPT_NOT_CONST;
return n;
}
/* Handle this_function */
if (ident == this_function_string) {
int i;
if ((i = Pike_compiler->compiler_frame->current_function_number) >= 0) {
struct identifier *id;
id = ID_FROM_INT(Pike_compiler->new_program, i);
-
+ if (colon_colon_ref) {
+ if (inherit_num == -1) inherit_num = INHERIT_ALL;
+ return find_inherited_identifier(state, state_depth, inherit_num,
+ id->name);
+ }
if (id->identifier_flags & IDENTIFIER_SCOPED) {
return mktrampolinenode(i, Pike_compiler->compiler_frame->previous);
} else {
return mkidentifiernode(i);
}
} else {
/* FIXME: Fall back to __INIT? */
}
}
- }
+
if (colon_colon_ref) {
int i = inherit_num;
/* These are only recognized when prefixed with the :: operator. */
if (inherit_num < 0) i = 0;
if(ident == lfun_strings[LFUN_ARROW] ||
ident == lfun_strings[LFUN_INDEX]) {
return mknode(F_MAGIC_INDEX, mknewintnode(i),
pike.git/src/program.c:2140:
struct program *prog = state->new_program->inherits[i].prog;
if (((id = FIND_LFUN(prog, LFUN_ARROW)) == -1) &&
(prog == state->new_program)) {
/* We are allowed to see private symbols in ourselves... */
id = really_low_find_shared_string_identifier(lfun_strings[LFUN_ARROW],
prog,
SEE_PROTECTED|SEE_PRIVATE);
} else if ((id != -1) && (prog != state->new_program)) {
id = really_low_reference_inherited_identifier(state, i, id);
}
- if ((id != -1) && (state->compiler_pass == 2)) {
+ if ((id != -1) && (state->compiler_pass == COMPILER_PASS_LAST)) {
if (inherit_num < 0) {
/* Find the closest inherit containing the lfun::`->()
* that is about to be called.
*
* In the single inherit case, this will always
* result in inherit_num == 1.
*/
struct inherit *inherits = state->new_program->inherits;
inherit_num = PTR_FROM_INT(state->new_program, id)->inherit_offset;
while (inherits[inherit_num].inherit_level > 1) {
pike.git/src/program.c:2224:
if (state->new_program && state->new_program->id == id) {
return state->new_program;
}
}
if ((id > 0) && (id < PROG_DYNAMIC_ID_START)) {
/* Reserved id. Attempt to load the proper dynamic module
* to resolv the id.
*/
char *module = NULL;
+ DECLARE_CYCLIC();
-
+ if (!BEGIN_CYCLIC(((ptrdiff_t)id), 0)) {
+ SET_CYCLIC_RET(1);
+
/* fprintf(stderr, "reserved "); */
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 >= 300) && (id < 400)) {
module = "Nettle";
} else if ((id >= 1000) && (id < 2000)) {
- module = "___GTK";
+ module = "___GTK1"; /* Deprecated */
} else if ((id >= 2000) && (id < 3000)) {
module = "___GTK2";
}
break;
}
-
+ }
+
if (module && get_master()) {
/* fprintf(stderr, "%s... ", module); */
push_text(module);
SAFE_APPLY_MASTER("resolv", 1);
pop_stack();
/* Try again... */
for(p=first_program;p;p=p->next)
{
if(id==p->id)
{
id_to_program_cache[h]=p;
/* fprintf(stderr, "found: %p\n", p); */
-
+ END_CYCLIC();
return p;
}
}
}
-
+ END_CYCLIC();
}
/* fprintf(stderr, "not found\n"); */
return 0;
}
/* Here starts routines which are used to build new programs */
/*
* A typical program goes through the following steps:
*
pike.git/src/program.c:2289:
*
* end_first_pass ==> PROGRAM_PASS_1_DONE
*
* fixate_program ==> PROGRAM_FIXED
*
* optimize_program ==> PROGRAM_OPTIMIZED
*
* end_first_pass(1) ==> PROGRAM_FINISHED
*/
- /* Re-allocate all the memory in the program in one chunk. because:
- * 1) The individual blocks are much bigger than they need to be
- * 2) cuts down on malloc overhead (maybe)
- * 3) localizes memory access (decreases paging)
+ /**
+ * Re-allocate all the memory in the program in one chunk. because:
+ * @b 1) The individual blocks are much bigger than they need to be
+ * @b 2) cuts down on malloc overhead (maybe)
+ * @b 3) localizes memory access (decreases paging)
*/
void optimize_program(struct program *p)
{
size_t size=0;
char *data;
/* Already done (shouldn't happen, but who knows?) */
if(p->flags & PROGRAM_OPTIMIZED) return;
#ifdef PIKE_USE_MACHINE_CODE
pike.git/src/program.c:2329:
size=0;
#ifdef PIKE_USE_MACHINE_CODE
/* As above. */
#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])); \
+ 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);
pike.git/src/program.c:2371:
#undef CMP
#ifdef PIKE_DEBUG
struct pike_string *find_program_name(struct program *p, INT_TYPE *line)
{
INT_TYPE l;
if(!line) line=&l;
#ifdef DEBUG_MALLOC
{
- char *tmp=dmalloc_find_name(p);
+ const char *tmp=dmalloc_find_name(p);
if (tmp) {
- char *p = STRCHR (tmp, ':');
+ char *p = strchr (tmp, ':');
if (p) {
char *pp;
- while ((pp = STRCHR (p + 1, ':'))) p = 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
pike.git/src/program.c:2442:
* since this makes it hard to identify in encode_value().
*/
if((ref->id_flags & (ID_INLINE|ID_INHERITED)) == (ID_INLINE|ID_INHERITED)
|| (ref->id_flags & new_ref->id_flags & ID_EXTERN)) {
/* But we still need to hide them, since we shadow them... */
ref->id_flags |= ID_HIDDEN;
continue;
}
#ifdef PROGRAM_BUILD_DEBUG
- fprintf(stderr, "%.*soverloaded reference %d (id_flags:0x%04x)\n",
+ fprintf(stderr, "%*soverloaded reference %d (id_flags:0x%04x)\n",
c->compilation_depth, "", cur_id, ref->id_flags);
#endif
if (!new_is_variable && IDENTIFIER_IS_VARIABLE(i->identifier_flags)) {
/* Overloading a variable with a constant or a function.
* This is generally a bad idea.
*/
ref->id_flags |= ID_INLINE|ID_HIDDEN;
yywarning("Attempt to override a non local variable %S "
"with a non-variable.", name);
pike.git/src/program.c:2481:
#endif
#endif
sub_ref = PTR_FROM_INT(inh->prog, cur_id - inh->identifier_level);
/* Check if the symbol was used before it was inherited. */
if ((c->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) &&
+ if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
!pike_types_le(ID_FROM_PTR(Pike_compiler->new_program,
new_ref)->type, sub_id->type)) {
yytype_report(REPORT_WARNING,
NULL, 0, sub_id->type,
NULL, 0, ID_FROM_PTR(Pike_compiler->new_program,
new_ref)->type,
0, "Type mismatch when overloading function %S.",
name);
}
} else {
pike.git/src/program.c:2696:
if (ref->id_flags & ID_HIDDEN) continue;
if (ref->id_flags & ID_VARIANT) continue;
if (ref->inherit_offset != 0) continue;
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);
}
}
- /* Set the PROGRAM_LIVE_OBJ flag by looking for destroy() and
+ /* Set the PROGRAM_LIVE_OBJ flag by looking for _destruct() and
* inherited PROGRAM_LIVE_OBJ flags. This is done at fixation time
* to allow the user to set and clear that flag while the program is
* being built. */
if (!(p->flags & PROGRAM_LIVE_OBJ)) {
- int e, destroy = p->lfuns[LFUN_DESTROY];
- if (destroy > -1) {
- struct identifier *id = ID_FROM_INT (p, destroy);
+ int e, destruct = p->lfuns[LFUN__DESTRUCT];
+ if (destruct > -1) {
+ struct identifier *id = ID_FROM_INT (p, destruct);
if (!IDENTIFIER_IS_PIKE_FUNCTION (id->identifier_flags) ||
id->func.offset != -1) {
- /* Got a destroy function that isn't a prototype. */
+ /* Got a _destruct function that isn't a prototype. */
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;
}
pike.git/src/program.c:2814:
}
}
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));
+ memset(p, 0, sizeof(struct program));
+ gc_init_marker(p);
p->flags|=PROGRAM_VIRGIN;
p->alignment_needed=1;
GC_ALLOC(p);
p->id=++current_program_id;
INIT_PIKE_MEMOBJ(p, T_PROGRAM);
DOUBLELINK(first_program, p);
ACCURATE_GETTIMEOFDAY(& p->timestamp);
return p;
}
- /*
+ /**
* Start building a new program
*/
void low_start_new_program(struct program *p,
int pass,
struct pike_string *name,
int flags,
int *idp)
{
struct compilation *c = THIS_COMPILATION;
int id=0;
struct svalue tmp;
CHECK_COMPILER();
- /* We don't want to change thread, but we don't want to
- * wait for the other threads to complete either.
+ /* We aren't thread safe, but we are reentrant.
+ *
+ * Lock out any other threads from the compiler until we are finished.
*/
- low_init_threads_disable();
+ lock_pike_compiler();
c->compilation_depth++;
SET_SVAL_TYPE(tmp, T_PROGRAM);
if(!p)
{
p=low_allocate_program();
if(name)
{
tmp.u.program=p;
pike.git/src/program.c:2869: Inside #if 0
name->str, c->compilation_depth);
}else{
fprintf(stderr,"Compiling file %s, depth=%d\n",
c->lex.current_file ? c->lex.current_file->str : "-",
c->compilation_depth);
#endif
}
}else{
tmp.u.program=p;
add_ref(p);
- if((pass == 2) && name)
+ if((pass != COMPILER_PASS_FIRST) && 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 (pass == COMPILER_PASS_FIRST) {
if(c->compilation_depth >= 1) {
add_ref(p->parent = Pike_compiler->new_program);
debug_malloc_touch (p);
}
}
p->flags &=~ PROGRAM_VIRGIN;
if(idp) *idp=id;
- CDFPRINTF((stderr, "th(%ld) %p low_start_new_program() %s "
- "pass=%d: threads_disabled:%d, compilation_depth:%d\n",
+ CDFPRINTF("th(%ld) %p low_start_new_program() %s "
+ "pass=%d: lock_depth:%d, compilation_depth:%d\n",
(long)th_self(), p, name ? name->str : "-",
Pike_compiler->compiler_pass,
- threads_disabled, c->compilation_depth));
+ lock_depth, c->compilation_depth);
init_type_stack();
#define PUSH
#include "compilation.h"
ba_init(&Pike_compiler->node_allocator, sizeof(struct node_s), 512);
Pike_compiler->parent_identifier=id;
Pike_compiler->compiler_pass = pass;
pike.git/src/program.c:2919:
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) {
/* Stipple to find illegal accesses */
- MEMSET(Pike_compiler->fake_object->storage,0x55,256*sizeof(struct svalue));
+ memset(Pike_compiler->fake_object->storage,0x55,256*sizeof(struct svalue));
PIKE_MEM_WO_RANGE (Pike_compiler->fake_object->storage,
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.");
}
/* Can't use GC_ALLOC on fake objects, but still it's good to know
pike.git/src/program.c:2944:
Pike_compiler->fake_object->prev=Pike_compiler->fake_object;
Pike_compiler->fake_object->refs=0;
add_ref(Pike_compiler->fake_object); /* For DMALLOC... */
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)
{
/* Fake objects have parents regardless of PROGRAM_USES_PARENT */
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): ",
+ fprintf (stderr, "%*sstarting program %d (pass=%d): ",
c->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",
+ fprintf (stderr, "%*sstarting program %d (pass=%d)\n",
c->compilation_depth, "",
Pike_compiler->new_program->id, Pike_compiler->compiler_pass);
#endif
if (c->compilation_depth >= 1) {
- if(TEST_COMPAT(7,2) || (c->lex.pragmas & ID_SAVE_PARENT))
+ if(c->lex.pragmas & ID_SAVE_PARENT)
{
p->flags |= PROGRAM_USES_PARENT;
- }else if (!(c->lex.pragmas & ID_DONT_SAVE_PARENT)) {
+ } else if (!(c->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); /* Default to true. */
free_node(n);
if (do_save_parent) p->flags |= PROGRAM_USES_PARENT;
}
pike.git/src/program.c:3121:
{ /* Trim off the leading path of the compilation environment. */
const char *p = DEFINETOSTR(PIKE_SRC_ROOT), *f = file;
while (*p && *p == *f) p++, f++;
while (*f == '/' || *f == '\\') f++;
c->lex.current_file = make_shared_string(f);
c->lex.current_line = line;
}
- CDFPRINTF((stderr,
- "th(%ld) start_new_program(%ld, %s): "
- "threads_disabled:%d, compilation_depth:%d\n",
+ CDFPRINTF("th(%ld) start_new_program(%ld, %s): "
+ "lock_depth:%d, compilation_depth:%d\n",
(long)th_self(), (long)line, file,
- threads_disabled, c->compilation_depth));
+ lock_depth, c->compilation_depth);
- low_start_new_program(0,1,0,0,0);
+ low_start_new_program(0, COMPILER_PASS_FIRST, 0, 0, 0);
store_linenumber(line,c->lex.current_file);
debug_malloc_name(Pike_compiler->new_program, file, line);
free_string(c->lex.current_file);
c->lex.current_file = dmalloc_touch(struct pike_string *, save_file);
c->lex.current_line = save_line;
}
static void exit_program_struct(struct program *p)
pike.git/src/program.c:3295: Inside #if defined(PIKE_DEBUG)
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));
+ (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);
pike.git/src/program.c:3390:
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;
}
+ if (Pike_compiler->current_attributes) {
+ free_node(Pike_compiler->current_attributes);
+ Pike_compiler->current_attributes = NULL;
+ }
+
unuse_modules(Pike_compiler->num_used_modules);
free_all_nodes();
ba_destroy(&Pike_compiler->node_allocator);
}
int sizeof_variable(int run_time_type)
{
switch(run_time_type)
pike.git/src/program.c:3701:
p->inherits[e].storage_offset)
Pike_fatal("Overlapping inherits! (3)\n");
}
}
if(p->flags & PROGRAM_FINISHED)
for(e=0;e<p->num_identifiers;e++)
{
check_string(p->identifiers[e].name);
- check_type_string(p->identifiers[e].type);
+
switch (p->identifiers[e].identifier_flags & IDENTIFIER_TYPE_MASK) {
case IDENTIFIER_VARIABLE:
case IDENTIFIER_PIKE_FUNCTION:
case IDENTIFIER_C_FUNCTION:
case IDENTIFIER_CONSTANT:
break;
default:
Pike_fatal("Invalid identifier type.\n");
pike.git/src/program.c:3731:
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))
{
dump_program_tables(p, 0);
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));
+ (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->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",
pike.git/src/program.c:3875:
"Program->identifier_index[%ld]\n",
(long)(e-1), (long)e);
}
}
}
#endif
static void f_dispatch_variant(INT32 args);
+ int low_is_variant_dispatcher(struct identifier *id)
+ {
+ if (!id) return 0;
+ return (IDENTIFIER_IS_C_FUNCTION(id->identifier_flags) &&
+ !IDENTIFIER_IS_ALIAS(id->identifier_flags) &&
+ (id->func.c_fun == f_dispatch_variant));
+ }
+
int is_variant_dispatcher(struct program *prog, int fun)
{
struct reference *ref;
struct identifier *id;
if (fun < 0) return 0;
ref = PTR_FROM_INT(prog, fun);
id = ID_FROM_PTR(prog, ref);
- return (IDENTIFIER_IS_C_FUNCTION(id->identifier_flags) &&
- !IDENTIFIER_IS_ALIAS(id->identifier_flags) &&
- (id->func.c_fun == f_dispatch_variant));
+ return low_is_variant_dispatcher(id);
}
static int add_variant_dispatcher(struct pike_string *name,
struct pike_type *type,
int id_flags)
{
union idptr dispatch_fun;
dispatch_fun.c_fun = f_dispatch_variant;
return define_function(name, type, id_flags & ~(ID_VARIANT|ID_LOCAL),
IDENTIFIER_C_FUNCTION, &dispatch_fun, 0);
}
- /* Note: This function is misnamed, since it's run after both passes. /mast */
- /* finish-states:
+ /**
+ * End the current compilation pass.
*
-
+ * @param finish
+ * finish-state:
+ *
* 0: First pass.
* 1: Last pass.
* 2: Called from decode_value().
-
+ *
+ * Note: This function is misnamed, since it's run after all passes.
*/
struct program *end_first_pass(int finish)
{
struct compilation *c = THIS_COMPILATION;
int e;
struct program *prog = Pike_compiler->new_program;
- struct pike_string *s;
+ struct pike_string *init_name;
int num_refs = prog->num_identifier_references;
union idptr dispatch_fun;
dispatch_fun.c_fun = f_dispatch_variant;
/* Collect variant functions that have been defined in this program,
* and add the corresponding dispatchers.
*/
for (e = 0; e < num_refs; e++) {
struct identifier *id;
pike.git/src/program.c:3935:
if (prog->identifier_references[e].inherit_offset) continue;
if (!is_variant_dispatcher(prog, e)) continue;
/* Found a dispatcher. */
id = ID_FROM_INT(prog, e);
name = id->name;
type = NULL;
id_flags = 0;
opt_flags = 0;
- CDFPRINTF((stderr, "Collecting variants of \"%s\"...\n", name->str));
+ CDFPRINTF("Collecting variants of \"%s\"...\n", name->str);
/* Collect the variants of the function. */
j = prog->num_identifier_references;
while ((j = really_low_find_variant_identifier(name, prog, NULL, j,
SEE_PROTECTED|SEE_PRIVATE)) >= 0) {
struct reference *ref = prog->identifier_references + j;
id = ID_FROM_INT(prog, j);
id_flags |= ref->id_flags;
opt_flags |= id->opt_flags;
/* NB: The dispatcher needs the variant references to
* not get overloaded for the ::-operator to work.
*/
- prog->identifier_references[j].id_flags |= ID_LOCAL;
+ ref->id_flags |= ID_LOCAL;
+ if (type)
{
struct pike_type * temp = type;
-
+ if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
+ !ref->inherit_offset &&
+ !check_variant_overload(id->type, type)) {
+ /* This symbol is shadowed by later variants. */
+ yytype_report(REPORT_WARNING,
+ NULL, 0, NULL,
+ Pike_compiler->new_program->strings[id->filename_strno],
+ id->linenumber, id->type,
+ 0, "Function %S() masked by later variant.",
+ name);
+ ref_push_type_value(type);
+ low_yyreport(REPORT_WARNING,
+ Pike_compiler->new_program->strings[id->filename_strno],
+ id->linenumber,
+ type_check_system_string,
+ 1, "Variant : %O.");
+ }
type = or_pike_types(type, id->type, 1);
- if (temp) free_type(temp);
+ free_type(temp);
+ } else {
+ add_ref(type = id->type);
}
#ifdef COMPILER_DEBUG
fprintf(stderr, "type: ");
simple_describe_type(id->type);
fprintf(stderr, "\n");
#endif
}
#ifdef COMPILER_DEBUG
fprintf(stderr, "Dispatcher type: ");
simple_describe_type(type);
fprintf(stderr, "\n");
#endif
/* Update the type of the dispatcher. */
id = ID_FROM_INT(prog, e);
free_type(id->type);
id->type = type;
id->opt_flags = opt_flags;
- prog->identifier_references->id_flags |= id_flags & ~(ID_VARIANT|ID_LOCAL);
+ prog->identifier_references[e].id_flags |= id_flags & ~(ID_VARIANT|ID_LOCAL);
next_ref:
;
}
debug_malloc_touch(Pike_compiler->fake_object);
debug_malloc_touch(Pike_compiler->fake_object->storage);
- MAKE_CONST_STRING(s,"__INIT");
+ init_name = lfun_strings[LFUN___INIT];
-
+
/* Collect references to inherited __INIT functions */
if (!(Pike_compiler->new_program->flags & PROGRAM_AVOID_CHECK)) {
for(e=Pike_compiler->new_program->num_inherits-1;e;e--)
{
int id;
if(Pike_compiler->new_program->inherits[e].inherit_level!=1) continue;
id = Pike_compiler->new_program->inherits[e].prog->lfuns[LFUN___INIT];
id = really_low_reference_inherited_identifier(0, e, id);
if(id!=-1)
{
Pike_compiler->init_node=mknode(F_COMMA_EXPR,
mkcastnode(void_type_string,
mkapplynode(mkidentifiernode(id),0)),
Pike_compiler->init_node);
}
}
}
-
+ if (finish == 1) {
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {
+ /* Called from end_program(). */
+ if (Pike_compiler->init_node) {
+ /* Make sure that the __INIT symbol exists, so that
+ * we won't get a fatal when we add the actual code
+ * further down when we have entered pass 2.
+ *
+ * Also make sure that it is marked as having side effects,
+ * or it will be optimized away when inherited...
+ */
+ define_function(init_name, function_type_string, ID_PROTECTED,
+ IDENTIFIER_PIKE_FUNCTION, NULL,
+ OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND);
+ }
+ }
+ Pike_compiler->compiler_pass = COMPILER_PASS_LAST;
+ }
+
/*
* Define the __INIT function, but only if there was any code
* to initialize.
*/
if(Pike_compiler->init_node)
{
-
+ /* Inhibit this_function. */
Pike_compiler->compiler_frame->current_function_number = -2;
- e=dooptcode(s,
+
+ e=dooptcode(init_name,
mknode(F_COMMA_EXPR,
Pike_compiler->init_node,
mknode(F_RETURN,mkintnode(0),0)),
function_type_string,
ID_PROTECTED);
Pike_compiler->init_node=0;
} else if (finish == 2) {
/* Called from decode_value(). */
e = low_find_lfun(Pike_compiler->new_program, LFUN___INIT);
if ((e != -1) &&
pike.git/src/program.c:4035:
* __INIT() is just a prototype or not.
*/
e=-1;
}
Pike_compiler->new_program->lfuns[LFUN___INIT]=e;
pop_compiler_frame(); /* Pop __INIT local variables */
if(Pike_compiler->num_parse_error > 0)
{
- CDFPRINTF((stderr, "th(%ld) %p Compilation errors (%d).\n",
+ CDFPRINTF("th(%ld) %p Compilation errors (%d).\n",
(long)th_self(), Pike_compiler->new_program,
- Pike_compiler->num_parse_error));
+ Pike_compiler->num_parse_error);
prog=0;
}else{
prog=Pike_compiler->new_program;
add_ref(prog);
Pike_compiler->new_program->flags |= PROGRAM_PASS_1_DONE;
if(finish)
{
if(Pike_compiler->new_program->flags & PROGRAM_USES_PARENT)
pike.git/src/program.c:4091: Inside #if defined(PIKE_DEBUG)
#ifdef PIKE_DEBUG
if (prog) {
check_program(prog);
if(l_flag)
dump_program_desc(prog);
}
#endif
}
#ifdef PROGRAM_BUILD_DEBUG
- fprintf (stderr, "%.*sfinishing program %d (pass=%d)\n",
+ fprintf (stderr, "%*sfinishing program %d (pass=%d)\n",
c->compilation_depth, "",
Pike_compiler->new_program->id, Pike_compiler->compiler_pass);
#endif
toss_compilation_resources();
#if 0
- CDFPRINTF((stderr,
- "th(%ld) end_first_pass(): "
+ CDFPRINTF("th(%ld) end_first_pass(): "
"%p compilation_depth:%d, Pike_compiler->compiler_pass:%d\n",
(long)th_self(), prog,
- c->compilation_depth, Pike_compiler->compiler_pass));
+ c->compilation_depth, Pike_compiler->compiler_pass);
#endif
- if(!Pike_compiler->compiler_frame && (Pike_compiler->compiler_pass==2 || !prog) && c->resolve_cache)
+ if(!Pike_compiler->compiler_frame &&
+ (Pike_compiler->compiler_pass == COMPILER_PASS_LAST || !prog) &&
+ c->resolve_cache)
{
free_mapping(dmalloc_touch(struct mapping *, c->resolve_cache));
c->resolve_cache=0;
}
- #ifdef SHARED_NODES
- /* free(node_hash.table); */
- #endif /* SHARED_NODES */
-
+
#define POP
#include "compilation.h"
exit_type_stack();
- CDFPRINTF((stderr,
- "th(%ld) %p end_first_pass(%d): "
- "threads_disabled:%d, compilation_depth:%d\n",
+ CDFPRINTF("th(%ld) %p end_first_pass(%d): "
+ "lock_depth:%d, compilation_depth:%d\n",
(long)th_self(), prog, finish,
- threads_disabled, c->compilation_depth));
+ lock_depth, c->compilation_depth);
c->compilation_depth--;
- exit_threads_disable(NULL);
+ unlock_pike_compiler();
#if 0
#ifdef PIKE_USE_MACHINE_CODE
if (prog &&
(((unsigned long long *)prog->program)[-1] != 0xdeadfeedf00dfaddLL)) {
Pike_fatal("Bad mexec magic!\n");
}
#endif /* PIKE_USE_MACHINE_CODE */
#endif /* 0 */
return prog;
}
- /*
+ /**
* Finish this program, returning the newly built program
*/
PMOD_EXPORT struct program *debug_end_program(void)
{
- Pike_compiler->compiler_pass = 2;
+
return end_first_pass(1);
}
- /*
+ /**
* Allocate space needed for this program in the object structure.
* An offset to the data is returned.
*/
PMOD_EXPORT size_t low_add_storage(size_t size, size_t alignment,
ptrdiff_t modulo_orig)
{
ptrdiff_t offset;
ptrdiff_t modulo;
if(!size) return Pike_compiler->new_program->storage_needed;
#ifdef PIKE_DEBUG
if(alignment <=0 || (alignment & (alignment-1)) || alignment > 256)
Pike_fatal("Alignment must be 1,2,4,8,16,32,64,128 or 256 not %ld\n",
- PTRDIFF_T_TO_LONG(alignment));
+ (long)alignment);
#endif
modulo=( modulo_orig /* +OFFSETOF(object,storage) */ ) % alignment;
offset=DO_ALIGN(Pike_compiler->new_program->storage_needed-modulo,alignment)+modulo;
if(!Pike_compiler->new_program->storage_needed) {
/* Shouldn't Pike_compiler->new_program->storage_needed be set here?
* Otherwise the debug code below ought to be trigged.
* But since it isn't, I guess this is dead code?
* /grubba 1999-09-28
pike.git/src/program.c:4197:
* STORAGE_NEEDED() is defined in program.h.
* /Hubbe 1999-09-29
*
* Oops, seems I read the test below the wrong way around.
* /grubba 1999-09-29
*/
Pike_compiler->new_program->inherits[0].storage_offset=offset;
}
if(Pike_compiler->new_program->alignment_needed<alignment)
- Pike_compiler->new_program->alignment_needed =
- DO_NOT_WARN((unsigned INT8)alignment);
+ Pike_compiler->new_program->alignment_needed = (unsigned INT8)alignment;
#ifdef PIKE_DEBUG
if(offset < Pike_compiler->new_program->storage_needed)
Pike_fatal("add_storage failed horribly!\n");
if( (offset /* + OFFSETOF(object,storage) */ - modulo_orig ) % alignment )
Pike_fatal("add_storage failed horribly(2) %ld %ld %ld %ld!\n",
- DO_NOT_WARN((long)offset),
+ (long)offset,
(long)0 /* + OFFSETOF(object,storage) */,
- DO_NOT_WARN((long)modulo_orig),
- DO_NOT_WARN((long)alignment));
+ (long)modulo_orig,
+ (long)alignment);
#endif
Pike_compiler->new_program->storage_needed = offset + size;
return (size_t) offset;
}
/*
* Internal function.
pike.git/src/program.c:4275:
static void add_compat_event_handler(void)
{
if(Pike_compiler->new_program->event_handler != compat_event_handler)
{
unsigned int e,d;
unsigned char *tmp=(unsigned char *)&Pike_compiler->new_program->event_handler;
for(d=0;d<NUM_PROG_EVENTS;d++) {
/* FIXME: This looks like it might be broken. */
/* Broken how? -Hubbe */
- #ifdef HAVE_COMPUTED_GOTO
- add_to_program(Pike_compiler->new_program->event_handler);
- #else /* !HAVE_COMPUTED_GOTO */
+
for(e=0;e<sizeof(Pike_compiler->new_program->event_handler);e++)
add_to_program(tmp[e]);
- #endif /* HAVE_COMPUTED_GOTO */
+
}
Pike_compiler->new_program->event_handler=compat_event_handler;
}
}
- /*
+ /**
* Set a callback to be called when this program is cloned.
*
* This function is obsolete; see pike_set_prog_event_callback for
* details.
*/
PMOD_EXPORT void set_init_callback(void (*init)(struct object *))
{
add_compat_event_handler();
((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_INIT]=init;
}
- /*
+ /**
* Set a callback to be called when clones of this program are
* destructed.
*
* This function is obsolete; see pike_set_prog_event_callback for
* details.
*
* Note: If the callback only does very trivial stuff, like freeing or
* clearing a few pointers in the object storage, you can do
*
* Pike_compiler->new_program->flags &= ~PROGRAM_LIVE_OBJ;
pike.git/src/program.c:4322:
* called out of order for PROG_EVENT_EXIT events; see the docs for
* PROGRAM_LIVE_OBJ in program.h for further details.
*/
PMOD_EXPORT void set_exit_callback(void (*exit)(struct object *))
{
add_compat_event_handler();
((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_EXIT]=exit;
Pike_compiler->new_program->flags |= PROGRAM_LIVE_OBJ;
}
- /*
+ /**
* This callback is used by the gc to traverse all references to
* things in memory. It should call some gc_recurse_* function exactly
* once for each reference that the pike internals doesn't know about.
*
* If a reference is shared between objects, it should be traversed
* once for every instance sharing it.
*
* The callback might be called more than once for the same instance
* during a gc pass. The gc assumes that the references are enumerated
* in the same order in that case.
pike.git/src/program.c:4357:
*
* This function is obsolete; see pike_set_prog_event_callback for
* details.
*/
PMOD_EXPORT void set_gc_recurse_callback(void (*m)(struct object *))
{
add_compat_event_handler();
((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_GC_RECURSE]=m;
}
- /*
+ /**
* This callback is used by the gc to count all references to things
* in memory. It should call gc_check, gc_check_(weak_)svalues or
* gc_check_(weak_)short_svalue exactly once for each reference that
* the pike internals don't know about.
*
* If a reference is shared between objects, it should be counted once
* for all shared instances. The return value from gc_check is useful
* to ensure this; it's zero when called the first time for its
* argument (it is perfectly fine to use gc_check on things that the
* pike core doesn't know about, but they must have an INT32 refcount
pike.git/src/program.c:4379:
*
* This function is obsolete; see pike_set_prog_event_callback for
* details.
*/
PMOD_EXPORT void set_gc_check_callback(void (*m)(struct object *))
{
add_compat_event_handler();
((oldhandlertype *)Pike_compiler->new_program->program)[PROG_EVENT_GC_CHECK]=m;
}
- /*
+ /**
* Set a callback to be called when any of the special program events
* occur. The event type is sent as an integer argument. The events
* include, but might not be limited to, the following:
*
* PROG_EVENT_INIT
* An object is being cloned from the program. See set_init_callback
* for details.
* PROG_EVENT_EXIT
* An object is being destructed. See set_exit_callback for details.
* PROG_EVENT_GC_RECURSE
pike.git/src/program.c:4428:
PMOD_EXPORT void pike_set_prog_optimize_callback(node *(*opt)(node *))
{
#ifdef PIKE_DEBUG
if(Pike_compiler->new_program->optimize)
Pike_fatal("Program already has an optimize handler!\n");
#endif
Pike_compiler->new_program->optimize = opt;
}
+ /**
+ * Reference an inherited identifier.
+ *
+ * @param q
+ * Program state for the program being compiled that will have
+ * the reference added. May be NULL to indicate Pike_compiler.
+ *
+ * @param i
+ * Inherit number in q->new_program.
+ *
+ * @param f
+ * Reference number in q->new_program->inherit[i].prog.
+ *
+ * @return
+ * Returns an equivalent reference that is INLINE|HIDDEN.
+ *
+ * Returns -1 if the referenced identifier is -1 or a prototype.
+ */
PMOD_EXPORT int really_low_reference_inherited_identifier(struct program_state *q,
int i,
int f)
{
struct program *np=(q?q:Pike_compiler)->new_program;
struct reference funp;
struct program *p;
int d, num_id_refs;
if(f==-1) return -1;
p = np->inherits[i].prog;
-
+ if ((q?q:Pike_compiler)->compiler_pass == COMPILER_PASS_LAST) {
+ struct identifier *id = ID_FROM_INT(p, f);
+ if (((id->identifier_flags & IDENTIFIER_TYPE_MASK) ==
+ IDENTIFIER_PIKE_FUNCTION) && (id->func.offset == -1)) {
+ /* Prototype. */
+ return -1;
+ }
+ }
+
funp = p->identifier_references[f];
funp.inherit_offset += i;
funp.id_flags = (funp.id_flags & ~ID_INHERITED) | ID_INLINE|ID_HIDDEN;
num_id_refs = np->num_identifier_references;
for(d = 0; d < num_id_refs; d++)
{
struct reference *refp;
refp = np->identifier_references + d;
pike.git/src/program.c:4470:
if(q)
low_add_to_identifier_references(q,funp);
else
add_to_identifier_references(funp);
/* NOTE: np->num_identifier_references has been increased by one by
* {low_,}add_to_identifier_references().
*/
#ifdef PIKE_DEBUG
if (num_id_refs != np->num_identifier_references-1) {
- fatal("Unexpected number of identifier references: %d != %d\n",
+ Pike_fatal("Unexpected number of identifier references: %d != %d\n",
num_id_refs, np->num_identifier_references-1);
}
#endif /* PIKE_DEBUG */
return num_id_refs; /* aka np->num_identifier_references - 1 */
}
PMOD_EXPORT int low_reference_inherited_identifier(struct program_state *q,
int e,
struct pike_string *name,
pike.git/src/program.c:4505:
if(p->identifier_references[i].id_flags & ID_HIDDEN)
return -1;
if(p->identifier_references[i].id_flags & ID_PRIVATE)
if(!(flags & SEE_PRIVATE))
return -1;
return really_low_reference_inherited_identifier(q, e, i);
}
- int find_inherit(struct program *p, struct pike_string *name)
+ int find_inherit(const struct program *p, const struct pike_string *name)
{
int e;
int level = p->num_inherits; /* Larger than any inherit_level. */
int res = 0;
#if 0
fprintf(stderr, "find_inherit(0x%08lx, \"%s\")...\n",
(unsigned long)p, name->str);
#endif /* 0 */
pike.git/src/program.c:4532:
if (p->inherits[e].inherit_level >= level) continue;
if (name == p->inherits[e].name) {
res = e;
level = p->inherits[e].inherit_level;
if (level == 1) break;
}
}
return res;
}
- /* Reference the symbol inherit::name in the lexical context
+ /**
+ * Reference the symbol inherit::name in the lexical context
* specified by state.
*
- * Returns the reference in state->new_program if found.
+ * @return Returns the reference in state->new_program if found.
*/
PMOD_EXPORT int reference_inherited_identifier(struct program_state *state,
struct pike_string *inherit,
struct pike_string *name)
{
int e, id;
struct program *p;
#ifdef PIKE_DEBUG
if (name != debug_findstring(name))
pike.git/src/program.c:4672: Inside #if 0
fprintf(stderr,"%p low_inherit(pid=%d, parent=%p, parid=%d, "
"paroff=%d, flags=0x%x, name=%s);\n",
Pike_compiler->new_program,
p ? p->id : 0,
parent,
parent_identifier,
parent_offset,
flags,
name? name->str : "");
#endif
- CDFPRINTF((stderr, "th(%ld) %p inherit %p\n",
- (long) th_self(), Pike_compiler->new_program, p));
+ CDFPRINTF("th(%ld) %p inherit %p\n",
+ (long) th_self(), Pike_compiler->new_program, p);
if(!p)
{
yyerror("Illegal program pointer.");
return;
}
- if (Pike_compiler->compiler_pass == 2) {
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_EXTRA) {
struct program *old_p =
- Pike_compiler->new_program->inherits[Pike_compiler->num_inherits+1].prog;
+ Pike_compiler->new_program->
+ inherits[Pike_compiler->num_inherits+1].prog;
Pike_compiler->num_inherits += old_p->num_inherits;
if (old_p != p) {
yyerror("Got different program for inherit in second pass "
"(resolver problem).");
}
-
+ return;
+ }
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
+ struct program *old_p =
+ Pike_compiler->new_program->
+ inherits[Pike_compiler->num_inherits+1].prog;
+ Pike_compiler->num_inherits += old_p->num_inherits;
-
+ if (old_p != p) {
+ yyerror("Got different program for inherit in second pass "
+ "(resolver problem).");
+ }
+
if (!(p->flags & PROGRAM_FINISHED)) {
/* Require that the inherited program really is finished in pass
* 2. Otherwise we might not have all definitions when we
* fixate our program.
*
* FIXME: Maybe this can be relaxed by registering a dependency
* and delaying compilation here?
*/
yyerror ("Cannot inherit program in pass 2 "
"which is not fully compiled yet.");
pike.git/src/program.c:4742:
yyerror ("(You probably have a cyclic symbol dependency that the "
"compiler cannot handle.)");
return;
}
if (p == placeholder_program) {
yyerror("Trying to inherit placeholder program (resolver problem).");
return;
}
- if (p->flags & PROGRAM_HAS_C_METHODS) {
- Pike_compiler->new_program->flags |= PROGRAM_HAS_C_METHODS;
+ /* Propagate the HAS_C_METHODS, CLEAR_STORAGE and DESTRUCT_IMMEDIATE flags. */
+ if (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE|PROGRAM_DESTRUCT_IMMEDIATE)) {
+ Pike_compiler->new_program->flags |=
+ (p->flags & (PROGRAM_HAS_C_METHODS|PROGRAM_CLEAR_STORAGE|PROGRAM_DESTRUCT_IMMEDIATE));
}
/* parent offset was increased by 42 for above test.. */
if(parent_offset)
parent_offset-=42;
inherit_offset = Pike_compiler->new_program->num_inherits;
/* alignment magic */
storage_offset=p->inherits[0].storage_offset % p->alignment_needed;
pike.git/src/program.c:4903:
fun.inherit_offset += inherit_offset;
fun.run_time_type = PIKE_T_UNKNOWN; /* Invalidate the vtable cache. */
if (fun.id_flags & ID_FINAL)
{
Pike_compiler->flags |= COMPILATION_CHECK_FINAL;
}
+ if (flags & ID_PUBLIC)
+ fun.id_flags &= ~(ID_PRIVATE|ID_PUBLIC);
+
if(fun.id_flags & ID_PRIVATE) fun.id_flags|=ID_HIDDEN;
- if (fun.id_flags & ID_PUBLIC)
- fun.id_flags |= flags & ~ID_PRIVATE;
- else
- fun.id_flags |= flags;
+ fun.id_flags |= flags & ~ID_PUBLIC;
fun.id_flags |= ID_INHERITED;
add_to_identifier_references(fun);
}
}
- /*
- * make this program inherit another program
+ /**
+ * Make the program being compiled inherit another program.
+ *
+ * @param p
+ * Program to inherit.
+ *
+ * @param parent
+ * Object containing p (if applicable).
+ *
+ * @param parent_identifier
+ * Identifier reference in parent->prog that is p.
+ *
+ * @param parent_offset
+ * Lexical scope to parent from the program being compiled
+ * offsetted by 42, or OBJECT_PARENT or INHERIT_PARENT.
+ *
+ * @param flags
+ * Modifier flags for the inherit.
+ *
+ * @param name
+ * Optional rename of the inherit.
*/
PMOD_EXPORT void low_inherit(struct program *p,
struct object *parent,
int parent_identifier,
int parent_offset,
INT32 flags,
struct pike_string *name)
{
lower_inherit(p, parent, parent_identifier, parent_offset, flags, name);
pike.git/src/program.c:4946:
parent_offset -= 42;
while (state && state->new_program && parent_offset--) {
state->new_program->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT;
state = state->previous;
}
}
}
}
+ /**
+ * Inherit a class from a lexically scoped identifier.
+ *
+ * @param scope_depth
+ * Scope at which the identifier is expected to be found.
+ *
+ * @param symbol
+ * Name of symbol to inherit from the specified scope.
+ *
+ * @param flags
+ * Modifier flags for the inherit.
+ *
+ * @param failure_severity_level
+ * Severity level to yyreport() failures to perform the inherit.
+ * Typically REPORT_ERROR, but eg REPORT_NOTICE and REPORT_WARNING
+ * are useful if the sybol is expected to sometimes be missing.
+ *
+ * @returns
+ * Returns NULL on failure and the inherited program on success.
+ */
+ PMOD_EXPORT struct program *lexical_inherit(int scope_depth,
+ struct pike_string *symbol,
+ INT32 flags,
+ int failure_severity_level)
+ {
+ struct program_state *state = Pike_compiler;
+ int e;
+ int class_fun_num;
+ struct program *prog;
+
+ for (e = 0; e < scope_depth; e++) {
+ state = state->previous;
+ if (!state) {
+ my_yyerror("Invalid lexical inherit of symbol %S at depth %d (max_depth: %d).",
+ symbol, scope_depth, e+1);
+ return NULL;
+ }
+ }
+
+ class_fun_num =
+ really_low_find_shared_string_identifier(symbol, state->new_program,
+ SEE_PROTECTED|SEE_PRIVATE);
+ if (class_fun_num < 0) {
+ yyreport(failure_severity_level, parser_system_string, 0,
+ "Symbol to inherit (%S) not found in parent scope #%d.",
+ symbol, scope_depth);
+ return NULL;
+ }
+
+ prog = low_program_from_function(state->fake_object, class_fun_num);
+ if (!prog) {
+ yyreport(failure_severity_level, parser_system_string, 0,
+ "Symbol %S in parent scope #%d is not a program.",
+ symbol, scope_depth);
+ return NULL;
+ }
+
+ if (scope_depth) {
+ /* Add a reference to the identifier. */
+ class_fun_num =
+ really_low_reference_inherited_identifier(state, 0, class_fun_num);
+ }
+ low_inherit(prog, 0, class_fun_num, 42 + scope_depth, flags, symbol);
+
+ return prog;
+ }
+
PMOD_EXPORT void do_inherit(struct svalue *s,
INT32 flags,
struct pike_string *name)
{
struct object *parent_obj = NULL;
int parent_id = -1;
struct program *p = low_program_from_svalue(s, &parent_obj, &parent_id);
low_inherit(p, parent_obj, parent_id, 0, flags, name);
}
pike.git/src/program.c:4970:
struct program *p;
struct identifier *i;
INT32 numid=-1, offset=0;
if(!n)
{
yyerror("Unable to inherit");
return;
}
+ if ((n->token == F_APPLY) && (CAR(n)->token == F_CONSTANT) &&
+ (TYPEOF(CAR(n)->u.sval) == T_FUNCTION) &&
+ (SUBTYPEOF(CAR(n)->u.sval) == FUNCTION_BUILTIN) &&
+ (CAR(n)->u.sval.u.efun->function == debug_f_aggregate)) {
+ /* Disambiguate multiple inherit ::-reference. */
+ node *arg;
+ while(1) {
+ while ((arg = CDR(n))) {
+ n = arg;
+ if (n->token != F_ARG_LIST) goto found;
+ }
+ /* Paranoia. */
+ if ((arg = CAR(n))) {
+ n = arg;
+ continue;
+ }
+ /* FIXME: Ought to go up a level and try the car there...
+ * But as this code probably won't be reached, we
+ * just fail.
+ */
+ yyerror("Unable to inherit");
+ return;
+ }
+ found:
+ /* NB: The traditional C grammar requires a statement after a label. */
+ ;
+ }
+
+ fix_type_field(n);
+
+ if (!pike_types_le(n->type, inheritable_type_string) &&
+ (THIS_COMPILATION->lex.pragmas & ID_STRICT_TYPES)) {
+ yytype_report(REPORT_WARNING,
+ n->current_file, n->line_number, inheritable_type_string,
+ n->current_file, n->line_number, n->type,
+ 0, "Program required for inherit.\n");
+ }
+
switch(n->token)
{
- case F_IDENTIFIER:
- p=Pike_compiler->new_program;
- offset=0;
- numid=n->u.id.number;
- goto continue_inherit;
-
+
case F_EXTERNAL:
{
struct program_state *state = Pike_compiler;
offset = 0;
while (state && (state->new_program->id != n->u.integer.a)) {
state = state->previous;
offset++;
}
if (!state) {
yyerror("Failed to resolv external constant.\n");
return;
}
p = state->new_program;
numid = n->u.integer.b;
-
+ if ((name == this_program_string) && (offset == 1)) {
+ /* Klugde: Default to renaming ::this_program
+ * to the name of the current class.
+ *
+ * Otherwise the this_program:-scope
+ * will become confusing, as it will
+ * refer to the inherit and not the
+ * current class.
+ */
+ name = ID_FROM_INT(p, numid)->name;
}
-
+ }
continue_inherit:
/* FIXME: Support external constants. */
if(numid != IDREF_MAGIC_THIS &&
(IDENTIFIER_IS_CONSTANT((i=ID_FROM_INT(p, numid))->
identifier_flags)) &&
(i->func.const_info.offset != -1))
{
struct svalue *s=&PROG_FROM_INT(p, numid)->
pike.git/src/program.c:5030:
}
break;
default:
resolv_class(n);
do_inherit(Pike_sp-1, flags, name);
pop_stack();
}
}
+ void compiler_do_implement(node *n)
+ {
+ if (!n) {
+ yyerror("Invalid implement directive.");
+ return;
+ }
+ /* FIXME: Implement. */
+ }
+
int call_handle_inherit(struct pike_string *s)
{
struct compilation *c = THIS_COMPILATION;
CHECK_COMPILER();
ref_push_string(s);
- if (!TEST_COMPAT(7,6)) {
- /* In Pike 7.7 and later filenames belonging to Pike are assumed
- * to be encoded according to UTF-8.
- */
+
f_string_to_utf8(1);
- }
+
if (safe_apply_current2(PC_HANDLE_INHERIT_FUN_NUM, 1, NULL))
if (TYPEOF(Pike_sp[-1]) != T_INT)
return 1;
else {
my_yyerror("Couldn't find program %S", s);
}
else {
handle_compile_exception ("Error finding program");
}
pike.git/src/program.c:5074:
if(name)
{
free_string(s);
s=name;
}
do_inherit(Pike_sp-1, flags, s);
free_string(s);
pop_stack();
}
- /*
- * Return the index of the identifier found, otherwise -1.
+ /**
+ * Find an identifier relative to the program being compiled.
+ *
+ * @return Return the index of the identifier found, otherwise -1.
*/
- int isidentifier(struct pike_string *s)
+ int isidentifier(const struct pike_string *s)
{
return really_low_find_shared_string_identifier(s,
Pike_compiler->new_program,
SEE_PROTECTED|SEE_PRIVATE);
}
/*
* Definition of identifiers.
*
* Pike has three plus one classes of identifiers:
*
* IDENTIFIER_VARIABLE - A value stored in object->storage
* IDENTIFIER_CONSTANT - A value stored in program->constants
* IDENTIFIER_FUNCTION - Either a C function or a Pike function
* and
* IDENTIFIER_ALIAS - An alias for a different identifier.
*
*/
- /* Define an alias for a (possibly extern) identifier.
+ /**
+ * 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 compilation *c = THIS_COMPILATION;
struct program_state *state = Pike_compiler;
- struct identifier dummy, *id;
- struct reference ref;
+ struct identifier *id;
+ union idptr func;
#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)
+ if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST)
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++) {
+ for(e = 0; DO_IF_DEBUG_ELSE(state, 1) && (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.filename_strno = store_prog_string(c->lex.current_file);
- dummy.linenumber = c->lex.current_line;
- 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;
- dummy.opt_flags = 0;
- #ifdef PROFILING
- dummy.self_time=0;
- dummy.num_calls=0;
- dummy.recur_depth=0;
- dummy.total_time=0;
- #endif
+ func.ext_ref.depth = depth;
+ func.ext_ref.id = refno;
if (flags & ID_PRIVATE) flags |= ID_INLINE;
- ref.id_flags=flags;
- ref.identifier_offset=Pike_compiler->new_program->num_identifiers;
- ref.inherit_offset=0;
- ref.run_time_type = PIKE_T_UNKNOWN;
-
- debug_add_to_identifiers(dummy);
-
- n = Pike_compiler->new_program->num_identifier_references;
- add_to_identifier_references(ref);
-
- return n;
+ return add_identifier(c, type ? type : id->type, name ? name : id->name,
+ flags, id->identifier_flags | IDENTIFIER_ALIAS, 0,
+ func, id->run_time_type);
}
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)
{
pike.git/src/program.c:5264:
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 compilation *c = THIS_COMPILATION;
- struct identifier dummy;
- struct reference ref;
+ unsigned int identifier_flags = IDENTIFIER_VARIABLE;
+ union idptr func;
#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)
+ if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST)
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);
- dummy.filename_strno = store_prog_string(c->lex.current_file);
- dummy.linenumber = c->lex.current_line;
- dummy.identifier_flags = IDENTIFIER_VARIABLE;
- dummy.run_time_type=run_time_type;
- dummy.func.offset=offset - Pike_compiler->new_program->inherits[0].storage_offset;
- dummy.opt_flags = 0;
- #ifdef PROFILING
- dummy.self_time=0;
- dummy.num_calls=0;
- dummy.recur_depth=0;
- dummy.total_time=0;
- #endif
+ func.offset = offset - Pike_compiler->new_program->inherits[0].storage_offset;
+ if (run_time_type == PIKE_T_FREE) func.offset = -1;
- if (run_time_type == PIKE_T_FREE) dummy.func.offset = -1;
+ if (run_time_type & PIKE_T_NO_REF_FLAG) {
+ run_time_type &= ~PIKE_T_NO_REF_FLAG;
+ identifier_flags |= IDENTIFIER_NO_THIS_REF;
+ }
if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;
- ref.id_flags=flags;
- ref.identifier_offset=Pike_compiler->new_program->num_identifiers;
- ref.inherit_offset=0;
- ref.run_time_type = PIKE_T_UNKNOWN;
-
- add_to_variable_index(ref.identifier_offset);
-
- debug_add_to_identifiers(dummy);
-
- n=Pike_compiler->new_program->num_identifier_references;
- add_to_identifier_references(ref);
-
- return n;
+ return
+ add_identifier(c, type, name,
+ flags, identifier_flags, 0,
+ func,
+ run_time_type);
}
- /* type is a textual type */
- PMOD_EXPORT int map_variable(const char *name,
- const char *type,
- INT32 flags,
- size_t offset,
- INT32 run_time_type)
- {
- int ret;
- struct pike_string *n;
- struct pike_type *t;
-
- #ifdef PROGRAM_BUILD_DEBUG
- struct compilation *c = THIS_COMPILATION;
- fprintf (stderr, "%.*sdefining variable (pass=%d): %s %s\n",
- c->compilation_depth, "",
- Pike_compiler->compiler_pass, type, name);
- #endif
-
- n=make_shared_string(name);
- t=parse_type(type);
- ret=low_define_variable(n,t,flags|ID_USED,offset,run_time_type);
- free_string(n);
- free_type(t);
- return ret;
- }
-
+
/* type is a serialized tokenized type. */
PMOD_EXPORT int quick_map_variable(const char *name,
int name_length,
size_t offset,
const char *type,
int UNUSED(type_length),
INT32 run_time_type,
INT32 flags)
{
int ret;
struct pike_string *n;
struct pike_type *t;
n = make_shared_binary_string(name, name_length);
t = make_pike_type(type);
#ifdef PROGRAM_BUILD_DEBUG
{
struct compilation *c = THIS_COMPILATION;
struct pike_string *d = describe_type (t);
- fprintf (stderr, "%.*sdefining variable (pass=%d): %s ",
+ fprintf (stderr, "%*sdefining variable (pass=%d): %s ",
c->compilation_depth, "", Pike_compiler->compiler_pass, d->str);
free_string (d);
push_string (n);
print_svalue (stderr, --Pike_sp);
putc ('\n', stderr);
}
#endif
ret=low_define_variable(n,t,flags|ID_USED,offset,run_time_type);
free_string(n);
free_type(t);
return ret;
}
-
+ int is_auto_variable_type( int variable )
+ {
+ struct identifier *id=ID_FROM_INT(Pike_compiler->new_program,variable);
+ if( id && id->type && id->type->type == PIKE_T_AUTO )
+ return 1;
+ return 0;
+ }
+
+ void fix_auto_variable_type( int variable, struct pike_type *type )
+ {
+ /* Update the type of a program variable (basically, if it's
+ * marked 'auto', set it to the given type)
+ */
+ struct identifier *id=ID_FROM_INT(Pike_compiler->new_program,variable);
+ if( id )
+ {
+ free_type(id->type);
+ copy_pike_type(id->type, type);
+ }
+ return;
+ }
+
/* argument must be a shared string */
int define_variable(struct pike_string *name,
struct pike_type *type,
INT32 flags)
{
int n, run_time_type;
-
+ int no_this = 0;
#ifdef PIKE_DEBUG
- if(name!=debug_findstring(name))
+ if(name != debug_findstring(name))
Pike_fatal("define_variable on nonshared string.\n");
#endif
#ifdef PROGRAM_BUILD_DEBUG
{
struct compilation *c = THIS_COMPILATION;
struct pike_string *d = describe_type (type);
- fprintf (stderr, "%.*sdefining variable (pass=%d): %s ",
+ fprintf (stderr, "%*sdefining variable (pass=%d): %s ",
c->compilation_depth, "", Pike_compiler->compiler_pass, d->str);
free_string (d);
push_string (name);
print_svalue (stderr, --Pike_sp);
putc ('\n', stderr);
}
#endif
if(type == void_type_string)
yyerror("Variables can't be of type void.");
pike.git/src/program.c:5442:
return n;
}
}
if (!(IDENTIFIERP(n)->id_flags & ID_EXTERN)) {
if (IDENTIFIERP(n)->id_flags & ID_FINAL)
my_yyerror("Illegal to redefine 'final' "
"variable/functions %S", name);
if(!(IDENTIFIERP(n)->id_flags & ID_INLINE) ||
- Pike_compiler->compiler_pass!=1)
+ Pike_compiler->compiler_pass != COMPILER_PASS_FIRST)
{
int n2;
if(ID_FROM_INT(Pike_compiler->new_program, n)->type != type &&
!pike_types_le(type,
ID_FROM_INT(Pike_compiler->new_program, n)->type)) {
int level = REPORT_WARNING;
if (!match_types(ID_FROM_INT(Pike_compiler->new_program, n)->type,
type)) {
level = REPORT_ERROR;
pike.git/src/program.c:5498:
ID_HIDDEN;
return n2;
} else if ((IDENTIFIERP(n)->id_flags & (ID_INLINE|ID_INHERITED)) ==
(ID_INLINE|ID_INHERITED)) {
/* Hide the overloaded inherited symbol. */
IDENTIFIERP(n)->id_flags |= ID_HIDDEN;
}
} else if ((IDENTIFIERP(n)->id_flags & (ID_EXTERN|ID_INHERITED)) ==
(ID_EXTERN|ID_INHERITED)) {
/* Hide the overloaded inherited symbol. */
- IDENTIFIERP(n)->id_flags |= ID_STATIC|ID_PRIVATE|ID_USED;
+ IDENTIFIERP(n)->id_flags |= ID_PROTECTED|ID_PRIVATE|ID_USED;
}
}
if (flags & ID_EXTERN) {
run_time_type = PIKE_T_FREE;
} else {
run_time_type=compile_type_to_runtime_type(type);
-
+ /* FIXME: Shouldn't these special cases be
+ * in compile_type_to_runtime_type()?
+ */
switch(run_time_type)
{
- case T_INT:
+
case T_OBJECT:
/* Make place for the object subtype. */
-
+ case T_MIXED:
case T_FUNCTION:
-
+ no_this = 1;
+ /* FALLTHRU */
case T_PROGRAM:
run_time_type = T_MIXED;
-
+ break;
+ case T_INT:
+ {
+ INT_TYPE int_range[] = { MAX_INT32, MIN_INT32 };
+ run_time_type = T_MIXED;
+ if (get_int_type_range(type, int_range) &&
+ (int_range[0] > MIN_INT32) && (int_range[1] < MAX_INT32) ) {
+ run_time_type = T_INT;
}
}
-
+ }
+ }
n=low_define_variable(name,type,flags,
low_add_storage(sizeof_variable(run_time_type),
alignof_variable(run_time_type),0),
run_time_type);
-
+ if( no_this )
ID_FROM_INT(Pike_compiler->new_program, n)->identifier_flags |= IDENTIFIER_NO_THIS_REF;
return n;
}
- PMOD_EXPORT int simple_add_variable(const char *name,
- const char *type,
- INT32 flags)
- {
- INT32 ret;
- struct pike_string *name_s;
- struct pike_type *type_s;
- name_s = make_shared_string(name);
- type_s = parse_type(type);
-
- ret=define_variable(name_s, type_s, flags);
- free_string(name_s);
- free_type(type_s);
- return ret;
- }
-
+
PMOD_EXPORT int add_constant(struct pike_string *name,
const struct svalue *c,
INT32 flags)
{
int n;
struct compilation *cc = THIS_COMPILATION;
struct identifier dummy;
struct reference ref;
-
+ struct pike_type *type;
+ unsigned int opt_flags;
+ union idptr func;
#ifdef PROGRAM_BUILD_DEBUG
{
if (c) {
struct pike_type *t = get_type_of_svalue(c);
struct pike_string *d = describe_type (t);
- fprintf (stderr, "%.*sdefining constant (pass=%d): %s ",
+ fprintf (stderr, "%*sdefining constant (pass=%d): %s ",
cc->compilation_depth, "",
Pike_compiler->compiler_pass, d->str);
free_type(t);
free_string (d);
push_string (name);
print_svalue (stderr, --Pike_sp);
fputs (" = ", stderr);
print_svalue (stderr, c);
}
else {
- fprintf (stderr, "%.*sdeclaring constant (pass=%d): ",
+ fprintf (stderr, "%*sdeclaring constant (pass=%d): ",
cc->compilation_depth, "",
Pike_compiler->compiler_pass);
push_string (name);
print_svalue (stderr, --Pike_sp);
}
putc ('\n', stderr);
}
#endif
#if 0
if (!c) {
c = &svalue_int_zero;
}
#endif
#ifdef PIKE_DEBUG
- if(name!=debug_findstring(name))
+ if(name != debug_findstring(name))
Pike_fatal("define_constant on nonshared string.\n");
if (c) {
- check_svalue (c);
+ check_svalue ((struct svalue*)c);
if (TYPEOF(*c) > MAX_TYPE)
/* check_svalue allows some things like T_SVALUE_PTR. */
Pike_fatal ("Invalid type in svalue: %d\n", TYPEOF(*c));
}
#endif
n = isidentifier(name);
if(
#if 1
pike.git/src/program.c:5636:
c = NULL;
} else {
/* Alias for a function or a variable or constant in a surrounding
* scope.
*/
int n = SUBTYPEOF(*c);
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);
+ if (n < 0) return n;
}
return define_alias(name, id->type, flags, depth, n);
}
}
}
if(
#if 1
c &&
#endif
pike.git/src/program.c:5661: Inside #if 1
if(n==-1
#if 1
|| !c
#endif
)
{
yyerror("Pass2: Constant disappeared!");
}else{
struct identifier *id;
id=ID_FROM_INT(Pike_compiler->new_program,n);
- if(id->func.const_info.offset>=0) {
+ if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {
+ /* FIXME: We probably ought to do something here... */
+ } else if(id->func.const_info.offset>=0) {
/* Update the stored constant. */
assign_svalue (&PROG_FROM_INT(Pike_compiler->new_program,n)->
constants[id->func.const_info.offset].sval, c);
} else {
id->run_time_type = (unsigned char) TYPEOF(*c);
id->func.const_info.offset = store_constant(c, 0, 0);
}
free_type(id->type);
if( !(flags & ID_INLINE) )
id->type = get_lax_type_of_svalue( c );
else
id->type = get_type_of_svalue( c );
#ifdef PROGRAM_BUILD_DEBUG
- fprintf (stderr, "%.*sstored constant #%d at %d\n",
+ fprintf (stderr, "%*sstored constant #%d at %d\n",
cc->compilation_depth, "",
n, id->func.const_info.offset);
#endif
}
return n;
}
#ifdef PIKE_DEBUG
if(Pike_compiler->new_program->flags & (PROGRAM_FIXED | PROGRAM_OPTIMIZED))
Pike_fatal("Attempting to add constant to fixed program\n");
- if(Pike_compiler->compiler_pass==2) {
+ if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
dump_program_tables(Pike_compiler->new_program, 2);
Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"
" Attempted to add the identifier \"%s\"\n",
name->str);
}
#endif
- copy_shared_string(dummy.name, name);
- dummy.identifier_flags = IDENTIFIER_CONSTANT;
- dummy.filename_strno = store_prog_string(cc->lex.current_file);
- dummy.linenumber = cc->lex.current_line;
-
+
#if 1
if (c) {
#endif
if( !(flags & ID_INLINE) )
- dummy.type = get_lax_type_of_svalue( c );
+ type = get_lax_type_of_svalue( c );
else
- dummy.type = get_type_of_svalue( c );
- dummy.run_time_type = (unsigned char) TYPEOF(*c);
- dummy.func.const_info.offset = store_constant(c, 0, 0);
- dummy.opt_flags=OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND;
+ type = get_type_of_svalue( c );
+ func.const_info.offset = store_constant(c, 0, 0);
+ opt_flags = OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND;
if(TYPEOF(*c) == PIKE_T_PROGRAM && (c->u.program->flags & PROGRAM_CONSTANT))
- dummy.opt_flags=0;
+ opt_flags = 0;
#if 1
}
else {
- copy_pike_type(dummy.type, mixed_type_string);
- dummy.run_time_type=T_MIXED;
- dummy.func.const_info.offset = -1;
- dummy.opt_flags=0;
+ copy_pike_type(type, mixed_type_string);
+ func.const_info.offset = -1;
+ opt_flags = 0;
}
#endif
if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;
ref.id_flags=flags;
- ref.identifier_offset=Pike_compiler->new_program->num_identifiers;
+ ref.identifier_offset =
+ low_add_identifier(cc, type, name,
+ IDENTIFIER_CONSTANT, opt_flags,
+ func, c ? TYPEOF(*c) : T_MIXED);
ref.inherit_offset=0;
ref.run_time_type = PIKE_T_UNKNOWN;
- #ifdef PROFILING
- dummy.self_time=0;
- dummy.num_calls=0;
- dummy.recur_depth=0;
- dummy.total_time=0;
- #endif
+ free_pike_type(type);
- debug_add_to_identifiers(dummy);
-
+
if(n != -1)
{
int overridden;
if(IDENTIFIERP(n)->id_flags & ID_FINAL)
my_yyerror("Illegal to redefine 'final' identifier %S", name);
- if(!TEST_COMPAT(7,2) &&
- IDENTIFIER_IS_VARIABLE(ID_FROM_INT(Pike_compiler->new_program,
+ if(IDENTIFIER_IS_VARIABLE(ID_FROM_INT(Pike_compiler->new_program,
n)->identifier_flags))
{
my_yyerror("Illegal to redefine variable %S as constant.", name);
}
/* not inherited */
if(Pike_compiler->new_program->identifier_references[n].inherit_offset == 0)
{
my_yyerror("Identifier %S defined twice.", name);
return n;
pike.git/src/program.c:5871:
{
INT32 ret;
struct svalue tmp;
if (p) {
SET_SVAL(tmp, T_PROGRAM, 0, program, p);
} else {
/* Probable compilation error in a C-module. */
SET_SVAL(tmp, T_INT, NUMBER_UNDEFINED, integer, 0);
my_yyerror("Program constant \"%s\" is NULL.", name);
}
+ if (!Pike_compiler->new_program) return -1;
ret=simple_add_constant(name, &tmp, flags);
return ret;
}
PMOD_EXPORT int add_object_constant(const char *name,
struct object *o,
INT32 flags)
{
INT32 ret;
struct svalue tmp;
pike.git/src/program.c:5920:
id=make_shared_binary_string(name,namelen);
ret=add_constant(id, &tmp, flags);
/* The following is not really true, but it helps encode_value()... */
Pike_compiler->new_program->flags |=
tmp.u.program->flags & PROGRAM_HAS_C_METHODS;
free_string(id);
free_svalue(&tmp);
return ret;
}
- /*
- * define a new function
+ /**
+ * Define a new function.
+ *
* if func isn't given, it is supposed to be a prototype.
*/
INT32 define_function(struct pike_string *name,
struct pike_type *type,
unsigned flags,
unsigned function_flags,
union idptr *func,
unsigned opt_flags)
{
struct compilation *c = THIS_COMPILATION;
struct program *prog = Pike_compiler->new_program;
- struct identifier *funp,fun;
+ struct identifier *funp;
+ union idptr idptr;
struct reference ref;
struct svalue *lfun_type;
int run_time_type = T_FUNCTION;
INT32 i;
int getter_setter = -1;
int is_setter = 0;
CHECK_COMPILER();
#ifdef PROGRAM_BUILD_DEBUG
{
struct pike_string *d = describe_type (type);
- fprintf (stderr, "%.*sdefining function (pass=%d): %s ",
+ fprintf (stderr, "%*sdefining function (pass=%d): %s ",
c->compilation_depth, "", Pike_compiler->compiler_pass, d->str);
free_string (d);
push_string (name);
print_svalue (stderr, --Pike_sp);
putc ('\n', stderr);
}
#endif
#ifdef PROFILING
fun.self_time=0;
pike.git/src/program.c:5970:
#endif
/* If this is an lfun, match against the predefined type. */
if ((lfun_type = low_mapping_string_lookup(lfun_types, name))) {
int orig_pragmas = c->lex.pragmas;
#ifdef PIKE_DEBUG
if (TYPEOF(*lfun_type) != T_TYPE) {
Pike_fatal("Bad entry in lfun_types for key \"%s\"\n", name->str);
}
#endif /* PIKE_DEBUG */
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
/* Inhibit deprecation warnings during the comparison. */
c->lex.pragmas |= ID_NO_DEPRECATION_WARNINGS;
if (!pike_types_le(type, lfun_type->u.type)) {
int level = REPORT_NOTICE;
if (!match_types(type, lfun_type->u.type)) {
level = REPORT_ERROR;
} else if (c->lex.pragmas & ID_STRICT_TYPES) {
level = REPORT_WARNING;
}
if (level != REPORT_NOTICE) {
yytype_report(level, NULL, 0, lfun_type->u.type,
NULL, 0, type, 0,
"Type mismatch for callback function %S:", name);
}
}
c->lex.pragmas = orig_pragmas;
-
+ }
} else if (((name->len > 3) &&
(index_shared_string(name, 0) == '`') &&
(index_shared_string(name, 1) == '-') &&
(index_shared_string(name, 2) == '>')) ||
((name->len > 1) &&
(index_shared_string(name, 0) == '`') &&
- ((index_shared_string(name, 1) >= 256) ||
- isidchar(index_shared_string(name, 1))))) {
+ wide_isidchar(index_shared_string(name, 1)))) {
/* Getter setter. */
struct pike_string *symbol = NULL;
struct pike_type *symbol_type = NULL;
struct pike_type *gs_type = NULL;
int delta = 1; /* new-style */
if (index_shared_string(name, 1) == '-') {
/* Getter setter (old-style). */
delta = 3;
}
if (index_shared_string(name, name->len-1) != '=') {
pike.git/src/program.c:6049:
if ((i >= 0) &&
!((ref = PTR_FROM_INT(prog, i))->id_flags & ID_INHERITED)) {
/* Not an inherited symbol. */
struct identifier *id = ID_FROM_INT(prog, i);
if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags)) {
my_yyerror("Illegal to redefine function %S with variable.", symbol);
} else if (id->run_time_type != PIKE_T_GET_SET) {
my_yyerror("Illegal to redefine a current variable with a getter/setter: %S.", symbol);
} else {
if ((ref->id_flags | ID_USED) != (flags | ID_USED)) {
- if (Pike_compiler->compiler_pass == 1) {
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {
yywarning("Modifier mismatch for variable %S.", symbol);
}
ref->id_flags &= flags | ID_USED;
}
getter_setter = i;
}
/* FIXME: Update id->type here. */
} else {
struct identifier *id;
i = low_define_variable(symbol, symbol_type, flags,
pike.git/src/program.c:6084:
*/
flags |= ID_PROTECTED /* | ID_PRIVATE | ID_INLINE | ID_USED */;
free_type(symbol_type);
free_string(symbol);
}
}
if(IDENTIFIER_IS_C_FUNCTION(function_flags))
prog->flags |= PROGRAM_HAS_C_METHODS;
- if (Pike_compiler->compiler_pass == 1) {
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {
/* Mark the type as tentative by setting the runtime-type
* to T_MIXED.
*
* NOTE: This should be reset to T_FUNCTION in pass 2.
*/
run_time_type = T_MIXED;
}
i = isidentifier(name);
- if (Pike_compiler->compiler_pass == 1) {
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) {
if (flags & ID_VARIANT) {
if (i >= 0) {
if (!is_variant_dispatcher(prog, i)) {
/* This function will be the termination function for
* our variant dispatcher.
*/
struct reference ref = prog->identifier_references[i];
/* Make sure to not get complaints about multiple
* definitions when adding the variant dispatcher.
*/
pike.git/src/program.c:6169:
}
}
if(i >= 0)
{
int overridden;
/* already defined */
#ifdef PROGRAM_BUILD_DEBUG
- fprintf(stderr, "%.*sexisted as identifier #%d\n",
+ fprintf(stderr, "%*sexisted as identifier #%d\n",
c->compilation_depth, "", i);
#endif
funp = ID_FROM_INT(prog, i);
ref = prog->identifier_references[i];
if (funp->identifier_flags & IDENTIFIER_HAS_BODY)
/* Keep this flag. */
function_flags |= IDENTIFIER_HAS_BODY;
pike.git/src/program.c:6199:
struct identifier *id = ID_FROM_INT(prog, getter_setter);
(&id->func.gs_info.getter)[is_setter] = i;
}
return i;
}
/* Note: The type from pass 1 may be incompatible with the one from
* pass 2. Only do this in pass 2, and only if the previous
* type isn't from pass 1.
*/
- if ((Pike_compiler->compiler_pass == 2) &&
+ if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
(funp->run_time_type == T_FUNCTION)) {
/* match types against earlier prototype or vice versa */
if(!match_types(type, funp->type))
{
yytype_report(REPORT_ERROR, NULL, 0,
funp->type,
NULL, 0, type, 0,
"Prototype doesn't match for function %S.", name);
}
}
pike.git/src/program.c:6227:
funp->identifier_flags=function_flags;
funp->run_time_type = run_time_type;
funp->opt_flags &= opt_flags;
free_type(funp->type);
copy_pike_type(funp->type, type);
}else{
#ifdef PROGRAM_BUILD_DEBUG
- fprintf(stderr, "%.*sidentifier was inherited\n",
+ fprintf(stderr, "%*sidentifier was inherited\n",
c->compilation_depth, "");
#endif
if((ref.id_flags & ID_FINAL)
#if 0
&& !(funp->func.offset == -1)
#endif
)
{
my_yyerror("Illegal to redefine 'final' function %S.", name);
}
- if (!(flags & ID_VARIANT) && (Pike_compiler->compiler_pass == 1) &&
+ if (!(flags & ID_VARIANT) &&
+ (Pike_compiler->compiler_pass == COMPILER_PASS_FIRST) &&
(funp->func.c_fun == f_dispatch_variant) &&
(!func || (func->c_fun != f_dispatch_variant) ||
!IDENTIFIER_IS_C_FUNCTION(function_flags)) &&
IDENTIFIER_IS_C_FUNCTION(funp->identifier_flags)) {
/* Overriding a variant function dispatcher with
* a non-variant function in pass 1.
*
* Hide the corresponding variant functions.
*/
int j = prog->num_identifier_references;
pike.git/src/program.c:6267:
my_yyerror("Overloading variant function %S with non-variant in same class.",
name);
}
prog->identifier_references[j].id_flags |= ID_HIDDEN;
}
}
if(ref.id_flags & ID_INLINE)
{
#ifdef PROGRAM_BUILD_DEBUG
- fprintf(stderr, "%.*sidentifier is local\n",
+ fprintf(stderr, "%*sidentifier is local\n",
c->compilation_depth, "");
#endif
/* Hide the previous definition, and make a new definition. */
prog->identifier_references[i].id_flags |= ID_PROTECTED;
goto make_a_new_def;
}
/* Otherwise we alter the existing definition */
#ifdef PROGRAM_BUILD_DEBUG
- fprintf(stderr, "%.*saltering the existing definition\n",
+ fprintf(stderr, "%*saltering the existing definition\n",
c->compilation_depth, "");
#endif
- copy_shared_string(fun.name, name);
- copy_pike_type(fun.type, type);
- fun.filename_strno = store_prog_string(c->lex.current_file);
- fun.linenumber = c->lex.current_line;
-
- fun.run_time_type = run_time_type;
-
- fun.identifier_flags=function_flags;
-
+
if(func)
- fun.func = *func;
+ idptr = *func;
else
- fun.func.offset = -1;
+ idptr.offset = -1;
- fun.opt_flags = opt_flags;
-
- ref.identifier_offset = prog->num_identifiers;
- debug_add_to_identifiers(fun);
+ ref.identifier_offset =
+ low_add_identifier(c, type, name,
+ function_flags, opt_flags,
+ idptr, run_time_type);
}
if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;
ref.inherit_offset = 0;
ref.id_flags = flags;
if (flags & ID_VARIANT) {
ref.id_flags |= ID_USED;
prog->identifier_references[i] = ref;
overridden = i;
pike.git/src/program.c:6348:
}
return overridden;
}
/* NOTE: At this point we already have the identifier in the
* new program, and just need to add the reference.
*/
} else {
make_a_new_def:
#ifdef PIKE_DEBUG
- if(Pike_compiler->compiler_pass==2)
- Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n");
+ if(Pike_compiler->compiler_pass == COMPILER_PASS_LAST)
+ Pike_fatal("Internal error: Not allowed to add more identifiers during second compiler pass.\n"
+ "Added identifier: \"%s\"\n", name->str);
#endif
/* Define a new function */
- copy_shared_string(fun.name, name);
- copy_pike_type(fun.type, type);
- fun.filename_strno = store_prog_string(c->lex.current_file);
- fun.linenumber = c->lex.current_line;
-
- fun.identifier_flags=function_flags;
- fun.run_time_type = run_time_type;
-
+
if(func)
- fun.func = *func;
+ idptr = *func;
else
- fun.func.offset = -1;
+ idptr.offset = -1;
- fun.opt_flags = opt_flags;
-
+
#ifdef PIKE_DEBUG
if (a_flag > 5) {
fprintf(stderr,
"Adding new function #%d: '%s'\n"
" identifier_flags:0x%02x opt_flags:0x%04x\n",
prog->num_identifiers,
- fun.name->str,
- fun.identifier_flags, fun.opt_flags);
+ name->str,
+ function_flags, opt_flags);
}
#endif /* PIKE_DEBUG */
- i = prog->num_identifiers;
+ i = low_add_identifier(c, type, name,
+ function_flags, opt_flags,
+ idptr, run_time_type);
- debug_add_to_identifiers(fun);
-
+
if (flags & ID_PRIVATE) flags |= ID_LOCAL|ID_PROTECTED;
ref.id_flags = flags;
ref.identifier_offset = i;
ref.inherit_offset = 0;
}
ref.run_time_type = PIKE_T_UNKNOWN;
/* Add the reference. */
i = prog->num_identifier_references;
add_to_identifier_references(ref);
#ifdef PROGRAM_BUILD_DEBUG
- fprintf(stderr, "%.*sadded new definition #%d\n",
+ fprintf(stderr, "%*sadded new definition #%d\n",
c->compilation_depth, "", i);
#endif
if (getter_setter != -1) {
struct identifier *id = ID_FROM_INT(prog, getter_setter);
INT32 old_i = (&id->func.gs_info.getter)[is_setter];
if (old_i >= 0) {
my_yyerror("Multiple definitions for %S.", name);
}
(&id->func.gs_info.getter)[is_setter] = i;
pike.git/src/program.c:6444: Inside #if 0
ref.identifier_offset = i;
ref.inherit_offset = 0;
ref.run_time_type = PIKE_T_UNKNOWN;
add_to_identifier_references(ref);
state->new_program->flags |= PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT;
return j;
}
#endif /* 0 */
- /* Identifier lookup
+ /**
+ * Identifier lookup
*
* The search algorithm has changed several times during Pike 7.3.
*
* It now (Pike 7.3.33 and later) looks up the most recent definition
* in the most recent inherit.
*
* In Pike 7.3.23 -- 7.3.32 it looked up the most recent definition
* with the least inherit depth.
*
* In Pike 7.3.22 and prior, it looked up the last definition regardless
pike.git/src/program.c:6511:
* C---B-+-foo Pike 7.3.23 ---
* |
* +-A---foo --- Pike 7.3.22
*
* Lookup of identifier "foo" in B():
*
* B-+-foo All versions of Pike
* |
* +-A---foo
*
- * External lookup of identifier "foo" in E():
+ * External lookup of identifier "foo" in F():
*
* F-+-A---foo --- Pike 7.7.33
* |
* +-E---foo Pike 7.7.34 ---
*/
- PMOD_EXPORT int really_low_find_shared_string_identifier(struct pike_string *name,
- struct program *prog,
+ PMOD_EXPORT int really_low_find_shared_string_identifier(const struct pike_string *name,
+ const struct program *prog,
int flags)
{
struct reference *funp;
struct identifier *fun;
int id, i, depth, last_inh;
#if 0
- CDFPRINTF((stderr,"th(%ld) %p Trying to find %s flags=%d\n",
- (long)th_self(), prog, name->str, flags));
+ CDFPRINTF("th(%ld) %p Trying to find %s flags=%d\n",
+ (long)th_self(), prog, name->str, flags);
#endif
#ifdef PIKE_DEBUG
if (!prog) {
Pike_fatal("really_low_find_shared_string_identifier(\"%s\", NULL, %d)\n"
"prog is NULL!\n", name->str, flags);
}
#endif /* PIKE_DEBUG */
id = -1;
pike.git/src/program.c:6595:
int really_low_find_variant_identifier(struct pike_string *name,
struct program *prog,
struct pike_type *type,
int start_pos,
int flags)
{
struct reference *funp;
struct identifier *fun;
int id, i, depth, last_inh;
+ int tentative = -1;
#if 1
#ifdef COMPILER_DEBUG
fprintf(stderr,"th(%ld) %p Trying to find variant \"%s\" start=%d flags=%d\n"
" type: ",
(long)th_self(), prog, name->str, start_pos, flags);
simple_describe_type(type);
fprintf(stderr, "\n");
#endif
#endif
pike.git/src/program.c:6636:
{
funp = prog->identifier_references + i;
if(funp->id_flags & ID_HIDDEN) continue;
if(!(funp->id_flags & ID_VARIANT)) continue;
if(funp->id_flags & ID_PROTECTED)
if(!(flags & SEE_PROTECTED))
continue;
fun = ID_FROM_PTR(prog, funp);
/* if(fun->func.offset == -1) continue; * Prototype */
if(!is_same_string(fun->name,name)) continue;
- if(type && (fun->type != type)) continue;
+ if(type && (fun->type != type)) {
+ if ((Pike_compiler->compiler_pass != COMPILER_PASS_FIRST) &&
+ !(funp->id_flags & ID_INHERITED) &&
+ match_types(fun->type, type)) {
+ tentative = i;
+ }
+ continue;
+ }
if(funp->id_flags & ID_INHERITED)
{
struct inherit *inh = INHERIT_FROM_PTR(prog, funp);
if ((funp->id_flags & ID_PRIVATE) && !(flags & SEE_PRIVATE)) continue;
if (!depth || (depth > inh->inherit_level)) {
if (id != -1) {
int j;
int min_level = depth;
for (j=last_inh-1; j > funp->inherit_offset; j--) {
struct inherit *inh2 = prog->inherits + j;
pike.git/src/program.c:6665:
}
/* Found new identifier on the path from the old identifier to
* the root.
*/
}
last_inh = funp->inherit_offset;
depth = inh->inherit_level;
id = i;
}
} else {
- CDFPRINTF((stderr, "Found %d\n", i));
+ CDFPRINTF("Found %d\n", i);
return i;
}
}
- CDFPRINTF((stderr, "Found %d\n", id));
+ if ((id < 0) && (tentative >= 0)) {
+ if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
+ // Usually due to forward-referring types. The tentative match
+ // is often correct, but may in some cases be wrong eg due to
+ // having fall back implementations that use the mixed type.
+ yytype_report(REPORT_WARNING,
+ NULL, 0, ID_FROM_INT(prog, tentative)->type,
+ NULL, 0, type,
+ 0, "Variant type mismatch in second pass for %S.",
+ name);
+ }
+ id = tentative;
+ }
+ CDFPRINTF("Found %d\n", id);
return id;
}
/**
* This is the dispatcher function for variant functions.
*
* cf end_first_pass().
*/
static void f_dispatch_variant(INT32 args)
{
struct pike_frame *fp = Pike_fp;
struct program *prog = fp->context->prog;
struct reference *funp = PTR_FROM_INT(fp->current_program, fp->fun);
struct identifier *id = ID_FROM_PTR(fp->current_program, funp);
struct pike_string *name = id->name;
int fun_num = prog->num_identifier_references;
int flags = 0;
-
+ int best = -1;
+ struct pike_type *t;
+ int expected = 0;
/* NB: The following is mostly to support a potential future
* case where a mixed set of protections would cause
* multiple dispatchers with the same name to be added
* (but different protection (and types)).
*/
if (funp->id_flags & ID_PRIVATE) {
flags = SEE_PRIVATE|SEE_PROTECTED;
} else if (funp->id_flags & ID_PROTECTED) {
flags = SEE_PROTECTED;
}
while ((fun_num = really_low_find_variant_identifier(name, prog, NULL,
fun_num, flags)) != -1) {
int i;
- struct pike_type *t;
+
struct pike_type *ret;
id = ID_FROM_INT(prog, fun_num);
add_ref(t = id->type);
/* Check whether the type is compatible with our arguments. */
for (i = 0; i < args; i++) {
- struct pike_type *cont = check_call_svalue(t, 0, Pike_sp+i - args);
+ struct pike_type *cont =
+ check_call_svalue(t, 0, Pike_sp+i - (args + expected));
+ if (!cont && (i >= best)) {
+ if ((i > best) && expected) {
+ pop_n_elems(expected);
+ expected = 0;
+ }
+ best = i;
+ push_type_value(t);
+ expected++;
+ t = NULL;
+ break;
+ } else {
free_type(t);
-
+ }
if (!(t = cont)) break;
}
if (!t) continue;
ret = new_get_return_type(t, 0);
-
+
+ if (!ret && (i+1 >= best)) {
+ if (((i+1) > best) && expected) {
+ pop_n_elems(expected);
+ expected = 0;
+ }
+ best = i+1;
+ push_type_value(t);
+ expected++;
+ continue;
+ }
free_type(t);
if (!ret) continue;
free_type(ret);
-
+ if (expected) {
+ pop_n_elems(expected);
+ }
+
/* Found a function to call! */
apply_current(fun_num, args);
return;
}
- Pike_error("Invalid arguments to %S()!\n", name);
+ if (!expected) {
+ /* No variants listed? */
+ Pike_error("No variants of %S() to dispatch to!\n", name);
}
-
+ if (expected > 1) {
+ f_or(expected);
+ }
+ f___get_first_arg_type(1);
+ if (!UNSAFE_IS_ZERO(Pike_sp-1)) {
+ if (best < args) {
+ Pike_error("Bad argument %d to %S(). Expected %O.\n",
+ best + 1, name, Pike_sp-1);
+ } else {
+ Pike_error("Too few arguments to %S(). Expected %O.\n",
+ name, Pike_sp-1);
+ }
+ } else {
+ Pike_error("Too many arguments to %S().\n", name);
+ }
+ }
- PMOD_EXPORT int low_find_lfun(struct program *p, ptrdiff_t lfun)
+ PMOD_EXPORT int low_find_lfun(struct program *p, enum LFUN lfun)
{
- struct pike_string *lfun_name = lfun_strings[lfun];
+ const struct pike_string *lfun_name;
unsigned int flags = 0;
- #if 0
+ int i;
struct identifier *id;
-
+ #ifdef PIKE_DEBUG
+ if ((size_t)lfun >= NELEM(lfun_strings)) {
+ return find_lfun_fatal(p, lfun);
+ }
#endif
- int i =
- really_low_find_shared_string_identifier(lfun_name,
+ lfun_name = lfun_strings[lfun];
+
+ i = really_low_find_shared_string_identifier(lfun_name,
dmalloc_touch(struct program *,
p),
SEE_PROTECTED);
- #if 0
- if (i < 0 || !(p->flags & PROGRAM_FIXED)) return i;
+
+ if ((i < 0) && (lfun == LFUN__DESTRUCT)) {
+ /* Try the Pike 8.0 compatibility name. */
+ i = really_low_find_shared_string_identifier(compat_lfun_destroy_string,
+ dmalloc_touch(struct program *,
+ p),
+ SEE_PROTECTED);
+ if ((i >= 0) && !(p->flags & PROGRAM_FINISHED) && !TEST_COMPAT(8,0)) {
+ struct compilation *c = MAYBE_THIS_COMPILATION;
+ if (c && !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS)) {
+ yywarning("Compat: Substituting destroy() for _destruct().");
+ }
+ }
+ }
+
+ if (i < 0 || !(p->flags & PROGRAM_FIXED)) {
+ return i;
+ }
id = ID_FROM_INT(p, i);
if (IDENTIFIER_IS_PIKE_FUNCTION(id->identifier_flags) &&
(id->func.offset == -1)) {
/* Function prototype. */
return -1;
}
- #endif /* 0 */
+
return i;
}
-
+ #ifdef PIKE_DEBUG
+ PMOD_EXPORT int find_lfun_fatal(struct program *UNUSED(p), enum LFUN lfun)
+ {
+ Pike_fatal("Invalid lfun number: %d\n", lfun);
+ UNREACHABLE(return -1);
+ }
+ #endif
int lfun_lookup_id(struct pike_string *lfun_name)
{
struct svalue *id = low_mapping_string_lookup(lfun_ids, lfun_name);
if (!id) return -1;
if (TYPEOF(*id) == T_INT) return id->u.integer;
my_yyerror("Bad entry in lfun lookup table for %S.", lfun_name);
return -1;
}
- /*
- * lookup the number of a function in a program given the name in
+ /**
+ * Lookup the number of a function in a program given the name in
* a shared_string
*/
- int low_find_shared_string_identifier(struct pike_string *name,
- struct program *prog)
+ int low_find_shared_string_identifier(const struct pike_string *name,
+ const struct program *prog)
{
int max,min,tst;
struct identifier *fun;
if(prog->flags & PROGRAM_FIXED)
{
unsigned short *funindex = prog->identifier_index;
size_t val_n = PTR_TO_INT (name);
#ifdef PIKE_DEBUG
pike.git/src/program.c:6820: Inside #if defined(FIND_FUNCTION_HASHSIZE)
{
struct pike_string *name;
int id;
int fun;
};
static struct ff_hash cache[FIND_FUNCTION_HASHSIZE];
#endif
int find_shared_string_identifier(struct pike_string *name,
- struct program *prog)
+ const struct program *prog)
{
#ifdef PIKE_DEBUG
if (!prog) {
Pike_fatal("find_shared_string_identifier(): No program!\n"
"Identifier: %s%s%s\n",
name?"\"":"", name?name->str:"NULL", name?"\"":"");
}
#endif /* PIKE_DEBUG */
#ifdef FIND_FUNCTION_HASHSIZE
if(prog -> flags & PROGRAM_FIXED
pike.git/src/program.c:6854: Inside #if defined(FIND_FUNCTION_HASHSIZE)
if(cache[hashval].name) free_string(cache[hashval].name);
copy_shared_string(cache[hashval].name,name);
cache[hashval].id=prog->id;
return cache[hashval].fun=low_find_shared_string_identifier(name,prog);
}
#endif /* FIND_FUNCTION_HASHSIZE */
return low_find_shared_string_identifier(name,prog);
}
- PMOD_EXPORT int find_identifier(const char *name,struct program *prog)
+ PMOD_EXPORT int find_identifier(const char *name,const struct program *prog)
{
struct pike_string *n;
if(!prog) {
if (strlen(name) < 1024) {
Pike_error("Lookup of identifier %s in destructed object.\n", name);
} else {
Pike_error("Lookup of long identifier in destructed object.\n");
}
}
n=findstring(name);
if(!n) return -1;
return find_shared_string_identifier(n,prog);
}
int store_prog_string(struct pike_string *str)
{
unsigned int i;
-
+ if( str->refs > 1 )
for (i=0;i<Pike_compiler->new_program->num_strings;i++)
if (Pike_compiler->new_program->strings[i] == str)
return i;
reference_shared_string(str);
add_to_strings(str);
- return i;
+ return Pike_compiler->new_program->num_strings-1;
}
/* NOTE: O(n²)! */
int store_constant(const struct svalue *foo,
int equal,
struct pike_string *UNUSED(constant_name))
{
struct program_constant tmp;
volatile unsigned int e;
JMP_BUF jmp;
if (SETJMP(jmp)) {
handle_compile_exception ("Error comparing constants.");
/* Assume that if `==() throws an error, the svalues aren't equal. */
e = Pike_compiler->new_program->num_constants;
} else {
-
+ if(!equal &&
+ (TYPEOF(*foo) == PIKE_T_MAPPING ||
+ TYPEOF(*foo) == PIKE_T_MULTISET ||
+ TYPEOF(*foo) == PIKE_T_STRING ||
+ TYPEOF(*foo) == PIKE_T_ARRAY )) /* no possibility of comparator. Check refs first. */
+ {
+ if(*foo->u.refs == 1 )
+ {
+ e = Pike_compiler->new_program->num_constants;
+ goto not_present;
+ }
+ }
+
for(e=0;e<Pike_compiler->new_program->num_constants;e++)
{
struct program_constant *c = Pike_compiler->new_program->constants+e;
if (TYPEOF(*foo) == TYPEOF(c->sval)) {
/* Make sure only to compare within the same basic type. */
if (TYPEOF(*foo) == T_OBJECT) {
/* Special case objects -- We don't want strange LFUN effects... */
if ((foo->u.object == c->sval.u.object) &&
(SUBTYPEOF(*foo) == SUBTYPEOF(c->sval))) {
UNSETJMP(jmp);
return e;
}
} else if (TYPEOF(*foo) == T_INT) {
if (foo->u.integer == c->sval.u.integer) {
/* Make sure UNDEFINED is kept (but not in compat mode). */
- if (foo->u.integer || (SUBTYPEOF(*foo) == SUBTYPEOF(c->sval)) ||
- TEST_COMPAT(7, 6)) {
+ if (foo->u.integer || (SUBTYPEOF(*foo) == SUBTYPEOF(c->sval))){
UNSETJMP(jmp);
return e;
}
}
} else if(equal ? is_equal(& c->sval,foo) : is_eq(& c->sval,foo)) {
UNSETJMP(jmp);
return e;
}
}
}
}
-
+ not_present:
UNSETJMP(jmp);
assign_svalue_no_free(&tmp.sval,foo);
#if 0
if((tmp.name=constant_name)) add_ref(constant_name);
#else /* !0 */
tmp.offset = -1;
#endif /* 0 */
add_to_constants(tmp);
return e;
}
/*
* program examination functions available from Pike.
*/
struct array *program_indices(struct program *p)
{
- int e;
+ int i;
int n = 0;
struct array *res;
- for (e = p->num_identifier_references; e--; ) {
+ for (i = p->num_identifier_index; i--; ) {
struct identifier *id;
-
+ int e = p->identifier_index[i];
if (p->identifier_references[e].id_flags &
(ID_HIDDEN|ID_VARIANT|ID_PROTECTED|ID_PRIVATE)) {
continue;
}
id = ID_FROM_INT(p, e);
if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {
/* FIXME!
*/
continue;
} else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {
pike.git/src/program.c:6983:
}
f_aggregate(n);
res = Pike_sp[-1].u.array;
add_ref(res);
pop_stack();
return(res);
}
struct array *program_values(struct program *p)
{
- int e;
+ int i;
int n = 0;
struct array *res;
- for(e = p->num_identifier_references; e--; ) {
+ for(i = p->num_identifier_index; i--; ) {
struct identifier *id;
-
+ int e = p->identifier_index[i];
if (p->identifier_references[e].id_flags &
(ID_HIDDEN|ID_VARIANT|ID_PROTECTED|ID_PRIVATE)) {
continue;
}
id = ID_FROM_INT(p, e);
if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {
/* FIXME!
*/
continue;
} else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {
pike.git/src/program.c:7022:
}
f_aggregate(n);
res = Pike_sp[-1].u.array;
add_ref(res);
pop_stack();
return(res);
}
struct array *program_types(struct program *p)
{
- int e;
+ int i;
int n = 0;
struct array *res;
- for (e = p->num_identifier_references; e--; ) {
+ for (i = p->num_identifier_index; i--; ) {
struct identifier *id;
-
+ int e = p->identifier_index[i];
if (p->identifier_references[e].id_flags &
(ID_HIDDEN|ID_VARIANT|ID_PROTECTED|ID_PRIVATE)) {
continue;
}
id = ID_FROM_INT(p, e);
if (IDENTIFIER_IS_ALIAS(id->identifier_flags)) {
/* FIXME!
*/
continue;
} else if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {
pike.git/src/program.c:7100:
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);
- #if 0 && defined (COMPILER_DEBUG)
- safe_pike_fprintf (stderr, "low_program_index_no_free1 %O->%S: %O\n",
- what, s, to);
- #endif
+
return 1;
}
}
if (IDENTIFIER_IS_CONSTANT(id->identifier_flags)) {
if (id->func.const_info.offset >= 0) {
struct program *p2 = PROG_FROM_INT(p, e);
struct svalue *val = &p2->constants[id->func.const_info.offset].sval;
assign_svalue_no_free(to, val);
} else {
/* Prototype constant. */
SET_SVAL(*to, T_INT, NUMBER_NUMBER, integer, 0);
}
- #if 0 && defined (COMPILER_DEBUG)
- safe_pike_fprintf (stderr, "low_program_index_no_free2 %O->%S: %O\n",
- what, s, to);
- #endif
+
return 1;
}
return 0;
}
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 (TYPEOF(*what) == T_PROGRAM) {
p = what->u.program;
} else if ((TYPEOF(*what) == T_FUNCTION) &&
(SUBTYPEOF(*what) != FUNCTION_BUILTIN) &&
pike.git/src/program.c:7157:
p = sub->u.program;
parent_identifier = SUBTYPEOF(*what);
} else {
/* Not a program. */
return 0;
}
if (TYPEOF(*ind) != T_STRING) {
Pike_error("Can't index a program with a %s (expected string)\n",
get_name_of_type(TYPEOF(*ind)));
}
- s = ind->u.string;
- e=find_shared_string_identifier(s, p);
+ e=find_shared_string_identifier(ind->u.string, p);
if(e!=-1)
{
if (low_program_index_no_free(to, p, e, parent, parent_identifier))
return 1;
}
SET_SVAL(*to, T_INT, NUMBER_UNDEFINED, integer, 0);
return 1;
}
pike.git/src/program.c:7212:
* number entry is stored. The first stored entry (at pc 0) is the
* file and line where the program is defined, if they are known. The
* definition line for a top level program is set to 0.
*/
INT_TYPE get_small_number(char **q)
{
/* This is a workaround for buggy cc & Tru64 */
unsigned char *addr = (unsigned char *)*q;
INT_TYPE ret = *((signed char *)addr);
- ret=*(signed char *)*q;
+
addr++;
switch(ret)
{
case -127:
- ret = (((signed char *)addr)[0]<<8) | addr[1];
+ ret = (INT16)get_unaligned_be16(addr);
addr += 2;
if (!ret) {
/* 64-bit signed number. */
- ret = *((signed char *)addr++);
- ret = (ret<<8) | *(addr++);
- ret = (ret<<8) | *(addr++);
- ret = (ret<<8) | *(addr++);
- ret = (ret<<8) | *(addr++);
- ret = (ret<<8) | *(addr++);
- ret = (ret<<8) | *(addr++);
- ret = (ret<<8) | *(addr++);
+ ret = get_unaligned_be64(addr);
+ addr += 8;
}
break;
case -128:
- ret = (((signed char *)addr)[0]<<24) | (addr[1]<<16) |
- (addr[2]<<8) | addr[3];
+ ret = (INT32)get_unaligned_be32(addr);
addr += 4;
break;
#ifdef PIKE_DEBUG
case 127:
Pike_fatal("get_small_number used on filename entry\n");
#endif
}
*q = (char *)addr;
return ret;
pike.git/src/program.c:7451:
if(Pike_compiler->last_line != current_line ||
Pike_compiler->last_file != current_file)
{
if(Pike_compiler->last_file != current_file)
{
if(Pike_compiler->last_file) free_string(Pike_compiler->last_file);
add_to_linenumbers(127);
insert_small_number(store_prog_string(current_file));
copy_shared_string(Pike_compiler->last_file, current_file);
}
- insert_small_number(DO_NOT_WARN((INT32)(PIKE_PC-Pike_compiler->last_pc)));
+ insert_small_number((INT32)(PIKE_PC-Pike_compiler->last_pc));
insert_small_number(current_line-Pike_compiler->last_line);
Pike_compiler->last_line = current_line;
- Pike_compiler->last_pc = DO_NOT_WARN((INT32)PIKE_PC);
+ Pike_compiler->last_pc = (INT32)PIKE_PC;
}
}
#define FIND_PROGRAM_LINE(prog, file, line) do { \
char *pos = prog->linenumbers; \
file = NULL; \
\
if (pos < prog->linenumbers + prog->num_linenumbers) { \
if (*pos == 127) { \
int strno; \
pike.git/src/program.c:7511:
if(shift)
{
size_t bufsize;
char *buffer;
PCHARP from=MKPCHARP(file, shift);
size_t ptr=0;
if (malloced) {
bufsize = len + 21;
buffer = malloc (bufsize);
+ if(!buffer) return NULL;
}
else {
bufsize = NELEM(buf) - 1;
buffer = buf;
}
for (; len--; INC_PCHARP(from, 1))
{
size_t space;
int chr = EXTRACT_PCHARP(from);
space = chr > 255 ? 20 : 1;
if (ptr + space > bufsize) {
if (malloced) {
-
+ char *new_buffer;
bufsize = (bufsize << 1) + space + 1;
- buffer = realloc (buffer, bufsize);
+ new_buffer = realloc (buffer, bufsize);
+ if(!new_buffer)
+ {
+ free(buffer);
+ return NULL;
}
-
+ buffer = new_buffer;
+ }
else
break;
}
if(chr > 255)
{
sprintf(buffer+ptr,"\\u%04X",chr);
ptr+=strlen(buffer+ptr);
}else{
buffer[ptr++]=chr;
pike.git/src/program.c:7554:
else{
char *buffer;
if (malloced)
buffer = malloc (len + 1);
else {
buffer = buf;
if (len > NELEM (buf) - 1)
len = NELEM (buf) - 1;
}
- MEMCPY (buffer, file, len);
+ memcpy (buffer, file, len);
buffer[len] = 0;
return buffer;
}
}
- /* Same as low_get_program_line but returns a plain char *. It's
+ /**
+ * Same as low_get_program_line but returns a plain char *. It's
* malloced if the malloced flag is set, otherwise it's a pointer to a
* static buffer which might be clobbered by later calls.
*
* This function is useful when the shared string table has been freed
* and in sensitive parts of the gc where the shared string structures
* can't be touched. It also converts wide strings to ordinary ones
* with escaping.
*/
PMOD_EXPORT char *low_get_program_line_plain(struct program *prog,
INT_TYPE *linep,
pike.git/src/program.c:7585:
if (prog->linenumbers) {
struct pike_string *file;
FIND_PROGRAM_LINE (prog, file, (*linep));
if (file)
return make_plain_file(file, malloced);
}
return NULL;
}
- /* Returns the file where the program is defined. The line of the
+ /**
+ * Returns the file where the program is defined. The line of the
* class start is written to linep, or 0 if the program is the top
- * level of the file. */
+ * level of the file.
+ */
PMOD_EXPORT struct pike_string *get_program_line(struct program *prog,
INT_TYPE *linep)
{
struct pike_string *res = low_get_program_line(prog, linep);
if (!res) {
struct pike_string *dash;
REF_MAKE_CONST_STRING(dash, "-");
return dash;
}
return res;
pike.git/src/program.c:7663:
pc, prog->program, (void *)prog->num_program);
}
} else {
fprintf(stderr, "No program of linenumbers program:%p linenumbers:%p\n",
prog->program, prog->linenumbers);
}
return NULL;
}
- /* This is to low_get_line as low_get_program_line_plain is to
- * low_get_program_line. */
+ /**
+ * This is to low_get_line as low_get_program_line_plain is to
+ * low_get_program_line.
+ */
PMOD_EXPORT char *low_get_line_plain (PIKE_OPCODE_T *pc, struct program *prog,
INT_TYPE *linep, int malloced)
{
linep[0] = 0;
if (prog->program && prog->linenumbers) {
ptrdiff_t offset = pc - prog->program;
if ((offset < (ptrdiff_t)prog->num_program) && (offset >= 0)) {
char *cnt = prog->linenumbers;
pike.git/src/program.c:7722: Inside #if defined(PIKE_DEBUG)
void gdb_get_line (PIKE_OPCODE_T *pc, struct program *prog)
{
INT_TYPE line;
char *file = low_get_line_plain (pc, prog, &line, 0);
fprintf (stderr, "%s:%ld\n", file, (long)line);
}
#endif
- /*
- * return the file in which we were executing. pc should be the
+ /**
+ * Return the file in which we were executing. pc should be the
* program counter (i.e. the address in prog->program), prog the
* current program, and line will be initialized to the line in that
* file.
*/
PMOD_EXPORT struct pike_string *get_line(PIKE_OPCODE_T *pc,
struct program *prog,
INT_TYPE *linep)
{
struct pike_string *res;
pike.git/src/program.c:7784:
if ((ret = get_identifier_line(o->prog, fun, linep))) {
add_ref(ret);
return ret;
}
return low_get_program_line(o->prog, linep);
}
*linep = 0;
return NULL;
}
- /* Return the file and line where the identifier with reference number
+ /**
+ * Return the file and line where the identifier with reference number
* fun was defined.
*
* Note: Unlike the other get*line() functions, this one does not
* add a reference to the returned string.
*/
PMOD_EXPORT struct pike_string *get_identifier_line(struct program *p,
int fun,
INT_TYPE *linep)
{
struct reference *ref = PTR_FROM_INT(p, fun);
struct identifier *id = ID_FROM_PTR(p, ref);
p = PROG_FROM_PTR(p, ref);
if (id->filename_strno >= p->num_strings) return NULL;
if (linep) *linep = id->linenumber;
return p->strings[id->filename_strno];
}
- /* Main entry point for compiler messages originating from
- * C-code.
- *
- * Sends the message along to PikeCompiler()->report().
- *
- * NOTE: The format string fmt (and vargs) is only formatted with
- * string_builder_vsprintf() if the number of extra
- * Pike stack arguments (args) is zero.
- *
- * NOTE: This function may be called from functions that sometimes
- * execute outside of the compilation context, eg by
- * __handle_sprintf_format(), which can be called directly
- * by Pike-code, in which case it is a NO-OP.
- */
- PMOD_EXPORT void va_yyreport(int severity_level,
- struct pike_string *file, INT_TYPE line,
- struct pike_string *system, INT32 args,
- const char *fmt, va_list vargs)
- {
- struct compilation *c = MAYBE_THIS_COMPILATION;
- struct string_builder s;
-
- if (!c) {
- /* No compiler context. */
- pop_n_elems(args);
- return;
- }
-
- STACK_LEVEL_START(args);
-
- #ifdef PIKE_DEBUG
- if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer)
- Pike_fatal("Stack error (underflow)\n");
- #endif
-
- /* Convert type errors to warnings in non-strict compat mode. */
- if ((system == type_check_system_string) &&
- (severity_level == REPORT_ERROR) &&
- (Pike_compiler->compat_major != -1) &&
- !(c->lex.pragmas & ID_STRICT_TYPES) &&
- ((Pike_compiler->compat_major < PIKE_MAJOR_VERSION) ||
- ((Pike_compiler->compat_major == PIKE_MAJOR_VERSION) &&
- (Pike_compiler->compat_minor < PIKE_MINOR_VERSION)))) {
- severity_level = REPORT_WARNING;
- }
-
- /* 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 ((severity_level <= REPORT_WARNING) &&
- Pike_compiler->num_parse_error) {
- pop_n_elems(args);
- return;
- }
-
- if (severity_level >= REPORT_ERROR) {
- if (Pike_compiler->num_parse_error > 20) {
- pop_n_elems(args);
- return;
- }
- Pike_compiler->num_parse_error++;
- cumulative_parse_error++;
- }
-
- push_int(severity_level);
- ref_push_string(file?file:c->lex.current_file);
- push_int(line?line:c->lex.current_line);
- ref_push_string(system);
- if (args) {
- int i = args;
- push_text(fmt);
- /* Copy the arguments. */
- while (i--) {
- push_svalue(Pike_sp-(args+5));
- }
- } else {
- init_string_builder(&s, 0);
- string_builder_vsprintf(&s, fmt, vargs);
- push_string(finish_string_builder(&s));
- }
-
- safe_apply_current(PC_REPORT_FUN_NUM, args + 5);
- pop_stack();
- if (args) pop_n_elems(args);
- STACK_LEVEL_DONE(0);
- }
-
- PMOD_EXPORT void low_yyreport(int severity_level,
- struct pike_string *file, INT_TYPE line,
- struct pike_string *system,
- INT32 args, const char *fmt, ...)
- {
- va_list vargs;
-
- va_start(vargs,fmt);
- va_yyreport(severity_level, file, line, system, args, fmt, vargs);
- va_end(vargs);
- }
-
- PMOD_EXPORT void yyreport(int severity_level, struct pike_string *system,
- INT32 args, const char *fmt, ...)
- {
- va_list vargs;
-
- va_start(vargs,fmt);
- va_yyreport(severity_level, NULL, 0, system, args, fmt, vargs);
- va_end(vargs);
- }
-
- PMOD_EXPORT void yywarning(char *fmt, ...)
- {
- va_list vargs;
-
- va_start(vargs,fmt);
- va_yyreport(REPORT_WARNING, NULL, 0, parser_system_string, 0, fmt, vargs);
- va_end(vargs);
- }
-
- /* FIXME: Consider converting these to using va_yyreport(). */
-
- PMOD_EXPORT void my_yyerror(const char *fmt,...)
- {
- va_list vargs;
- va_start(vargs,fmt);
- va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0, fmt, vargs);
- va_end(vargs);
- }
-
- PMOD_EXPORT void yyerror(const char *str)
- {
- my_yyerror("%s", str);
- }
-
- /* Main entry point for errors from the type-checking subsystems.
- *
- * The message (if any) will be formatted for the same source
- * position as the got_t.
- *
- * The expect_t will be formatted for the same position as the got_t
- * if there's no expected_file/expected_line.
- *
- * The got_t will be formatted for the current lex position if there's
- * no got_file/got_line.
- */
- void yytype_report(int severity_level,
- struct pike_string *expected_file, INT_TYPE expected_line,
- struct pike_type *expected_t,
- struct pike_string *got_file, INT_TYPE got_line,
- struct pike_type *got_t,
- INT32 args, const char *fmt, ...)
- {
- if (fmt)
- {
- va_list vargs;
- va_start(vargs, fmt);
- va_yyreport(severity_level, got_file, got_line, type_check_system_string,
- args, fmt, vargs);
- va_end(vargs);
- }
-
- if (expected_t && got_t) {
- yyexplain_nonmatching_types(severity_level,
- expected_file?expected_file:got_file,
- expected_line?expected_line:got_line,
- expected_t,
- got_file, got_line, got_t);
- } else if (expected_t) {
- ref_push_type_value(expected_t);
- low_yyreport(severity_level,
- expected_file?expected_file:got_file,
- expected_line?expected_line:got_line,
- type_check_system_string,
- 1, "Expected: %O.");
- } else if (got_t) {
- ref_push_type_value(got_t);
- low_yyreport(severity_level, got_file, got_line, type_check_system_string,
- 1, "Got : %O.");
- }
- }
-
- void yytype_error(const char *msg, struct pike_type *expected_t,
- struct pike_type *got_t, unsigned int flags)
- {
- yytype_report((flags & YYTE_IS_WARNING)?REPORT_WARNING:REPORT_ERROR,
- NULL, 0, expected_t, NULL, 0, got_t, 0, "%s", msg);
- }
-
- struct pike_string *format_exception_for_error_msg (struct svalue *thrown)
- {
- struct pike_string *s = NULL;
-
- push_svalue (thrown);
- SAFE_APPLY_MASTER ("describe_error", 1);
-
- if (TYPEOF(sp[-1]) == T_STRING) {
- f_string_trim_all_whites(1);
- push_constant_text("\n");
- push_constant_text(" ");
- f_replace(3);
- return (--sp)->u.string;
- }
- else {
- pop_stack();
- return NULL;
- }
- }
-
- void handle_compile_exception (const char *yyerror_fmt, ...)
- {
- struct svalue thrown;
- struct compilation *c = THIS_COMPILATION;
-
- CHECK_COMPILER();
-
- move_svalue (&thrown, &throw_value);
- mark_free_svalue (&throw_value);
-
- if (yyerror_fmt) {
- va_list args;
- va_start (args, yyerror_fmt);
- va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0,
- yyerror_fmt, args);
- va_end (args);
- }
-
- push_svalue(&thrown);
- /* safe_apply_current(PC_FILTER_EXCEPTION_FUN_NUM, 1); */
- low_safe_apply_handler("compile_exception", c->handler, c->compat_handler, 1);
-
- if (SAFE_IS_ZERO(sp-1)) {
- struct pike_string *s = format_exception_for_error_msg (&thrown);
- if (s) {
- push_string(s);
- yyreport(REPORT_ERROR, parser_system_string, 1, "%s");
- }
- }
-
- pop_stack();
- free_svalue(&thrown);
- }
-
- extern int yyparse(void);
-
- #ifdef PIKE_DEBUG
- #define do_yyparse() do { \
- struct svalue *save_sp=Pike_sp; \
- yyparse(); /* Parse da program */ \
- if(save_sp != Pike_sp) { \
- Pike_fatal("yyparse() left %"PRINTPTRDIFFT"d droppings on the stack!\n", \
- Pike_sp - save_sp); \
- } \
- }while(0)
- #else
- #define do_yyparse() yyparse()
- #endif
-
- struct Supporter *current_supporter=0;
-
-
- #ifdef PIKE_DEBUG
-
- struct supporter_marker
- {
- struct supporter_marker *next;
- void *data;
- int level, verified;
- };
-
- #undef INIT_BLOCK
- #define INIT_BLOCK(X) do { (X)->level = (X)->verified = 0; }while(0)
- PTR_HASH_ALLOC(supporter_marker, 128);
-
- static int supnum;
-
- #define SNUM(X) (get_supporter_marker((X))->level)
-
- static void mark_supporters(struct Supporter *s)
- {
- struct supporter_marker *m;
-
- if(!s) return;
- debug_malloc_touch(s);
- m=get_supporter_marker(s);
-
- if(m->level) return;
- m->level = -1;
-
- if(s->magic != 0x500b0127)
- {
- #ifdef DEBUG_MALLOC
- describe(s);
- #endif
- Pike_fatal("This is not a supporter (addr=%p, magic=%x)!\n",s,s->magic);
- }
-
- mark_supporters(s->dependants);
- mark_supporters(s->next_dependant);
-
- m->level=supnum++;
-
- mark_supporters(s->previous);
- mark_supporters(s->depends_on);
- }
-
- static void low_verify_supporters(struct Supporter *s)
- {
- struct Supporter *ss;
- struct supporter_marker *m;
-
- if(!s) return;
- debug_malloc_touch(s);
- m=get_supporter_marker(s);
-
- if(m->verified) return;
- m->verified = 1;
-
- low_verify_supporters(s->dependants);
- low_verify_supporters(s->next_dependant);
-
- #if 0
- fprintf(stderr, "low_verify_supporters %p%s, level %d: "
- "previous %p, depends_on %p, dependants %p, next_dependant %p\n",
- s, s == current_supporter ? " == current_supporter" : "",
- m->level, s->previous, s->depends_on, s->dependants, s->next_dependant);
- #endif
-
- if(s->previous && SNUM(s->previous) <= m->level)
- Pike_fatal("Que, numbers out of whack1\n");
-
- if(s->depends_on && SNUM(s->depends_on) <= m->level)
- Pike_fatal("Que, numbers out of whack2\n");
-
- for(ss=s->dependants;ss;ss=ss->next_dependant) {
- if (ss->depends_on != s)
- Pike_fatal("Dependant hasn't got depends_on set properly.\n");
- if(SNUM(ss) >= m->level)
- Pike_fatal("Que, numbers out of whack3\n");
- }
-
- low_verify_supporters(s->previous);
- low_verify_supporters(s->depends_on);
- }
-
- void verify_supporters()
- {
- if(d_flag)
- {
- supnum=1;
- init_supporter_marker_hash();
-
- #if 0
- fprintf(stderr, "verify_supporters start\n");
- #endif
-
- mark_supporters(current_supporter);
- low_verify_supporters(current_supporter);
- #ifdef DO_PIKE_CLEANUP
- {
- size_t e=0;
- for(e=0;e<supporter_marker_hash_table_size;e++)
- while(supporter_marker_hash_table[e])
- remove_supporter_marker(supporter_marker_hash_table[e]->data);
- }
- #endif
- exit_supporter_marker_hash();
-
- #if 0
- fprintf(stderr, "verify_supporters end\n");
- #endif
- }
- }
- #else
- #define verify_supporters();
- #endif
-
- void init_supporter(struct Supporter *s,
- supporter_callback *fun,
- void *data)
- {
- CDFPRINTF((stderr, "th(%ld) init_supporter() supporter=%p data=%p.\n",
- (long) th_self(), s, data));
- verify_supporters();
- #ifdef PIKE_DEBUG
- s->magic = 0x500b0127;
- #endif
- s->previous=current_supporter;
- current_supporter=s;
-
- s->depends_on=0;
- s->dependants=0;
- s->next_dependant=0;
- s->fun=fun;
- s->data=data;
- s->prog=0;
- verify_supporters();
- }
-
- int unlink_current_supporter(struct Supporter *c)
- {
- int ret=0;
- #ifdef PIKE_DEBUG
- if(c != current_supporter)
- Pike_fatal("Previous unlink failed.\n");
- #endif
- debug_malloc_touch(c);
- verify_supporters();
- if(c->depends_on)
- {
- #ifdef PIKE_DEBUG
- struct Supporter *s;
- for (s = c->depends_on->dependants; s; s = s->next_dependant)
- if (s == c) Pike_fatal("Dependant already linked in.\n");
- #endif
- ret++;
- c->next_dependant = c->depends_on->dependants;
- c->depends_on->dependants=c;
- add_ref(c->self);
- CDFPRINTF((stderr, "th(%ld) unlink_current_supporter() "
- "supporter=%p (prog %p) depends on %p (prog %p).\n",
- (long) th_self(), c, c->prog,
- c->depends_on, c->depends_on->prog));
- }
- current_supporter=c->previous;
- verify_supporters();
- return ret;
- }
-
- void free_supporter(struct Supporter *c)
- {
- verify_supporters();
- if (c->depends_on) {
- struct Supporter **s;
- for (s = &c->depends_on->dependants; *s; s = &(*s)->next_dependant)
- if (*s == c) {*s = c->next_dependant; break;}
- c->depends_on = 0;
- }
- verify_supporters();
- }
-
- int call_dependants(struct Supporter *s, int finish)
- {
- int ok = 1;
- struct Supporter *tmp;
- CDFPRINTF((stderr, "th(%ld) call_dependants() supporter=%p (prog %p) "
- "finish=%d.\n", (long) th_self(), s, s->prog, finish));
- verify_supporters();
- while((tmp=s->dependants))
- {
- CDFPRINTF((stderr, "th(%ld) dependant: %p (prog %p) (data:%p).\n",
- (long) th_self(), tmp, tmp->prog, tmp->data));
- s->dependants=tmp->next_dependant;
- #ifdef PIKE_DEBUG
- tmp->next_dependant=0;
- #endif
- verify_supporters();
- if (!tmp->fun(tmp->data, finish)) ok = 0;
- verify_supporters();
- free_object(tmp->self);
- }
- return ok;
- }
-
- int report_compiler_dependency(struct program *p)
- {
- int ret=0;
- struct Supporter *c,*cc;
-
- if (p == Pike_compiler->new_program) {
- /* Depends on self... */
- return 0;
- }
-
- CDFPRINTF((stderr, "th(%ld) compiler dependency on %p from %p\n",
- (long)th_self(), p, Pike_compiler->new_program));
-
- verify_supporters();
- if (Pike_compiler->flags & COMPILATION_FORCE_RESOLVE)
- return 0;
- for(cc=current_supporter;cc;cc=cc->previous)
- {
- if(cc->prog &&
- !(cc->prog->flags & PROGRAM_PASS_1_DONE))
- {
- c=cc->depends_on;
- if(!c) c=cc->previous;
- for(;c;c=c->previous)
- {
- if(c->prog == p)
- {
- cc->depends_on=c;
- CDFPRINTF ((stderr, "th(%ld) supporter %p (prog %p) "
- "now depends on %p (prog %p)\n",
- (long) th_self(), cc, cc->prog, c, c->prog));
- verify_supporters();
- ret++; /* dependency registred */
- }
- }
- }
- }
- verify_supporters();
- return ret;
- }
-
- /*! @class Reporter
- *!
- *! API for reporting parse errors and similar.
- */
-
- /*! @decl enum SeverityLevel
- *! Message severity level.
- *! { NOTICE, WARNING, ERROR, FATAL }
- *!
- *! @constant NOTICE
- *! @constant WARNING
- *! @constant ERROR
- *! @constant FATAL
- *!
- *! @seealso
- *! @[report()]
- */
-
- /*! @decl void report(SeverityLevel severity, @
- *! string filename, int linenumber, @
- *! string subsystem, @
- *! string message, mixed ... extra_args)
- *!
- *! Report a diagnostic from the compiler.
- *!
- *! @param severity
- *! The severity of the diagnostic.
- *!
- *! @param filename
- *! @param linenumber
- *! Location which triggered the diagnostic.
- *!
- *! @param subsystem
- *! Compiler subsystem that generated the diagnostic.
- *!
- *! @param message
- *! @[sprintf()]-style formatting string with the diagnostic message.
- *!
- *! @param extra_args
- *! Extra arguments to @[sprintf()].
- *!
- *! The default implementation does the following:
- *!
- *! @ul
- *! @item
- *! If there's a @[MasterObject()->report()], call it
- *! with the same arguments as ourselves.
- *! @item
- *! Otherwise depending on @[severity]:
- *! @int
- *! @value NOTICE
- *! Ignored.
- *! @value WARNING
- *! Calls @[MasterObject()->compile_warning()].
- *! @value ERROR
- *! @value FATAL
- *! Calls @[MasterObject()->compile_error()].
- *! @endint
- *! @endul
- *!
- *! If there's no master object yet, the diagnostic is output to
- *! @[Stdio.stderr].
- *!
- *! @note
- *! In Pike 7.8 and earlier @[MasterObject()->report()] was not called.
- *!
- *! @seealso
- *! @[PikeCompiler()->report()]
- */
- /* NOTE: This function MUST NOT use any storage in the Reporter program! */
- static void f_reporter_report(INT32 args)
- {
- int level;
- struct pike_string *filename;
- INT_TYPE linenumber;
- struct pike_string *subsystem;
- struct pike_string *message;
- struct object *master_ob;
-
- if ((master_ob = get_master()) && master_ob->prog) {
- int fun = find_identifier("report", master_ob->prog);
- if (fun >= 0) {
- apply_low(master_ob, fun, args);
- return;
- }
- }
-
- if (args > 5) {
- f_sprintf(args - 4);
- args = 5;
- }
- get_all_args("report", args, "%d%W%i%W%W",
- &level, &filename, &linenumber, &subsystem, &message);
-
- /* Ignore informational level messages */
- if (level >= REPORT_WARNING) {
- if (master_ob && master_ob->prog) {
- ref_push_string(filename);
- push_int(linenumber);
- ref_push_string(message);
- if (level >= REPORT_ERROR) {
- APPLY_MASTER("compile_error", 3);
- args++;
- } else {
- APPLY_MASTER("compile_warning", 3);
- args++;
- }
- } else {
- /* We hope that errors from compiling the master
- * won't contain wide-strings... */
- if (level >= REPORT_ERROR) {
- fprintf(stderr, "%s:%ld: %s\n",
- filename->str, (long)linenumber, message->str);
- } else {
- fprintf(stderr, "%s:%ld: Warning: %s\n",
- filename->str, (long)linenumber, message->str);
- }
- fflush(stderr);
- }
- }
- pop_n_elems(args);
- push_int(0);
- }
-
- /*! @endclass
- */
-
- /*! @module DefaultCompilerEnvironment
- *!
- *! The @[CompilerEnvironment] object that is used
- *! for loading C-modules and by @[predef::compile()].
- *!
- *! @note
- *! @[predef::compile()] is essentially an alias for the
- *! @[CompilerEnvironment()->compile()] in this object.
- *!
- *! @seealso
- *! @[CompilerEnvironment], @[predef::compile()]
- */
-
- /*! @endmodule
- */
-
- /*! @class CompilerEnvironment
- *!
- *! The compiler environment.
- *!
- *! By inheriting this class and overloading the functions,
- *! it is possible to make a custom Pike compiler.
- *!
- *! @note
- *! Prior to Pike 7.8 this sort of customization has to be done
- *! either via custom master objects, or via @[CompilationHandler]s.
- *!
- *! @seealso
- *! @[CompilationHandler], @[MasterObject], @[master()], @[replace_master()]
- */
-
- /*! @decl inherit Reporter
- *!
- *! Implements the @[Reporter] API.
- *!
- *! @seealso
- *! @[Reporter()->report()], @[Reporter()->SeverityLevel]
- */
-
- /*! @decl program compile(string source, CompilationHandler|void handler, @
- *! int|void major, int|void minor,@
- *! program|void target, object|void placeholder)
- *!
- *! Compile a string to a program.
- *!
- *! This function takes a piece of Pike code as a string and
- *! compiles it into a clonable program.
- *!
- *! The optional argument @[handler] is used to specify an alternative
- *! error handler. If it is not specified the current master object will
- *! be used.
- *!
- *! The optional arguments @[major] and @[minor] are used to tell the
- *! compiler to attempt to be compatible with Pike @[major].@[minor].
- *!
- *! @note
- *! This function essentially performs
- *! @code
- *! program compile(mixed ... args)
- *! {
- *! return PikeCompiler(@@args)->compile();
- *! }
- *! @endcode
- *!
- *! @note
- *! Note that @[source] must contain the complete source for a program.
- *! It is not possible to compile a single expression or statement.
- *!
- *! Also note that @[compile()] does not preprocess the program.
- *! To preprocess the program you can use @[compile_string()] or
- *! call the preprocessor manually by calling @[cpp()].
- *!
- *! @seealso
- *! @[compile_string()], @[compile_file()], @[cpp()], @[master()],
- *! @[CompilationHandler]
- */
- static void f_compilation_env_compile(INT32 args)
- {
- apply_current(CE_PIKE_COMPILER_FUN_NUM, args);
- args = 1;
- if (TYPEOF(Pike_sp[-1]) != T_OBJECT) {
- Pike_error("Bad return value from PikeCompiler().\n");
- }
- apply(Pike_sp[-1].u.object, "compile", 0);
- stack_pop_n_elems_keep_top(args);
- }
-
- /*! @decl mixed resolv(string identifier, string filename, @
- *! object|void handler)
- *!
- *! Look up @[identifier] in the current context.
- *!
- *! The default implementation calls the corresponding
- *! function in the master object.
- */
- static void f_compilation_env_resolv(INT32 args)
- {
- struct pike_string *ident;
- struct pike_string *filename;
- struct object *handler = NULL;
-
- get_all_args("resolv", args, "%W%W.%O",
- &ident, &filename, &handler);
-
- if(get_master())
- {
- DECLARE_CYCLIC();
- if(BEGIN_CYCLIC(ident, filename))
- {
- my_yyerror("Recursive module dependency in %S.", ident);
- }else{
- SET_CYCLIC_RET(1);
-
- APPLY_MASTER("resolv", args);
- }
- END_CYCLIC();
- } else {
- pop_n_elems(args);
- push_undefined();
- }
- }
-
- /*! @decl object get_compilation_handler(int major, int minor)
- *!
- *! Get compatibility handler for Pike @[major].@[minor].
- *!
- *! The default implementation calls the corresponding
- *! function in the master object.
- *!
- *! @note
- *! This function is typically called by
- *! @[PikeCompiler()->get_compilation_handler()].
- *!
- *! @seealso
- *! @[MasterObject()->get_compilation_handler()].
- */
- static void f_compilation_env_get_compilation_handler(INT32 args)
- {
- if(get_master())
- {
- APPLY_MASTER("get_compilation_handler", args);
- } else {
- pop_n_elems(args);
- push_undefined();
- }
- }
-
- /*! @decl mapping(string:mixed)|object get_default_module()
- *!
- *! Get the default module for the current compatibility level
- *! (ie typically the value returned by @[predef::all_constants()]).
- *!
- *! The default implementation calls the corresponding function
- *! in the master object.
- *!
- *! @returns
- *! @mixed
- *! @type mapping(string:mixed)|object
- *! Constant table to use.
- *!
- *! @type int(0..0)
- *! Use the builtin constant table.
- *! @endmixed
- *!
- *! @note
- *! This function is typically called by
- *! @[Pike_compiler()->get_default_module()].
- *!
- *! @seealso
- *! @[MasterObject()->get_default_module()].
- */
- static void f_compilation_env_get_default_module(INT32 args)
- {
- if(get_master())
- {
- APPLY_MASTER("get_default_module", args);
- } else {
- pop_n_elems(args);
- push_undefined();
- }
- }
-
- /*! @decl program handle_inherit(string inh, string current_file, @
- *! object|void handler)
- *!
- *! Look up an inherit @[inh].
- *!
- *! The default implementation calls the corresponding function
- *! in the master object.
- *!
- *! @seealso
- *! @[MasterObject()->handle_inherit()].
- */
- static void f_compilation_env_handle_inherit(INT32 args)
- {
- if(get_master())
- {
- APPLY_MASTER("handle_inherit", args);
- } else {
- pop_n_elems(args);
- push_undefined();
- }
- }
-
- /*! @decl int filter_exception(SeverityLevel level, mixed err)
- *!
- *! The default implementation calls
- *! @[MasterObject()->compile_exception()] for @[level] @[ERROR]
- *! and @[FATAL].
- *!
- *! @note
- *! This function is not implemented in Pike 7.8.
- *!
- *! @seealso
- *! @[MasterObject()->compile_exception()].
- */
- static void f_compilation_env_filter_exception(INT32 args)
- {
- int level;
- struct svalue *err;
-
- get_all_args("filter_exception", args, "%d%*", &level, &err);
- if (args > 2) {
- pop_n_elems(args-2);
- args = 2;
- }
-
- #if 0
- if (level >= REPORT_WARNING) {
- if (level >= REPORT_ERROR) {
- APPLY_MASTER("compile_exception", 1);
- /* FIXME! */
- } else {
- push_int(level);
- push_string(format_exception_for_error_msg(err));
- /* FIXME! */
- }
- }
- #endif
-
- pop_n_elems(args);
- push_undefined();
- return;
- }
-
- /*! @class PikeCompiler
- *!
- *! The Pike compiler.
- *!
- *! An object of this class compiles a single string
- *! of Pike code.
- */
-
- static void free_compilation(struct compilation *c)
- {
- debug_malloc_touch(c);
- if (c->prog) {
- free_string(c->prog);
- c->prog = NULL;
- }
- if(c->handler) {
- free_object(c->handler);
- c->handler = NULL;
- }
- if(c->compat_handler) {
- free_object(c->compat_handler);
- c->compat_handler = NULL;
- }
- if(c->target) {
- free_program(c->target);
- c->target = NULL;
- }
- if(c->p) {
- free_program(c->p);
- c->p = NULL;
- }
- if(c->placeholder) {
- free_object(c->placeholder);
- c->placeholder = NULL;
- }
- if(c->lex.current_file) {
- free_string(c->lex.current_file);
- c->lex.current_file = NULL;
- }
- if (c->resolve_cache) {
- free_mapping(c->resolve_cache);
- c->resolve_cache = NULL;
- }
- free_svalue(& c->default_module);
- SET_SVAL(c->default_module, T_INT, NUMBER_NUMBER, integer, 0);
- free_supporter(&c->supporter);
- verify_supporters();
- }
-
- static void run_init(struct compilation *c)
- {
- debug_malloc_touch(c);
-
- if (c->compat_handler) free_object(c->compat_handler);
- c->compat_handler=0;
-
- if (c->resolve_cache) {
- free_mapping(c->resolve_cache);
- c->resolve_cache = 0;
- }
-
- c->lex.current_line=1;
- free_string(c->lex.current_file);
- c->lex.current_file=make_shared_string("-");
-
- if (runtime_options & RUNTIME_STRICT_TYPES)
- {
- c->lex.pragmas = ID_STRICT_TYPES;
- } else {
- c->lex.pragmas = 0;
- }
-
- c->lex.end = c->prog->str + (c->prog->len << c->prog->size_shift);
-
- switch(c->prog->size_shift)
- {
- case 0: c->lex.current_lexer = yylex0; break;
- case 1: c->lex.current_lexer = yylex1; break;
- case 2: c->lex.current_lexer = yylex2; break;
- #ifdef PIKE_DEBUG
- default:
- Pike_fatal("Program has bad shift %d!\n", c->prog->size_shift);
- break;
- #endif
- }
-
- c->lex.pos=c->prog->str;
- }
-
- static void run_init2(struct compilation *c)
- {
- #if 0
- int i;
- struct program *p;
- struct reference *refs;
- #endif /* 0 */
- debug_malloc_touch(c);
- Pike_compiler->compiler = c;
-
- /* Get the proper default module. */
- safe_apply_current2(PC_GET_DEFAULT_MODULE_FUN_NUM, 0, NULL);
- if(TYPEOF(Pike_sp[-1]) == T_INT)
- {
- pop_stack();
- ref_push_mapping(get_builtin_constants());
- }
- assign_svalue(&c->default_module, Pike_sp-1);
- pop_stack();
-
- use_module(& c->default_module);
-
- Pike_compiler->compat_major=PIKE_MAJOR_VERSION;
- Pike_compiler->compat_minor=PIKE_MINOR_VERSION;
-
- if(c->major>=0)
- change_compiler_compatibility(c->major, c->minor);
-
- #if 0
- /* Make all inherited private symbols that weren't overloaded
- * in the first pass local.
- */
- p = c->new_program;
- i = p->num_identifier_references;
- refs = p->identifier_references;
- while (i--) {
- if (refs[i].id_flags & ID_PRIVATE) refs[i].id_flags |= ID_INLINE;
- }
- #endif /* 0 */
- }
-
- static void run_exit(struct compilation *c)
- {
- debug_malloc_touch(c);
-
- #ifdef PIKE_DEBUG
- if(c->num_used_modules)
- Pike_fatal("Failed to pop modules properly.\n");
- #endif
-
- #ifdef PIKE_DEBUG
- if (c->compilation_depth != -1) {
- fprintf(stderr, "compile(): compilation_depth is %d\n",
- c->compilation_depth);
- }
- #endif /* PIKE_DEBUG */
-
- if (c->resolve_cache) {
- free_mapping(c->resolve_cache);
- c->resolve_cache = NULL;
- }
-
- verify_supporters();
- }
-
- static void zap_placeholder(struct compilation *c)
- {
- /* fprintf(stderr, "Destructing placeholder.\n"); */
- if (c->placeholder->storage) {
- yyerror("Placeholder already has storage!");
- #if 0
- fprintf(stderr, "Placeholder already has storage!\n"
- "placeholder: %p, storage: %p, prog: %p\n",
- c->placeholder, c->placeholder->storage, c->placeholder->prog);
- #endif
- debug_malloc_touch(c->placeholder);
- destruct(c->placeholder);
- } else {
- /* FIXME: Is this correct? */
- /* It would probably be nicer if it was possible to just call
- * destruct on the object, but this works too. -Hubbe
- */
- free_program(c->placeholder->prog);
- c->placeholder->prog = NULL;
- debug_malloc_touch(c->placeholder);
- }
- free_object(c->placeholder);
- c->placeholder=0;
- verify_supporters();
- }
-
- /* NOTE: Must not throw errors! */
- static int run_pass1(struct compilation *c)
- {
- int ret=0;
-
- debug_malloc_touch(c);
- run_init(c);
-
- #if 0
- CDFPRINTF((stderr, "th(%ld) compile() starting compilation_depth=%d\n",
- (long)th_self(), c->compilation_depth));
- #endif
-
- if(c->placeholder && c->placeholder->prog != null_program) {
- yyerror("Placeholder object is not a null_program clone!");
- return 0;
- }
- debug_malloc_touch(c->placeholder);
-
- if(c->target && !(c->target->flags & PROGRAM_VIRGIN)) {
- yyerror("Placeholder program is not virgin!");
- return 0;
- }
-
- low_start_new_program(c->target,1,0,0,0);
- c->supporter.prog = Pike_compiler->new_program;
-
- CDFPRINTF((stderr,
- "th(%ld) %p run_pass1() start: "
- "threads_disabled:%d, compilation_depth:%d\n",
- (long)th_self(), Pike_compiler->new_program,
- threads_disabled, c->compilation_depth));
-
- run_init2(c);
-
- if(c->placeholder)
- {
- if(c->placeholder->prog != null_program)
- {
- yyerror("Placeholder argument is not a null_program clone!");
- c->placeholder=0;
- debug_malloc_touch(c->placeholder);
- }else{
- free_program(c->placeholder->prog);
- add_ref(c->placeholder->prog=Pike_compiler->new_program);
- debug_malloc_touch(c->placeholder);
- }
- }
-
- #if 0
- CDFPRINTF((stderr, "th(%ld) %p compile(): First pass\n",
- (long)th_self(), Pike_compiler->new_program));
- #endif
-
- do_yyparse(); /* Parse da program */
-
- if (!Pike_compiler->new_program->num_linenumbers) {
- /* The lexer didn't write an initial entry. */
- store_linenumber(0, c->lex.current_file);
- #ifdef DEBUG_MALLOC
- if(strcmp(c->lex.current_file->str,"-"))
- debug_malloc_name(Pike_compiler->new_program, c->lex.current_file->str, 0);
- #endif
- }
-
- CDFPRINTF((stderr, "th(%ld) %p run_pass1() done for %s\n",
- (long)th_self(), Pike_compiler->new_program,
- c->lex.current_file->str));
-
- ret=unlink_current_supporter(& c->supporter);
-
- c->p=debug_malloc_pass(end_first_pass(0));
-
- run_exit(c);
-
- if(c->placeholder)
- {
- if(!c->p || (c->placeholder->storage))
- {
- debug_malloc_touch(c->placeholder);
- zap_placeholder(c);
- } else {
- #ifdef PIKE_DEBUG
- if (c->placeholder->prog != c->p)
- Pike_fatal("Placeholder object got wrong program after first pass.\n");
- #endif
- debug_malloc_touch(c->placeholder);
- c->placeholder->storage=c->p->storage_needed ?
- (char *)xcalloc(c->p->storage_needed, 1) :
- (char *)NULL;
- call_c_initializers(c->placeholder);
- }
- }
-
- verify_supporters();
- return ret;
- }
-
- void run_pass2(struct compilation *c)
- {
- debug_malloc_touch(c);
- debug_malloc_touch(c->placeholder);
-
- if (!c->p) {
- c->flags &= ~(COMPILER_BUSY);
- c->flags |= COMPILER_DONE;
- return;
- }
-
- run_init(c);
- low_start_new_program(c->p,2,0,0,0);
- free_program(c->p);
- c->p=0;
-
- run_init2(c);
-
- CDFPRINTF((stderr,
- "th(%ld) %p run_pass2() start: "
- "threads_disabled:%d, compilation_depth:%d\n",
- (long)th_self(), Pike_compiler->new_program,
- threads_disabled, c->compilation_depth));
-
- verify_supporters();
-
- do_yyparse(); /* Parse da program */
-
- CDFPRINTF((stderr, "th(%ld) %p run_pass2() done for %s\n",
- (long)th_self(), Pike_compiler->new_program,
- c->lex.current_file->str));
-
- verify_supporters();
-
- c->p=debug_malloc_pass(end_program());
-
- run_exit(c);
- }
-
- static void run_cleanup(struct compilation *c, int delayed)
- {
- debug_malloc_touch(c);
- debug_malloc_touch(c->placeholder);
- #if 0 /* FIXME */
- #ifdef PIKE_THREADS
- if (threads_disabled != c->saved_threads_disabled) {
- Pike_fatal("compile(): threads_disabled:%d saved_threads_disabled:%d\n",
- threads_disabled, c->saved_threads_disabled);
- }
- #endif
- #endif /* PIKE_DEBUG */
-
- exit_threads_disable(NULL);
-
- CDFPRINTF((stderr,
- "th(%ld) %p run_cleanup(): "
- "threads_disabled:%d, compilation_depth:%d\n",
- (long)th_self(), c->target,
- threads_disabled, c->compilation_depth));
- if (!c->p)
- {
- /* fprintf(stderr, "Destructing placeholder.\n"); */
- if(c->placeholder) {
- debug_malloc_touch(c->placeholder);
- zap_placeholder(c);
- }
-
- if(delayed && c->target)
- {
- struct program *p = c->target;
-
- /* Free the constants in the failed program, to untangle the
- * cyclic references we might have to this program, typically
- * in parent pointers in nested classes. */
- if (p->constants) {
- int i;
- for (i = 0; i < p->num_constants; i++) {
- free_svalue(&p->constants[i].sval);
- SET_SVAL(p->constants[i].sval, T_INT, NUMBER_NUMBER,
- integer, 0);
- }
- }
-
- /* We have to notify the master object that
- * a previous compile() actually failed, even
- * if we did not know it at the time
- */
- CDFPRINTF((stderr, "th(%ld) %p unregistering failed delayed compile.\n",
- (long) th_self(), p));
- ref_push_program(p);
- /* FIXME: Shouldn't the compilation handler be used here? */
- SAFE_APPLY_MASTER("unregister",1);
- pop_stack();
-
- {
- #ifdef PIKE_DEBUG
- int refs = p->refs;
- #endif
-
- /* Free the target here to avoid false alarms in the debug
- * check below. */
- free_program (c->target);
- c->target = NULL;
-
- #ifdef PIKE_DEBUG
- if (refs > 1) {
- /* Other programs can have indexed out constants from p, which
- * might be broken themselves and/or keep references to p
- * through the parent pointer. We should find all those other
- * programs and invalidate them too, but how can that be done?
- * The whole delayed compilation thingie is icky icky icky... :P
- * /mast */
- fprintf(stderr, "Warning: Program %p still got %d "
- "external refs after unregister:\n", p, p->refs);
- locate_references(p);
- fprintf (stderr, "Describing program:\n");
- describe_something (p, T_PROGRAM, 0, 0, 0, NULL);
- }
- #endif
- }
- }
- }
- else
- {
- if (c->placeholder)
- {
- if (c->target->flags & PROGRAM_FINISHED) {
- JMP_BUF rec;
- /* Initialize the placeholder. */
- #ifdef PIKE_DEBUG
- if (c->placeholder->prog != c->p)
- Pike_fatal("Placeholder object got wrong program after second pass.\n");
- #endif
- if(SETJMP(rec))
- {
- handle_compile_exception (NULL);
- debug_malloc_touch(c->placeholder);
- zap_placeholder(c);
- }else{
- debug_malloc_touch(c->placeholder);
- call_pike_initializers(c->placeholder,0);
- }
- UNSETJMP(rec);
- }
- else {
- debug_malloc_touch(c->placeholder);
- zap_placeholder(c);
- }
- }
- }
- verify_supporters();
- c->flags &= ~(COMPILER_BUSY);
- c->flags |= COMPILER_DONE;
- }
-
- static int call_delayed_pass2(struct compilation *cc, int finish)
- {
- int ok = 0;
- debug_malloc_touch(cc);
-
- debug_malloc_touch(cc->p);
-
- CDFPRINTF((stderr, "th(%ld) %p %s delayed compile.\n",
- (long) th_self(), cc->p, finish ? "continuing" : "cleaning up"));
-
- /* Reenter the delayed compilation. */
- add_ref(cc->supporter.self);
- low_enter_compiler(cc->supporter.self, cc->compilation_inherit);
-
- if(finish && cc->p) run_pass2(cc);
- run_cleanup(cc,1);
-
- exit_compiler();
-
- debug_malloc_touch(cc);
-
- #ifdef PIKE_DEBUG
- if(cc->supporter.dependants)
- Pike_fatal("Que???\n");
- #endif
- if(cc->p) {
- ok = finish;
- free_program(cc->p); /* later */
- cc->p = NULL;
- }
-
- CDFPRINTF((stderr, "th(%ld) %p delayed compile %s.\n",
- (long) th_self(), cc->target, ok ? "done" : "failed"));
-
- verify_supporters();
-
- return ok;
- }
-
- static void compilation_event_handler(int e)
- {
- struct compilation *c = THIS_COMPILATION;
-
- switch (e) {
- case PROG_EVENT_INIT:
- CDFPRINTF((stderr, "th(%ld) compilation: INIT(%p).\n",
- (long) th_self(), c));
- MEMSET(c, 0, sizeof(*c));
- c->supporter.self = Pike_fp->current_object; /* NOTE: Not ref-counted! */
- c->compilation_inherit =
- Pike_fp->context - Pike_fp->current_object->prog->inherits;
- initialize_buf(&c->used_modules);
- SET_SVAL(c->default_module, T_MAPPING, 0, mapping, get_builtin_constants());
- add_ref(c->default_module.u.mapping);
- c->major = -1;
- c->minor = -1;
- c->lex.current_line = 1;
- c->lex.current_file = make_shared_string("-");
- c->compilation_depth = -1;
- break;
- case PROG_EVENT_EXIT:
- CDFPRINTF((stderr, "th(%ld) compilation: EXIT(%p).\n",
- (long) th_self(), c));
- toss_buffer(&c->used_modules);
- free_compilation(c);
- break;
- }
- }
-
- /*! @decl void report(SeverityLevel severity, @
- *! string filename, int linenumber, @
- *! string subsystem, @
- *! string message, mixed ... extra_args)
- *!
- *! Report a diagnostic from the compiler.
- *!
- *! The default implementation attempts to call the first
- *! corresponding function in the active handlers in priority order:
- *!
- *! @ol
- *! @item
- *! Call handler->report().
- *! @item
- *! Call handler->compile_warning() or handler->compile_error()
- *! depending on @[severity].
- *! @item
- *! Call compat->report().
- *! @item
- *! Call compat->compile_warning() or compat->compile_error()
- *! depending on @[severity].
- *! @item
- *! Fallback: Call @[CompilerEnvironment()->report()]
- *! in the parent object.
- *! @endol
- *!
- *! The arguments will be as follows:
- *! @dl
- *! @item report()
- *! The report() function will be called with the same arguments
- *! as this function.
- *! @item compile_warning()/compile_error()
- *! Depending on the @[severity] either compile_warning()
- *! or compile_error() will be called.
- *!
- *! They will be called with the @[filename], @[linenumber]
- *! and formatted @[message] as arguments.
- *!
- *! Note that these will not be called for the @[NOTICE] severity,
- *! and that compile_error() will be used for both @[ERROR] and
- *! @[FATAL].
- *! @enddl
- *!
- *! @note
- *! In Pike 7.8 and earlier the report() function was not called
- *! in the handlers.
- *!
- *! @seealso
- *! @[CompilerEnvironment()->report()]
- */
- static void f_compilation_report(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- int level;
- struct pike_string *filename;
- INT_TYPE linenumber;
- struct pike_string *subsystem;
- struct pike_string *message;
- struct object *handler = NULL;
- int fun = -1;
-
- /* FIXME: get_all_args() ought to have a marker
- * indicating that we accept more arguments...
- */
- get_all_args("report", args, "%d", &level);
-
- if ((c->handler || c->compat_handler)) {
- const char *fun_name = "compile_warning";
-
- if (level >= REPORT_ERROR) fun_name = "compile_error";
-
- if((handler = c->handler) && handler->prog) {
- if ((fun = find_identifier("report", handler->prog)) != -1) {
- apply_low(handler, fun, args);
- return;
- }
- if ((fun = find_identifier(fun_name, handler->prog)) != -1) {
- goto apply_handler;
- }
- }
- if ((handler = c->compat_handler) && handler->prog) {
- if ((fun = find_identifier("report", handler->prog)) != -1) {
- apply_low(handler, fun, args);
- return;
- }
- if ((fun = find_identifier(fun_name, handler->prog)) != -1) {
- goto apply_handler;
- }
- }
- }
- /* Nothing apropriate in any handlers.
- * Call the report() in our parent.
- */
- apply_external(1, CE_REPORT_FUN_NUM, args);
- return;
-
- apply_handler:
- /* Ignore informational level messages */
- if (level < REPORT_WARNING) return;
- if (args > 5) {
- f_sprintf(args - 4);
- args = 5;
- }
- get_all_args("report", args, "%d%W%i%W%W",
- &level, &filename, &linenumber,
- &subsystem, &message);
-
- ref_push_string(filename);
- push_int(linenumber);
- ref_push_string(message);
- apply_low(handler, fun, 3);
- stack_pop_n_elems_keep_top(args);
- }
-
- /*! @decl void create(string|void source, @
- *! CompilationHandler|void handler, @
- *! int|void major, int|void minor,@
- *! program|void target, object|void placeholder)
- *!
- *! Create a PikeCompiler object for a source string.
- *!
- *! This function takes a piece of Pike code as a string and
- *! initializes a compiler object accordingly.
- *!
- *! @param source
- *! Source code to compile.
- *!
- *! @param handler
- *! The optional argument @[handler] is used to specify an alternative
- *! error handler. If it is not specified the current master object
- *! at compile time will be used.
- *!
- *! @param major
- *! @param minor
- *! The optional arguments @[major] and @[minor] are used to tell the
- *! compiler to attempt to be compatible with Pike @[major].@[minor].
- *!
- *! @param target
- *! @[__empty_program()] program to fill in. The virgin program
- *! returned by @[__empty_program()] will be modified and returned
- *! by @[compile()] on success.
- *!
- *! @param placeholder
- *! @[__null_program()] placeholder object to fill in. The object
- *! will be modified into an instance of the resulting program
- *! on successfull compile. Note that @[lfun::create()] in the
- *! program will be called without any arguments.
- *!
- *! @note
- *! Note that @[source] must contain the complete source for a program.
- *! It is not possible to compile a single expression or statement.
- *!
- *! Also note that no preprocessing is performed.
- *! To preprocess the program you can use @[compile_string()] or
- *! call the preprocessor manually by calling @[cpp()].
- *!
- *! @note
- *! Note that all references to @[target] and @[placeholder] should
- *! removed if @[compile()] failes. On failure the @[placeholder]
- *! object will be destructed.
- *!
- *! @seealso
- *! @[compile_string()], @[compile_file()], @[cpp()], @[master()],
- *! @[CompilationHandler]
- */
- static void f_compilation_create(INT32 args)
- {
- struct pike_string *aprog = NULL;
- struct object *ahandler = NULL;/* error handler */
- int amajor = -1;
- int aminor = -1;
- struct program *atarget = NULL;
- struct object *aplaceholder = NULL;
- int dependants_ok = 1;
- struct compilation *c = THIS_COMPILATION;
-
- if (c->flags & COMPILER_BUSY) {
- Pike_error("PikeCompiler object is in use.\n");
- }
-
- STACK_LEVEL_START(args);
-
- get_all_args("create", args, ".%W%O%d%d%P%O",
- &aprog, &ahandler,
- &amajor, &aminor,
- &atarget, &aplaceholder);
-
- if (args == 3) {
- SIMPLE_BAD_ARG_ERROR("create", 4, "int");
- }
-
- check_c_stack(65536);
-
- CDFPRINTF((stderr, "th(%ld) %p compilation create() enter, placeholder=%p\n",
- (long) th_self(), atarget, aplaceholder));
-
- debug_malloc_touch(c);
-
- verify_supporters();
-
- c->flags &= ~COMPILER_DONE;
-
- if (c->p) free_program(c->p);
- c->p = NULL;
-
- if (c->prog) free_string(c->prog);
- if ((c->prog=aprog)) add_ref(aprog);
-
- if (c->handler) free_object(c->handler);
- if ((c->handler=ahandler)) add_ref(ahandler);
-
- if (c->target) free_program(c->target);
- if ((c->target=atarget)) add_ref(atarget);
-
- if (c->placeholder) free_object(c->placeholder);
- if ((c->placeholder=aplaceholder)) add_ref(aplaceholder);
-
- c->major = amajor?amajor:-1;
- c->minor = aminor?aminor:-1;
-
- STACK_LEVEL_DONE(args);
- pop_n_elems(args);
-
- push_int(0);
- }
-
- /*! @decl program compile()
- *!
- *! Compile the current source into a program.
- *!
- *! This function compiles the current Pike source code
- *! into a clonable program.
- *!
- *! @seealso
- *! @[compile_string()], @[compile_file()], @[cpp()], @[master()],
- *! @[CompilationHandler], @[create()]
- */
- static void f_compilation_compile(INT32 args)
- {
- int delay, dependants_ok = 1;
- struct program *ret;
- #ifdef PIKE_DEBUG
- ONERROR tmp;
- #endif
- struct compilation *c = THIS_COMPILATION;
-
- if (c->flags & COMPILER_BUSY) {
- Pike_error("PikeCompiler in use.\n");
- }
-
- get_all_args("compile", args, "");
-
- check_c_stack(65536);
-
- CDFPRINTF((stderr, "th(%ld) %p f_compilation_compile() enter, "
- "placeholder=%p\n", (long) th_self(), c->target, c->placeholder));
-
- debug_malloc_touch(c);
-
- verify_supporters();
-
- if (c->flags & COMPILER_DONE) {
- /* Already compiled. */
- pop_n_elems(args);
- if (c->p) ref_push_program(c->p);
- else push_int(0);
- return;
- }
-
- if (!c->prog) {
- /* No program text. */
- low_start_new_program(c->target, 1, NULL, 0, NULL);
- c->p = end_program();
- c->flags |= COMPILER_DONE;
- pop_n_elems(args);
- ref_push_program(c->p);
- return;
- }
-
- #ifdef PIKE_DEBUG
- SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n");
- #endif
-
- c->flags |= COMPILER_BUSY;
-
- low_init_threads_disable();
- #ifdef PIKE_THREADS
- c->saved_threads_disabled = threads_disabled;
- #endif
-
- init_supporter(& c->supporter,
- (supporter_callback *) call_delayed_pass2,
- (void *)c);
-
- delay=run_pass1(c);
- dependants_ok = call_dependants(& c->supporter, !!c->p );
- #ifdef PIKE_DEBUG
- /* FIXME */
- UNSET_ONERROR(tmp);
- #endif
-
- if(delay)
- {
- CDFPRINTF((stderr, "th(%ld) %p f_compilation_compile() finish later, "
- "placeholder=%p.\n",
- (long) th_self(), c->target, c->placeholder));
- /* finish later */
- verify_supporters();
- /* We're hanging in the supporter. */
- ret = debug_malloc_pass(c->p);
- }else{
- CDFPRINTF((stderr, "th(%ld) %p f_compilation_compile() finish now.\n",
- (long) th_self(), c->target));
- /* finish now */
- run_pass2(c);
- debug_malloc_touch(c);
- run_cleanup(c,0);
-
- ret = debug_malloc_pass(c->p);
-
- debug_malloc_touch(c);
-
- if (!dependants_ok) {
- CDFPRINTF((stderr, "th(%ld) %p f_compilation_compile() reporting failure "
- "since a dependant failed.\n",
- (long) th_self(), c->target));
- throw_error_object(fast_clone_object(compilation_error_program), 0, 0, 0,
- "Compilation failed.\n");
- }
- if(!ret) {
- CDFPRINTF((stderr, "th(%ld) %p f_compilation_compile() failed.\n",
- (long) th_self(), c->target));
- throw_error_object(fast_clone_object(compilation_error_program), 0, 0, 0,
- "Compilation failed.\n");
- }
- debug_malloc_touch(ret);
- #ifdef PIKE_DEBUG
- if (a_flag > 2) {
- dump_program_tables(ret, 0);
- }
- #endif /* PIKE_DEBUG */
- verify_supporters();
- }
- pop_n_elems(args);
- if (ret)
- ref_push_program(ret);
- else
- push_int(0);
- }
-
- /*! @decl mixed resolv(string identifier, string filename, @
- *! object handler)
- *!
- *! Resolve the symbol @[identifier].
- *!
- *! The default implementation calls the corresponding function
- *! in any active handler, and otherwise falls back to
- *! @[CompilerEnvironment()->resolv()] in the parent object.
- */
- static void f_compilation_resolv(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- struct object *handler;
- int fun = -1;
-
- if (((handler = c->handler) && handler->prog &&
- ((fun = find_identifier("resolv", handler->prog)) != -1)) ||
- ((handler = c->compat_handler) && handler->prog &&
- ((fun = find_identifier("resolv", handler->prog)) != -1))) {
- apply_low(handler, fun, args);
- } else {
- apply_external(1, CE_RESOLV_FUN_NUM, args);
- }
- }
-
- /*! @decl object get_compilation_handler(int major, int minor)
- *!
- *! Get compatibility handler for Pike @[major].@[minor].
- *!
- *! @note
- *! This function is called by @[change_compiler_compatibility()].
- */
- static void f_compilation_get_compilation_handler(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- struct object *handler;
- int fun = -1;
-
- if (((handler = c->handler) && handler->prog &&
- ((fun = find_identifier("get_compilation_handler", handler->prog)) != -1)) ||
- ((handler = c->compat_handler) && handler->prog &&
- ((fun = find_identifier("get_compilation_handler", handler->prog)) != -1))) {
- apply_low(handler, fun, args);
- } else {
- apply_external(1, CE_GET_COMPILATION_HANDLER_FUN_NUM, args);
- }
- }
-
- /*! @decl mapping(string:mixed)|object get_default_module()
- *!
- *! Get the default module for the current compatibility level
- *! (ie typically the value returned by @[predef::all_constants()]).
- *!
- *! The default implementation calls the corresponding function
- *! in the current handler, the current compatibility handler
- *! or in the parent @[CompilerEnvironment] in that order.
- *!
- *! @returns
- *! @mixed
- *! @type mapping(string:mixed)|object
- *! Constant table to use.
- *!
- *! @type int(0..0)
- *! Use the builtin constant table.
- *! @endmixed
- *!
- *! @note
- *! This function is called by @[change_compiler_compatibility()].
- */
- static void f_compilation_get_default_module(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- struct object *handler;
- int fun = -1;
-
- if (((handler = c->handler) && handler->prog &&
- ((fun = find_identifier("get_default_module", handler->prog)) != -1)) ||
- ((handler = c->compat_handler) && handler->prog &&
- ((fun = find_identifier("get_default_module", handler->prog)) != -1))) {
- apply_low(handler, fun, args);
- } else {
- apply_external(1, CE_GET_DEFAULT_MODULE_FUN_NUM, args);
- }
- }
-
- /*! @decl void change_compiler_compatibility(int major, int minor)
- *!
- *! Change compiler to attempt to be compatible with Pike @[major].@[minor].
- */
- static void f_compilation_change_compiler_compatibility(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- int major = -1;
- int minor = -1;
-
- STACK_LEVEL_START(args);
-
- get_all_args("change_compiler_compatibility", args, "%d%d",
- &major, &minor);
-
- if ((major == -1) && (minor == -1)) {
- major = PIKE_MAJOR_VERSION;
- minor = PIKE_MINOR_VERSION;
- }
-
- if ((major == Pike_compiler->compat_major) &&
- (minor == Pike_compiler->compat_minor)) {
- /* Optimization: Already at this compat level. */
- pop_n_elems(args);
- push_int(0);
- return;
- }
-
- Pike_compiler->compat_major=major;
- Pike_compiler->compat_minor=minor;
-
- /* Optimization: The up to date compiler shouldn't need a compat handler. */
- if((major != PIKE_MAJOR_VERSION) || (minor != PIKE_MINOR_VERSION))
- {
- apply_current(PC_GET_COMPILATION_HANDLER_FUN_NUM, args);
-
- if((TYPEOF(Pike_sp[-1]) == T_OBJECT) && (Pike_sp[-1].u.object->prog))
- {
- if (SUBTYPEOF(Pike_sp[-1])) {
- /* FIXME: */
- Pike_error("Subtyped compat handlers are not supported yet.\n");
- }
- if (c->compat_handler == Pike_sp[-1].u.object) {
- /* Still at the same compat level. */
- pop_stack();
- push_int(0);
- return;
- } else {
- if(c->compat_handler) free_object(c->compat_handler);
- c->compat_handler = Pike_sp[-1].u.object;
- dmalloc_touch_svalue(Pike_sp-1);
- Pike_sp--;
- }
- } else {
- pop_stack();
- if(c->compat_handler) {
- free_object(c->compat_handler);
- c->compat_handler = NULL;
- } else {
- /* No change in compat handler. */
- push_int(0);
- return;
- }
- }
- } else {
- pop_n_elems(args);
- if (c->compat_handler) {
- free_object(c->compat_handler);
- c->compat_handler = NULL;
- } else {
- /* No change in compat handler. */
- push_int(0);
- return;
- }
- }
-
- STACK_LEVEL_CHECK(0);
-
- Pike_fp->args = 0; /* Clean up the stack frame. */
-
- apply_current(PC_GET_DEFAULT_MODULE_FUN_NUM, 0);
-
- if(TYPEOF(Pike_sp[-1]) == T_INT)
- {
- pop_stack();
- ref_push_mapping(get_builtin_constants());
- }
-
- STACK_LEVEL_CHECK(1);
-
- assign_svalue(&c->default_module, Pike_sp-1);
-
- /* Replace the implicit import of all_constants() with
- * the new value.
- */
- if(c->num_used_modules)
- {
- free_svalue( (struct svalue *)c->used_modules.s.str );
- ((struct svalue *)c->used_modules.s.str)[0]=sp[-1];
- sp--;
- dmalloc_touch_svalue(sp);
- if(Pike_compiler->module_index_cache)
- {
- free_mapping(Pike_compiler->module_index_cache);
- Pike_compiler->module_index_cache=0;
- }
- }else{
- use_module(sp-1);
- pop_stack();
- }
-
- STACK_LEVEL_DONE(0);
- push_int(0);
- }
-
- /*! @decl program handle_inherit(string inh)
- *!
- *! Look up an inherit @[inh] in the current program.
- */
- static void f_compilation_handle_inherit(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- struct object *handler;
- int fun = -1;
-
- if (args > 1) pop_n_elems(args-1);
-
- ref_push_string(c->lex.current_file);
- if (c->handler && c->handler->prog) {
- ref_push_object(c->handler);
- args = 3;
- }
- else args = 2;
-
- if (((handler = c->handler) && handler->prog &&
- ((fun = find_identifier("handle_inherit", handler->prog)) != -1)) ||
- ((handler = c->compat_handler) && handler->prog &&
- ((fun = find_identifier("handle_inherit", handler->prog)) != -1))) {
- apply_low(handler, fun, args);
- } else {
- apply_external(1, CE_HANDLE_INHERIT_FUN_NUM, args);
- }
- }
-
- /*! @decl int(0..1) pop_type_attribute(string attribute, type a, type b)
- *!
- *! Type attribute handler.
- *!
- *! Called during type checking when @expr{a <= b@} and
- *! @[a] had the type attribute @[attribute] before the
- *! comparison.
- *!
- *! The default implementation implements the "deprecated"
- *! attribute.
- *!
- *! @returns
- *! Returns @expr{1@} if the type check should be allowed
- *! (ie @expr{__attribute__(attribute, a) <= b@}), and
- *! @expr{0@} (zero) otherwise.
- *!
- *! @seealso
- *! @[push_type_attribute()]
- */
- static void f_compilation_pop_type_attribute(INT32 args)
- {
- struct pike_string *attr;
- struct svalue *a, *b;
- struct compilation *c = THIS_COMPILATION;
- struct pike_string *deprecated_string;
-
- get_all_args("pop_type_attribute", args, "%W%*%*", &attr, &a, &b);
-
- if (Pike_compiler->compiler_pass == 2) {
- MAKE_CONST_STRING(deprecated_string, "deprecated");
- if ((attr == deprecated_string) &&
- !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS)) {
- push_svalue(a);
- yytype_report(REPORT_WARNING, NULL, 0, NULL,
- NULL, 0, NULL,
- 1, "Using deprecated %O value.");
- }
- }
- pop_n_elems(args);
- push_int(1);
- }
-
- /*! @decl int(0..1) push_type_attribute(string attribute, type a, type b)
- *!
- *! Type attribute handler.
- *!
- *! Called during type checking when @expr{a <= b@} and
- *! @[b] had the type attribute @[attribute] before the
- *! comparison.
- *!
- *! The default implementation implements the "deprecated"
- *! attribute.
- *!
- *! @returns
- *! Returns @expr{1@} if the type check should be allowed
- *! (ie @expr{a <= __attribute__(attribute, b)@}), and
- *! @expr{0@} (zero) otherwise.
- *!
- *! @seealso
- *! @[pop_type_attribute()]
- */
- static void f_compilation_push_type_attribute(INT32 args)
- {
- struct pike_string *attr;
- struct svalue *a, *b;
- struct compilation *c = THIS_COMPILATION;
- struct pike_string *deprecated_string;
-
- get_all_args("push_type_attribute", args, "%W%*%*", &attr, &a, &b);
-
- if (Pike_compiler->compiler_pass == 2) {
- MAKE_CONST_STRING(deprecated_string, "deprecated");
- if ((attr == deprecated_string) &&
- !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS) &&
- !((TYPEOF(*a) == PIKE_T_TYPE) && (a->u.type == zero_type_string))) {
- /* Don't warn about setting deprecated values to zero. */
- push_svalue(b);
- yytype_report(REPORT_WARNING, NULL, 0, NULL,
- NULL, 0, NULL,
- 1, "Using deprecated %O value.");
- }
- }
- pop_n_elems(args);
- push_int(1);
- }
-
- /*! @decl int(0..1) apply_type_attribute(string attribute, @
- *! type a, type|void b)
- *!
- *! Type attribute handler.
- *!
- *! @param attribute
- *! Attribute that @[a] had.
- *!
- *! @param a
- *! Type of the value being called.
- *!
- *! @param b
- *! Type of the first argument in the call, or
- *! @[UNDEFINED] if no more arguments.
- *!
- *! Called during type checking when @[a] has been successfully
- *! had a partial evaluation with the argument @[b] and
- *! @[a] had the type attribute @[attribute] before the
- *! evaluation.
- *!
- *! The default implementation implements the "deprecated"
- *! attribute.
- *!
- *! @returns
- *! Returns @expr{1@} if the type check should be allowed
- *! (ie @expr{__attribute__(attribute, a)(b)@}) is valid,
- *! and @expr{0@} (zero) otherwise.
- *!
- *! @seealso
- *! @[pop_type_attribute()], @[push_type_attribute()]
- */
- static void f_compilation_apply_type_attribute(INT32 args)
- {
- struct pike_string *attr;
- struct svalue *a, *b = NULL;
- struct compilation *c = THIS_COMPILATION;
- struct pike_string *deprecated_string;
-
- get_all_args("apply_type_attribute", args, "%W%*.%*", &attr, &a, &b);
-
- if (Pike_compiler->compiler_pass == 2) {
- MAKE_CONST_STRING(deprecated_string, "deprecated");
- if ((attr == deprecated_string) &&
- !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS) &&
- (!b ||
- ((TYPEOF(*b) == T_INT) && (SUBTYPEOF(*b) == NUMBER_UNDEFINED) &&
- (!b->u.integer)))) {
- /* push_svalue(a); */
- yytype_report(REPORT_WARNING, NULL, 0, NULL,
- NULL, 0, NULL,
- 0, "Calling a deprecated value.");
- }
- }
- pop_n_elems(args);
- push_int(1);
- }
-
- /*! @decl type(mixed) apply_attribute_constant(string attr, @
- *! mixed value, @
- *! type arg_type, @
- *! void cont_type)
- *!
- *! Handle constant arguments to attributed function argument types.
- *!
- *! @param attr
- *! Attribute that @[arg_type] had.
- *!
- *! @param value
- *! Constant value sent as parameter.
- *!
- *! @param arg_type
- *! Declared type of the function argument.
- *!
- *! @param cont_type
- *! Continuation function type after the current argument.
- *!
- *! This function is called when a function is called
- *! with the constant value @[value] and it has been
- *! successfully matched against @[arg_type],
- *! and @[arg_type] had the type attribute @[attr].
- *!
- *! This function is typically used to perform specialized
- *! argument checking and to allow for a strengthening
- *! of the function type based on @[value].
- *!
- *! The default implementation implements the @expr{"sprintf_format"@},
- *! @expr{"sscanf_format"@} and @expr{"sscanf_76_format"@} attributes.
- *!
- *! @returns
- *! Returns a continuation type if it succeeded in strengthening the type.
- *!
- *! Returns @tt{UNDEFINED@} otherwise (this is not an error indication).
- *!
- *! @seealso
- *! @[pop_type_attribute()], @[push_type_attribute()]
- */
- static void f_compilation_apply_attribute_constant(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- struct pike_string *attribute;
- struct pike_string *test;
- struct svalue *sval;
- get_all_args("apply_attribute_constant", args, "%S%*", &attribute, &sval);
-
- if ((TYPEOF(*sval) == T_INT) && !sval->u.integer) {
- pop_n_elems(args);
- push_undefined();
- return;
- }
-
- MAKE_CONST_STRING(test, "sprintf_format");
- if (attribute == test) {
- f___handle_sprintf_format(args);
- return;
- }
- MAKE_CONST_STRING(test, "strict_sprintf_format");
- if (attribute == test) {
- f___handle_sprintf_format(args);
- return;
- }
- MAKE_CONST_STRING(test, "sscanf_format");
- if (attribute == test) {
- f___handle_sscanf_format(args);
- return;
- }
- MAKE_CONST_STRING(test, "sscanf_76_format");
- if (attribute == test) {
- f___handle_sscanf_format(args);
- return;
- }
- pop_n_elems(args);
- push_undefined();
- }
-
- static void f_compilation__sprintf(INT32 args)
- {
- struct compilation *c = THIS_COMPILATION;
- struct string_builder buf;
- init_string_builder_alloc(&buf, 50, 0);
- string_builder_strcat(&buf, "PikeCompiler(");
- if (c->prog) {
- string_builder_strcat(&buf, "\"\", ");
- } else {
- string_builder_strcat(&buf, "UNDEFINED, ");
- }
- if (c->handler) {
- ref_push_object(c->handler);
- string_builder_sprintf(&buf, "%O, ", Pike_sp-1);
- pop_stack();
- } else {
- string_builder_strcat(&buf, "UNDEFINED, ");
- }
- string_builder_sprintf(&buf, "%d, %d, %s, %s)",
- c->major, c->minor,
- c->target?"target":"UNDEFINED",
- c->placeholder?"placeholder":"UNDEFINED");
- pop_n_elems(args);
- push_string(finish_string_builder(&buf));
- }
-
- /* Fake being called via PikeCompiler()->compile()
- *
- * This function is used to set up the environment for
- * compiling C efuns and modules.
- *
- * Note: Since this is a stack frame, it will be cleaned up
- * automatically on error, so no need to use ONERROR().
- *
- * Note: Steals a reference from ce.
- */
- static void low_enter_compiler(struct object *ce, int inherit)
- {
- struct pike_frame *new_frame = alloc_pike_frame();
- #ifdef PROFILING
- new_frame->children_base = Pike_interpreter.accounted_time;
- new_frame->start_time = get_cpu_time() - Pike_interpreter.unlocked_time;
- new_frame->ident = PC_COMPILE_FUN_NUM; /* Fake call of compile(). */
- #endif /* PROFILING */
- new_frame->next = Pike_fp;
- new_frame->current_object = ce;
- /* Note: The compilation environment object hangs on this frame,
- * so that it will be freed when the frame dies.
- */
- new_frame->current_program = ce->prog;
- add_ref(new_frame->current_program);
- new_frame->context = compilation_program->inherits + inherit;
- new_frame->current_storage = ce->storage + new_frame->context->storage_offset;
- #ifdef PIKE_DEBUG
- if (new_frame->context->prog != compilation_program) {
- Pike_fatal("Invalid inherit for compilation context (%p != %p).\n",
- new_frame->context->prog, compilation_program);
- }
- #endif /* PIKE_DEBUG */
- new_frame->fun = new_frame->context->identifier_level + PC_COMPILE_FUN_NUM;
- new_frame->expendible = Pike_sp;
- new_frame->locals = Pike_sp;
- new_frame->save_sp = Pike_sp;
- new_frame->save_mark_sp = Pike_mark_sp;
- new_frame->mark_sp_base = Pike_mark_sp;
- new_frame->args = 0;
- new_frame->num_args = 0;
- new_frame->num_locals = 0;
- new_frame->pc = 0;
- new_frame->return_addr = 0;
- new_frame->scope = 0;
- new_frame->save_sp = Pike_sp;
- Pike_fp = new_frame;
- }
-
- PMOD_EXPORT void enter_compiler(struct pike_string *filename,
- INT_TYPE linenumber)
- {
- struct object *ce = parent_clone_object(compilation_program,
- compilation_environment,
- CE_PIKE_COMPILER_FUN_NUM, 0);
- struct compilation *c;
-
- low_enter_compiler(ce, 0);
-
- c = THIS_COMPILATION;
- if (filename) {
- free_string(c->lex.current_file);
- copy_shared_string(c->lex.current_file, filename);
- }
- if (linenumber) {
- c->lex.current_line = linenumber;
- }
- }
-
- /* Reverse the effect of enter_compiler().
- */
- PMOD_EXPORT void exit_compiler(void)
- {
- #ifdef PIKE_DEBUG
- if ((Pike_fp->current_program != compilation_program) ||
- (Pike_fp->fun != PC_COMPILE_FUN_NUM)) {
- Pike_fatal("exit_compiler(): Frame stack out of whack!\n");
- }
- #endif /* PIKE_DEBUG */
- POP_PIKE_FRAME();
- }
-
- /*! @class CompilerState
- *!
- *! Keeps the state of a single program/class during compilation.
- *!
- *! @note
- *! Not in use yet!
- */
-
- #define THIS_PROGRAM_STATE ((struct program_state *)(Pike_fp->current_storage))
-
- static void program_state_event_handler(int UNUSED(event))
- {
- #if 0
- struct program_state *c = THIS_PROGRAM_STATE;
- switch (event) {
- case PROG_EVENT_INIT:
- #define INIT
- #include "compilation.h"
- break;
- case PROG_EVENT_EXIT:
- #define EXIT
- #include "compilation.h"
- break;
- }
- #endif /* 0 */
- }
-
- /*! @endclass
- */
-
- /*! @endclass
- */
-
- /*! @endclass
- */
-
- /* Strap the compiler by creating the compilation program by hand. */
- static void compile_compiler(void)
- {
- struct program *p = low_allocate_program();
- struct program *p2 = compilation_program = low_allocate_program();
- struct object *co;
- struct inherit *inh;
-
- p->parent_info_storage = -1;
- /* p->event_handler = compilation_env_event_handler; */
- p->flags |= PROGRAM_HAS_C_METHODS;
-
- #if 0
- /* ADD_STORAGE(struct compilation_env); */
- p->alignment_needed = ALIGNOF(struct compilation_env);
- p->storage_needed = p->xstorage + sizeof(struct compilation_env);
- #endif /* 0 */
-
- /* Add the initial inherit, this is needed for clone_object()
- * to actually call the event handler, and for low_enter_compiler()
- * to find the storage and context. */
- p->inherits = inh = xalloc(sizeof(struct inherit));
- inh->prog = p;
- inh->inherit_level = 0;
- inh->identifier_level = 0;
- inh->parent_identifier = -1;
- inh->parent_offset = OBJECT_PARENT;
- inh->identifier_ref_offset = 0;
- inh->storage_offset = p->xstorage;
- inh->parent = NULL;
- inh->name = NULL;
- p->num_inherits = 1;
-
- /* Force clone_object() to accept the program...
- */
- p->flags |= PROGRAM_PASS_1_DONE;
- compilation_environment = clone_object(p, 0);
- p->flags &= ~PROGRAM_PASS_1_DONE;
-
- /* Once more, this time for p2...
- */
-
- p2->parent_info_storage = 0;
- p2->xstorage = sizeof(struct parent_info);
- p2->event_handler = compilation_event_handler;
- p2->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS;
-
- /* ADD_STORAGE(struct compilation); */
- p2->alignment_needed = ALIGNOF(struct compilation);
- p2->storage_needed = p2->xstorage + sizeof(struct compilation);
-
- p2->inherits = inh = xalloc(sizeof(struct inherit));
- inh->prog = p2;
- inh->inherit_level = 0;
- inh->identifier_level = 0;
- inh->parent_identifier = CE_PIKE_COMPILER_FUN_NUM;
- inh->parent_offset = OBJECT_PARENT;
- inh->identifier_ref_offset = 0;
- inh->storage_offset = p2->xstorage;
- inh->parent = NULL;
- inh->name = NULL;
- p2->num_inherits = 1;
-
- p2->flags |= PROGRAM_PASS_1_DONE;
- co = parent_clone_object(p2, compilation_environment,
- CE_PIKE_COMPILER_FUN_NUM, 0);
- p2->flags &= ~PROGRAM_PASS_1_DONE;
-
- low_enter_compiler(co, 0);
-
- low_start_new_program(p, 1, NULL, 0, NULL);
- free_program(p); /* Remove the extra ref we just got... */
-
- /* NOTE: The order of these identifiers is hard-coded in
- * the CE_*_FUN_NUM definitions in "pike_compiler.h".
- */
-
- /* NB: Overloaded properly by inherit of Reporter later on. */
- ADD_FUNCTION("report", f_reporter_report,
- tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
- tStr tStr, tMix, tVoid),0);
-
- ADD_FUNCTION("compile", f_compilation_env_compile,
- tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid)
- tOr(tInt, tVoid) tOr(tInt, tVoid)
- tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid),
- tPrg(tObj)), 0);
-
- ADD_FUNCTION("resolv", f_compilation_env_resolv,
- tFunc(tStr tStr tObj, tMix), 0);
-
- low_start_new_program(p2, 1, NULL, 0, NULL);
-
- /* low_start_new_program() has zapped the inherit we created
- * for p2 above, so we need to repair the frame pointer.
- */
- Pike_fp->context = p2->inherits;
-
- /* MAGIC! We're now executing inside the object being compiled,
- * and have done sufficient stuff to be able to call and use
- * the normal program building functions.
- */
-
- /* NOTE: The order of these identifiers is hard-coded in
- * the PC_*_FUN_NUM definitions in "pike_compiler.h".
- */
-
- ADD_FUNCTION("report", f_compilation_report,
- tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
- tStr tStr, tMix, tVoid),0);
-
- ADD_FUNCTION("compile", f_compilation_compile,
- tFunc(tNone, tPrg(tObj)), 0);
-
- ADD_FUNCTION("resolv", f_compilation_resolv,
- tFunc(tStr tStr tObj, tMix), 0);
-
- ADD_FUNCTION("create", f_compilation_create,
- tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid)
- tOr(tInt, tVoid) tOr(tInt, tVoid)
- tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid), tVoid),
- ID_PROTECTED);
-
- ADD_FUNCTION("get_compilation_handler",
- f_compilation_get_compilation_handler,
- tFunc(tInt tInt, tObj), 0);
-
- ADD_FUNCTION("get_default_module", f_compilation_get_default_module,
- tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0);
-
- ADD_FUNCTION("change_compiler_compatibility",
- f_compilation_change_compiler_compatibility,
- tFunc(tInt tInt, tVoid), 0);
-
- ADD_FUNCTION("handle_inherit", f_compilation_handle_inherit,
- tFunc(tStr, tPrg(tObj)), 0);
-
- ADD_FUNCTION("pop_type_attribute", f_compilation_pop_type_attribute,
- tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);
-
- ADD_FUNCTION("push_type_attribute", f_compilation_push_type_attribute,
- tFunc(tStr tType(tMix) tType(tMix), tInt01), 0);
-
- ADD_FUNCTION("apply_type_attribute", f_compilation_apply_type_attribute,
- tFunc(tStr tType(tMix) tOr(tType(tMix), tVoid), tInt01), 0);
-
- ADD_FUNCTION("apply_attribute_constant",
- f_compilation_apply_attribute_constant,
- tFunc(tStr tMix tType(tMix) tType(tFunction),
- tType(tFunction)), 0);
-
- ADD_FUNCTION("_sprintf", f_compilation__sprintf,
- tFunc(tInt tOr(tMap(tStr, tMix), tVoid), tStr), ID_PROTECTED);
-
- start_new_program();
-
- ADD_STORAGE(struct program_state);
- Pike_compiler->new_program->event_handler = program_state_event_handler;
- Pike_compiler->new_program->flags |=
- PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS;
-
- /* Alias for report above. */
- low_define_alias(NULL, NULL, 0, 1, PC_REPORT_FUN_NUM);
-
- end_class("CompilerState", 0);
-
- /* Map some of our variables so that the gc can find them. */
- PIKE_MAP_VARIABLE("prog", OFFSETOF(compilation, prog),
- tStr, PIKE_T_STRING, ID_HIDDEN);
- PIKE_MAP_VARIABLE("handler", OFFSETOF(compilation, handler),
- tObj, PIKE_T_OBJECT, 0);
- PIKE_MAP_VARIABLE("compat_handler", OFFSETOF(compilation, compat_handler),
- tObj, PIKE_T_OBJECT, 0);
- PIKE_MAP_VARIABLE("target", OFFSETOF(compilation, target),
- tPrg(tObj), PIKE_T_PROGRAM, ID_HIDDEN);
- PIKE_MAP_VARIABLE("placeholder", OFFSETOF(compilation, placeholder),
- tObj, PIKE_T_OBJECT, ID_HIDDEN);
- PIKE_MAP_VARIABLE("p", OFFSETOF(compilation, p),
- tPrg(tObj), PIKE_T_PROGRAM, ID_HIDDEN);
- PIKE_MAP_VARIABLE("current_file", OFFSETOF(compilation, lex.current_file),
- tStr, PIKE_T_STRING, ID_HIDDEN);
- PIKE_MAP_VARIABLE("default_module", OFFSETOF(compilation, default_module),
- tOr(tMap(tStr,tMix),tObj), PIKE_T_MIXED, 0);
-
- /* end_class()/end_program() adds the parent_info storage once more.
- * Remove the one we added above, so that we don't get it double.
- */
- p2->xstorage = 0;
-
- end_class("PikeCompiler", 0);
- /* end_class()/end_program() has zapped the inherit once again,
- * so we need to repair the frame pointer.
- */
- Pike_fp->context = compilation_program->inherits;
-
- ADD_FUNCTION("get_compilation_handler",
- f_compilation_env_get_compilation_handler,
- tFunc(tInt tInt, tObj), 0);
-
- ADD_FUNCTION("get_default_module",
- f_compilation_env_get_default_module,
- tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0);
-
- ADD_FUNCTION("handle_inherit", f_compilation_env_handle_inherit,
- tFunc(tStr tStr tOr(tObj, tVoid), tPrg(tObj)), 0);
-
- /* Reporter */
- start_new_program();
- {
- struct svalue type_value;
-
- ADD_FUNCTION("report", f_reporter_report,
- tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos
- tStr tStr, tMix, tVoid),0);
-
- /* enum SeverityLevel { NOTICE, WARNING, ERROR, FATAL } */
- SET_SVAL(type_value, PIKE_T_TYPE, 0, type,
- CONSTTYPE(tName("SeverityLevel", tInt03)));
- simple_add_constant("SeverityLevel", &type_value, 0);
- free_svalue(&type_value);
-
- add_integer_constant("NOTICE", REPORT_NOTICE, 0);
- add_integer_constant("WARNING", REPORT_WARNING, 0);
- add_integer_constant("ERROR", REPORT_ERROR, 0);
- add_integer_constant("FATAL", REPORT_FATAL, 0);
-
- reporter_program = end_program();
- }
- add_global_program("Reporter", reporter_program);
-
- low_inherit(reporter_program, NULL, -1, 0, 0, 0);
-
- compilation_env_program = end_program();
-
- add_global_program("CompilerEnvironment", compilation_env_program);
-
- exit_compiler();
-
- ref_push_object(compilation_environment);
- low_add_constant("DefaultCompilerEnvironment", Pike_sp-1);
- pop_stack();
- }
-
- struct program *compile(struct pike_string *aprog,
- struct object *ahandler,/* error handler */
- int amajor, int aminor,
- struct program *atarget,
- struct object *aplaceholder)
- {
- int delay, dependants_ok = 1;
- struct program *ret;
- #ifdef PIKE_DEBUG
- ONERROR tmp;
- #endif
- struct object *ce;
- struct compilation *c;
-
- /* FIXME! */
-
- Pike_fatal("Old C-level compile() function called!\n");
-
- CDFPRINTF((stderr, "th(%ld) %p compile() enter, placeholder=%p\n",
- (long) th_self(), atarget, aplaceholder));
-
- ce = clone_object(compilation_program, 0);
- c = (struct compilation *)ce->storage;
-
- debug_malloc_touch(c);
-
- verify_supporters();
-
- c->p = NULL;
- add_ref(c->prog=aprog);
- if((c->handler=ahandler)) add_ref(ahandler);
- c->major=amajor;
- c->minor=aminor;
- if((c->target=atarget)) add_ref(atarget);
- if((c->placeholder=aplaceholder)) add_ref(aplaceholder);
- SET_SVAL(c->default_module, T_INT, NUMBER_NUMBER, integer, 0);
-
- if (c->handler)
- {
- if (safe_apply_handler ("get_default_module", c->handler, NULL,
- 0, BIT_MAPPING|BIT_OBJECT|BIT_ZERO)) {
- if(SAFE_IS_ZERO(Pike_sp-1))
- {
- pop_stack();
- ref_push_mapping(get_builtin_constants());
- }
- } else {
- ref_push_mapping(get_builtin_constants());
- }
- }else{
- ref_push_mapping(get_builtin_constants());
- }
- free_svalue(& c->default_module);
- move_svalue (&c->default_module, --Pike_sp);
-
- #ifdef PIKE_DEBUG
- SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n");
- #endif
-
- low_init_threads_disable();
- #ifdef PIKE_THREADS
- c->saved_threads_disabled = threads_disabled;
- #endif
-
- init_supporter(& c->supporter,
- (supporter_callback *) call_delayed_pass2,
- (void *)c);
-
- delay=run_pass1(c);
- dependants_ok = call_dependants(& c->supporter, !!c->p );
- #ifdef PIKE_DEBUG
- /* FIXME */
- UNSET_ONERROR(tmp);
- #endif
-
- if(delay)
- {
- CDFPRINTF((stderr, "th(%ld) %p compile() finish later, placeholder=%p.\n",
- (long) th_self(), c->target, c->placeholder));
- /* finish later */
- add_ref(c->p);
- verify_supporters();
- return c->p; /* freed later */
- }else{
- CDFPRINTF((stderr, "th(%ld) %p compile() finish now\n",
- (long) th_self(), c->target));
- /* finish now */
- if(c->p) run_pass2(c);
- debug_malloc_touch(c);
- run_cleanup(c,0);
-
- ret=c->p;
- /* FIXME: Looks like ret should get an extra ref here, but I'm not
- * sure. Besides, this function isn't used anymore. /mast */
-
- debug_malloc_touch(c);
- free_object(ce);
-
- if (!dependants_ok) {
- CDFPRINTF((stderr, "th(%ld) %p compile() reporting failure "
- "since a dependant failed.\n",
- (long) th_self(), c->target));
- if (ret) free_program(ret);
- throw_error_object(fast_clone_object(compilation_error_program), 0, 0, 0,
- "Compilation failed.\n");
- }
- if(!ret) {
- CDFPRINTF((stderr, "th(%ld) %p compile() failed.\n",
- (long) th_self(), c->target));
- throw_error_object(fast_clone_object(compilation_error_program), 0, 0, 0,
- "Compilation failed.\n");
- }
- debug_malloc_touch(ret);
- #ifdef PIKE_DEBUG
- if (a_flag > 2) {
- dump_program_tables(ret, 0);
- }
- #endif /* PIKE_DEBUG */
- verify_supporters();
- return ret;
- }
- }
-
- PMOD_EXPORT int pike_add_function2(const char *name, void (*cfun)(INT32),
- const char *type, unsigned flags,
- unsigned opt_flags)
- {
- int ret;
- struct pike_string *name_tmp;
- struct pike_type *type_tmp;
- union idptr tmp;
-
- name_tmp=make_shared_string(name);
- type_tmp=parse_type(type);
-
- if(cfun)
- {
- tmp.c_fun=cfun;
- ret=define_function(name_tmp,
- type_tmp,
- flags,
- IDENTIFIER_C_FUNCTION,
- &tmp,
- opt_flags);
- }else{
- ret=define_function(name_tmp,
- type_tmp,
- flags,
- IDENTIFIER_C_FUNCTION,
- 0,
- opt_flags);
- }
- free_string(name_tmp);
- free_type(type_tmp);
- return ret;
- }
-
- PMOD_EXPORT int quick_add_function(const char *name,
- int name_length,
+ PMOD_EXPORT int low_quick_add_function(struct pike_string * name_tmp,
void (*cfun)(INT32),
const char *type,
int UNUSED(type_length),
unsigned flags,
unsigned opt_flags)
{
int ret;
- struct pike_string *name_tmp;
+
struct pike_type *type_tmp;
union idptr tmp;
/* fprintf(stderr,"ADD_FUNC: %s\n",name); */
- name_tmp = make_shared_binary_string(name, name_length);
+
type_tmp = make_pike_type(type);
if(cfun)
{
tmp.c_fun=cfun;
ret=define_function(name_tmp,
type_tmp,
flags,
IDENTIFIER_C_FUNCTION,
&tmp,
pike.git/src/program.c:10590: Inside #if defined(PIKE_DEBUG) and #if defined(FIND_FUNCTION_HASHSIZE)
if(cache[e].fun < -1 || cache[e].fun > 65536)
Pike_fatal("Error in find_function_cache[%ld].fun\n",(long)e);
}
}
}
#endif
}
#endif
- #undef THIS
- #define THIS ((struct pike_trampoline *)(CURRENT_STORAGE))
- struct program *pike_trampoline_program=0;
+
- static void apply_trampoline(INT32 UNUSED(args))
- {
- Pike_error("Internal error: Trampoline magic failed!\n");
- }
-
- static void not_trampoline(INT32 args)
- {
- pop_n_elems(args);
- if (!THIS->frame || !THIS->frame->current_object ||
- !THIS->frame->current_object->prog) {
- push_int(1);
- } else {
- push_int(0);
- }
- }
-
- static void sprintf_trampoline (INT32 args)
- {
- dynamic_buffer save_buf;
- dynbuf_string str;
-
- if (!args || TYPEOF(sp[-args]) != T_INT || sp[-args].u.integer != 'O' ||
- !THIS->frame || !THIS->frame->current_object) {
- pop_n_elems (args);
- push_int (0);
- return;
- }
- pop_n_elems (args);
-
- ref_push_function (THIS->frame->current_object, THIS->func);
- init_buf(&save_buf);
- describe_svalue (sp - 1, 0, 0);
- str = complex_free_buf(&save_buf);
- pop_stack();
- push_string (make_shared_binary_string (str.str, str.len));
- free (str.str);
- }
-
- static void init_trampoline(struct object *UNUSED(o))
- {
- THIS->frame=0;
- }
-
- static void exit_trampoline(struct object *UNUSED(o))
- {
- if(THIS->frame)
- {
- free_pike_scope(THIS->frame);
- THIS->frame=0;
- }
- }
-
- static void gc_check_frame(struct pike_frame *f)
- {
- if(f->flags & PIKE_FRAME_MALLOCED_LOCALS)
- {
- if(f->current_object)
- debug_gc_check (f->current_object, " as current_object in trampoline frame");
- if(f->current_program)
- debug_gc_check (f->current_program, " as current_program in trampoline frame");
- debug_gc_check_svalues (f->locals, f->num_locals, " in locals of trampoline frame");
- if(f->scope && !debug_gc_check (f->scope, " as scope frame of trampoline frame"))
- gc_check_frame(f->scope);
- }
- }
-
- static void gc_check_trampoline(struct object *UNUSED(o))
- {
- if (THIS->frame &&
- !debug_gc_check (THIS->frame, " as trampoline frame"))
- gc_check_frame(THIS->frame);
- }
-
- static void gc_recurse_frame(struct pike_frame *f)
- {
- if(f->current_object) gc_recurse_object(f->current_object);
- if(f->current_program) gc_recurse_program(f->current_program);
- if(f->flags & PIKE_FRAME_MALLOCED_LOCALS)
- gc_recurse_svalues(f->locals,f->num_locals);
- if(f->scope) gc_recurse_frame(f->scope);
- }
-
- static void gc_recurse_trampoline(struct object *UNUSED(o))
- {
- if (THIS->frame) gc_recurse_frame(THIS->frame);
- }
-
-
- /* This placeholder should be used
- * in the first compiler pass to take the place
- * of unknown things
- */
- struct program *placeholder_program;
- struct object *placeholder_object;
-
- void placeholder_index(INT32 args)
- {
- pop_n_elems(args);
- ref_push_object(Pike_fp->current_object);
- }
-
- static void placeholder_sprintf (INT32 args)
- {
- struct pike_string *s;
-
- if (!args || TYPEOF(sp[-args]) != T_INT || sp[-args].u.integer != 'O') {
- pop_n_elems (args);
- push_int (0);
- return;
- }
-
- pop_n_elems (args);
- MAKE_CONST_STRING (s, "__placeholder_object");
- ref_push_string (s);
- }
-
+
void init_program(void)
{
size_t i;
struct svalue key;
struct svalue val;
struct svalue id;
MAKE_CONST_STRING(this_function_string,"this_function");
MAKE_CONST_STRING(this_program_string,"this_program");
MAKE_CONST_STRING(this_string,"this");
MAKE_CONST_STRING(UNDEFINED_string,"UNDEFINED");
-
+ MAKE_CONST_STRING(args_string, "__args__");
MAKE_CONST_STRING(parser_system_string, "parser");
MAKE_CONST_STRING(type_check_system_string, "type_check");
-
+ MAKE_CONST_STRING(compat_lfun_destroy_string, "destroy");
+
lfun_ids = allocate_mapping(NUM_LFUNS);
lfun_types = allocate_mapping(NUM_LFUNS);
for (i=0; i < NELEM(lfun_names); i++) {
- lfun_strings[i] = make_shared_string(lfun_names[i]);
+ lfun_strings[i] = make_shared_static_string(lfun_names[i], strlen(lfun_names[i]), eightbit);
SET_SVAL(id, T_INT, NUMBER_NUMBER, integer, i);
SET_SVAL(key, T_STRING, 0, string, lfun_strings[i]);
mapping_insert(lfun_ids, &key, &id);
SET_SVAL(val, T_TYPE, 0, type, make_pike_type(raw_lfun_types[i]));
mapping_insert(lfun_types, &key, &val);
free_type(val.u.type);
}
lfun_getter_type_string = make_pike_type(tFuncV(tNone, tVoid, tMix));
lfun_setter_type_string = make_pike_type(tFuncV(tZero, tVoid, tVoid));
- compile_compiler();
+ init_pike_compiler();
enter_compiler(NULL, 0);
- start_new_program();
- debug_malloc_touch(Pike_compiler->fake_object);
- debug_malloc_touch(Pike_compiler->fake_object->storage);
- ADD_STORAGE(struct pike_trampoline);
- ADD_FUNCTION("`()",apply_trampoline,tFunction,0);
- ADD_FUNCTION("`!",not_trampoline,tFunc(tVoid,tInt),0);
- ADD_FUNCTION("_sprintf", sprintf_trampoline,
- tFunc(tInt tOr(tMapping,tVoid),tStr), 0);
- set_init_callback(init_trampoline);
- set_exit_callback(exit_trampoline);
- set_gc_check_callback(gc_check_trampoline);
- set_gc_recurse_callback(gc_recurse_trampoline);
- debug_malloc_touch(Pike_compiler->fake_object);
- debug_malloc_touch(Pike_compiler->fake_object->storage);
- pike_trampoline_program=end_program();
-
- /*! @decl constant __null_program
- *!
- *! Program used internally by the compiler to create objects
- *! that are later modified into instances of the compiled program
- *! by the compiler.
- *!
- *! @seealso
- *! @[__placeholder_object]
- */
- {
- struct svalue s;
- debug_start_new_program(0, "__null_program");
- null_program=end_program();
- SET_SVAL(s, T_PROGRAM, 0, program, null_program);
- low_add_constant("__null_program",&s);
- debug_malloc_touch(null_program);
- }
-
- /*! @decl constant __placeholder_object
- *!
- *! Object used internally by the compiler.
- *!
- *! @seealso
- *! @[__null_program]
- */
- {
- struct svalue s;
- start_new_program();
- ADD_FUNCTION("`()", placeholder_index, tFuncV(tNone,tMix,tObj), 0);
- ADD_FUNCTION("`[]", placeholder_index, tFunc(tMix,tObj), 0);
- ADD_FUNCTION("_sprintf", placeholder_sprintf,
- tFunc(tInt tOr(tMapping,tVoid),tStr), 0);
- placeholder_program=end_program();
- placeholder_object=fast_clone_object(placeholder_program);
-
- SET_SVAL(s, T_OBJECT, 0, object, placeholder_object);
- low_add_constant("__placeholder_object",&s);
- debug_malloc_touch(placeholder_object);
- }
-
+
exit_compiler();
}
void cleanup_program(void)
{
size_t e;
free_type(lfun_setter_type_string);
free_type(lfun_getter_type_string);
free_mapping(lfun_types);
pike.git/src/program.c:10828: Inside #if defined(FIND_FUNCTION_HASHSIZE)
{
if(cache[e].name)
{
free_string(cache[e].name);
cache[e].name=0;
}
}
#endif
#ifdef DO_PIKE_CLEANUP
- if(pike_trampoline_program)
- {
- free_program(pike_trampoline_program);
- pike_trampoline_program=0;
+ if (reverse_symbol_table) {
+ free_mapping(reverse_symbol_table);
+ reverse_symbol_table = NULL;
}
if(null_program)
{
free_program(null_program);
null_program=0;
}
if(placeholder_object)
{
pike.git/src/program.c:10853: Inside #if defined(DO_PIKE_CLEANUP)
placeholder_object=0;
}
if(placeholder_program)
{
free_program(placeholder_program);
placeholder_program=0;
}
#endif
- if (compilation_program) {
- free_program(compilation_program);
- compilation_program = 0;
+ cleanup_pike_compiler();
}
- if (compilation_environment) {
- free_object(compilation_environment);
- compilation_environment = 0;
- }
- if (compilation_env_program) {
- free_program(compilation_env_program);
- compilation_env_program = 0;
- }
- if (reporter_program) {
- free_program(reporter_program);
- reporter_program = 0;
- }
- }
+
- PMOD_EXPORT void visit_program (struct program *p, int action)
+ PMOD_EXPORT void visit_program (struct program *p, int action, void *extra)
{
- switch (action) {
+ visit_enter(p, T_PROGRAM, extra);
+ switch (action & VISIT_MODE_MASK) {
#ifdef PIKE_DEBUG
default:
Pike_fatal ("Unknown visit action %d.\n", action);
case VISIT_NORMAL:
case VISIT_COMPLEX_ONLY:
break;
#endif
case VISIT_COUNT_BYTES:
mc_counted_bytes += p->total_size;
break;
}
if (!(p->flags & PROGRAM_AVOID_CHECK)) {
int e;
struct program_constant *consts = p->constants;
struct inherit *inh = p->inherits;
for (e = p->num_constants - 1; e >= 0; e--)
- visit_svalue (&consts[e].sval, REF_TYPE_NORMAL);
+ visit_svalue (&consts[e].sval, REF_TYPE_NORMAL, extra);
for (e = p->num_inherits - 1; e >= 0; e--) {
if (inh[e].parent)
- visit_object_ref (inh[e].parent, REF_TYPE_NORMAL);
+ visit_object_ref (inh[e].parent, REF_TYPE_NORMAL, extra);
if (e && inh[e].prog)
- visit_program_ref (inh[e].prog, REF_TYPE_NORMAL);
+ visit_program_ref (inh[e].prog, REF_TYPE_NORMAL, extra);
}
if (!(action & VISIT_COMPLEX_ONLY)) {
struct identifier *ids = p->identifiers;
struct pike_string **strs = p->strings;
for (e = p->num_inherits - 1; e >= 0; e--) {
if (inh[e].name)
- visit_string_ref (inh[e].name, REF_TYPE_NORMAL);
+ visit_string_ref (inh[e].name, REF_TYPE_NORMAL, extra);
}
for (e = p->num_identifiers - 1; e >= 0; e--) {
struct identifier *id = ids + e;
- visit_string_ref (id->name, REF_TYPE_NORMAL);
- visit_type_ref (id->type, REF_TYPE_NORMAL);
+ visit_string_ref (id->name, REF_TYPE_NORMAL, extra);
+ visit_type_ref (id->type, REF_TYPE_NORMAL, extra);
}
for (e = p->num_strings - 1; e >= 0; e--)
- visit_string_ref (strs[e], REF_TYPE_NORMAL);
+ visit_string_ref (strs[e], REF_TYPE_NORMAL, extra);
}
/* Strong ref follows. It must be last. */
if (p->parent)
- visit_program_ref (p->parent, REF_TYPE_STRONG);
+ visit_program_ref (p->parent, REF_TYPE_STRONG, extra);
}
-
+ visit_leave(p, T_PROGRAM, extra);
}
static void gc_check_program(struct program *p);
void gc_mark_program_as_referenced(struct program *p)
{
debug_malloc_touch(p);
if (p->flags & PROGRAM_AVOID_CHECK) {
/* Program is in an inconsistent state.
pike.git/src/program.c:11201: Inside #if defined(PIKE_DEBUG)
tmp++;
}
if(tmp >= p->refs)
gc_fatal(p, 1 ,"garbage collector failed to free program!!!\n");
}
#endif
return unreferenced;
}
-
- void push_compiler_frame(int lexical_scope)
+ PMOD_EXPORT void *get_inherit_storage(struct object *o, int inherit)
{
- struct compiler_frame *f;
- f=ALLOC_STRUCT(compiler_frame);
- f->previous=Pike_compiler->compiler_frame;
- f->lexical_scope=lexical_scope;
- f->current_type=0;
- f->current_return_type=0;
-
- f->current_number_of_locals=0;
- f->max_number_of_locals=0;
- f->min_number_of_locals=0;
- f->last_block_level=-1;
-
- f->current_function_number=-2; /* no function */
- f->recur_label=-1;
- f->is_inline=0;
- f->num_args=-1;
- f->opt_flags = OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND; /* FIXME: Should be 0. */
- Pike_compiler->compiler_frame=f;
- }
-
- void low_pop_local_variables(int level)
- {
- struct compilation *c = THIS_COMPILATION;
- while(Pike_compiler->compiler_frame->current_number_of_locals > level)
- {
- int e;
- e=--(Pike_compiler->compiler_frame->current_number_of_locals);
- if ((Pike_compiler->compiler_pass == 2) &&
- !(Pike_compiler->compiler_frame->variable[e].flags &
- LOCAL_VAR_IS_USED)) {
- ref_push_string(Pike_compiler->compiler_frame->variable[e].name);
- low_yyreport(REPORT_WARNING,
- Pike_compiler->compiler_frame->variable[e].file,
- Pike_compiler->compiler_frame->variable[e].line,
- parser_system_string,
- 1, "Unused local variable %s.");
- }
- free_string(Pike_compiler->compiler_frame->variable[e].name);
- free_type(Pike_compiler->compiler_frame->variable[e].type);
- if(Pike_compiler->compiler_frame->variable[e].def)
- free_node(Pike_compiler->compiler_frame->variable[e].def);
-
- free_string(Pike_compiler->compiler_frame->variable[e].file);
- }
- }
-
- void pop_local_variables(int level)
- {
- #if 1
- struct compilation *c = THIS_COMPILATION;
- /* We need to save the variables Kuppo (but not their names) */
- if(level < Pike_compiler->compiler_frame->min_number_of_locals)
- {
- /* FIXME: Consider using flags to indicate whether a local variable
- * actually is used from a nested scope. */
- for(;level<Pike_compiler->compiler_frame->min_number_of_locals;level++)
- {
- if ((Pike_compiler->compiler_pass == 2) &&
- !(Pike_compiler->compiler_frame->variable[level].flags &
- LOCAL_VAR_IS_USED)) {
- ref_push_string(Pike_compiler->compiler_frame->variable[level].name);
- low_yyreport(REPORT_WARNING,
- Pike_compiler->compiler_frame->variable[level].file,
- Pike_compiler->compiler_frame->variable[level].line,
- parser_system_string,
- 1, "Unused local variable %s.");
- /* Make sure we only warn once... */
- Pike_compiler->compiler_frame->variable[level].flags |=
- LOCAL_VAR_IS_USED;
- }
- free_string(Pike_compiler->compiler_frame->variable[level].name);
- copy_shared_string(Pike_compiler->compiler_frame->variable[level].name,
- empty_pike_string);
- /* FIXME: Do we need to keep the filenames? */
- }
- }
- #endif
- low_pop_local_variables(level);
- }
-
-
- void pop_compiler_frame(void)
- {
- struct compiler_frame *f;
-
- f=Pike_compiler->compiler_frame;
- #ifdef PIKE_DEBUG
- if(!f)
- Pike_fatal("Popping out of compiler frames\n");
- #endif
-
- low_pop_local_variables(0);
- if(f->current_type)
- free_type(f->current_type);
-
- if(f->current_return_type)
- free_type(f->current_return_type);
-
- Pike_compiler->compiler_frame=f->previous;
- dmfree((char *)f);
- }
-
-
- PMOD_EXPORT char *get_inherit_storage(struct object *o, int inherit)
- {
+
if (!o || !o->prog) return NULL;
#ifdef PIKE_DEBUG
if ((inherit < 0) || (inherit >= o->prog->num_inherits))
Pike_fatal("Inherit #%d out of range [0..%d]\n",
inherit, o->prog->num_inherits-1);
#endif
return o->storage + o->prog->inherits[inherit].storage_offset;
}
#define GET_STORAGE_CACHE_SIZE 1024
pike.git/src/program.c:11334:
PMOD_EXPORT ptrdiff_t low_get_storage(struct program *o, struct program *p)
{
INT32 oid, pid;
ptrdiff_t offset;
unsigned INT32 hval;
if(!o) return -1;
oid=o->id;
pid=p->id;
- hval=oid*9248339 + pid;
- hval%=GET_STORAGE_CACHE_SIZE;
- #ifdef PIKE_DEBUG
- if(hval>GET_STORAGE_CACHE_SIZE)
- Pike_fatal("hval>GET_STORAGE_CACHE_SIZE\n");
- #endif
+ hval=(unsigned)oid*9248339 + (unsigned)pid;
+ hval&=GET_STORAGE_CACHE_SIZE-1;
if(get_storage_cache[hval].oid == oid &&
get_storage_cache[hval].pid == pid)
{
offset=get_storage_cache[hval].offset;
}else{
INT32 e;
offset=-1;
for(e=0;e<o->num_inherits;e++)
{
if(o->inherits[e].prog==p)
pike.git/src/program.c:11364:
}
get_storage_cache[hval].oid=oid;
get_storage_cache[hval].pid=pid;
get_storage_cache[hval].offset=offset;
}
return offset;
}
- PMOD_EXPORT char *get_storage(struct object *o, struct program *p)
+ PMOD_EXPORT void *get_storage(struct object *o, struct program *p)
{
ptrdiff_t offset;
#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;
pike.git/src/program.c:11413:
}
PMOD_EXPORT struct program *program_from_function(const struct svalue *f)
{
if(TYPEOF(*f) != T_FUNCTION) return 0;
if(SUBTYPEOF(*f) == FUNCTION_BUILTIN) return 0;
return low_program_from_function(f->u.object, SUBTYPEOF(*f));
}
+ PMOD_EXPORT struct program *program_from_type(const struct pike_type *t)
+ {
+ if (!t) return NULL;
+
+ switch(t->type) {
+ case T_OBJECT:
+ if (t->cdr) break;
+ return NULL;
+ case T_TUPLE:
+ case T_OR:
+ case T_AND:
+ case PIKE_T_RING:
+ {
+ struct program *res;
+ res = program_from_type(t->car);
+ if (res) return res;
+ }
+ /* FALLTHRU */
+ case T_SCOPE:
+ case T_ASSIGN:
+ case PIKE_T_ATTRIBUTE:
+ case PIKE_T_NAME:
+ return program_from_type(t->cdr);
+ break;
+ default:
+ return NULL;
+ }
+
+ return id_to_program((int)(ptrdiff_t)t->cdr);
+ }
+
/* NOTE: Does not add references to the return value! */
PMOD_EXPORT struct program *low_program_from_svalue(const struct svalue *s,
struct object **parent_obj,
int *parent_id)
{
switch(TYPEOF(*s))
{
case T_OBJECT:
{
struct program *p = s->u.object->prog;
pike.git/src/program.c:11452:
return p; /* We trust that there is a reference somewhere... */
}
case T_FUNCTION:
if (SUBTYPEOF(*s) == FUNCTION_BUILTIN) return 0;
return low_program_from_function(*parent_obj = s->u.object,
*parent_id = SUBTYPEOF(*s));
case T_PROGRAM:
return s->u.program;
+
+ case PIKE_T_TYPE:
+ return program_from_type(s->u.type);
+
default:
return 0;
}
}
/* NOTE: Does not add references to the return value! */
PMOD_EXPORT struct program *program_from_svalue(const struct svalue *s)
{
struct object *parent_obj = NULL;
int parent_id = -1;
pike.git/src/program.c:11505: Inside #if 0
return i;
}
}
}
return -1;
}
#endif /* 0 */
- /* returns 1 if a implements b */
+ /**
+ * @return Returns 1 if a implements b.
+ */
static int low_implements(struct program *a, struct program *b)
{
-
+ DECLARE_CYCLIC();
int e;
- struct pike_string *s=findstring("__INIT");
+ int ret = 1;
+
+ if (BEGIN_CYCLIC(a, b)) {
+ END_CYCLIC();
+ return 1; /* Tentatively ok, */
+ }
+ SET_CYCLIC_RET(1);
+
for(e=0;e<b->num_identifier_references;e++)
{
struct identifier *bid;
int i;
if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))
continue; /* Skip protected & hidden */
bid = ID_FROM_INT(b,e);
- if(s == bid->name) continue; /* Skip __INIT */
+ if(lfun_strings[LFUN___INIT] == bid->name) continue; /* Skip __INIT */
i = find_shared_string_identifier(bid->name,a);
if (i == -1) {
if (b->identifier_references[e].id_flags & (ID_OPTIONAL))
continue; /* It's ok... */
#if 0
fprintf(stderr, "Missing identifier \"%s\"\n", bid->name->str);
#endif /* 0 */
- return 0;
+ ret = 0;
+ break;
}
if (!pike_types_le(bid->type, ID_FROM_INT(a, i)->type)) {
if(!match_types(ID_FROM_INT(a,i)->type, bid->type)) {
#if 0
fprintf(stderr, "Identifier \"%s\" is incompatible.\n",
bid->name->str);
#endif /* 0 */
- return 0;
+ ret = 0;
+ break;
} else {
#if 0
fprintf(stderr, "Identifier \"%s\" is not strictly compatible.\n",
bid->name->str);
#endif /* 0 */
}
}
}
- return 1;
+
+ END_CYCLIC();
+ return ret;
}
- #define IMPLEMENTS_CACHE_SIZE 4711
+ #define IMPLEMENTS_CACHE_SIZE 1024
struct implements_cache_s { INT32 aid, bid, ret; };
static struct implements_cache_s implements_cache[IMPLEMENTS_CACHE_SIZE];
- /* returns 1 if a implements b, but faster */
+ static int implements_hval( INT32 aid, INT32 bid )
+ {
+ return ((aid<<4) ^ bid ^ (aid>>4)) & (IMPLEMENTS_CACHE_SIZE-1);
+ }
+
+ /**
+ * @return Returns 1 if a implements b, but faster.
+ */
PMOD_EXPORT int implements(struct program *a, struct program *b)
{
unsigned long hval;
if(!a || !b) return -1;
if(a==b) return 1;
- hval = a->id*9248339 + b->id;
- hval %= IMPLEMENTS_CACHE_SIZE;
- #ifdef PIKE_DEBUG
- if(hval >= IMPLEMENTS_CACHE_SIZE)
- Pike_fatal("Implements_cache failed!\n");
- #endif
+ hval = implements_hval(a->id,b->id);
if(implements_cache[hval].aid==a->id && implements_cache[hval].bid==b->id)
{
return implements_cache[hval].ret;
}
/* Do it the tedious way */
implements_cache[hval].aid=a->id;
implements_cache[hval].bid=b->id;
implements_cache[hval].ret = 1; /* Tentatively compatible. */
implements_cache[hval].ret = low_implements(a,b);
/* NOTE: If low_implements() returns 0, the cache may have received
* some false positives. Those should be cleared.
*/
return implements_cache[hval].ret;
}
- /* Returns 1 if a is compatible with b */
+ /**
+ * @return Returns 1 if a is compatible with b.
+ */
static int low_is_compatible(struct program *a, struct program *b)
{
-
+ DECLARE_CYCLIC();
int e;
- struct pike_string *s=findstring("__INIT");
+ int ret = 1;
-
+ if (BEGIN_CYCLIC(a, b)) {
+ END_CYCLIC();
+ return 1;
+ }
+ SET_CYCLIC_RET(1);
+
/* Optimize the loop somewhat */
if (a->num_identifier_references < b->num_identifier_references) {
struct program *tmp = a;
a = b;
b = tmp;
}
for(e=0;e<b->num_identifier_references;e++)
{
struct identifier *bid;
int i;
if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))
continue; /* Skip protected & hidden */
/* FIXME: What if they aren't protected & hidden in a? */
bid = ID_FROM_INT(b,e);
- if(s == bid->name) continue; /* Skip __INIT */
+ if(lfun_strings[LFUN___INIT] == bid->name) continue; /* Skip __INIT */
i = find_shared_string_identifier(bid->name,a);
if (i == -1) {
continue; /* It's ok... */
}
/* Note: Uses weaker check for constant integers. */
if(((bid->run_time_type != PIKE_T_INT) ||
(ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) &&
!match_types(ID_FROM_INT(a,i)->type, bid->type)) {
#if 0
fprintf(stderr, "Identifier \"%s\" is incompatible.\n",
bid->name->str);
#endif /* 0 */
- return 0;
+ ret = 0;
+ break;
}
}
- return 1;
+
+ END_CYCLIC();
+ return ret;
}
static struct implements_cache_s is_compatible_cache[IMPLEMENTS_CACHE_SIZE];
- /* Returns 1 if a is compatible with b
+ /**
+ * Returns 1 if a is compatible with b.
+ *
* ie it's possible to write a hypothetical c that implements both.
*/
PMOD_EXPORT int is_compatible(struct program *a, struct program *b)
{
unsigned long hval;
unsigned long rhval;
int aid, bid;
if(!a || !b) return -1;
if(a==b) return 1;
/* Order the id's so we don't need double entries in the cache. */
aid = a->id;
bid = b->id;
if (aid > bid) {
int tmp = aid;
aid = bid;
bid = tmp;
}
- hval = aid*9248339 + bid;
- hval %= IMPLEMENTS_CACHE_SIZE;
- #ifdef PIKE_DEBUG
- if(hval >= IMPLEMENTS_CACHE_SIZE)
- Pike_fatal("Implements_cache failed!\n");
- #endif
+ hval = implements_hval(aid,bid);
if(is_compatible_cache[hval].aid==aid &&
is_compatible_cache[hval].bid==bid)
{
return is_compatible_cache[hval].ret;
}
if(implements_cache[hval].aid==aid &&
implements_cache[hval].bid==bid &&
implements_cache[hval].ret)
{
/* a implements b */
return 1;
}
- rhval = bid*9248339 + aid;
- rhval %= IMPLEMENTS_CACHE_SIZE;
- #ifdef PIKE_DEBUG
- if(rhval >= IMPLEMENTS_CACHE_SIZE)
- Pike_fatal("Implements_cache failed!\n");
- #endif
+ rhval = implements_hval(bid,aid);
if(implements_cache[rhval].aid==bid &&
implements_cache[rhval].bid==aid &&
implements_cache[rhval].ret)
{
/* b implements a */
return 1;
}
/* Do it the tedious way */
is_compatible_cache[hval].aid=aid;
is_compatible_cache[hval].bid=bid;
is_compatible_cache[hval].ret = 1; /* Tentatively compatible. */
is_compatible_cache[hval].ret = low_is_compatible(a,b);
/* NOTE: If low_is compatible() returns 0, the cache may have received
* some false positives. Those should be cleared.
*/
return is_compatible_cache[hval].ret;
}
- /* Explains why a is not compatible with b */
+ /**
+ * Explains why a is not compatible with b.
+ */
void yyexplain_not_compatible(int severity_level,
struct program *a, struct program *b)
{
int e;
- struct pike_string *s=findstring("__INIT");
+
int res = 1;
INT_TYPE a_line = 0;
INT_TYPE b_line = 0;
struct pike_string *a_file;
struct pike_string *b_file;
DECLARE_CYCLIC();
/* Optimize the loop somewhat */
if (a->num_identifier_references < b->num_identifier_references) {
struct program *tmp = a;
pike.git/src/program.c:11723:
for(e=0;e<b->num_identifier_references;e++)
{
struct identifier *bid;
int i;
if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))
continue; /* Skip protected & hidden */
/* FIXME: What if they aren't protected & hidden in a? */
bid = ID_FROM_INT(b,e);
- if(s == bid->name) continue; /* Skip __INIT */
+ if(lfun_strings[LFUN___INIT] == bid->name) continue; /* Skip __INIT */
i = find_shared_string_identifier(bid->name,a);
if (i == -1) {
continue; /* It's ok... */
}
/* Note: Uses weaker check for constant integers. */
if(((bid->run_time_type != PIKE_T_INT) ||
(ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) &&
!match_types(ID_FROM_INT(a,i)->type, bid->type)) {
INT_TYPE aid_line = a_line;
pike.git/src/program.c:11754:
bid_file, bid_line, bid->type, 3,
"Identifier %s in %O is incompatible with the same in %O.");
}
}
free_string(b_file);
free_string(a_file);
END_CYCLIC();
return;
}
- /* Explains why a does not implement b */
+ /**
+ * Explains why a does not implement b.
+ */
void yyexplain_not_implements(int severity_level,
struct program *a, struct program *b)
{
int e;
- struct pike_string *s=findstring("__INIT");
+
INT_TYPE a_line = 0;
INT_TYPE b_line = 0;
struct pike_string *a_file;
struct pike_string *b_file;
DECLARE_CYCLIC();
if (BEGIN_CYCLIC(a, b)) {
END_CYCLIC();
return;
}
pike.git/src/program.c:11782:
a_file = get_program_line(a, &a_line);
b_file = get_program_line(b, &b_line);
for(e=0;e<b->num_identifier_references;e++)
{
struct identifier *bid;
int i;
if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))
continue; /* Skip protected & hidden */
bid = ID_FROM_INT(b,e);
- if(s == bid->name) continue; /* Skip __INIT */
+ if(lfun_strings[LFUN___INIT] == bid->name) continue; /* Skip __INIT */
i = find_shared_string_identifier(bid->name,a);
if (i == -1) {
INT_TYPE bid_line = b_line;
struct pike_string *bid_file;
if (b->identifier_references[e].id_flags & (ID_OPTIONAL))
continue; /* It's ok... */
bid_file = get_identifier_line(b, e, &bid_line);
if (!bid_file) bid_file = b_file;
yytype_report(severity_level,
bid_file, bid_line, bid->type,
pike.git/src/program.c:11827:
}
continue;
}
}
free_string(b_file);
free_string(a_file);
END_CYCLIC();
}
/* FIXME: Code duplication of yyexplain_not_compatible() above! */
- /* Explains why a is not compatible with b */
+ /**
+ * Explains why a is not compatible with b.
+ */
void string_builder_explain_not_compatible(struct string_builder *s,
struct program *a,
struct program *b)
{
int e;
- struct pike_string *init_string = findstring("__INIT");
+
int res = 1;
DECLARE_CYCLIC();
/* Optimize the loop somewhat */
if (a->num_identifier_references < b->num_identifier_references) {
struct program *tmp = a;
a = b;
b = tmp;
}
pike.git/src/program.c:11860:
for(e=0;e<b->num_identifier_references;e++)
{
struct identifier *bid;
int i;
if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))
continue; /* Skip protected & hidden */
/* FIXME: What if they aren't protected & hidden in a? */
bid = ID_FROM_INT(b,e);
- if(init_string == bid->name) continue; /* Skip __INIT */
+ if(lfun_strings[LFUN___INIT] == bid->name) continue; /* Skip __INIT */
i = find_shared_string_identifier(bid->name,a);
if (i == -1) {
continue; /* It's ok... */
}
/* Note: Uses weaker check for constant integers. */
if(((bid->run_time_type != PIKE_T_INT) ||
(ID_FROM_INT(a, i)->run_time_type != PIKE_T_INT)) &&
!match_types(ID_FROM_INT(a,i)->type, bid->type)) {
ref_push_program(a);
pike.git/src/program.c:11891:
Pike_sp-2,
Pike_sp-1);
pop_n_elems(4);
}
}
END_CYCLIC();
return;
}
/* FIXME: code duplication of yyexplain_not_implements() above! */
- /* Explains why a does not implement b */
+ /**
+ * Explains why a does not implement b.
+ */
void string_builder_explain_not_implements(struct string_builder *s,
struct program *a,
struct program *b)
{
int e;
- struct pike_string *init_string = findstring("__INIT");
+
DECLARE_CYCLIC();
if (BEGIN_CYCLIC(a, b)) {
END_CYCLIC();
return;
}
SET_CYCLIC_RET(1);
for(e=0;e<b->num_identifier_references;e++)
{
struct identifier *bid;
int i;
if (b->identifier_references[e].id_flags & (ID_PROTECTED|ID_HIDDEN|ID_VARIANT))
continue; /* Skip protected & hidden */
bid = ID_FROM_INT(b,e);
- if(init_string == bid->name) continue; /* Skip __INIT */
+ if(lfun_strings[LFUN___INIT] == bid->name) continue; /* Skip __INIT */
i = find_shared_string_identifier(bid->name,a);
if (i == -1) {
if (b->identifier_references[e].id_flags & (ID_OPTIONAL))
continue; /* It's ok... */
ref_push_type_value(bid->type);
string_builder_sprintf(s,
"Missing identifier %O %S.\n",
Pike_sp-1, bid->name);
pop_stack();
continue;
pike.git/src/program.c:11939:
if(!match_types(ID_FROM_INT(a,i)->type, bid->type)) {
string_builder_sprintf(s,
"Type of identifier %S does not match.\n"
"Expected: %O.\n"
"Got : %O.\n",
bid->name,
Pike_sp-2,
Pike_sp-1);
} else {
string_builder_sprintf(s,
- "Type of identifier %S is not strictly compatible.",
+ "Type of identifier %S is not strictly compatible."
"Expected: %O.\n"
"Got : %O.\n",
bid->name,
Pike_sp-2,
Pike_sp-1);
}
pop_n_elems(2);
continue;
}
}
END_CYCLIC();
}
- PMOD_EXPORT void *parent_storage(int depth)
+ PMOD_EXPORT void *parent_storage(int depth, struct program *expected)
{
struct external_variable_context loc;
-
+ int i;
loc.o = Pike_fp->current_object;
loc.parent_identifier = 0;
loc.inherit = Pike_fp->context;
find_external_context(&loc, depth);
if (!loc.o->prog)
Pike_error ("Cannot access storage of destructed parent object.\n");
-
+ for (i = 0; i < loc.inherit->prog->num_inherits; i++) {
+ if (loc.inherit[i].prog == expected) {
+ /* Found. */
+ loc.inherit += i;
+ break;
+ }
+ }
+
+ #ifdef PIKE_DEBUG
+ if (loc.inherit->prog != expected) {
+ Pike_fatal("Failed to find expected parent storage.\n");
+ }
+ #endif
+
return loc.o->storage + loc.inherit->storage_offset;
}
- PMOD_EXPORT void change_compiler_compatibility(int major, int minor)
+ PMOD_EXPORT void *get_inherited_storage(int inh,
+ struct program *DEBUGUSED(expected))
{
- CHECK_COMPILER();
+ struct inherit *i = Pike_fp->context + inh;
- push_int(major);
- push_int(minor);
+ #ifdef PIKE_DEBUG
+ struct program *p = Pike_fp->current_program;
+ if (i >= (p->inherits + p->num_inherits)) {
+ Pike_fatal("Inherit out of range!\n");
+ }
+ if (i->prog != expected) {
+ Pike_fatal("Unexpected program at inherit #%d!\n", inh);
+ }
+ #endif
- safe_apply_current2(PC_CHANGE_COMPILER_COMPATIBILITY_FUN_NUM, 2,
- "change_compiler_compatibility");
- pop_stack();
+ return Pike_fp->current_object->storage + i->storage_offset;
}
#ifdef PIKE_USE_MACHINE_CODE
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
-
+ #if defined(HAVE_SYNC_INSTRUCTION_MEMORY) || defined(FLUSH_INSTRUCTION_CACHE) || !defined(USE_MY_MEXEC_ALLOC)
void make_area_executable (char *start, size_t len)
{
#ifndef USE_MY_MEXEC_ALLOC
{
/* Perform page alignment. */
void *addr = (void *)(((size_t)start) & ~(page_size-1));
size_t l = ((start + len) - ((char *)addr) +
(page_size - 1)) & ~(page_size-1);
if (mprotect(addr, l, PROT_EXEC | PROT_READ | PROT_WRITE) < 0) {
pike.git/src/program.c:12011: Inside #if undefined(USE_MY_MEXEC_ALLOC)
}
}
#endif /* !USE_MY_MEXEC_ALLOC */
#ifdef HAVE_SYNC_INSTRUCTION_MEMORY
sync_instruction_memory(start, len);
#elif defined(FLUSH_INSTRUCTION_CACHE)
FLUSH_INSTRUCTION_CACHE(start, len);
#endif /* HAVE_SYNC_INSTRUCTION_MEMORY || FLUSH_INSTRUCTION_CACHE */
}
+ #else
+ void make_area_executable (char *UNUSED(start), size_t UNUSED(len))
+ {
+ }
+ #endif
void make_program_executable(struct program *p)
{
if (!p->num_program) return;
if ((p->event_handler == compat_event_handler) &&
((p->num_program * sizeof(p->program[0]) <=
(NUM_PROG_EVENTS * sizeof(p->event_handler))))) {
/* Only event handlers. */
return;
}
make_area_executable ((char *) p->program,
p->num_program * sizeof (p->program[0]));
}
#endif
-
+
+ PMOD_EXPORT void string_builder_append_disassembly(struct string_builder *s,
+ const PIKE_OPCODE_T *start,
+ const PIKE_OPCODE_T *end,
+ const char *opcode,
+ const char **params,
+ const char *comment)
+ {
+ while ((start < end) || opcode || (params && params[0]) ||
+ (comment && comment[0])) {
+ ptrdiff_t field_width = sizeof(PIKE_OPCODE_T) * 2;
+ ptrdiff_t i;
+ int skip_params = 0;
+ int skip_comment = 0;
+
+ if (end) {
+ /* Address */
+ string_builder_sprintf(s, "0x%016lx ", start);
+
+ if (start < end) {
+ /* Memory dump */
+ for (i = 0; i < 8; i += field_width) {
+ if (start < end) {
+ string_builder_sprintf(s, "%0*x ", field_width, start[0]);
+ start++;
+ if (start == end) {
+ end = NULL;
+ }
+ } else {
+ string_builder_sprintf(s, "%*s ", field_width, "");
+ }
+ }
+ } else {
+ end = NULL;
+ string_builder_sprintf(s, "%*s ", 8 + 8/field_width, "");
+ }
+ } else {
+ string_builder_sprintf(s, "%*s ", 18 + 8 + 8/field_width, "");
+ }
+
+ /* Opcode */
+ if (opcode) {
+ if (strlen(opcode) < 8) {
+ string_builder_sprintf(s, " %-8s ", opcode);
+ } else if (strlen(opcode) < 32) {
+ string_builder_sprintf(s, " %-28s ", opcode);
+ skip_params = 1;
+ } else {
+ string_builder_sprintf(s, " %s", opcode);
+ skip_params = skip_comment = 1;
+ }
+ opcode = NULL;
+ } else if ((params && params[0]) || (comment && comment[0])) {
+ /* No need to pad if there's no argument and no comment. */
+ string_builder_sprintf(s, " %8s ", "");
+ }
+
+ /* Params */
+ if (skip_params) {
+ } else if (params && params[0]) {
+ ptrdiff_t bytes_left = 20;
+ do {
+ string_builder_sprintf(s, "%s", params[0]);
+ bytes_left -= strlen(params[0]);
+ params++;
+ if (params[0]) {
+ string_builder_sprintf(s, ", ");
+ bytes_left -= 2;
+ }
+ } while (params[0] && (((ptrdiff_t)strlen(params[0])) <= bytes_left));
+ if (bytes_left < 0) {
+ skip_comment = 1;
+ } else if (comment && comment[0]) {
+ /* No need to pad if there's no comment. */
+ string_builder_sprintf(s, "%*s ", bytes_left-1, "");
+ }
+ } else if (comment && comment[0]) {
+ /* No need to pad if there's no comment. */
+ string_builder_sprintf(s, "%*s ", 19, "");
+ }
+
+ /* Comment */
+ if (!skip_comment && (comment && comment[0])) {
+ const char *ptr = strchr(comment, '\n');
+ if (ptr) {
+ string_builder_sprintf(s, " # %.*s\n", ptr - comment, comment);
+ comment = ptr + 1;
+ if (!comment[0]) comment = NULL;
+ } else {
+ string_builder_sprintf(s, " # %s\n", comment);
+ comment = NULL;
+ }
+ } else {
+ string_builder_sprintf(s, "\n");
+ }
+ }
+ }
+
+ PMOD_EXPORT void string_builder_append_pike_opcode(struct string_builder *s,
+ const PIKE_OPCODE_T *addr,
+ enum Pike_opcodes op,
+ int arg1,
+ int arg2)
+ {
+ char buf[3][32];
+ const char *params[3] = { NULL, NULL, NULL };
+ const struct instr *instr = &instrs[op - F_OFFSET];
+ sprintf(buf[0], "%d", arg1);
+ sprintf(buf[1], "%d", arg2);
+ if (instr->flags & I_HASARG) {
+ params[0] = buf[0];
+ }
+ if (instr->flags & I_HASARG2) {
+ params[1] = buf[1];
+ }
+ sprintf(buf[2], "# %s", instr->name);
+ string_builder_append_disassembly(s, addr, addr, buf[2], params, NULL);
+ }
+
+ PMOD_EXPORT void add_reverse_symbol(struct pike_string *sym, void *addr)
+ {
+ struct svalue key;
+ struct svalue val;
+ SET_SVAL(key, PIKE_T_INT, NUMBER_NUMBER, integer, (ptrdiff_t)addr);
+ SET_SVAL(val, PIKE_T_STRING, 0, string, sym);
+ low_mapping_insert(reverse_symbol_table, &key, &val, 1);
+ }
+
+ PMOD_EXPORT void simple_add_reverse_symbol(const char *sym, void *addr)
+ {
+ struct pike_string *s = make_shared_string(sym);
+ add_reverse_symbol(s, addr);
+ free_string(s);
+ }
+
+ PMOD_EXPORT void init_reverse_symbol_table()
+ {
+ int op;
+
+ if (reverse_symbol_table) return;
+ reverse_symbol_table = allocate_mapping(256);
+
+ /* Initialize with the most popular symbols. */
+ #define ADD_SYMBOL(SYM) simple_add_reverse_symbol(#SYM "()", (void *)(SYM))
+ #if defined(PIKE_DEBUG) && defined(PIKE_USE_MACHINE_CODE)
+ ADD_SYMBOL(simple_debug_instr_prologue_0);
+ ADD_SYMBOL(simple_debug_instr_prologue_1);
+ ADD_SYMBOL(simple_debug_instr_prologue_2);
+ #endif
+ ADD_SYMBOL(low_return);
+ ADD_SYMBOL(low_return_pop);
+ ADD_SYMBOL(really_free_svalue);
+ ADD_SYMBOL(lvalue_to_svalue_no_free);
+ ADD_SYMBOL(f_add);
+ ADD_SYMBOL(really_free_string);
+ ADD_SYMBOL(pike_sizeof);
+ ADD_SYMBOL(o_subtract);
+ ADD_SYMBOL(svalue_is_true);
+ ADD_SYMBOL(assign_lvalue);
+ ADD_SYMBOL(really_free_array);
+ ADD_SYMBOL(object_low_set_index);
+ ADD_SYMBOL(low_object_index_no_free);
+ ADD_SYMBOL(assign_to_short_svalue);
+ ADD_SYMBOL(really_free_short_svalue_ptr);
+ ADD_SYMBOL(mega_apply);
+
+ simple_add_reverse_symbol("Pike_interpreter_pointer",
+ (void *)&Pike_interpreter_pointer);
+
+ #ifdef PIKE_USE_MACHINE_CODE
+ /* Add the opcodes as well. */
+ for (op = 1; op < (F_MAX_INSTR - F_OFFSET); op++) {
+ if (!instrs[op].address) continue;
+ simple_add_reverse_symbol(instrs[op].name, instrs[op].address);
+ }
+ #endif /* PIKE_USE_MACHINE_CODE */
+ }
+
+ PMOD_EXPORT struct pike_string *reverse_symbol_lookup(void *addr)
+ {
+ struct svalue key;
+ struct svalue *s;
+ if (!reverse_symbol_table) {
+ init_reverse_symbol_table();
+ }
+ SET_SVAL(key, PIKE_T_INT, NUMBER_NUMBER, integer, (ptrdiff_t)addr);
+ s = low_mapping_lookup(reverse_symbol_table, &key);
+
+ /* FIXME: Fall back to using dladdr() on supported OSes? */
+ if (!s || (TYPEOF(*s) != PIKE_T_STRING)) return NULL;
+ return s->u.string;
+ }