mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-01 04:10:18 +02:00
Optimize struct initialization and accessors for the common case.
* libguile/struct.c (set_vtable_layout_flags): New function. (scm_i_struct_inherit_vtable_magic): Use it. (scm_struct_init): Optimize the case where HANDLE's vtable has the `SCM_VTABLE_FLAG_SIMPLE' flag. (scm_struct_ref): Likewise. (scm_struct_ref): Likewise, when `SCM_VTABLE_FLAG_SIMPLE_RW' is also set. * libguile/struct.h (SCM_VTABLE_BASE_LAYOUT): Update comment for the next-to-last hidden field. (scm_vtable_index_reserved_6): Rename to... (scm_vtable_index_size): ... this. (SCM_VTABLE_FLAG_RESERVED_0): Rename to... (SCM_VTABLE_FLAG_SIMPLE): ... this. (SCM_VTABLE_FLAG_RESERVED_1): Rename to... (SCM_VTABLE_FLAG_SIMPLE_RW): ... this. * test-suite/tests/structs.test ("low-level struct procedures")["struct-ref", "struct-set!", "struct-ref out-of-range", "struct-set! out-of-range"]: New tests.
This commit is contained in:
parent
0e64cbea3d
commit
aa42c03669
3 changed files with 266 additions and 154 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
|
@ -22,6 +22,7 @@
|
|||
#endif
|
||||
|
||||
#include <alloca.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "libguile/_scm.h"
|
||||
#include "libguile/async.h"
|
||||
|
@ -151,6 +152,61 @@ SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
|
|||
#undef FUNC_NAME
|
||||
|
||||
|
||||
/* Check whether VTABLE instances have a simple layout (i.e., either only "pr"
|
||||
or only "pw" fields) and update its flags accordingly. */
|
||||
static void
|
||||
set_vtable_layout_flags (SCM vtable)
|
||||
{
|
||||
size_t len, field;
|
||||
SCM layout;
|
||||
const char *c_layout;
|
||||
scm_t_bits flags = SCM_VTABLE_FLAG_SIMPLE;
|
||||
|
||||
layout = SCM_VTABLE_LAYOUT (vtable);
|
||||
c_layout = scm_i_symbol_chars (layout);
|
||||
len = scm_i_symbol_length (layout);
|
||||
|
||||
assert (len % 2 == 0);
|
||||
|
||||
/* Update FLAGS according to LAYOUT. */
|
||||
for (field = 0;
|
||||
field < len && flags & SCM_VTABLE_FLAG_SIMPLE;
|
||||
field += 2)
|
||||
{
|
||||
if (c_layout[field] != 'p')
|
||||
flags = 0;
|
||||
else
|
||||
switch (c_layout[field + 1])
|
||||
{
|
||||
case 'w':
|
||||
case 'W':
|
||||
if (!(flags & SCM_VTABLE_FLAG_SIMPLE_RW) && field > 0)
|
||||
/* There's a mixture of `w' and `r' flags. */
|
||||
flags = 0;
|
||||
else
|
||||
flags |= SCM_VTABLE_FLAG_SIMPLE_RW;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
if (flags & SCM_VTABLE_FLAG_SIMPLE_RW)
|
||||
/* There's a mixture of `w' and `r' flags. */
|
||||
flags = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & SCM_VTABLE_FLAG_SIMPLE)
|
||||
{
|
||||
/* VTABLE is simple so update its flags and record the size of its
|
||||
instances. */
|
||||
SCM_SET_VTABLE_FLAGS (vtable, flags);
|
||||
SCM_STRUCT_DATA_SET (vtable, scm_vtable_index_size, len / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scm_i_struct_inherit_vtable_magic (SCM vtable, SCM obj)
|
||||
|
@ -171,6 +227,8 @@ scm_i_struct_inherit_vtable_magic (SCM vtable, SCM obj)
|
|||
scm_misc_error (FUNC_NAME, "invalid layout for new vtable",
|
||||
scm_list_1 (SCM_VTABLE_LAYOUT (obj)));
|
||||
|
||||
set_vtable_layout_flags (obj);
|
||||
|
||||
/* if obj's vtable is compatible with the required vtable (class) layout, it
|
||||
is a metaclass */
|
||||
olayout = scm_symbol_to_string (SCM_VTABLE_LAYOUT (obj));
|
||||
|
@ -215,60 +273,74 @@ static void
|
|||
scm_struct_init (SCM handle, SCM layout, size_t n_tail,
|
||||
size_t n_inits, scm_t_bits *inits)
|
||||
{
|
||||
scm_t_wchar prot = 0;
|
||||
int n_fields = scm_i_symbol_length (layout) / 2;
|
||||
int tailp = 0;
|
||||
int i;
|
||||
size_t inits_idx = 0;
|
||||
scm_t_bits *mem = SCM_STRUCT_DATA (handle);
|
||||
SCM vtable;
|
||||
scm_t_bits *mem;
|
||||
|
||||
i = -2;
|
||||
while (n_fields)
|
||||
vtable = SCM_STRUCT_VTABLE (handle);
|
||||
mem = SCM_STRUCT_DATA (handle);
|
||||
|
||||
if (SCM_UNPACK (vtable) != 0
|
||||
&& SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
|
||||
&& n_tail == 0
|
||||
&& n_inits == SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size))
|
||||
/* The fast path: HANDLE has N_INITS "p" fields. */
|
||||
memcpy (mem, inits, n_inits * sizeof (SCM));
|
||||
else
|
||||
{
|
||||
if (!tailp)
|
||||
scm_t_wchar prot = 0;
|
||||
int n_fields = scm_i_symbol_length (layout) / 2;
|
||||
int tailp = 0;
|
||||
int i;
|
||||
size_t inits_idx = 0;
|
||||
|
||||
i = -2;
|
||||
while (n_fields)
|
||||
{
|
||||
i += 2;
|
||||
prot = scm_i_symbol_ref (layout, i+1);
|
||||
if (SCM_LAYOUT_TAILP (prot))
|
||||
if (!tailp)
|
||||
{
|
||||
tailp = 1;
|
||||
prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
|
||||
*mem++ = (scm_t_bits)n_tail;
|
||||
n_fields += n_tail - 1;
|
||||
if (n_fields == 0)
|
||||
break;
|
||||
i += 2;
|
||||
prot = scm_i_symbol_ref (layout, i+1);
|
||||
if (SCM_LAYOUT_TAILP (prot))
|
||||
{
|
||||
tailp = 1;
|
||||
prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
|
||||
*mem++ = (scm_t_bits)n_tail;
|
||||
n_fields += n_tail - 1;
|
||||
if (n_fields == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (scm_i_symbol_ref (layout, i))
|
||||
{
|
||||
case 'u':
|
||||
if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
|
||||
*mem = 0;
|
||||
else
|
||||
{
|
||||
*mem = scm_to_ulong (SCM_PACK (inits[inits_idx]));
|
||||
inits_idx++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
|
||||
*mem = SCM_UNPACK (SCM_BOOL_F);
|
||||
else
|
||||
{
|
||||
*mem = inits[inits_idx];
|
||||
inits_idx++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 's':
|
||||
*mem = SCM_UNPACK (handle);
|
||||
break;
|
||||
}
|
||||
|
||||
n_fields--;
|
||||
mem++;
|
||||
}
|
||||
switch (scm_i_symbol_ref (layout, i))
|
||||
{
|
||||
case 'u':
|
||||
if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
|
||||
*mem = 0;
|
||||
else
|
||||
{
|
||||
*mem = scm_to_ulong (SCM_PACK (inits[inits_idx]));
|
||||
inits_idx++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if ((prot != 'r' && prot != 'w') || inits_idx == n_inits)
|
||||
*mem = SCM_UNPACK (SCM_BOOL_F);
|
||||
else
|
||||
{
|
||||
*mem = inits[inits_idx];
|
||||
inits_idx++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 's':
|
||||
*mem = SCM_UNPACK (handle);
|
||||
break;
|
||||
}
|
||||
|
||||
n_fields--;
|
||||
mem++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -627,71 +699,81 @@ SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
|
|||
"integer value small enough to fit in one machine word.")
|
||||
#define FUNC_NAME s_scm_struct_ref
|
||||
{
|
||||
SCM answer = SCM_UNDEFINED;
|
||||
scm_t_bits * data;
|
||||
SCM layout;
|
||||
size_t layout_len;
|
||||
SCM vtable, answer = SCM_UNDEFINED;
|
||||
scm_t_bits *data;
|
||||
size_t p;
|
||||
scm_t_bits n_fields;
|
||||
scm_t_wchar field_type = 0;
|
||||
|
||||
|
||||
SCM_VALIDATE_STRUCT (1, handle);
|
||||
|
||||
layout = SCM_STRUCT_LAYOUT (handle);
|
||||
vtable = SCM_STRUCT_VTABLE (handle);
|
||||
data = SCM_STRUCT_DATA (handle);
|
||||
p = scm_to_size_t (pos);
|
||||
|
||||
layout_len = scm_i_symbol_length (layout);
|
||||
n_fields = layout_len / 2;
|
||||
if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
|
||||
n_fields += data[n_fields - 1];
|
||||
|
||||
SCM_ASSERT_RANGE(1, pos, p < n_fields);
|
||||
|
||||
if (p * 2 < layout_len)
|
||||
if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
|
||||
&& p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
|
||||
{
|
||||
scm_t_wchar ref;
|
||||
field_type = scm_i_symbol_ref (layout, p * 2);
|
||||
ref = scm_i_symbol_ref (layout, p * 2 + 1);
|
||||
if ((ref != 'r') && (ref != 'w') && (ref != 'h'))
|
||||
{
|
||||
if ((ref == 'R') || (ref == 'W'))
|
||||
field_type = 'u';
|
||||
else
|
||||
SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
|
||||
}
|
||||
/* The fast path: HANDLE is a struct with only "p" fields. */
|
||||
answer = SCM_PACK (data[p]);
|
||||
}
|
||||
else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
|
||||
field_type = scm_i_symbol_ref(layout, layout_len - 2);
|
||||
else
|
||||
SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
|
||||
|
||||
switch (field_type)
|
||||
{
|
||||
case 'u':
|
||||
answer = scm_from_ulong (data[p]);
|
||||
break;
|
||||
SCM layout;
|
||||
size_t layout_len, n_fields;
|
||||
scm_t_wchar field_type = 0;
|
||||
|
||||
layout = SCM_STRUCT_LAYOUT (handle);
|
||||
layout_len = scm_i_symbol_length (layout);
|
||||
n_fields = layout_len / 2;
|
||||
|
||||
if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
|
||||
n_fields += data[n_fields - 1];
|
||||
|
||||
SCM_ASSERT_RANGE (1, pos, p < n_fields);
|
||||
|
||||
if (p * 2 < layout_len)
|
||||
{
|
||||
scm_t_wchar ref;
|
||||
field_type = scm_i_symbol_ref (layout, p * 2);
|
||||
ref = scm_i_symbol_ref (layout, p * 2 + 1);
|
||||
if ((ref != 'r') && (ref != 'w') && (ref != 'h'))
|
||||
{
|
||||
if ((ref == 'R') || (ref == 'W'))
|
||||
field_type = 'u';
|
||||
else
|
||||
SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
|
||||
}
|
||||
}
|
||||
else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
|
||||
field_type = scm_i_symbol_ref(layout, layout_len - 2);
|
||||
else
|
||||
SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
|
||||
|
||||
switch (field_type)
|
||||
{
|
||||
case 'u':
|
||||
answer = scm_from_ulong (data[p]);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case 'i':
|
||||
answer = scm_from_long (data[p]);
|
||||
break;
|
||||
case 'i':
|
||||
answer = scm_from_long (data[p]);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
answer = scm_make_real (*((double *)&(data[p])));
|
||||
break;
|
||||
case 'd':
|
||||
answer = scm_make_real (*((double *)&(data[p])));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 's':
|
||||
case 'p':
|
||||
answer = SCM_PACK (data[p]);
|
||||
break;
|
||||
case 's':
|
||||
case 'p':
|
||||
answer = SCM_PACK (data[p]);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
SCM_MISC_ERROR ("unrecognized field type: ~S",
|
||||
scm_list_1 (SCM_MAKE_CHAR (field_type)));
|
||||
default:
|
||||
SCM_MISC_ERROR ("unrecognized field type: ~S",
|
||||
scm_list_1 (SCM_MAKE_CHAR (field_type)));
|
||||
}
|
||||
}
|
||||
|
||||
return answer;
|
||||
|
@ -706,65 +788,76 @@ SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
|
|||
"to.")
|
||||
#define FUNC_NAME s_scm_struct_set_x
|
||||
{
|
||||
scm_t_bits * data;
|
||||
SCM layout;
|
||||
size_t layout_len;
|
||||
SCM vtable;
|
||||
scm_t_bits *data;
|
||||
size_t p;
|
||||
int n_fields;
|
||||
scm_t_wchar field_type = 0;
|
||||
|
||||
SCM_VALIDATE_STRUCT (1, handle);
|
||||
|
||||
layout = SCM_STRUCT_LAYOUT (handle);
|
||||
vtable = SCM_STRUCT_VTABLE (handle);
|
||||
data = SCM_STRUCT_DATA (handle);
|
||||
p = scm_to_size_t (pos);
|
||||
|
||||
layout_len = scm_i_symbol_length (layout);
|
||||
n_fields = layout_len / 2;
|
||||
if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
|
||||
n_fields += data[n_fields - 1];
|
||||
|
||||
SCM_ASSERT_RANGE (1, pos, p < n_fields);
|
||||
|
||||
if (p * 2 < layout_len)
|
||||
{
|
||||
char set_x;
|
||||
field_type = scm_i_symbol_ref (layout, p * 2);
|
||||
set_x = scm_i_symbol_ref (layout, p * 2 + 1);
|
||||
if (set_x != 'w' && set_x != 'h')
|
||||
SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
|
||||
}
|
||||
else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
|
||||
field_type = scm_i_symbol_ref (layout, layout_len - 2);
|
||||
if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
|
||||
&& SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE_RW)
|
||||
&& p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
|
||||
/* The fast path: HANDLE is a struct with only "p" fields. */
|
||||
data[p] = SCM_UNPACK (val);
|
||||
else
|
||||
SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
|
||||
|
||||
switch (field_type)
|
||||
{
|
||||
case 'u':
|
||||
data[p] = SCM_NUM2ULONG (3, val);
|
||||
break;
|
||||
SCM layout;
|
||||
size_t layout_len, n_fields;
|
||||
scm_t_wchar field_type = 0;
|
||||
|
||||
layout = SCM_STRUCT_LAYOUT (handle);
|
||||
layout_len = scm_i_symbol_length (layout);
|
||||
n_fields = layout_len / 2;
|
||||
|
||||
if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
|
||||
n_fields += data[n_fields - 1];
|
||||
|
||||
SCM_ASSERT_RANGE (1, pos, p < n_fields);
|
||||
|
||||
if (p * 2 < layout_len)
|
||||
{
|
||||
char set_x;
|
||||
field_type = scm_i_symbol_ref (layout, p * 2);
|
||||
set_x = scm_i_symbol_ref (layout, p * 2 + 1);
|
||||
if (set_x != 'w' && set_x != 'h')
|
||||
SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
|
||||
}
|
||||
else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
|
||||
field_type = scm_i_symbol_ref (layout, layout_len - 2);
|
||||
else
|
||||
SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
|
||||
|
||||
switch (field_type)
|
||||
{
|
||||
case 'u':
|
||||
data[p] = SCM_NUM2ULONG (3, val);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case 'i':
|
||||
data[p] = SCM_NUM2LONG (3, val);
|
||||
break;
|
||||
case 'i':
|
||||
data[p] = SCM_NUM2LONG (3, val);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
*((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
|
||||
break;
|
||||
case 'd':
|
||||
*((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'p':
|
||||
data[p] = SCM_UNPACK (val);
|
||||
break;
|
||||
case 'p':
|
||||
data[p] = SCM_UNPACK (val);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
|
||||
case 's':
|
||||
SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
|
||||
|
||||
default:
|
||||
SCM_MISC_ERROR ("unrecognized field type: ~S",
|
||||
scm_list_1 (SCM_MAKE_CHAR (field_type)));
|
||||
default:
|
||||
SCM_MISC_ERROR ("unrecognized field type: ~S",
|
||||
scm_list_1 (SCM_MAKE_CHAR (field_type)));
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue