1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-15 16:20:17 +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:
Ludovic Courtès 2010-01-23 16:21:13 +01:00
parent 0e64cbea3d
commit aa42c03669
3 changed files with 266 additions and 154 deletions

View file

@ -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));
@ -214,13 +272,26 @@ scm_i_struct_inherit_vtable_magic (SCM vtable, SCM obj)
static void
scm_struct_init (SCM handle, SCM layout, size_t n_tail,
size_t n_inits, scm_t_bits *inits)
{
SCM vtable;
scm_t_bits *mem;
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
{
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);
i = -2;
while (n_fields)
@ -271,6 +342,7 @@ scm_struct_init (SCM handle, SCM layout, size_t n_tail,
mem++;
}
}
}
SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
@ -627,23 +699,32 @@ 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 vtable, answer = SCM_UNDEFINED;
scm_t_bits *data;
SCM layout;
size_t layout_len;
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);
if (SCM_LIKELY (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
&& p < SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)))
{
/* The fast path: HANDLE is a struct with only "p" fields. */
answer = SCM_PACK (data[p]);
}
else
{
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];
@ -693,6 +774,7 @@ SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
SCM_MISC_ERROR ("unrecognized field type: ~S",
scm_list_1 (SCM_MAKE_CHAR (field_type)));
}
}
return answer;
}
@ -706,21 +788,31 @@ SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
"to.")
#define FUNC_NAME s_scm_struct_set_x
{
SCM vtable;
scm_t_bits *data;
SCM layout;
size_t layout_len;
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);
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 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];
@ -766,6 +858,7 @@ SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
SCM_MISC_ERROR ("unrecognized field type: ~S",
scm_list_1 (SCM_MAKE_CHAR (field_type)));
}
}
return val;
}

View file

@ -3,7 +3,7 @@
#ifndef SCM_STRUCT_H
#define SCM_STRUCT_H
/* Copyright (C) 1995,1997,1999,2000,2001, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
/* Copyright (C) 1995,1997,1999,2000,2001, 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
@ -46,7 +46,7 @@
"uh" /* finalizer */ \
"pw" /* printer */ \
"ph" /* name (hidden from make-struct for back-compat reasons) */ \
"uh" /* reserved */ \
"uh" /* size */ \
"uh" /* reserved */
#define scm_vtable_index_layout 0 /* A symbol describing the physical arrangement of this type. */
@ -55,7 +55,7 @@
#define scm_vtable_index_instance_finalize 3 /* Finalizer for instances of this struct type. */
#define scm_vtable_index_instance_printer 4 /* A printer for this struct type. */
#define scm_vtable_index_name 5 /* Name of this vtable. */
#define scm_vtable_index_reserved_6 6
#define scm_vtable_index_size 6 /* Number of fields, for simple structs. */
#define scm_vtable_index_reserved_7 7
#define scm_vtable_offset_user 8 /* Where do user fields start in the vtable? */
@ -79,8 +79,8 @@
#define SCM_VTABLE_FLAG_APPLICABLE (1L << 2) /* instances of this vtable are applicable? */
#define SCM_VTABLE_FLAG_SETTER_VTABLE (1L << 3) /* instances of this vtable are applicable-with-setter vtables? */
#define SCM_VTABLE_FLAG_SETTER (1L << 4) /* instances of this vtable are applicable-with-setters? */
#define SCM_VTABLE_FLAG_RESERVED_0 (1L << 5)
#define SCM_VTABLE_FLAG_RESERVED_1 (1L << 6)
#define SCM_VTABLE_FLAG_SIMPLE (1L << 5) /* instances of this vtable have only "pr" fields */
#define SCM_VTABLE_FLAG_SIMPLE_RW (1L << 6) /* instances of this vtable have only "pw" fields */
#define SCM_VTABLE_FLAG_SMOB_0 (1L << 7)
#define SCM_VTABLE_FLAG_GOOPS_0 (1L << 8)
#define SCM_VTABLE_FLAG_GOOPS_1 (1L << 9)

View file

@ -1,7 +1,7 @@
;;;; structs.test --- Test suite for Guile's structures. -*- Scheme -*-
;;;; Ludovic Courtès <ludovic.courtes@laas.fr>, 2006-06-12.
;;;; structs.test --- Structures. -*- mode: scheme; coding: utf-8; -*-
;;;; Ludovic Courtès <ludo@gnu.org>, 2006-06-12.
;;;;
;;;; Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
;;;; Copyright (C) 2006, 2007, 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
@ -80,9 +80,33 @@
(pass-if "struct-set!"
(let ((ball (make-ball green "Bob")))
(set-owner! ball "Bill")
(string=? (owner ball) "Bill"))))
(string=? (owner ball) "Bill")))
(pass-if "struct-ref"
(let ((ball (make-ball red "Alice")))
(equal? (struct-ref ball 0) "Alice")))
(pass-if "struct-set!"
(let* ((v (make-vtable "pw"))
(s (make-struct v 0))
(r (struct-set! s 0 'a)))
(eq? r
(struct-ref s 0)
'a)))
(pass-if-exception "struct-ref out-of-range"
exception:out-of-range
(let* ((v (make-vtable "prpr"))
(s (make-struct v 0 'a 'b)))
(struct-ref s 2)))
(pass-if-exception "struct-set! out-of-range"
exception:out-of-range
(let* ((v (make-vtable "pwpw"))
(s (make-struct v 0 'a 'b)))
(struct-set! s 2 'c))))
(with-test-prefix "equal?"
(pass-if "simple structs"
@ -153,8 +177,3 @@
(lambda (port)
(display struct port)))))
(equal? str "hello")))))
;;; Local Variables:
;;; coding: latin-1
;;; End: