2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/pmc/unmanagedstruct.pmc - C struct with unmanaged memory
11 PMC class to hold C C<struct>s that Parrot's not responsible for
14 Buffer can be accessed using keyed assignments to PMC. Out of
15 bounds access will very likely segfault.
25 #include "parrot/parrot.h"
26 #include "parrot/compiler.h"
28 static INTVAL key_2_idx(PARROT_INTERP, PMC *pmc, PMC *key);
29 static size_t calc_offsets(PARROT_INTERP, PMC*, PMC *init, size_t toff);
34 char_offset_int(PARROT_INTERP, PMC *pmc, INTVAL ix, int *type)>
36 Returns the pointer for the element at index C<ix>, and sets the element
44 char_offset_int(PARROT_INTERP, PMC *pmc, INTVAL ix, int *type)
49 if (!PMC_pmc_val(pmc))
50 real_exception(interp, NULL, E_ValueError,
51 "Missing struct initializer");
53 n = (size_t)VTABLE_elements(interp, PMC_pmc_val(pmc));
56 real_exception(interp, NULL, E_ValueError,
57 "Non existent elements in struct "
58 "ix = %d n=%d", (int)ix, (int)n);
60 /* use structure init */
61 *type = (int) VTABLE_get_integer_keyed_int(interp,
62 PMC_pmc_val(pmc), ix);
64 offs = (size_t) VTABLE_get_integer_keyed_int(interp,
65 PMC_pmc_val(pmc), ix + 2);
67 return ((char *)PMC_data(pmc)) + offs;
73 key_2_idx(PARROT_INTERP, PMC *pmc, PMC *key)>
75 Returns the index for the element associated with key C<*key>. Raises an
76 exception if the key doesn't exist.
83 key_2_idx(PARROT_INTERP, PMC *pmc, PMC *key)
87 if (!PMC_pmc_val(pmc))
88 real_exception(interp, NULL, E_ValueError,
89 "Missing struct initializer");
91 if (PObj_get_FLAGS(key) & KEY_string_FLAG) {
92 PMC * const types = PMC_pmc_val(pmc);
94 if (types->vtable->base_type == enum_class_OrderedHash) {
95 Hash * const hash = (Hash *)PMC_struct_val(types);
96 HashBucket * const b = parrot_hash_get_bucket(interp, hash,
97 key_string(interp, key));
100 real_exception(interp, NULL, E_KeyError, "key doesn't exist");
105 real_exception(interp, NULL, E_TypeError,
106 "unhandled type aggregate");
111 ix = key_integer(interp, key);
118 =item C<static char *
119 char_offset_key(PARROT_INTERP, PMC *pmc, PMC *key, int *type)>
121 Returns the pointer for the element associated with key C<*key>, and
122 sets the element type in C<*type>.
129 char_offset_key(PARROT_INTERP, PMC *pmc, PMC *key, int *type)
131 size_t offs, count, size, max;
137 trace_key_dump(interp, key);
140 ix = key_2_idx(interp, pmc, key);
141 next = key_next(interp, key);
142 p = char_offset_int(interp, pmc, ix, type);
148 if (PObj_get_FLAGS(next) & KEY_integer_FLAG)
149 count = key_integer(interp, next);
153 init = PMC_pmc_val(pmc);
154 max = (size_t)VTABLE_get_integer_keyed_int(interp, init, ix + 1);
157 PIO_eprintf(interp, " count = %d ix = %d max = %d\n",
158 (int)count, (int)ix, (int)max);
161 if (*type == enum_type_struct_ptr || *type == enum_type_struct) {
162 /* the struct PMC is hanging off the initializer element
163 * as property "_struct"
165 PMC * const ptr = VTABLE_get_pmc_keyed_int(interp, init, ix);
166 init = VTABLE_getprop(interp, ptr, CONST_STRING(interp, "_struct"));
168 PARROT_ASSERT(init &&
169 (init->vtable->base_type == enum_class_UnManagedStruct ||
170 init->vtable->base_type == enum_class_ManagedStruct));
172 /* array of structs */
174 if (key_next(interp, next))
175 next = key_next(interp, next);
177 offs = PMC_int_val(init);
180 PIO_eprintf(interp, "offs = %d\n", (int)offs);
185 if (init->vtable->base_type == enum_class_UnManagedStruct) {
186 /* now point PMC_data of this struct to the real data */
187 if (*type == enum_type_struct_ptr) {
188 /* that is either a pointer */
189 PARROT_ASSERT((PTR2INTVAL(p) & (PARROT_PTR_ALIGNMENT - 1)) == 0);
190 PMC_data(init) = *(void**)p;
193 /* or just an offset for nested structs */
197 else if (init->vtable->base_type == enum_class_ManagedStruct &&
198 *type == enum_type_struct_ptr) {
199 /* a nested struct pointer belonging to us
200 * p is the location of the struct pointer in the
201 * outer struct, the inner is at PMC_data(init)
203 PARROT_ASSERT((PTR2INTVAL(p) & (PARROT_PTR_ALIGNMENT - 1)) == 0);
204 *(void **)p = PMC_data(init);
207 return char_offset_key(interp, init, next, type);
211 real_exception(interp, NULL, E_LookupError,
212 "Non existent array element in struct: "
213 "count = %d max=%d", (int)count, (int)max);
214 size = data_types[*type - enum_first_type].size;
215 return p + count * size;
220 =item C<static INTVAL
221 ret_int(PARROT_INTERP, const char *p, int type)>
223 Returns the element of type C<type> starting at C<*p> as an C<INTVAL>.
225 If, for example, C<char> or c<short> type size doesn't match, this will fail
226 we need some more configure support for type sizes.
233 ret_int(PARROT_INTERP, const char *p, int type)
234 __attribute__nonnull__(1);
237 ret_int(PARROT_INTERP, const char *p, int type)
240 case enum_type_INTVAL:
241 return *(const INTVAL*) p;
244 case enum_type_int32:
245 case enum_type_uint32:
249 case enum_type_int64:
250 case enum_type_uint64:
254 return *(const int *)p;
256 #if (LONG_SIZE == 4) && !(INT_SIZE == 4) /* Unlikely combination. */
257 case enum_type_int32:
258 case enum_type_uint32:
261 #if (LONG_SIZE == 8) && !(INT_SIZE == 8)
262 case enum_type_int64:
263 case enum_type_uint64:
267 case enum_type_ulong:
268 return *(const long *)p;
271 case enum_type_int16:
272 case enum_type_uint16:
275 /* If SHORT_SIZE != 2 getting int16s requires extra tricks. */
276 case enum_type_short:
277 return *(const short *)p;
278 case enum_type_uint8:
279 case enum_type_uchar:
281 const unsigned char *uc = (const unsigned char *)p;
288 real_exception(interp, NULL, 1,
289 "returning unhandled int type in struct");
295 =item C<static FLOATVAL
296 ret_float(PARROT_INTERP, const char *p, int type)>
298 Returns the element of type C<type> starting at C<*p> as a C<FLOATVAL>.
305 ret_float(PARROT_INTERP, const char *p, int type)
306 __attribute__nonnull__(1);
309 ret_float(PARROT_INTERP, const char *p, int type)
312 case enum_type_FLOATVAL:
313 return (FLOATVAL) *(const FLOATVAL *)p;
314 case enum_type_float:
315 return (FLOATVAL) *(const float *)p;
316 case enum_type_double:
317 return (FLOATVAL) *(const double *)p;
319 real_exception(interp, NULL, 1,
320 "returning unhandled float type in struct");
326 =item C<static STRING*
327 ret_string(PARROT_INTERP, char *p, int type)>
329 Returns the element of type C<type> starting at C<*p> as a Parrot string.
336 ret_string(PARROT_INTERP, char *p, int type)
338 if (type == enum_type_cstr) {
339 char *cstr = *(char **) p;
340 size_t len = strlen(cstr);
341 return string_make(interp, cstr, len, "iso-8859-1", PObj_external_FLAG);
344 real_exception(interp, NULL, E_TypeError,
345 "returning unhandled string type in struct");
351 ret_pmc(PARROT_INTERP, PMC *pmc, char *p, int type, INTVAL idx)>
353 Returns the element of type C<type> starting at C<*p> as a PMC.
360 ret_pmc(PARROT_INTERP, PMC *pmc, char *p, int type, INTVAL idx)
362 PMC *ret = NULL, *init, *ptr;
365 case enum_type_func_ptr:
366 /* this is a raw function pointer - not a PMC */
369 /* now check if initializer has a signature attached */
370 init = PMC_pmc_val(pmc);
371 ptr = VTABLE_get_pmc_keyed_int(interp, init, idx*3);
373 if (ptr->pmc_ext && PMC_metadata(ptr)) {
374 STRING *signature_str = CONST_STRING(interp, "_signature");
375 PMC *sig = VTABLE_getprop(interp, ptr, signature_str);
376 if (VTABLE_defined(interp, sig)) {
377 STRING *sig_str = VTABLE_get_string(interp, sig);
378 ret = pmc_new(interp, enum_class_NCI);
379 VTABLE_set_pointer_keyed_str(interp, ret, sig_str,
385 case enum_type_struct_ptr:
386 /* check the metadata for an initializer */
387 init = PMC_pmc_val(pmc);
388 ptr = VTABLE_get_pmc_keyed_int(interp, init, idx * 3);
390 /* grab the struct from the metadata */
391 if (ptr->pmc_ext && PMC_metadata(ptr)) {
392 ret = VTABLE_getprop(interp, ptr, CONST_STRING(interp, "_struct"));
395 real_exception(interp, NULL, E_TypeError,
396 "no initializer available for nested struct");
399 /* assign the pointer */
400 PMC_data(ret) = *(void**)p;
404 real_exception(interp, NULL, E_TypeError,
405 "returning unhandled pmc type (%d) in struct", type);
412 set_int(PARROT_INTERP, char *p, int type, INTVAL value)>
419 set_int(PARROT_INTERP, char *p, int type, INTVAL value)
422 case enum_type_uint8:
425 case enum_type_uchar:
426 *(char *)p = (char)(value & 0xff);
428 case enum_type_INTVAL:
429 *(INTVAL *)p = value;
434 case enum_type_int16:
435 case enum_type_uint16:
436 case enum_type_short:
437 *(short *)p = (short)value;
440 real_exception(interp, NULL, 1,
441 "setting unhandled int type in struct");
449 set_float(PARROT_INTERP, char *p, int type, FLOATVAL value)>
451 Sets the value of the element of type C<type> starting at C<*p> to
459 set_float(PARROT_INTERP, char *p, int type, FLOATVAL value)
462 case enum_type_FLOATVAL:
463 *(FLOATVAL *)p = (FLOATVAL)value;
465 case enum_type_float:
466 *(float *)p = (float)value;
468 case enum_type_double:
469 *(double *)p = (double)value;
472 real_exception(interp, NULL, 1,
473 "setting unhandled float type in struct");
481 set_string(PARROT_INTERP, char *p, int type, STRING *value)>
483 Sets the value of the element of type C<type> starting at C<*p> to
491 set_string(PARROT_INTERP, char *p, int type, STRING *value)
493 if (type == enum_type_cstr) {
494 /* assuming 0-terminated C-string here;
495 * we can't use string_to_cstring easily */
496 char *cstr = value->strstart;
500 real_exception(interp, NULL, 1,
501 "setting unhandled string type in struct (%d)", type);
507 calc_align(PARROT_INTERP, PMC *pmc, PMC *type_pmc,
510 Alignment of contained structures is the alignment of the
511 biggest item in that C<struct>.
513 i386: C<long long> or C<double> is aligned on 4.
515 This is recursive as structure definitions.
522 calc_align(PARROT_INTERP, PMC *pmc, PMC *type_pmc,
525 int align = data_types[type - enum_first_type].size;
527 PMC *nested_init = NULL;
529 if (type == enum_type_struct || type == enum_type_struct_ptr) {
530 /* a nested structs alignment is the biggest item in it
531 * so go through that struct and check
533 nested = VTABLE_getprop(interp, type_pmc, CONST_STRING(interp, "_struct"));
534 nested_init = PMC_pmc_val(nested);
536 if (type == enum_type_struct) {
537 size_t i, n = (size_t)VTABLE_elements(interp, nested_init);
542 real_exception(interp, NULL, E_TypeError,
543 "Illegal initializer for struct");
545 for (i = 0; i < n; i += 3) {
546 PMC *nested_type_pmc = VTABLE_get_pmc_keyed_int(interp,
548 int nested_type = (int)VTABLE_get_integer(interp,
550 new_offs = calc_align(interp, nested,
551 nested_type_pmc, nested_type, offs);
553 if (new_offs > a_max)
560 if (align && offs % align) {
561 const int diff = align - (offs % align);
565 if (type == enum_type_struct || type == enum_type_struct_ptr)
566 calc_offsets(interp, nested, nested_init, 0);
573 =item C<static size_t
574 calc_offsets(PARROT_INTERP, PMC *pmc, PMC *value, size_t toff)>
576 Calculates the offsets for the C<struct>. See C<init_pmc()> for a
577 description of C<*value>.
584 calc_offsets(PARROT_INTERP, PMC *pmc, PMC *value, size_t toff)
586 size_t i, n = (size_t)VTABLE_elements(interp, value);
590 real_exception(interp, NULL, E_TypeError,
591 "Illegal initializer for struct");
593 for (i = 0; i < n; i += 3) {
594 PMC *type_pmc = VTABLE_get_pmc_keyed_int(interp, value, i);
595 int type = (int)VTABLE_get_integer(interp, type_pmc);
596 int count = (int)VTABLE_get_integer_keyed_int(interp, value, i + 1);
597 int offs = (int)VTABLE_get_integer_keyed_int(interp, value, i + 2);
599 if (type < enum_first_type || type >= enum_last_type)
600 real_exception(interp, NULL, E_TypeError,
601 "Illegal type in initializer for struct");
605 VTABLE_set_integer_keyed_int(interp, value, i+1, count);
609 offs = toff = calc_align(interp, pmc, type_pmc, type, toff);
610 VTABLE_set_integer_keyed_int(interp, value, i+2, offs);
615 if (type == enum_type_struct) {
616 PMC *nested = VTABLE_getprop(interp, type_pmc, CONST_STRING(interp, "_struct"));
617 size = PMC_int_val(nested);
620 size = data_types[type - enum_first_type].size;
622 toff += count * size;
624 /* set / allocate size */
626 VTABLE_set_integer_native(interp, pmc, toff);
632 pmclass UnManagedStruct extends default need_ext no_ro {
644 Initializes the C<struct> with a default value of C<NULL>.
651 PMC_pmc_val(SELF) = NULL;
656 =item C<void init_pmc(PMC *value)>
658 Initialize the struct with some data.
660 C<*value> should be an array of triples of:
666 The datatype. See the C<enum> in F<include/parrot/datatypes.h>.
682 VTABLE void init_pmc(PMC *value) {
688 =item C<void set_pmc(PMC *value)>
690 Sets C<*value> (see C<init_pmc()> and calculates the offsets.
696 VTABLE void set_pmc(PMC *value) {
697 PMC_pmc_val(SELF) = value;
698 PObj_custom_mark_SET(SELF);
699 calc_offsets(INTERP, SELF, value, 0);
706 Marks the C<struct> as live.
713 if (PMC_pmc_val(SELF))
714 pobject_lives(INTERP, (PObj *)PMC_pmc_val(SELF));
719 =item C<INTVAL is_equal(PMC *value)>
721 Returns whether the two C<struct>s are equivalent.
727 VTABLE INTVAL is_equal(PMC *value) {
728 return (SELF->vtable == value->vtable &&
729 PMC_data(SELF) == PMC_data(value));
734 =item C<INTVAL defined()>
736 Returns whether the C<struct> is defined.
742 VTABLE INTVAL defined() {
743 return PMC_data(SELF) != NULL;
748 =item C<INTVAL get_integer()>
750 Returns the size of the C<struct>.
756 VTABLE INTVAL get_integer() {
757 return PMC_int_val(SELF);
762 =item C<void set_integer_native(INTVAL size)>
764 Sets the size of the C<struct>.
770 VTABLE void set_integer_native(INTVAL size) {
771 PMC_int_val(SELF) = size;
776 =item C<INTVAL get_integer_keyed_int(INTVAL ix)>
778 Returns the integer value at index C<ix>.
784 VTABLE INTVAL get_integer_keyed_int(INTVAL ix) {
786 char *p = char_offset_int(INTERP, pmc, ix, &type);
787 return ret_int(INTERP, p, type);
792 =item C<INTVAL get_integer_keyed(PMC *key)>
794 Returns the integer value associated with C<*key>.
800 VTABLE INTVAL get_integer_keyed(PMC *key) {
802 char *p = char_offset_key(INTERP, pmc, key, &type);
803 return ret_int(INTERP, p, type);
808 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
810 Returns the floating-point value at index C<ix>.
816 VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
818 char *p = char_offset_int(INTERP, pmc, key, &type);
819 return ret_float(INTERP, p, type);
824 =item C<FLOATVAL get_number_keyed(PMC *key)>
826 Returns the floating-point value associated with C<*key>.
832 VTABLE FLOATVAL get_number_keyed(PMC *key) {
834 char *p = char_offset_key(INTERP, pmc, key, &type);
835 return ret_float(INTERP, p, type);
840 =item C<STRING *get_string_keyed_int(INTVAL key)>
842 Returns the Parrot string value at index C<ix>.
848 VTABLE STRING *get_string_keyed_int(INTVAL key) {
850 char *p = char_offset_int(INTERP, pmc, key, &type);
851 return ret_string(INTERP, p, type);
856 =item C<STRING *get_string_keyed(PMC *key)>
858 Returns the Parrot string value associated with C<*key>.
864 VTABLE STRING *get_string_keyed(PMC *key) {
866 char *p = char_offset_key(INTERP, pmc, key, &type);
867 return ret_string(INTERP, p, type);
872 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
874 Returns the PMC value at index C<ix>.
880 VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
882 char *p = char_offset_int(INTERP, pmc, key, &type);
883 return ret_pmc(INTERP, pmc, p, type, key);
888 =item C<PMC *get_pmc_keyed(PMC *key)>
890 Returns the PMC value associated with C<*key>.
896 VTABLE PMC *get_pmc_keyed(PMC *key) {
898 char *p = char_offset_key(INTERP, pmc, key, &type);
899 return ret_pmc(INTERP, pmc, p, type, key_2_idx(INTERP, pmc, key));
904 =item C<void *get_pointer()>
906 Returns the pointer to the actual C C<struct>.
912 VTABLE void *get_pointer() {
913 return PMC_data(SELF);
918 =item C<void set_pointer(void *value)>
920 Set the pointer to the actual C C<struct>.
926 VTABLE void set_pointer(void *value) {
927 PMC_data(SELF) = value;
932 =item C<void set_integer_keyed_int(INTVAL ix, INTVAL value)>
934 Sets the value of the element at index C<ix> to C<value>.
940 VTABLE void set_integer_keyed_int(INTVAL ix, INTVAL value) {
942 char *p = char_offset_int(INTERP, pmc, ix, &type);
943 set_int(INTERP, p, type, value);
948 =item C<void set_integer_keyed(PMC *key, INTVAL value)>
950 Sets the value of the element associated with key C<*key> to C<value>.
952 May cause segfaults if value is out of bounds.
958 VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
960 char *p = char_offset_key(INTERP, pmc, key, &type);
961 set_int(INTERP, p, type, value);
966 =item C<void set_number_keyed_int(INTVAL key, FLOATVAL value)>
968 Sets the value of the element at index C<ix> to C<value>.
974 VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL value) {
976 char *p = char_offset_int(INTERP, pmc, key, &type);
977 set_float(INTERP, p, type, value);
982 =item C<void set_number_keyed(PMC *key, FLOATVAL value)>
984 Sets the value of the element associated with key C<*key> to C<value>.
990 VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
992 char *p = char_offset_key(INTERP, pmc, key, &type);
993 set_float(INTERP, p, type, value);
998 =item C<void set_string_keyed_int(INTVAL key, STRING *value)>
1000 Sets the value of the element at index C<key> to C<*value>.
1006 VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
1008 char *p = char_offset_int(INTERP, pmc, key, &type);
1009 set_string(INTERP, p, type, value);
1014 =item C<void set_string_keyed(PMC *key, STRING *value)>
1016 Sets the value of the element associated with key C<*key> to C<*value>.
1022 VTABLE void set_string_keyed(PMC *key, STRING *value) {
1024 char *p = char_offset_key(INTERP, pmc, key, &type);
1025 set_string(INTERP, p, type, value);
1036 Initial revision by sean 2002/08/04
1040 F<docs/pmc/struct.pod>
1048 * c-file-style: "parrot"
1050 * vim: expandtab shiftwidth=4: