Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 61 additions & 32 deletions lib/lpc/identifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
ident_hash_elem_list_t *ihe_list = NULL;

static int num_free = 0;
static ident_hash_elem_t **ident_hash_table;
static ident_hash_elem_t **ident_hash_head;
static ident_hash_elem_t **ident_hash_tail;
static ident_hash_elem_t **ident_hash_table; /* ident hash, current position */
static ident_hash_elem_t **ident_hash_head; /* ident hash, head of permanent idents */
static ident_hash_elem_t **ident_hash_tail; /* ident hash, tail of permanent idents */

static ident_hash_elem_t *ident_dirty_list = 0;

Expand All @@ -31,38 +31,49 @@ static ident_hash_elem_t *ident_dirty_list = 0;
* hash value are used often within close proximity in the source.
* This should be rare, esp since the hash table is fairly sparse.
*
* ident_hash_table[hash] points to our current position (last lookup)
* ident_hash_head[hash] points to the first permanent identifier
* ident_hash_tail[hash] points to the last one
* ident_hash_table[hash] points to our current position (last successful lookup) in the bucket
* ident_hash_head[hash] points to the first permanent identifier in the bucket
* ident_hash_tail[hash] points to the last permanent identifier in the bucket
* ident_dirty_list is a linked list of identifiers that need to be cleaned
* when we're done; this happens if you define a global or function with
* the same name (hashed) as an efun or sefun.
* the same name (hashed) as an efun or simul efun.
*/

#define CHECK_ELEM(x, y, z) if (!strcmp((x)->name, (y))) { \
if (((x)->token & IHE_RESWORD) || ((x)->sem_value)) { z } \
else return 0; }

/**
* Lookup an identifier by name in the identifier hash table.
* Each bucket in the hash table is a circular linked list.
* In the case of collisions, the bucket is searched starting from current position (last lookup).
* When found, the found element is rotated to the front of the list for faster future access.
*
* @param name The name of the identifier.
* @return A pointer to the identifier hash element, or NULL if not found.
*/
ident_hash_elem_t *lookup_ident (const char *name) {
int h = IdentHash (name);
ident_hash_elem_t *hptr, *hptr2;

if (ident_hash_table && (hptr = ident_hash_table[h]))
if (ident_hash_table && (hptr = ident_hash_table[h])) /* non-empty bucket */
{
CHECK_ELEM (hptr, name, return hptr;);
CHECK_ELEM (hptr, name, return hptr;); /* if found, already at front */
hptr2 = hptr->next;
while (hptr2 != hptr)
{
CHECK_ELEM (hptr2, name, ident_hash_table[h] = hptr2;
return hptr2;);
CHECK_ELEM (hptr2, name, ident_hash_table[h] = hptr2; return hptr2;); /* if found, rotate to here */
hptr2 = hptr2->next;
}
}
return 0;
return 0; /* not found */
}

/**
* @brief Find or add a permanent identifier.
* Find or add a permanent identifier. The following identifiers are added as permanent:
* - efuns
* - simul efuns
* (reserved words are also permanent, but they are added by add_keyword() in lex.c)
* @param name The name of the identifier. No reference is made to the string after this call.
* @return A pointer to the identifier hash element.
*/
Expand Down Expand Up @@ -92,8 +103,8 @@ ident_hash_elem_t* find_or_add_perm_ident (char *name) {
{
/* no collision, add to hash table */
hptr = (ident_hash_table[h] = ALLOCATE (ident_hash_elem_t, TAG_PERM_IDENT, "find_or_add_perm_ident:2"));
ident_hash_head[h] = hptr;
ident_hash_tail[h] = hptr;
ident_hash_head[h] = hptr; /* first permanent ident */
ident_hash_tail[h] = hptr; /* last permanent ident */
hptr->next = hptr;
}

Expand All @@ -118,12 +129,16 @@ typedef struct lname_linked_buf_s {
static lname_linked_buf_t *lnamebuf = 0;
static size_t lb_index = 4096;

static char *alloc_local_name (const char *name)
{
size_t len = strlen (name) + 1;
/**
* Allocate a local name string.
* @param name The name to allocate.
* @return A pointer to the allocated name string.
*/
static char *alloc_local_name (const char *name) {
size_t len = strlen (name) + 1; /* include null terminator */
char *res;

if (lb_index + len > 4096)
if (lb_index + len > sizeof (lnamebuf->block))
{
lname_linked_buf_t *new_buf;
new_buf = ALLOCATE (lname_linked_buf_t, TAG_COMPILER, "alloc_local_name");
Expand All @@ -137,9 +152,10 @@ static char *alloc_local_name (const char *name)
return res;
}

void
free_unused_identifiers ()
{
/**
* Free unused identifiers from the identifier hash table.
*/
void free_unused_identifiers () {
ident_hash_elem_list_t *ihel, *next;
lname_linked_buf_t *lnb, *lnbn;
int i;
Expand All @@ -165,10 +181,12 @@ free_unused_identifiers ()
ident_dirty_list = ident_dirty_list->next_dirty;
}

/* remove non-permanent identifier hash elements from hash table */
for (i = 0; i < IDENT_HASH_SIZE; i++)
if ((ident_hash_table[i] = ident_hash_head[i]))
ident_hash_tail[i]->next = ident_hash_head[i];

/* free all non-permanent identifier hash elements */
ihel = ihe_list;
while (ihel)
{
Expand All @@ -179,6 +197,7 @@ free_unused_identifiers ()
ihe_list = 0;
num_free = 0;

/* free all allocated local name buffers */
lnb = lnamebuf;
while (lnb)
{
Expand All @@ -190,23 +209,24 @@ free_unused_identifiers ()
lb_index = 4096;
}

static ident_hash_elem_t *
quick_alloc_ident_entry ()
{
/**
* Quickly allocate an identifier hash element.
* @return A pointer to the allocated identifier hash element.
*/
static ident_hash_elem_t* quick_alloc_ident_entry () {
if (num_free)
{
num_free--;
return &(ihe_list->items[num_free]);
}
else
{
ident_hash_elem_list_t *ihel;
ihel = ALLOCATE (ident_hash_elem_list_t, TAG_COMPILER, "quick_alloc_ident_entry");
ihel->next = ihe_list;
ihe_list = ihel;
num_free = 127;
return &(ihe_list->items[127]);
num_free = sizeof (ihe_list->items) / sizeof (ihe_list->items[0]) - 1;
}
return &(ihe_list->items[num_free]);
}

ident_hash_elem_t *find_or_add_ident (char *name, int flags) {
Expand Down Expand Up @@ -283,9 +303,16 @@ ident_hash_elem_t *find_or_add_ident (char *name, int flags) {
}

/**
* @brief Add a keyword to the identifier hash table.
* Add a keyword to the identifier hash table.
*
* A keyword is a permanent identifier that is always defined (can be found by lookup_ident
* regardless of sem_value).
*
* @param name The name of the keyword.
* @param entry Pointer to the keyword entry. This must point to a mutable memory location
* that remains valid until deinit_identifiers() is called.
*/
void add_keyword_t (char *name, keyword_t * entry) {
void add_keyword (const char *name, keyword_t* entry) {
int h = IdentHash (name);

if (ident_hash_table[h])
Expand Down Expand Up @@ -325,7 +352,9 @@ void init_identifiers () {
}

/**
* @brief Deinitialize identifier management structures. All identifiers including permanents are freed.
* Deinitialize identifier management structures.
* All identifiers including permanents are freed.
* (reserved words are not freed since they point to static memory locations)
*/
void deinit_identifiers () {
int i, n = 0;
Expand All @@ -346,7 +375,7 @@ void deinit_identifiers () {
else
{
if (!(hptr->token & IHE_RESWORD))
debug_warn ("leaked identifier: %s", hptr->name);
debug_warn ("leaked identifier (token: 0x%x): %s", hptr->token, hptr->name);
hptr = hptr->next;
}
}
Expand Down
11 changes: 6 additions & 5 deletions lib/lpc/identifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@

#define INDENT_HASH_SIZE 1024 /* must be a power of 2 */

typedef struct {
/* identifier semantics */
typedef struct defined_name_s {
short local_num, global_num, efun_num;
short function_num, simul_num, class_num;
} defined_name_t;

typedef struct ident_hash_elem_s {
char *name;
short token; /* only flags */
short sem_value; /* for these, a count of the ambiguity */
short token; /* only flags */
short sem_value; /* 0: reserved word or not defined, >1 a count of the ambiguity */
struct ident_hash_elem_s *next;
/* the fields above must correspond to struct keyword_t */
struct ident_hash_elem_s *next_dirty;
Expand All @@ -31,7 +32,7 @@ typedef struct ident_hash_elem_list_s {

extern ident_hash_elem_list_t *ihe_list;

typedef struct {
typedef struct keyword_s {
char *word;
unsigned short token; /* flags here too */
short sem_value; /* semantic value for predefined tokens */
Expand All @@ -56,6 +57,6 @@ ident_hash_elem_t *find_or_add_ident(char *, int);
ident_hash_elem_t *find_or_add_perm_ident(char *);
ident_hash_elem_t *lookup_ident(const char *);
void free_unused_identifiers(void);
void add_keyword_t (char *name, keyword_t * entry);
void add_keyword (const char *name, keyword_t * entry);
void init_identifiers(void);
void deinit_identifiers(void);
2 changes: 1 addition & 1 deletion lib/lpc/lex.c
Original file line number Diff line number Diff line change
Expand Up @@ -3510,7 +3510,7 @@ void init_keywords (void) {
for (i = 0; i < sizeof(reswords) / sizeof(reswords[0]); i++)
{
keyword_t *entry = &reswords[i];
add_keyword_t (entry->word, entry);
add_keyword (entry->word, entry);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/port/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#define TT_COMPILE 0020U
#define TT_SIMUL_EFUN 0040U
#define TT_BACKEND 0100U
#define TT_COMM 0200U
#define TT_COMM 0200U
#define TT_MEMORY 0400U

/**
Expand Down
39 changes: 20 additions & 19 deletions src/simul_efun.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "lpc/object.h"
#include "lpc/include/origin.h"

#include <assert.h>

/*
* This file rewritten by Beek because it was inefficient and slow. We
* now keep track of two mappings:
Expand Down Expand Up @@ -78,7 +80,8 @@ void init_simul_efun (const char *file) {
}

/**
* @brief Remove all old simul_efuns from the tables and identifier hash.
* Remove all current simul efuns from the simuls/simuls_sorted tables and
* turn off IHE_SIMUL flag of the simul efun name identifier hash.
*/
static void remove_simuls () {
int i;
Expand All @@ -98,15 +101,16 @@ static void remove_simuls () {
ihe->sem_value--;
ihe->dn.simul_num = -1;
ihe->token &= ~IHE_SIMUL;
free_string (simuls_sorted[i].name); /* reference added by find_or_add_simul_efun() */
/* the simul efun could be overriding an efun, do not remove the permanent identifier here */
}
free_string (simuls_sorted[i].name); /* reference added by find_or_add_simul_efun() */
}
}

/**
* Add all functions in 'prog' as simul_efuns.
* If 'prog' is NULL, remove all simul_efuns.
* @param prog The new program containing the simul_efuns to add.
* Add all functions in 'prog' as simul efuns.
* If 'prog' is NULL, remove all simul efuns.
* @param prog The new program containing the simul efuns to add.
*/
static void get_simul_efuns (program_t* prog) {

Expand All @@ -118,7 +122,7 @@ static void get_simul_efuns (program_t* prog) {
remove_simuls ();
if (!num_new)
{
opt_trace (TT_SIMUL_EFUN|2, "no new simul_efuns, removing all");
opt_trace (TT_SIMUL_EFUN|2, "no new simul efuns, removing all");
FREE (simuls_sorted);
simuls_sorted = 0;
FREE (simuls);
Expand Down Expand Up @@ -161,7 +165,6 @@ static void get_simul_efuns (program_t* prog) {
index = func_entry->inh.index;
func_entry = FIND_FUNC_ENTRY (nprog, index);
}

find_or_add_simul_efun (nprog, func_entry->def.f_index, i);
}

Expand Down Expand Up @@ -271,21 +274,19 @@ static void find_or_add_simul_efun (program_t* prog, function_number_t index, fu

void set_simul_efun (object_t* ob) {

if (!ob || ob->flags & O_DESTRUCTED)
if (ob && ob->flags & O_DESTRUCTED)
error ("Bad simul_efun object\n");

get_simul_efuns (ob->prog);
simul_efun_ob = ob;
add_ref (simul_efun_ob, "set_simul_efun");
}

void unset_simul_efun () {
if (simul_efun_ob)
{
get_simul_efuns (NULL); /* remove all simul_efuns */
free_object (simul_efun_ob, "set_simul_efun");
}

get_simul_efuns (NULL); /* remove all simul_efuns */
if (simul_efun_ob) {
free_object (simul_efun_ob, "unset_simul_efun");
simul_efun_ob = NULL;
}
if (!(simul_efun_ob = ob))
return;
get_simul_efuns (simul_efun_ob->prog);
add_ref (simul_efun_ob, "set_simul_efun");
}

void call_simul_efun (int simul_num, int num_args)
Expand Down
14 changes: 7 additions & 7 deletions src/simul_efun.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ extern void init_simul_efun(const char *file);
*/
extern void set_simul_efun (object_t *ob);

/**
* Unset the current simul_efun object.
* @return Upon return, the simul_efun object is unset and its reference is released.
*/
extern void unset_simul_efun();

/**
* Find the index (simul_num) of a simul_efun function by its name string pointer.
* The search uses binary search on the address of the name string (not string comparison).
Expand All @@ -57,8 +51,14 @@ extern void unset_simul_efun();
extern int find_simul_efun(const char *func_name);

/**
* Call a simul_efun by its index in the simul_efun table.
* Call a simul_efun by its index (simul_num) in the simul_efun table.
*
* The LPC opcode F_SIMUL_EFUN uses this function.
* Note that the simul_num is stored in the compiled opcode, which is bounded to the simul efun name at compile time.
* If the simul_efun object changes, the opcode still uses the same simul_num to refer to the simul efun.
* If the new simul_efun object does not have a function of that name or changed the order of function definitions,
* the behavior is undefined.
*
* @param simul_num The index in the simul_efun table. It is stored in LPC opcode as a 16-bit unsigned integer.
* @param num_args The number of arguments on the stack.
* @return Upon return, the return value is on the stack.
Expand Down
Loading
Loading