parrotcode: Fetch/store packfile data | |
Contents | C |
src/packfile/pf_items.c - Fetch/store packfile data
Low level packfile functions to fetch and store Parrot data,
i.e.
INTVAL
,
FLOATVAL
,
STRING
...
PF_fetch_<item>()
functions retrieve the datatype item from the opcode stream and convert byteordering or binary format on the fly,
depending on the packfile header.
PF_store_<item>()
functions write the datatype item to the stream as is.
These functions don't check the available size.
PF_size_<item>()
functions return the store size of item in opcode_t
units.
*/
#include "parrot/parrot.h"
/* HEADERIZER HFILE: include/parrot/packfile.h */
/* HEADERIZER BEGIN: static */
static void cvt_num12_num8( NOTNULL(unsigned char *dest), NOTNULL(const unsigned char *src) ) __attribute__nonnull__(1) __attribute__nonnull__(2);
static void cvt_num12_num8_be( NOTNULL(unsigned char *dest), NOTNULL(const unsigned char *src) ) __attribute__nonnull__(1) __attribute__nonnull__(2);
static void cvt_num12_num8_le( NOTNULL(unsigned char *dest), NOTNULL(unsigned char *src) ) __attribute__nonnull__(1) __attribute__nonnull__(2);
static opcode_t fetch_op_be_4( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
static opcode_t fetch_op_be_8( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
static opcode_t fetch_op_le_4( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
static opcode_t fetch_op_le_8( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
static opcode_t fetch_op_mixed_be( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
static opcode_t fetch_op_mixed_le( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
static opcode_t fetch_op_test( NOTNULL(unsigned char *b) ) __attribute__nonnull__(1);
/* HEADERIZER END: static */
#define TRACE_PACKFILE 0 #define TRACE_PACKFILE_PMC 0
/* * round val up to whole size, return result in bytes */ #define ROUND_UP_B(val,size) ((((val) + (size - 1))/(size)) * (size))
/* * round val up to whole opcode_t, return result in opcodes */ #define ROUND_UP(val,size) (((val) + ((size) - 1))/(size))
/* * low level FLOATVAL fetch and convert functions * * * convert i386 LE 12 byte long double to IEEE 754 8 byte double */ static void cvt_num12_num8(NOTNULL(unsigned char *dest), NOTNULL(const unsigned char *src)) { int expo, i, s; #ifdef __LCC__ int expo2; #endif
memset (dest, 0, 8);
/* exponents 15 -> 11 bits */
s = src[9] & 0x80; /* sign */
expo = ((src[9] & 0x7f)<< 8 | src[8]);
if (expo == 0) {
nul:
if (s)
dest[7] |= 0x80;
return;
}
#ifdef __LCC__
/* Yet again, LCC blows up mysteriously until a temporary variable is
* added. */
expo2 = expo - 16383;
expo = expo2;
#else
expo -= 16383; /* - bias */
#endif
expo += 1023; /* + bias 8byte */
if (expo <= 0) /* underflow */
goto nul;
if (expo > 0x7ff) { /* inf/nan */
dest[7] = 0x7f;
dest[6] = src[7] == 0xc0 ? 0xf8 : 0xf0 ;
goto nul;
}
expo <<= 4;
dest[6] = (expo & 0xff);
dest[7] = (expo & 0x7f00) >> 8;
if (s)
dest[7] |= 0x80;
/* long double frac 63 bits => 52 bits
src[7] &= 0x7f; reset integer bit */
for (i = 0; i < 6; i++) {
dest[i+1] |= (i==5 ? src[7]&0x7f : src[i+2]) >> 3;
dest[i] |= (src[i+2] & 0x1f) << 5;
}
dest[0] |= src[1] >> 3;
}
static void cvt_num12_num8_be(NOTNULL(unsigned char *dest), NOTNULL(const unsigned char *src)) { cvt_num12_num8(dest, src); /* TODO endianize */ internal_exception(1, "TODO cvt_num12_num8_be\n"); }
static void cvt_num12_num8_le(NOTNULL(unsigned char *dest), NOTNULL(unsigned char *src)) { unsigned char b[8]; cvt_num12_num8(b, src); fetch_buf_le_8(dest, b); } static opcode_t fetch_op_test(NOTNULL(unsigned char *b)) { union { unsigned char buf[4]; opcode_t o; } u; fetch_buf_le_4(u.buf, b); return u.o; }
/* * opcode fetch helper function * * This is mostly wrong or at least untested * * Fetch an opcode and convert to LE */ static opcode_t fetch_op_mixed_le(NOTNULL(unsigned char *b)) { #if OPCODE_T_SIZE == 4 union { unsigned char buf[8]; opcode_t o[2]; } u; /* wordsize = 8 then */ fetch_buf_le_8(u.buf, (unsigned char *) b); return u.o[0]; /* or u.o[1] */ #else union { unsigned char buf[4]; opcode_t o; } u;
/* wordsize = 4 */
u.o = 0;
fetch_buf_le_4(u.buf, b);
return u.o;
#endif
}
/* * Fetch an opcode and convert to BE */ static opcode_t fetch_op_mixed_be(NOTNULL(unsigned char *b)) { #if OPCODE_T_SIZE == 4 union { unsigned char buf[8]; opcode_t o[2]; } u; /* wordsize = 8 then */ fetch_buf_be_8(u.buf, (unsigned char *) b); return u.o[1]; /* or u.o[0] */ #else union { unsigned char buf[4]; opcode_t o; } u; /* wordsize = 4 */ u.o = 0; fetch_buf_be_4(u.buf, b); return u.o; #endif }
static opcode_t fetch_op_be_4(NOTNULL(unsigned char *b)) { union { unsigned char buf[4]; opcode_t o; } u; fetch_buf_be_4(u.buf, b); #if PARROT_BIGENDIAN # if OPCODE_T_SIZE == 8 return u.o >> 32; # else return u.o; # endif #else # if OPCODE_T_SIZE == 8 return (opcode_t)(fetch_iv_le((INTVAL)u.o) & 0xffffffff); # else return (opcode_t) fetch_iv_le((INTVAL)u.o); # endif #endif }
static opcode_t fetch_op_be_8(NOTNULL(unsigned char *b)) { union { unsigned char buf[8]; opcode_t o[2]; } u; fetch_buf_be_8(u.buf, b); #if PARROT_BIGENDIAN # if OPCODE_T_SIZE == 8 return u.o[0]; # else return u.o[1]; # endif #else return (opcode_t)fetch_iv_le((INTVAL)u.o[0]); #endif }
static opcode_t fetch_op_le_4(NOTNULL(unsigned char *b)) { union { unsigned char buf[4]; opcode_t o; } u; fetch_buf_le_4(u.buf, b); #if PARROT_BIGENDIAN # if OPCODE_T_SIZE == 8 return u.o >> 32; # else return (opcode_t) fetch_iv_be((INTVAL)u.o); # endif #else # if OPCODE_T_SIZE == 8 return u.o & 0xffffffff; # else return u.o; # endif #endif }
static opcode_t fetch_op_le_8(NOTNULL(unsigned char *b)) { union { unsigned char buf[8]; opcode_t o[2]; } u; fetch_buf_le_8(u.buf, b); #if PARROT_BIGENDIAN # if OPCODE_T_SIZE == 8 return u.o[0]; # else return (opcode_t)fetch_op_be((INTVAL)u.o[1]); # endif #else return u.o[0]; #endif }
/*
FUNCDOC: PF_fetch_opcode
Fetch an opcode_t
from the stream, converting byteorder if needed.
*/
PARROT_WARN_UNUSED_RESULT opcode_t PF_fetch_opcode(NULLOK(PackFile *pf), NOTNULL(opcode_t **stream)) { opcode_t o; if (!pf || !pf->fetch_op) return *(*stream)++; #if TRACE_PACKFILE == 2 PIO_eprintf(NULL, "PF_fetch_opcode: Reordering.\n"); #endif o = (pf->fetch_op)(*((unsigned char **)stream)); *((unsigned char **) (stream)) += pf->header->wordsize; return o; }
/*
FUNCDOC: PF_store_opcode
Store an opcode_t
to stream as is.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL opcode_t* PF_store_opcode(NOTNULL(opcode_t *cursor), opcode_t val) { *cursor++ = val; return cursor; }
/*
FUNCDOC: PF_size_opcode
Return size of an item in opcode_t
units, which is 1 per definitionem.
*/
PARROT_CONST_FUNCTION size_t PF_size_opcode(void) { return 1; }
/*
FUNCDOC: PF_fetch_integer
Fetch an INTVAL
from the stream, converting byteorder if needed.
XXX assumes sizeof (INTVAL) == sizeof (opcode_t)
- we don't have INTVAL
size in the PackFile header.
*/
PARROT_WARN_UNUSED_RESULT INTVAL PF_fetch_integer(NULLOK(PackFile *pf), NOTNULL(opcode_t **stream)) { INTVAL i; if (!pf || pf->fetch_iv == NULL) return *(*stream)++; i = (pf->fetch_iv)(*((unsigned char **)stream)); /* XXX assume sizeof (opcode_t) == sizeof (INTVAL) on the * machine producing this PBC */ *((unsigned char **) (stream)) += pf->header->wordsize; return i; }
/*
FUNCDOC: PF_store_integer
Store an INTVAL
to stream as is.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL opcode_t* PF_store_integer(NOTNULL(opcode_t *cursor), INTVAL val) { *cursor++ = (opcode_t)val; /* XXX */ return cursor; }
/*
FUNCDOC: PF_size_integer
Return store size of INTVAL
in opcode_t
units.
*/
PARROT_CONST_FUNCTION size_t PF_size_integer(void) { const size_t s = sizeof (INTVAL) / sizeof (opcode_t); return s ? s : 1; }
/*
FUNCDOC: PF_fetch_number
Fetch a FLOATVAL
from the stream, converting byteorder if needed. Then advance stream pointer by amount of packfile float size.
*/
PARROT_WARN_UNUSED_RESULT FLOATVAL PF_fetch_number(NULLOK(PackFile *pf), NOTNULL(opcode_t **stream)) { /* When we have alignment all squared away we don't need * to use memcpy() for native byteorder. */ FLOATVAL f; double d; if (!pf || !pf->fetch_nv) { #if TRACE_PACKFILE PIO_eprintf(NULL, "PF_fetch_number: Native [%d bytes]\n", sizeof (FLOATVAL)); #endif memcpy(&f, (char*)*stream, sizeof (FLOATVAL)); (*stream) += (sizeof (FLOATVAL) + sizeof (opcode_t) - 1)/ sizeof (opcode_t); return f; } f = (FLOATVAL) 0; #if TRACE_PACKFILE PIO_eprintf(NULL, "PF_fetch_number: Byteordering..\n"); #endif /* Here is where the size transforms get messy */ if (NUMVAL_SIZE == 8 && pf->header->floattype == 1) { (pf->fetch_nv)((unsigned char *)&f, (unsigned char *) *stream); *((unsigned char **) (stream)) += 12; } else { (pf->fetch_nv)((unsigned char *)&d, (unsigned char *) *stream); *((unsigned char **) (stream)) += 8; f = d; } return f; }
/*
FUNCDOC: PF_store_number
Write a FLOATVAL
to the opcode stream as is.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL opcode_t* PF_store_number(NOTNULL(opcode_t *cursor), NOTNULL(const FLOATVAL *val)) { opcode_t padded_size = (sizeof (FLOATVAL) + sizeof (opcode_t) - 1) / sizeof (opcode_t); mem_sys_memcopy(cursor, val, sizeof (FLOATVAL)); cursor += padded_size; return cursor; }
/*
FUNCDOC: PF_size_number
Return store size of FLOATVAL in opcode_t units.
*/
PARROT_CONST_FUNCTION size_t PF_size_number(void) { return ROUND_UP(sizeof (FLOATVAL), sizeof (opcode_t)); }
/*
FUNCDOC: PF_fetch_string
Fetch a STRING
from bytecode and return a new STRING
.
Opcode format is:
opcode_t flags
opcode_t encoding
opcode_t type
opcode_t size
* data
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL STRING * PF_fetch_string(PARROT_INTERP, NULLOK(PackFile *pf), NOTNULL(opcode_t **cursor)) { UINTVAL flags; opcode_t charset_nr; size_t size; STRING *s; const int wordsize = pf ? pf->header->wordsize : sizeof (opcode_t); const char *charset_name;
flags = PF_fetch_opcode(pf, cursor);
/* don't let PBC mess our internals - only constant or not */
flags &= (PObj_constant_FLAG | PObj_private7_FLAG);
charset_nr = PF_fetch_opcode(pf, cursor);
/* These may need to be separate */
size = (size_t)PF_fetch_opcode(pf, cursor);
/* #define TRACE_PACKFILE 1 */ #if TRACE_PACKFILE PIO_eprintf(NULL, "PF_fetch_string(): flags are 0x%04x...\n", flags); PIO_eprintf(NULL, "PF_fetch_string(): charset_nr is %ld...\n", charset_nr); PIO_eprintf(NULL, "PF_fetch_string(): size is %ld...\n", size); #endif
charset_name = Parrot_charset_c_name(interp, charset_nr);
s = string_make(interp, (char *)*cursor, size, charset_name, flags);
#if TRACE_PACKFILE PIO_eprintf(NULL, "PF_fetch_string(): string is: "); PIO_putps(interp, PIO_STDERR(interp), s); PIO_eprintf(NULL, "\n"); #endif
/* s = string_make(interp, *cursor, size, encoding_lookup_index(encoding), flags); */
size = ROUND_UP_B(size, wordsize);
*((unsigned char **) (cursor)) += size;
return s;
}
/*
FUNCDOC: PF_store_string
Write a STRING to the opcode stream.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL opcode_t* PF_store_string(NOTNULL(opcode_t *cursor), NOTNULL(STRING *s)) { opcode_t padded_size = s->bufused; char *charcursor; size_t i;
/* PIO_eprintf(NULL, "PF_store_string(): size is %ld...\n", s->bufused); */
if (padded_size % sizeof (opcode_t)) {
padded_size += sizeof (opcode_t) - (padded_size % sizeof (opcode_t));
}
*cursor++ = PObj_get_FLAGS(s); /* only constant_FLAG and private7 */
/*
* TODO as soon as we have dynamically loadable charsets
* we have to store the charset name, not the number
*
* TODO encoding
*
* see also PF_fetch_string
*/
*cursor++ = Parrot_charset_number_of_str(NULL, s);
*cursor++ = s->bufused;
/* Switch to char * since rest of string is addressed by
* characters to ensure padding. */
charcursor = (char *)cursor;
if (s->strstart) {
mem_sys_memcopy(charcursor, s->strstart, s->bufused);
charcursor += s->bufused;
if (s->bufused % sizeof (opcode_t)) {
for (i = 0; i < (sizeof (opcode_t) -
(s->bufused % sizeof (opcode_t))); i++) {
*charcursor++ = 0;
}
}
}
PARROT_ASSERT(((long)charcursor & 3) == 0);
cursor = (opcode_t *)charcursor;
return cursor;
}
/*
FUNCDOC: PF_size_string
Report store size of STRING
in opcode_t
units.
*/
PARROT_PURE_FUNCTION size_t PF_size_string(NOTNULL(const STRING *s)) { opcode_t padded_size = s->bufused;
if (padded_size % sizeof (opcode_t)) {
padded_size += sizeof (opcode_t) - (padded_size % sizeof (opcode_t));
}
/* Include space for flags, representation, and size fields. */
return 3 + (size_t)padded_size / sizeof (opcode_t);
}
/*
FUNCDOC: PF_fetch_cstring
Fetch a cstring from bytecode and return an allocated copy
*/
PARROT_MALLOC PARROT_CANNOT_RETURN_NULL char * PF_fetch_cstring(NOTNULL(PackFile *pf), NOTNULL(opcode_t **cursor)) { const size_t str_len = strlen ((char *)(*cursor)) + 1; char * const p = (char *)mem_sys_allocate(str_len);
const int wordsize = pf->header->wordsize;
strcpy(p, (char*) (*cursor));
*((unsigned char **) (cursor)) += ROUND_UP_B(str_len, wordsize);
return p;
}
/*
FUNCDOC: PF_store_cstring
Write a 0-terminated string to the stream.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL opcode_t* PF_store_cstring(NOTNULL(opcode_t *cursor), NOTNULL(const char *s)) { strcpy((char *) cursor, s); return cursor + PF_size_cstring(s); }
/*
FUNCDOC: PF_size_cstring
Return store size of a C-string in opcode_t
units.
*/
PARROT_PURE_FUNCTION size_t PF_size_cstring(NOTNULL(const char *s)) { size_t str_len;
PARROT_ASSERT(s);
str_len = strlen(s);
return ROUND_UP(str_len + 1, sizeof (opcode_t));
}
/*
FUNCDOC: PackFile_assign_transforms
Assign transform functions to vtable.
*/
void PackFile_assign_transforms(NOTNULL(PackFile *pf)) { const int need_endianize = pf->header->byteorder != PARROT_BIGENDIAN; const int need_wordsize = pf->header->wordsize != sizeof (opcode_t);
pf->need_endianize = need_endianize;
pf->need_wordsize = need_wordsize;
#if PARROT_BIGENDIAN
/*
* this Parrot is on a BIG ENDIAN machine
*/
if (need_endianize) {
if (pf->header->wordsize == 4)
pf->fetch_op = fetch_op_le_4;
else
pf->fetch_op = fetch_op_le_8;
if (pf->header->floattype == 0)
pf->fetch_nv = fetch_buf_le_8;
else if (pf->header->floattype == 1)
pf->fetch_nv = cvt_num12_num8_le;
}
else {
if (pf->header->wordsize == 4)
pf->fetch_op = fetch_op_be_4;
else
pf->fetch_op = fetch_op_be_8;
}
#else
/*
* this Parrot is on a LITTLE ENDIAN machine
*/
if (need_endianize) {
if (pf->header->wordsize == 4)
pf->fetch_op = fetch_op_be_4;
else
pf->fetch_op = fetch_op_be_8;
if (pf->header->floattype == 0)
pf->fetch_nv = fetch_buf_be_8;
else if (pf->header->floattype == 1)
pf->fetch_nv = cvt_num12_num8_be;
}
else {
if (pf->header->wordsize == 4)
pf->fetch_op = fetch_op_le_4;
else
pf->fetch_op = fetch_op_le_8;
if (NUMVAL_SIZE == 8 && pf->header->floattype == 1)
pf->fetch_nv = cvt_num12_num8;
else if (NUMVAL_SIZE != 8 && pf->header->floattype == 0)
pf->fetch_nv = fetch_buf_le_8;
}
#endif
pf->fetch_iv = pf->fetch_op;
}
/*
Initial review by leo 2003.11.21
Most routines moved from src/packfile.c.
Renamed PackFile_* to PF_*
<PF_store_<type
()>> - write an opcode_t stream to cursor in natural byte-ordering.
<PF_fetch_<type
()>> - read items and possibly convert the foreign format.
<PF_size_<type
()>> - return the needed size in opcode_t
units.
*/
/* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */
|