Add a hash for pathname searches, instead of searching very pass

We have been doing a pathname search every time we encounter a file,
which means every file in every pass.  Instead, put the pathnames
found in a hash table.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2016-09-25 17:08:05 -07:00
parent 96921a5ad8
commit 169ac7c152
4 changed files with 117 additions and 51 deletions

View File

@ -348,8 +348,12 @@ int main(int argc, char **argv)
preproc = &nasmpp;
operating_mode = OP_NORMAL;
/* Define some macros dependent on the runtime, but not
on the command line. */
/*
* Define some macros dependent on the runtime, but not
* on the command line. This only works because the only
* alternative preprocessor is preproc_nop...
*/
preproc->init();
define_macros_early();
parse_cmdline(argc, argv);

View File

@ -57,6 +57,11 @@
static FILE *nop_fp;
static int32_t nop_lineinc;
static void nop_init(void)
{
/* Nothing to do */
}
static void nop_reset(char *file, int pass, StrList **deplist)
{
src_set(0, file);
@ -174,6 +179,7 @@ static void nop_error_list_macros(int severity)
}
const struct preproc_ops preproc_nop = {
nop_init,
nop_reset,
nop_getline,
nop_cleanup,

View File

@ -285,6 +285,13 @@ struct IncPath {
char *path;
};
/*
* File real name hash, so we don't have to re-search the include
* path for every pass (and potentially more than that if a file
* is used more than once.)
*/
struct hash_table FileHash;
/*
* Conditional assembly: we maintain a separate stack of these for
* each level of file inclusion. (The only reason we keep the
@ -1515,13 +1522,13 @@ enum incopen_mode {
INC_PROBE /* Only an existence probe */
};
static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
char **found_path, enum incopen_mode omode,
enum file_flags fmode)
/* This is conducts a full pathname search */
static FILE *inc_fopen_search(const char *file, StrList **slpath,
enum incopen_mode omode, enum file_flags fmode)
{
FILE *fp;
char *prefix = "";
IncPath *ip = ipath;
const IncPath *ip = ipath;
int len = strlen(file);
size_t prefix_len = 0;
StrList *sl;
@ -1534,6 +1541,7 @@ static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
sl = nasm_malloc(path_len + sizeof sl->next);
memcpy(sl->str, prefix, prefix_len);
memcpy(sl->str+prefix_len, file, len+1);
sl->next = NULL;
if (omode == INC_PROBE) {
fp = NULL;
@ -1543,47 +1551,92 @@ static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
found = (fp != NULL);
}
if (found) {
if (found_path)
*found_path = nasm_strdup(sl->str);
if (dhead && !in_list(*dhead, sl->str)) {
sl->next = NULL;
**dtail = sl;
*dtail = &sl->next;
} else {
nasm_free(sl);
}
}
if (found)
*slpath = sl;
return fp;
}
nasm_free(sl);
if (!ip) {
if (omode == INC_NEEDED)
break;
prefix = NULL;
} else {
prefix = ip->path;
ip = ip->next;
if (!ip)
return NULL;
prefix = ip->path;
prefix_len = strlen(prefix);
ip = ip->next;
}
}
/*
* Open a file, or test for the presence of one (depending on omode),
* considering the include path.
*/
static FILE *inc_fopen(const char *file,
StrList **dhead, StrList ***dtail,
char **found_path,
enum incopen_mode omode,
enum file_flags fmode)
{
StrList *sl;
struct hash_insert hi;
void **hp;
char *path;
FILE *fp = NULL;
hp = hash_find(&FileHash, file, &hi);
if (hp) {
path = *hp;
} else {
/* Need to do the actual path search */
size_t file_len;
sl = NULL;
fp = inc_fopen_search(file, &sl, omode, fmode);
file_len = strlen(file);
if (!sl) {
/* Store negative result for this file */
sl = nasm_malloc(file_len + 1 + sizeof sl->next);
memcpy(sl->str, file, file_len+1);
sl->next = NULL;
file = sl->str;
path = NULL;
} else {
path = sl->str;
file = strchr(path, '\0') - file_len;
}
if (prefix) {
prefix_len = strlen(prefix);
} else {
/* -MG given and file not found */
if (dhead && !in_list(*dhead, file)) {
sl = nasm_malloc(len+1+sizeof sl->next);
sl->next = NULL;
strcpy(sl->str, file);
hash_add(&hi, file, path); /* Positive or negative result */
if (path || omode != INC_NEEDED) {
/*
* Add file to dependency path. The in_list() is needed
* in case the file was already added with %depend.
*/
if (dhead && !in_list(*dhead, sl->str)) {
**dtail = sl;
*dtail = &sl->next;
}
return NULL;
}
}
nasm_error(ERR_FATAL, "unable to open include file `%s'", file);
return NULL;
if (!path) {
if (omode == INC_NEEDED)
nasm_fatal(0, "unable to open include file `%s'", file);
if (found_path)
*found_path = NULL;
return NULL;
}
if (!fp && omode != INC_PROBE)
fp = nasm_open_read(file, fmode);
if (found_path)
*found_path = nasm_strdup(path);
return fp;
}
/*
@ -1593,14 +1646,7 @@ static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
*/
FILE *pp_input_fopen(const char *filename, enum file_flags mode)
{
FILE *fp;
StrList *xsl = NULL;
StrList **xst = &xsl;
fp = inc_fopen(filename, &xsl, &xst, NULL, INC_OPTIONAL, mode);
if (xsl)
nasm_free(xsl);
return fp;
return inc_fopen(filename, NULL, NULL, NULL, INC_OPTIONAL, mode);
}
/*
@ -3249,8 +3295,7 @@ issue_error:
case PP_PATHSEARCH:
{
StrList *xsl = NULL;
StrList **xst = &xsl;
char *found_path;
casesense = true;
@ -3288,16 +3333,16 @@ issue_error:
if (t->type != TOK_INTERNAL_STRING)
nasm_unquote(p, NULL);
inc_fopen(p, &xsl, &xst, NULL, INC_PROBE, NF_BINARY);
if (xsl)
p = xsl->str;
inc_fopen(p, NULL, NULL, &found_path, INC_PROBE, NF_BINARY);
if (found_path)
p = found_path;
macro_start = nasm_malloc(sizeof(*macro_start));
macro_start->next = NULL;
macro_start->text = nasm_quote(p, strlen(p));
macro_start->type = TOK_STRING;
macro_start->a.mac = NULL;
if (xsl)
nasm_free(xsl);
if (found_path)
nasm_free(found_path);
/*
* We now have a macro name, an implicit parameter count of
@ -4930,6 +4975,11 @@ pp_reset(char *file, int apass, StrList **deplist)
define_smacro(NULL, "__PASS__", true, 0, t);
}
static void pp_init(void)
{
hash_init(&FileHash, HASH_MEDIUM);
}
static char *pp_getline(void)
{
char *line;
@ -5325,6 +5375,7 @@ static void pp_error_list_macros(int severity)
}
const struct preproc_ops nasmpp = {
pp_init,
pp_reset,
pp_getline,
pp_cleanup,

View File

@ -344,6 +344,11 @@ typedef struct string_list {
* preprocessors ought to look like this:
*/
struct preproc_ops {
/*
* Called once at the very start of assembly.
*/
void (*init)(void);
/*
* Called at the start of a pass; given a file name, the number
* of the pass, an error reporting function, an evaluator