/*
Copyright (C) 2010-2011, Parrot Foundation.
=head1 NAME
src/pmc/imageiothaw.pmc - ImageIOThaw PMC
=head1 DESCRIPTION
Thaws PMCs from packfile images.
=head1 VTABLES
=over 4
=cut
*/
#include "parrot/imageio.h"
#define BYTECODE_SHIFT_OK(interp, pmc) PARROT_ASSERT( \
PARROT_IMAGEIOTHAW(pmc)->curs <= (opcode_t *) \
(PARROT_IMAGEIOTHAW(pmc)->img->strstart + \
Parrot_str_byte_length((interp), PARROT_IMAGEIOTHAW(pmc)->img)))
/* HEADERIZER HFILE: none */
pmclass ImageIOThaw auto_attrs {
ATTR STRING *img;
ATTR opcode_t *curs;
ATTR PMC *seen;
ATTR PMC *todo;
ATTR PackFile *pf;
ATTR PackFile_ConstTable *pf_ct;
/*
=item C<void init()>
Initializes the PMC.
=cut
*/
VTABLE void init() {
PARROT_IMAGEIOTHAW(SELF)->seen =
Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
PARROT_IMAGEIOTHAW(SELF)->todo =
Parrot_pmc_new(INTERP, enum_class_ResizableIntegerArray);
PObj_flag_CLEAR(private1, SELF);
PObj_custom_mark_SET(SELF);
}
/*
=item C<void destroy()>
Destroys the PMC.
=cut
*/
VTABLE void destroy() {
PackFile_destroy(INTERP, PARROT_IMAGEIOTHAW(SELF)->pf);
PARROT_IMAGEIOTHAW(SELF)->pf = NULL;
}
/*
=item C<void mark()>
Marks the PMC as alive.
=cut
*/
VTABLE void mark() {
Parrot_gc_mark_STRING_alive(INTERP, PARROT_IMAGEIOTHAW(SELF)->img);
Parrot_gc_mark_PMC_alive(INTERP, PARROT_IMAGEIOTHAW(SELF)->seen);
Parrot_gc_mark_PMC_alive(INTERP, PARROT_IMAGEIOTHAW(SELF)->todo);
}
/*
=item C<void set_string_native(STRING *image)>
Thaws the PMC contained in C<image>.
=cut
*/
VTABLE void set_string_native(STRING *image) {
if (!PObj_external_TEST(image))
Parrot_str_pin(INTERP, image);
PARROT_IMAGEIOTHAW(SELF)->img = image;
PARROT_IMAGEIOTHAW(SELF)->curs = (opcode_t *)image->strstart;
if (PObj_flag_TEST(private1, SELF)) {
PARROT_IMAGEIOTHAW(SELF)->pf = PARROT_IMAGEIOTHAW(SELF)->pf_ct->base.pf;
}
else {
const UINTVAL header_length =
GROW_TO_16_BYTE_BOUNDARY(PACKFILE_HEADER_BYTES);
int unpacked_length;
PARROT_IMAGEIOTHAW(SELF)->pf = PackFile_new(INTERP, 0);
PObj_custom_destroy_SET(SELF);
PARROT_IMAGEIOTHAW(SELF)->pf->options |= PFOPT_PMC_FREEZE_ONLY;
unpacked_length = PackFile_unpack(INTERP, PARROT_IMAGEIOTHAW(SELF)->pf,
PARROT_IMAGEIOTHAW(SELF)->curs,
Parrot_str_byte_length(interp, image));
if (unpacked_length)
PARROT_IMAGEIOTHAW(SELF)->curs += header_length / sizeof (opcode_t*);
else
Parrot_ex_throw_from_c_args(INTERP, NULL,
EXCEPTION_INVALID_STRING_REPRESENTATION,
"PackFile header failed during unpack");
}
STATICSELF.shift_pmc();
{
PMC * const seen = PARROT_IMAGEIOTHAW(SELF)->seen;
PMC * const todo = PARROT_IMAGEIOTHAW(SELF)->todo;
INTVAL i, n;
for (i = 0; i < VTABLE_elements(INTERP, todo); i++) {
const INTVAL idx = VTABLE_get_integer_keyed_int(INTERP, todo, i);
PMC * const current = VTABLE_get_pmc_keyed_int(INTERP, seen, idx);
if (PMC_IS_NULL(current))
Parrot_ex_throw_from_c_args(interp, NULL,
EXCEPTION_MALFORMED_PACKFILE,
"NULL current PMC at %d in thaw",
(int)i);
VTABLE_thaw(INTERP, current, SELF);
VTABLE_visit(INTERP, current, SELF);
PMC_metadata(current) = SELF.shift_pmc();
}
n = i;
/* we're done reading the image */
PARROT_ASSERT(image->strstart + Parrot_str_byte_length(interp, image) ==
(char *)PARROT_IMAGEIOTHAW(SELF)->curs);
for (i = 0; i < n; i++) {
const INTVAL idx = VTABLE_get_integer_keyed_int(INTERP, todo, i);
PMC * const current = VTABLE_get_pmc_keyed_int(INTERP, seen, idx);
VTABLE_thawfinish(INTERP, current, SELF);
}
}
if (!PObj_external_TEST(image))
Parrot_str_unpin(INTERP, image);
}
/*
=item C<PMC *get_pmc()>
Get the thawed PMC.
=cut
*/
VTABLE PMC *get_pmc() {
if (PObj_flag_TEST(private1, SELF))
return PARROT_IMAGEIOTHAW(SELF)->seen;
else
return VTABLE_get_pmc_keyed_int(INTERP, (PARROT_IMAGEIOTHAW(SELF))->seen, 0);
}
/*
=item C<INTVAL get_integer()>
Get the visit action.
=cut
*/
VTABLE INTVAL get_integer() {
return VISIT_THAW_NORMAL;
}
/*
=item C<void set_pointer(void *value)>
Set an exterior constant table to use for cross-referencing constants.
=cut
*/
VTABLE void set_pointer(void *value) {
PObj_flag_SET(private1, SELF);
PARROT_IMAGEIOTHAW(SELF)->pf_ct = (PackFile_ConstTable *)value;
}
/*
=item C<INTVAL shift_integer()>
Retrieve an integer as the next item from the image.
=cut
*/
VTABLE INTVAL shift_integer() {
/* inlining PF_fetch_integer speeds up PBC thawing measurably */
PackFile * const pf = PARROT_IMAGEIOTHAW(SELF)->pf;
const unsigned char *stream = (const unsigned char *)PARROT_IMAGEIOTHAW(SELF)->curs;
const INTVAL i = pf->fetch_iv(stream);
DECL_CONST_CAST;
PARROT_IMAGEIOTHAW(SELF)->curs = (opcode_t *)PARROT_const_cast(unsigned char *,
stream + pf->header->wordsize);
BYTECODE_SHIFT_OK(INTERP, SELF);
return i;
}
/*
=item C<FLOATVAL shift_float()>
Retrieve a float as the next item from the image.
=cut
*/
VTABLE FLOATVAL shift_float() {
PackFile * const pf = PARROT_IMAGEIOTHAW(SELF)->pf;
const opcode_t *curs = PARROT_IMAGEIOTHAW(SELF)->curs;
const FLOATVAL f = PF_fetch_number(pf, &curs);
DECL_CONST_CAST;
PARROT_IMAGEIOTHAW(SELF)->curs = PARROT_const_cast(opcode_t *, curs);
BYTECODE_SHIFT_OK(INTERP, SELF);
return f;
}
/*
=item C<STRING *shift_string()>
Retrieve a string as the next item from the image.
=cut
*/
VTABLE STRING *shift_string() {
if (PObj_flag_TEST(private1, SELF)) {
const INTVAL i = STATICSELF.shift_integer();
BYTECODE_SHIFT_OK(INTERP, SELF);
if (i >= 0) {
PackFile_ConstTable *table = PARROT_IMAGEIOTHAW(SELF)->pf_ct;
return table->str.constants[i];
}
/* XXX
* only got here because constant table doesn't contain the string
* fallback on inline strings
*/
}
{
PackFile * const pf = PARROT_IMAGEIOTHAW(SELF)->pf;
const opcode_t *curs = PARROT_IMAGEIOTHAW(SELF)->curs;
STRING *s = PF_fetch_string(INTERP, pf, &curs);
DECL_CONST_CAST;
PARROT_IMAGEIOTHAW(SELF)->curs = PARROT_const_cast(opcode_t *, curs);
BYTECODE_SHIFT_OK(INTERP, SELF);
return s;
}
}
/*
=item C<PMC *shift_pmc()>
Retrieve a PMC as the next item from the image.
=cut
*/
VTABLE PMC *shift_pmc() {
const UINTVAL n = SELF.shift_integer();
const INTVAL id = PackID_get_PMCID(n);
const int packid_flags = PackID_get_FLAGS(n);
PMC *pmc = PMCNULL;
PMC *seen = PARROT_IMAGEIOTHAW(SELF)->seen;
PMC *todo = PARROT_IMAGEIOTHAW(SELF)->todo;
switch (packid_flags) {
case enum_PackID_seen:
if (id) /* got a non-NULL PMC */
pmc = VTABLE_get_pmc_keyed_int(INTERP, seen, id - 1);
break;
case enum_PackID_pbc_backref:
{
PackFile_ConstTable *table = PARROT_IMAGEIOTHAW(SELF)->pf_ct;
INTVAL constno = SELF.shift_integer();
INTVAL idx = SELF.shift_integer();
PMC *olist = table->pmc.constants[constno];
pmc = VTABLE_get_pmc_keyed_int(INTERP, olist, idx);
PARROT_ASSERT(id - 1 == VTABLE_elements(INTERP, seen));
VTABLE_set_pmc_keyed_int(INTERP, seen, id - 1, pmc);
break;
}
case enum_PackID_normal:
{
const INTVAL type = SELF.shift_integer();
PARROT_ASSERT(id - 1 == VTABLE_elements(INTERP, seen));
if (type <= 0 || type > INTERP->n_vtable_max)
Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
"Unknown PMC type to thaw %d", type);
pmc = Parrot_pmc_new_noinit(INTERP, type);
VTABLE_set_pmc_keyed_int(INTERP, seen, id - 1, pmc);
VTABLE_push_integer(INTERP, todo, id - 1);
}
break;
default:
Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
"Unknown PMC id args thaw %d", packid_flags);
break;
}
return pmc;
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/