Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: b9261ad17c
Fetching contributors…

Cannot retrieve contributors at this time

1137 lines (942 sloc) 37.3 kb
/*
Copyright (C) 2001-2011, Parrot Foundation.
=head1 NAME
src/pmc/structview.pmc - C struct view for pointers.
=head1 DESCRIPTION
PMC class to view pointers as C C<struct>s. This includes read, write, allocate,
and deallocate operations. Bounds checking is implemented where the pointer
class reports a non-zero bound. Recursive definition through nesting is not
supported but can be emulated by interpreting pointer or buffer elements as
structs once dereferenced.
Elements are get/set using keyed access of the form C<[Ptr; Idx]>, which will
interpret the C<Ptr> PMC and lookup the C<Idx>'th element.
=head2 Vtables and Methods
=over 4
=cut
*/
#include "pmc/pmc_ptrobj.h"
BEGIN_PMC_HEADER_PREAMBLE
typedef enum {
int_access = 1,
unaligned_access,
num_access,
str_access,
pmc_access
} elt_access_t;
typedef struct elt_desc_t {
elt_access_t access;
PARROT_DATA_TYPE type;
size_t byte_offset;
unsigned char bit_offset;
size_t size;
} elt_desc_t;
END_PMC_HEADER_PREAMBLE
#define ALIGN_UP(addr, align) (((addr) + ((align) - 1)) & ~((align) - 1))
#define MAX(x, y) ((y) > (x) ? (y) : (x))
#define BEGIN_KEYED(interp, s, k) \
size_t n_elts; \
elt_desc_t *elts; \
PMC *ptr_pmc; \
void *ptr, *base_ptr; \
INTVAL i; \
PMC *orig_k = (k); \
GETATTR_StructView_n_elts((interp), (s), n_elts); \
GETATTR_StructView_elts((interp), (s), elts); \
ptr_pmc = Parrot_key_pmc((interp), (k)); \
(k) = Parrot_key_next((interp), (k)); \
i = Parrot_key_integer((interp), (k)); \
(k) = orig_k; \
if (i < 0 || n_elts <= (size_t)i) \
Parrot_ex_throw_from_c_args((interp), NULL, 0, \
"Struct index out of bounds (%d)", \
i); \
base_ptr = VTABLE_get_pointer((interp), ptr_pmc); \
ptr = ((char *)base_ptr) + elts[i].byte_offset; \
/* guard against null pointer dereference */ \
if (!base_ptr) \
Parrot_ex_throw_from_c_args((interp), NULL, 0, \
"Attempt to derefrence null pointer"); \
/* guard against out of bounds access */ \
{ \
size_t buf_size = VTABLE_get_integer((interp), ptr_pmc); \
size_t self_size; \
GETATTR_StructView_size((interp), (s), self_size); \
if (buf_size && buf_size < self_size) \
Parrot_ex_throw_from_c_args((interp), NULL, 0, \
"Buffer length too small for struct " \
"(at least %d required, got %d)", \
self_size, buf_size); \
} \
/* guard against unaligned access */ \
{ \
size_t align; \
GETATTR_StructView_align((interp), (s), align); \
if ((size_t)base_ptr != ALIGN_UP((size_t)base_ptr, align)) \
Parrot_ex_throw_from_c_args((interp), NULL, 0, \
"Attempt to dereference unaligned pointer " \
"(%x, required alignment: %d)", \
base_ptr, align); \
}
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
static void deallocate_ptrobj(PARROT_INTERP, PMC *obj, ARGFREE(void *ptr));
#define ASSERT_ARGS_deallocate_ptrobj __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=item C<static void deallocate_ptrobj(PARROT_INTERP, PMC *obj, void *ptr)>
Deallocation function to be attached to allocated instances.
=cut
*/
static void
deallocate_ptrobj(SHIM_INTERP, SHIM(PMC *obj), ARGFREE(void *ptr))
{
ASSERT_ARGS(deallocate_ptrobj)
mem_sys_free(ptr);
}
pmclass StructView auto_attrs {
ATTR PARROT_DATA_TYPE pack_type;
ATTR size_t n_elts;
ATTR elt_desc_t *elts;
ATTR size_t align;
ATTR size_t size;
/*
=item C<void init()>
Creating an instance without an initializer is dissallowed and will throw an
exception.
=cut
*/
VTABLE void init() {
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Meaningless creation of %Ss without initializer",
SELF->vtable->whoami);
}
/*
=item C<void init_pmc(PMC *p)>
Create a new StructView for viewing buffers as described by the initializer.
An initializer is an array-aggregate of integers. For example,
C<FixedIntegerArray> will work for this purpose.
The first element of the initializer is interpreted as the type of the
C<StructView>. There are three supported types of view: struct, indicated with
the C<DATATYPE_STRUCT> flag; union, indicated with the C<DATATYPE_UNION> flag;
and custom, indicated with the C<DATATYPE_SIZED> flag.
The second element of the initializer is interpreted as the number of elements
contained within the view.
If using a custom view, the third and fourth elements are interpreted as the
size and alignment in bytes respectively.
The remainder of the initializer is interpreted as a description of the
elements of the view. For struct and union views, elements are described
by a single integer flag from C<datatypes.pasm>, with layout being determined
automatically identical to what your C compiler would have done. For custom
views, elements are represented by a 3-tuple of
C<{type, byte-offset, bit-offset}>, which can be used for arbitrary layouts.
Note, however, that unaligned access is only supported on unsigned integers,
and even then, it is inefficient. You have been warned.
Supported element types are include:
=over 4
=item Parrot Types
C<INTVAL>, C<FLOATVAL>, C<STRING>, and C<PMC>
=item C-Native Types
Integer: C<char>, C<uchar>, C<short>, C<ushort>, C<int>, C<uint>, C<long>,
C<ulong>, C<longlong> (*), and C<ulonglong> (*)
Float: C<float>, C<double>, C<longdouble>
PMC: data pointer (C<ptr>), function pointer (C<func_ptr>), buffer (C<sized>) (**)
(*) Only available if your C system sports a C<long long> type.
(**) Requires 2 additional following parameters - buffer size and alignment.
=item Explicitly Sized Types
C<uint1> (also known as C<bit>), C<uint4>, C<int8>, C<uint8>, C<int16>,
C<uint16>, C<int32>, C<uint32>, C<int64>(*), and C<uint64>(*)
(*) Only available if your C system sports a 64 bit integer type.
=back
=cut
*/
VTABLE void init_pmc(PMC *p) {
const INTVAL init_len = VTABLE_elements(INTERP, p);
const PARROT_DATA_TYPE pack_type = (PARROT_DATA_TYPE)
VTABLE_get_integer_keyed_int(INTERP, p, 0);
const INTVAL n_elts = VTABLE_get_integer_keyed_int(INTERP, p, 1);
elt_desc_t *elt_ary;
size_t bit_cursor = 0;
size_t byte_cursor = 0;
size_t size, align;
int incr, i, j;
switch (pack_type) {
case enum_type_struct:
case enum_type_union:
size = 0;
align = 1; /* sorry, no sub-byte alignment */
incr = 1;
i = 2;
break;
case enum_type_sized:
size = VTABLE_get_integer_keyed_int(INTERP, p, 2);
align = VTABLE_get_integer_keyed_int(INTERP, p, 3);
incr = 3;
i = 4;
break;
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Unknown struct type `%Ss'",
Parrot_dt_get_datatype_name(INTERP, pack_type));
}
if (init_len < n_elts + i)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Initializer too short (%d) for struct type `%Ss' with %d elements",
init_len,
Parrot_dt_get_datatype_name(INTERP, pack_type),
n_elts);
elt_ary = mem_gc_allocate_n_zeroed_typed(INTERP, n_elts, elt_desc_t);
PObj_custom_destroy_SET(SELF);
SET_ATTR_pack_type(INTERP, SELF, pack_type);
SET_ATTR_elts(INTERP, SELF, elt_ary);
SET_ATTR_n_elts(INTERP, SELF, n_elts);
for (/* i already initialized */ j = 0; i < init_len && j < n_elts; i += incr, j++) {
elt_desc_t * const elt = &elt_ary[j];
const PARROT_DATA_TYPE elt_type = (PARROT_DATA_TYPE)
VTABLE_get_integer_keyed_int(INTERP, p, i);
size_t elt_size, elt_align;
elt_access_t elt_access;
if ((elt_type & ~enum_type_ref_flag) < enum_first_type
|| (elt_type & ~enum_type_ref_flag) >= enum_last_type)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Invalid type flag for struct element (%d)", elt_type);
elt->type = elt_type;
elt_size = data_types[elt_type - enum_first_type].size;
elt_align = data_types[elt_type - enum_first_type].align;
switch (elt_type) {
/* aligned integer types */
case enum_type_INTVAL:
case enum_type_char:
case enum_type_short:
case enum_type_int:
case enum_type_long:
#if PARROT_HAS_LONGLONG
case enum_type_longlong:
#endif
case enum_type_int8:
case enum_type_int16:
case enum_type_int32:
#if PARROT_HAS_INT64
case enum_type_int64:
#endif
case enum_type_uchar:
case enum_type_ushort:
case enum_type_uint:
case enum_type_ulong:
#if PARROT_HAS_LONGLONG
case enum_type_ulonglong:
#endif
case enum_type_uint8:
case enum_type_uint16:
case enum_type_uint32:
#if PARROT_HAS_INT64
case enum_type_uint64:
#endif
elt_access = int_access;
break;
/* unaligned integer types */
case enum_type_uint1:
case enum_type_uint4:
elt_access = unaligned_access;
break;
/* float types */
case enum_type_FLOATVAL:
case enum_type_float:
case enum_type_double:
case enum_type_longdouble:
elt_access = num_access;
break;
/* other types */
case enum_type_STRING:
elt_access = str_access;
break;
case enum_type_sized:
/* arbitrary buffers extended with size and align fields */
elt->size = elt_size = VTABLE_get_integer_keyed_int(INTERP, p, ++i);
elt_align = VTABLE_get_integer_keyed_int(INTERP, p, ++i);
/* fallthrough */
case enum_type_PMC:
case enum_type_ptr:
case enum_type_func_ptr:
elt_access = pmc_access;
break;
/* locally unsupported types */
#if !PARROT_HAS_LONGLONG
case enum_type_longlong:
case enum_type_ulonglong:
#endif
#if !PARROT_HAS_INT64
case enum_type_int64:
case enum_type_uint64:
#endif
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Unsupported struct element type `%Ss' (index %d)",
Parrot_dt_get_datatype_name(INTERP, elt_type),
j);
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Unknown struct element type `%Ss' (index %i)",
Parrot_dt_get_datatype_name(INTERP, elt_type),
j);
}
switch (pack_type) {
case enum_type_struct:
elt->access = elt_access;
align = MAX(align, elt_align);
switch (elt_access) {
case int_access:
case num_access:
case pmc_access:
if (bit_cursor) {
byte_cursor += 1;
bit_cursor = 0;
}
elt->byte_offset = ALIGN_UP(byte_cursor, elt_align);
byte_cursor = elt->byte_offset + elt_size;
break;
case unaligned_access:
elt->byte_offset = byte_cursor;
elt->bit_offset = bit_cursor;
byte_cursor = (bit_cursor + 1) / 8;
bit_cursor = (bit_cursor + 1) % 8;
break;
default:
break;
}
break;
case enum_type_union:
elt->access = elt_access;
size = MAX(size, elt_size);
align = MAX(align, elt_align);
/* all union elements are at 0 offset */
break;
case enum_type_sized:
elt->byte_offset = VTABLE_get_integer_keyed_int(INTERP, p, i + 1);
elt->bit_offset = VTABLE_get_integer_keyed_int(INTERP, p, i + 2);
switch (elt_access) {
case num_access:
case str_access:
case pmc_access:
if (align < elt_align
|| elt->bit_offset
|| elt->byte_offset % elt_align)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Unaligned access unsupported on type `%Ss' (index: %i)",
Parrot_dt_get_datatype_name(INTERP, elt_type),
j);
elt->access = elt_access;
break;
case int_access:
if (align < elt_align
|| elt->bit_offset
|| elt->byte_offset % elt_align) {
switch (elt_type) {
case enum_type_uchar:
case enum_type_ushort:
case enum_type_uint:
case enum_type_ulong:
#if PARROT_HAS_LONGLONG
case enum_type_ulonglong:
#endif
case enum_type_uint8:
case enum_type_uint16:
case enum_type_uint32:
#if PARROT_HAS_INT64
case enum_type_uint64:
#endif
elt->access = unaligned_access;
break;
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Unaligned access unsupported on type `%Ss' (index: %i)",
Parrot_dt_get_datatype_name(INTERP, elt_type),
j);
}
}
else {
elt->access = int_access;
}
break;
case unaligned_access:
elt->access = unaligned_access;
break;
default:
break;
}
default:
break;
}
}
if (pack_type == enum_type_struct) {
size = byte_cursor + !!bit_cursor;
}
SET_ATTR_align(INTERP, SELF, align);
SET_ATTR_size(INTERP, SELF, size);
}
/*
=item C<void destroy()>
Free internal offsets array.
=cut
*/
VTABLE void destroy() {
elt_desc_t *elts;
GET_ATTR_elts(INTERP, SELF, elts);
mem_gc_free(INTERP, elts);
}
/*
=item C<INTVAL get_integer_keyed(PMC *k)>
=item C<void set_integer_keyed(PMC *k, INTVAL x)>
Get/Set an integer-type element from a struct-pointer PMC.
=cut
*/
VTABLE INTVAL get_integer_keyed(PMC *k) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case int_access:
switch (elts[i].type) {
#define CASE_RET2(type, name) \
case enum_type_ ## name: return *(type *)ptr;
#define CASE_RET1(type) \
CASE_RET2(type, type) \
CASE_RET2(unsigned type, u ## type)
CASE_RET2(INTVAL, INTVAL)
CASE_RET1(char);
CASE_RET1(short);
CASE_RET1(int);
CASE_RET1(long);
#if PARROT_HAS_LONGLONG
CASE_RET2(long long, longlong);
CASE_RET2(unsigned long long, ulonglong);
#endif
CASE_RET2(Parrot_Int1, int8);
CASE_RET2(Parrot_UInt1, uint8);
CASE_RET2(Parrot_Int2, int16);
CASE_RET2(Parrot_UInt2, uint16);
CASE_RET2(Parrot_Int4, int32);
CASE_RET2(Parrot_UInt4, uint32);
#if PARROT_HAS_INT64
CASE_RET2(Parrot_Int8, int64);
CASE_RET2(Parrot_UInt8, uint64);
#endif
#undef CASE_RET1
#undef CASE_RET2
default:
break;
}
/* should not get here - inserted to avoid compiler warnings */
return 0;
case unaligned_access:
{
INTVAL acc = 0;
size_t bits, n;
unsigned char *cptr = (unsigned char *)ptr;
switch (elts[i].type) {
case enum_type_uint1:
bits = 1;
break;
case enum_type_uint4:
bits = 4;
break;
default:
bits = 8 * data_types[elts[i].type - enum_first_type].size;
break;
}
/* fetch hi bits of first byte */
acc = *cptr++ >> elts[i].bit_offset;
n = 8 - elts[i].bit_offset;
/* read whole bytes until complete */
while (n < bits) {
acc |= ((UINTVAL)*cptr++) << n;
n += 8;
}
/* mask off hi bits of last byte */
acc &= (~(UINTVAL)0) >> (sizeof (UINTVAL) * 8 - bits);
return acc;
}
/* should not get here - inserted to avoid compiler warnings */
return 0;
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Not a valid integer type (`%Ss')",
Parrot_dt_get_datatype_name(INTERP, elts[i].type));
}
}
VTABLE void set_integer_keyed(PMC *k, INTVAL x) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case int_access:
switch (elts[i].type) {
#define CASE_SET2(type, name) \
case enum_type_ ## name: *(type *)ptr = x; return;
#define CASE_SET1(type) \
CASE_SET2(type, type) \
CASE_SET2(unsigned type, u ## type)
CASE_SET2(INTVAL, INTVAL)
CASE_SET1(char);
CASE_SET1(short);
CASE_SET1(int);
CASE_SET1(long);
#if PARROT_HAS_LONGLONG
CASE_SET2(long long, longlong);
CASE_SET2(unsigned long long, ulonglong);
#endif
CASE_SET2(Parrot_Int1, int8);
CASE_SET2(Parrot_UInt1, uint8);
CASE_SET2(Parrot_Int2, int16);
CASE_SET2(Parrot_UInt2, uint16);
CASE_SET2(Parrot_Int4, int32);
CASE_SET2(Parrot_UInt4, uint32);
#if PARROT_HAS_INT64
CASE_SET2(Parrot_Int8, int64);
CASE_SET2(Parrot_UInt8, uint64);
#endif
#undef CASE_SET1
#undef CASE_SET2
default:
break;
}
break;
case unaligned_access:
{
UINTVAL ux = x;
size_t bits, n;
unsigned char tempc;
unsigned char *cptr = (unsigned char *)ptr;
switch (elts[i].type) {
case enum_type_uint1:
bits = 1;
break;
case enum_type_uint4:
bits = 4;
break;
default:
bits = 8 * data_types[elts[i].type - enum_first_type].size;
break;
}
/* cache last byte (for restoring hi bits) */
tempc = cptr[(bits + elts[i].bit_offset)/8];
/* write hi bits of first byte */
n = 8 - elts[i].bit_offset;
*cptr &= (1 << elts[i].bit_offset) - 1;
*cptr++ |= (ux & ((1 << n) - 1)) << elts[i].bit_offset;
/* write whole bytes until complete */
while (n < bits) {
*cptr++ = ux >> n;
n += 8;
}
/* restore hi bits of last byte */
cptr--;
n = 8 - (n - bits); /* how many bits of last byte we should have written */
*cptr &= (1 << n) - 1;
*cptr |= tempc & ~((1 << n) - 1);
}
break;
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Not a valid integer type (`%Ss')",
Parrot_dt_get_datatype_name(INTERP, elts[i].type));
}
}
/*
=item C<FLOATVAL get_number_keyed(PMC *k)>
=item C<void set_number_keyed(PMC *k, FLOATVAL n)>
Get/Set a float-like element from a struct-pointer PMC.
=cut
*/
VTABLE FLOATVAL get_number_keyed(PMC *k) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case num_access:
switch (elts[i].type) {
case enum_type_FLOATVAL:
return *(FLOATVAL *)ptr;
case enum_type_float:
return *(float *)ptr;
case enum_type_double:
return *(double *)ptr;
case enum_type_longdouble:
return *(long double *)ptr;
default:
break;
}
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Not a valid number type (`%Ss')",
Parrot_dt_get_datatype_name(INTERP, elts[i].type));
}
}
VTABLE void set_number_keyed(PMC *k, FLOATVAL n) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case num_access:
switch (elts[i].type) {
case enum_type_FLOATVAL:
*(FLOATVAL *)ptr = n;
return;
case enum_type_float:
*(float *)ptr = n;
return;
case enum_type_double:
*(double *)ptr = n;
return;
case enum_type_longdouble:
*(long double *)ptr = n;
return;
default:
break;
}
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Not a valid number type (`%Ss')",
Parrot_dt_get_datatype_name(INTERP, elts[i].type));
}
}
/*
=item C<STRING *get_string keyed(PMC *k)>
=item C<void set_string_keyed(PMC *k, STRING *)>
Get/Set a string element from a struct-pointer PMC.
=cut
*/
VTABLE STRING *get_string_keyed(PMC *k) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case str_access:
switch (elts[i].type) {
case enum_type_STRING:
return *(STRING **)ptr;
default:
break;
}
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Not a valid string type (`%Ss')",
Parrot_dt_get_datatype_name(INTERP, elts[i].type));
}
}
VTABLE void set_string_keyed(PMC *k, STRING *s) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case str_access:
switch (elts[i].type) {
case enum_type_STRING:
*(STRING **)ptr = s;
return;
default:
break;
}
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Not a valid string type (`%Ss')",
Parrot_dt_get_datatype_name(INTERP, elts[i].type));
}
}
/*
=item C<PMC *get_pmc_keyed(PMC *k)>
=item C<void set_pmc_keyed(PMC *k, PMC *p)>
Get/Set a PMC-like element from a struct-pointer PMC or box/unbox values from
any other type of element.
=cut
*/
VTABLE PMC *get_pmc_keyed(PMC *k) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case int_access:
case unaligned_access:
return Parrot_pmc_box_integer(INTERP, SELF.get_integer_keyed(k));
case num_access:
return Parrot_pmc_box_number(INTERP, SELF.get_number_keyed(k));
case str_access:
return Parrot_pmc_box_string(INTERP, SELF.get_string_keyed(k));
case pmc_access:
{
PMC *ret;
switch (elts[i].type) {
case enum_type_PMC:
return *(PMC **)ptr;
case enum_type_func_ptr:
case enum_type_ptr:
return Parrot_pmc_new_init_int(INTERP, enum_class_Ptr,
(INTVAL)*(void **)ptr);
case enum_type_sized:
ret = Parrot_pmc_new_init_int(INTERP, enum_class_PtrBuf,
(INTVAL)*(void **)ptr);
VTABLE_set_integer_native(INTERP, ret, elts[i].size);
return ret;
default:
/* should never get here - put in to quiet compiler warnings */
return NULL;
}
}
default:
/* should never get here - put in to quiet compiler warnings */
return NULL;
}
}
VTABLE void set_pmc_keyed(PMC *k, PMC *p) {
BEGIN_KEYED(INTERP, SELF, k)
switch (elts[i].access) {
case int_access:
case unaligned_access:
SELF.set_integer_keyed(k, VTABLE_get_integer(INTERP, p));
break;
case num_access:
SELF.set_number_keyed(k, VTABLE_get_number(INTERP, p));
break;
case str_access:
SELF.set_string_keyed(k, VTABLE_get_string(INTERP, p));
break;
case pmc_access:
{
switch (elts[i].type) {
case enum_type_PMC:
*(PMC **)ptr = p;
break;
case enum_type_func_ptr:
case enum_type_ptr:
*(void **)ptr = VTABLE_get_pointer(INTERP, p);
break;
case enum_type_sized:
if (VTABLE_does(INTERP, p, CONST_STRING(INTERP, "buffer"))) {
void * const q = VTABLE_get_pointer(INTERP, p);
size_t len = VTABLE_get_integer(INTERP, p);
if (len == 0 || len > elts[i].size)
len = elts[i].size;
memcpy(ptr, q, len);
break;
}
else {
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Type `%Ss' unsuitable for buffer assignment",
p->vtable->whoami);
}
default:
break;
}
}
default:
break;
}
}
/*
=item C<INTVAL get_integer()>
=item C<METHOD size()>
Get the size (in bytes) required for one instance.
=cut
*/
VTABLE INTVAL get_integer() {
size_t size;
GET_ATTR_size(INTERP, SELF, size);
return size;
}
METHOD size() {
size_t size;
GET_ATTR_size(INTERP, SELF, size);
RETURN(INTVAL size);
}
/*
=item C<METHOD align()>
Get the alignment (in bytes) required for an instance.
=cut
*/
METHOD align() {
size_t align;
GET_ATTR_align(INTERP, SELF, align);
RETURN(INTVAL align);
}
/*
=item C<METHOD aligned_size()>
Get the size of one instance plus the pad bytes to align a subsequent
instance.
=cut
*/
METHOD aligned_size() {
size_t size, align;
INTVAL ret;
GET_ATTR_size(INTERP, SELF, size);
GET_ATTR_align(INTERP, SELF, align);
ret = ALIGN_UP(size, align);
RETURN(INTVAL ret);
}
/*
=item C<METHOD alloc(INTVAL n :optional)>
Allocate an instance, or an array of instances when C<n> has been provided.
=cut
*/
METHOD alloc(INTVAL n :optional, int has_n :opt_flag) {
size_t size, align;
PMC *ret;
void *buf;
GET_ATTR_size(INTERP, SELF, size);
if (has_n) {
GET_ATTR_align(INTERP, SELF, align);
size = ALIGN_UP(size, align) * n;
}
buf = mem_sys_allocate_zeroed(size);
ret = Parrot_pmc_new_init_int(INTERP, enum_class_PtrObj, (INTVAL)buf);
SETATTR_PtrObj_destroy(INTERP, ret, deallocate_ptrobj);
RETURN(PMC ret);
}
/*
=item C<METHOD array_offs(PMC *array, INTVAL n)>
Return a C<Ptr> to the C<n>th element of an array of structs.
=cut
*/
METHOD array_offs(PMC *array, INTVAL n) {
void *p = VTABLE_get_pointer(INTERP, array);
INTVAL array_size = VTABLE_get_integer(INTERP, array);
PMC *ret;
size_t size, align;
GET_ATTR_size(INTERP, SELF, size);
GET_ATTR_align(INTERP, SELF, align);
/* sanity checks */
if (!p)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Attempt to dereference null pointer");
if (array_size && array_size < (int)size * n)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Buffer length too small for struct array "
"(at least %d required, got %d)",
size * n, array_size);
if ((size_t)p != ALIGN_UP((size_t)p, align))
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Attempt to dereference unaligned pointer "
"(%x, required alignment: %d)",
p, align);
size = ALIGN_UP(size, align);
ret = Parrot_pmc_new_init_int(INTERP, enum_class_Ptr, (INTVAL)((char *)p + size * n));
RETURN(PMC ret);
}
/*
=item C<METHOD elt_offs(PMC *array, INTVAL n)>
Return a C<Ptr> to the C<n>th element of a struct.
=cut
*/
METHOD elt_offs(PMC *array, INTVAL n) {
void *p = VTABLE_get_pointer(INTERP, array);
PMC *ret;
size_t n_elts;
elt_desc_t *elts;
GET_ATTR_n_elts(INTERP, SELF, n_elts);
GET_ATTR_elts(INTERP, SELF, elts);
/* sanity checks */
if (n < 0 || n_elts <= (size_t)n)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Struct index out of bounds (%d)", n);
if (!p)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Attempt to dereference null pointer");
{
size_t buf_size = VTABLE_get_integer(INTERP, array);
size_t self_size;
GET_ATTR_size(INTERP, SELF, self_size);
if (buf_size && buf_size < self_size)
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Buffer length too small for struct "
"(at least %d required, got %d)",
self_size, buf_size);
}
{
size_t align;
GET_ATTR_align(INTERP, SELF, align);
if ((size_t)p != ALIGN_UP((size_t)p, align))
Parrot_ex_throw_from_c_args(INTERP, NULL, 0,
"Attempt to dereference unaligned pointer "
"(%x, required alignment: %d)",
p, align);
}
p = ((char *)p) + elts[n].byte_offset;
ret = Parrot_pmc_new_init_int(INTERP, enum_class_Ptr, (INTVAL)p);
RETURN(PMC ret);
}
/*
=item C<METHOD get_shape()>
Obtain an integer array which describes the shape of this object.
The returned array is of the same format as the one used for C<StructView.init_pmc>.
=cut
*/
METHOD get_shape() {
int i, j;
size_t n;
elt_desc_t *elts;
PARROT_DATA_TYPE pack_type;
PMC *result;
GET_ATTR_n_elts(INTERP, SELF, n);
GET_ATTR_elts(INTERP, SELF, elts);
GET_ATTR_pack_type(INTERP, SELF, pack_type);
switch (pack_type) {
case enum_type_struct:
case enum_type_union:
result = Parrot_pmc_new_init_int(INTERP, enum_class_ResizableIntegerArray, n + 2);
VTABLE_set_integer_keyed_int(INTERP, result, 0, pack_type);
VTABLE_set_integer_keyed_int(INTERP, result, 1, n);
break;
case enum_type_sized:
result = Parrot_pmc_new_init_int(INTERP, enum_class_ResizableIntegerArray, n * 3 + 4);
{
size_t s;
VTABLE_set_integer_keyed_int(INTERP, result, 0, pack_type);
VTABLE_set_integer_keyed_int(INTERP, result, 1, n);
GET_ATTR_size(INTERP, SELF, s);
VTABLE_set_integer_keyed_int(INTERP, result, 2, s);
GET_ATTR_align(INTERP, SELF, s);
VTABLE_set_integer_keyed_int(INTERP, result, 3, s);
}
break;
default:
break;
}
for (i = 1, j = 1; i <= (int)n; i++) {
switch (pack_type) {
case enum_type_struct:
case enum_type_union:
VTABLE_set_integer_keyed_int(INTERP, result, i + j, elts[i - 1].type);
if (elts[i - 1].type == enum_type_sized) {
VTABLE_set_integer_keyed_int(interp, result, i + ++j, elts[i - 1].size);
VTABLE_set_integer_keyed_int(interp, result, i + ++j, 0);
}
break;
case enum_type_sized:
VTABLE_set_integer_keyed_int(INTERP, result, i * 3 + j, elts[i - 1].type);
if (elts[i - 1].type == enum_type_sized) {
VTABLE_set_integer_keyed_int(interp, result, i * 3 + ++j, elts[i - 1].size);
VTABLE_set_integer_keyed_int(interp, result, i * 3 + ++j, 0);
}
VTABLE_set_integer_keyed_int(INTERP,
result, i * 3 + j + 1, elts[i - 1].byte_offset);
VTABLE_set_integer_keyed_int(INTERP,
result, i * 3 + j + 2, elts[i - 1].bit_offset);
default:
break;
}
}
RETURN(PMC result);
}
/*
=item C<void freeze(PMC *v)>
=item C<void thaw(PMC *v)>
Implement the freeze/thaw API.
=cut
*/
VTABLE void freeze(PMC *v) {
PMC *shape;
Parrot_pcc_invoke_method_from_c_args(INTERP, SELF, CONST_STRING(INTERP, "get_shape"),
"->P", &shape);
VTABLE_freeze(INTERP, shape, v);
}
VTABLE void thaw(PMC *v) {
PMC *shape = Parrot_pmc_new_noinit(INTERP, enum_class_ResizableIntegerArray);
VTABLE_thaw(INTERP, shape, v);
SELF.init_pmc(shape);
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/
Jump to Line
Something went wrong with that request. Please try again.