mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-17 09:10:22 +02:00
make symbol -> opcode lookup faster
* libguile/instructions.c (fetch_instruction_table) (scm_lookup_instruction_by_name): Rework so we lazily load instructions into an array keyed by opcode, and a hash table keyed by symbolic name. Much faster, in this hot spot of compilation. * libguile/vm-engine.c (vm_run): Use malloc instead of scm_gc_malloc, given that we aren't ever going to free this thing. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_LOADER): Rework to always be aliases to VM_DEFINE_INSTRUCTION. (VM_DEFINE_INSTRUCTION): In the table case, update to work with fetch_instruction_table().
This commit is contained in:
parent
ef7e18683c
commit
f775e51bce
3 changed files with 72 additions and 50 deletions
|
@ -57,16 +57,7 @@ struct scm_instruction {
|
||||||
-1 for insns like `call' which can take
|
-1 for insns like `call' which can take
|
||||||
any number of arguments. */
|
any number of arguments. */
|
||||||
char npush; /* the number of values pushed */
|
char npush; /* the number of values pushed */
|
||||||
};
|
SCM symname; /* filled in later */
|
||||||
|
|
||||||
static struct scm_instruction scm_instruction_table[] = {
|
|
||||||
#define VM_INSTRUCTION_TO_TABLE 1
|
|
||||||
#include "vm-expand.h"
|
|
||||||
#include "vm-i-system.i"
|
|
||||||
#include "vm-i-scheme.i"
|
|
||||||
#include "vm-i-loader.i"
|
|
||||||
#undef VM_INSTRUCTION_TO_TABLE
|
|
||||||
{scm_op_last}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCM_VALIDATE_LOOKUP_INSTRUCTION(pos, var, cvar) \
|
#define SCM_VALIDATE_LOOKUP_INSTRUCTION(pos, var, cvar) \
|
||||||
|
@ -76,27 +67,58 @@ static struct scm_instruction scm_instruction_table[] = {
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
static struct scm_instruction*
|
||||||
|
fetch_instruction_table ()
|
||||||
|
{
|
||||||
|
static struct scm_instruction *table = NULL;
|
||||||
|
|
||||||
|
if (SCM_UNLIKELY (!table))
|
||||||
|
{
|
||||||
|
size_t bytes = scm_op_last * sizeof(struct scm_instruction);
|
||||||
|
int i;
|
||||||
|
table = malloc (bytes);
|
||||||
|
memset (table, 0, bytes);
|
||||||
|
#define VM_INSTRUCTION_TO_TABLE 1
|
||||||
|
#include "vm-expand.h"
|
||||||
|
#include "vm-i-system.i"
|
||||||
|
#include "vm-i-scheme.i"
|
||||||
|
#include "vm-i-loader.i"
|
||||||
|
#undef VM_INSTRUCTION_TO_TABLE
|
||||||
|
for (i = 0; i < scm_op_last; i++)
|
||||||
|
{
|
||||||
|
table[i].opcode = i;
|
||||||
|
if (table[i].name)
|
||||||
|
table[i].symname = scm_from_locale_symbol (table[i].name);
|
||||||
|
else
|
||||||
|
table[i].symname = SCM_BOOL_F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
static struct scm_instruction *
|
static struct scm_instruction *
|
||||||
scm_lookup_instruction_by_name (SCM name)
|
scm_lookup_instruction_by_name (SCM name)
|
||||||
{
|
{
|
||||||
struct scm_instruction *ip;
|
static SCM instructions_by_name = SCM_BOOL_F;
|
||||||
char *symbol;
|
struct scm_instruction *table = fetch_instruction_table ();
|
||||||
|
SCM op;
|
||||||
|
|
||||||
if (SCM_SYMBOLP (name))
|
if (SCM_UNLIKELY (SCM_FALSEP (instructions_by_name)))
|
||||||
for (ip = scm_instruction_table; ip->opcode != scm_op_last; ip++)
|
{
|
||||||
{
|
int i;
|
||||||
symbol = scm_to_locale_string (scm_symbol_to_string (name));
|
instructions_by_name = scm_make_hash_table (SCM_I_MAKINUM (scm_op_last));
|
||||||
if ((symbol) && (strcmp (ip->name, symbol) == 0))
|
for (i = 0; i < scm_op_last; i++)
|
||||||
{
|
if (scm_is_true (table[i].symname))
|
||||||
free (symbol);
|
scm_hashq_set_x (instructions_by_name, table[i].symname,
|
||||||
return ip;
|
SCM_I_MAKINUM (i));
|
||||||
}
|
instructions_by_name = scm_permanent_object (instructions_by_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
op = scm_hashq_ref (instructions_by_name, name, SCM_UNDEFINED);
|
||||||
|
if (SCM_I_INUMP (op))
|
||||||
|
return &table[SCM_I_INUM (op)];
|
||||||
|
|
||||||
if (symbol)
|
return NULL;
|
||||||
free (symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,8 +131,9 @@ SCM_DEFINE (scm_instruction_list, "instruction-list", 0, 0, 0,
|
||||||
{
|
{
|
||||||
SCM list = SCM_EOL;
|
SCM list = SCM_EOL;
|
||||||
struct scm_instruction *ip;
|
struct scm_instruction *ip;
|
||||||
for (ip = scm_instruction_table; ip->opcode != scm_op_last; ip++)
|
for (ip = fetch_instruction_table (); ip->opcode != scm_op_last; ip++)
|
||||||
list = scm_cons (scm_from_locale_symbol (ip->name), list);
|
if (ip->name)
|
||||||
|
list = scm_cons (ip->symname, list);
|
||||||
return scm_reverse_x (list, SCM_EOL);
|
return scm_reverse_x (list, SCM_EOL);
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
@ -173,18 +196,19 @@ SCM_DEFINE (scm_opcode_to_instruction, "opcode->instruction", 1, 0, 0,
|
||||||
"")
|
"")
|
||||||
#define FUNC_NAME s_scm_opcode_to_instruction
|
#define FUNC_NAME s_scm_opcode_to_instruction
|
||||||
{
|
{
|
||||||
struct scm_instruction *ip;
|
|
||||||
int opcode;
|
int opcode;
|
||||||
|
SCM ret = SCM_BOOL_F;
|
||||||
|
|
||||||
SCM_MAKE_VALIDATE (1, op, I_INUMP);
|
SCM_MAKE_VALIDATE (1, op, I_INUMP);
|
||||||
opcode = SCM_I_INUM (op);
|
opcode = SCM_I_INUM (op);
|
||||||
|
|
||||||
for (ip = scm_instruction_table; ip->opcode != scm_op_last; ip++)
|
if (opcode < scm_op_last)
|
||||||
if (opcode == ip->opcode)
|
ret = fetch_instruction_table ()[opcode].symname;
|
||||||
return scm_from_locale_symbol (ip->name);
|
|
||||||
|
|
||||||
scm_wrong_type_arg_msg (FUNC_NAME, 1, op, "INSTRUCTION_P");
|
if (scm_is_false (ret))
|
||||||
return SCM_BOOL_F; /* not reached */
|
scm_wrong_type_arg_msg (FUNC_NAME, 1, op, "INSTRUCTION_P");
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,7 @@ vm_run (SCM vm, SCM program, SCM args)
|
||||||
if (SCM_UNLIKELY (!jump_table))
|
if (SCM_UNLIKELY (!jump_table))
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
jump_table = scm_gc_malloc (SCM_VM_NUM_INSTRUCTIONS * sizeof(void*),
|
jump_table = malloc (SCM_VM_NUM_INSTRUCTIONS * sizeof(void*));
|
||||||
"jump table");
|
|
||||||
for (i = 0; i < SCM_VM_NUM_INSTRUCTIONS; i++)
|
for (i = 0; i < SCM_VM_NUM_INSTRUCTIONS; i++)
|
||||||
jump_table[i] = &&vm_error_bad_instruction;
|
jump_table[i] = &&vm_error_bad_instruction;
|
||||||
#define VM_INSTRUCTION_TO_LABEL 1
|
#define VM_INSTRUCTION_TO_LABEL 1
|
||||||
|
|
|
@ -52,19 +52,24 @@
|
||||||
#endif /* not HAVE_LABELS_AS_VALUES */
|
#endif /* not HAVE_LABELS_AS_VALUES */
|
||||||
#endif /* VM_LABEL */
|
#endif /* VM_LABEL */
|
||||||
|
|
||||||
#undef VM_DEFINE_INSTRUCTION
|
|
||||||
#undef VM_DEFINE_FUNCTION
|
#undef VM_DEFINE_FUNCTION
|
||||||
#undef VM_DEFINE_LOADER
|
#undef VM_DEFINE_LOADER
|
||||||
#ifdef VM_INSTRUCTION_TO_TABLE
|
#define VM_DEFINE_FUNCTION(code,tag,name,nargs) \
|
||||||
|
VM_DEFINE_INSTRUCTION(code,tag,name,0,nargs,1)
|
||||||
|
#define VM_DEFINE_LOADER(code,tag,name) \
|
||||||
|
VM_DEFINE_INSTRUCTION(code,tag,name,-1,0,1)
|
||||||
|
|
||||||
|
#undef VM_DEFINE_INSTRUCTION
|
||||||
/*
|
/*
|
||||||
* These will go to scm_instruction_table in instructions.c
|
* These will go to scm_instruction_table in instructions.c
|
||||||
*/
|
*/
|
||||||
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) \
|
#ifdef VM_INSTRUCTION_TO_TABLE
|
||||||
{VM_OPCODE (tag), name, len, npop, npush},
|
#define VM_DEFINE_INSTRUCTION(code_,tag_,name_,len_,npop_,npush_) \
|
||||||
#define VM_DEFINE_FUNCTION(code,tag,name,nargs) \
|
table[VM_OPCODE (tag_)].opcode = VM_OPCODE (tag_); \
|
||||||
{VM_OPCODE (tag), name, 0, nargs, 1},
|
table[VM_OPCODE (tag_)].name = name_; \
|
||||||
#define VM_DEFINE_LOADER(code,tag,name) \
|
table[VM_OPCODE (tag_)].len = len_; \
|
||||||
{VM_OPCODE (tag), name, -1, 0, 1},
|
table[VM_OPCODE (tag_)].npop = npop_; \
|
||||||
|
table[VM_OPCODE (tag_)].npush = npush_;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#ifdef VM_INSTRUCTION_TO_LABEL
|
#ifdef VM_INSTRUCTION_TO_LABEL
|
||||||
|
@ -72,8 +77,6 @@
|
||||||
* These will go to jump_table in vm_engine.c
|
* These will go to jump_table in vm_engine.c
|
||||||
*/
|
*/
|
||||||
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) jump_table[VM_OPCODE (tag)] = VM_ADDR (tag);
|
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) jump_table[VM_OPCODE (tag)] = VM_ADDR (tag);
|
||||||
#define VM_DEFINE_FUNCTION(code,tag,name,nargs) jump_table[VM_OPCODE (tag)] = VM_ADDR (tag);
|
|
||||||
#define VM_DEFINE_LOADER(code,tag,name) jump_table[VM_OPCODE (tag)] = VM_ADDR (tag);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#ifdef VM_INSTRUCTION_TO_OPCODE
|
#ifdef VM_INSTRUCTION_TO_OPCODE
|
||||||
|
@ -81,16 +84,12 @@
|
||||||
* These will go to scm_opcode in instructions.h
|
* These will go to scm_opcode in instructions.h
|
||||||
*/
|
*/
|
||||||
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) VM_OPCODE (tag) = code,
|
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) VM_OPCODE (tag) = code,
|
||||||
#define VM_DEFINE_FUNCTION(code,tag,name,nargs) VM_OPCODE (tag) = code,
|
|
||||||
#define VM_DEFINE_LOADER(code,tag,name) VM_OPCODE (tag) = code,
|
|
||||||
|
|
||||||
#else /* Otherwise */
|
#else /* Otherwise */
|
||||||
/*
|
/*
|
||||||
* These are directly included in vm_engine.c
|
* These are directly included in vm_engine.c
|
||||||
*/
|
*/
|
||||||
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) VM_TAG (tag)
|
#define VM_DEFINE_INSTRUCTION(code,tag,name,len,npop,npush) VM_TAG (tag)
|
||||||
#define VM_DEFINE_FUNCTION(code,tag,name,nargs) VM_TAG (tag)
|
|
||||||
#define VM_DEFINE_LOADER(code,tag,name) VM_TAG (tag)
|
|
||||||
|
|
||||||
#endif /* VM_INSTRUCTION_TO_OPCODE */
|
#endif /* VM_INSTRUCTION_TO_OPCODE */
|
||||||
#endif /* VM_INSTRUCTION_TO_LABEL */
|
#endif /* VM_INSTRUCTION_TO_LABEL */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue