SCM_VALIDATE_VTABLE (1, vtable);
SCM_VALIDATE_REST_ARGUMENT (init);
- layout = SCM_PACK (SCM_STRUCT_DATA (vtable) [scm_vtable_index_layout]);
+ c_vtable = SCM_STRUCT_DATA (vtable);
+
+ layout = SCM_PACK (c_vtable [scm_vtable_index_layout]);
basic_size = scm_i_symbol_length (layout) / 2;
tail_elts = scm_to_size_t (tail_array_size);
+
+ /* A tail array is only allowed if the layout fields string ends in "R",
+ "W" or "O". */
+ if (tail_elts != 0)
+ {
+ SCM layout_str, last_char;
+
+ if (basic_size == 0)
+ {
+ bad_tail:
+ SCM_MISC_ERROR ("tail array not allowed unless layout ends R, W, or O", SCM_EOL);
+ }
+
+ layout_str = scm_symbol_to_string (layout);
+ last_char = scm_string_ref (layout_str,
+ scm_from_size_t (2 * basic_size - 1));
+ if (! SCM_LAYOUT_TAILP (SCM_CHAR (last_char)))
+ goto bad_tail;
+ }
+
SCM_CRITICAL_SECTION_START;
- if (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
+ if (c_vtable[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
{
data = scm_alloc_struct (basic_size + tail_elts,
scm_struct_entity_n_extra_words,
data = scm_alloc_struct (basic_size + tail_elts,
scm_struct_n_extra_words,
"struct");
- handle = scm_double_cell ((((scm_t_bits) SCM_STRUCT_DATA (vtable))
+ handle = scm_double_cell ((((scm_t_bits) c_vtable)
+ scm_tc3_struct),
(scm_t_bits) data, 0, 0);
- scm_struct_init (handle, layout, data, tail_elts, init);
+
+ if (c_vtable[scm_struct_i_free])
+ {
+ /* Register a finalizer for the newly created instance. */
+ GC_finalization_proc prev_finalizer;
+ GC_PTR prev_finalizer_data;
+ scm_t_struct_free free_struct =
+ (scm_t_struct_free)c_vtable[scm_struct_i_free];
+
+ GC_REGISTER_FINALIZER_NO_ORDER (SCM2PTR (handle),
+ struct_finalizer_trampoline,
+ free_struct,
+ &prev_finalizer,
+ &prev_finalizer_data);
+ }
+
SCM_CRITICAL_SECTION_END;
+
+ /* In guile 1.8.1 and earlier, the SCM_CRITICAL_SECTION_END above covered
+ also the following scm_struct_init. But that meant if scm_struct_init
+ finds an invalid type for a "u" field then there's an error throw in a
+ critical section, which results in an abort(). Not sure if we need any
+ protection across scm_struct_init. The data array contains garbage at
+ this point, but until we return it's not visible to anyone except
+ `gc'. */
+ scm_struct_init (handle, layout, data, tail_elts, init);
+
return handle;
}
#undef FUNC_NAME