fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / imageio.pmc
blob755932c30cfcdcb5cbd7239c76d27d03a77aa634
1 /*
2 Copyright (C) 2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/imageio.pmc - ImageIO PMC
9 =head1 DESCRIPTION
11 Freezes and thaws other PMCs.
13 =head1 FUNCTIONS
15 =over 4
17 =cut
21 #define GROW_TO_16_BYTE_BOUNDARY(size) ((size) + ((size) % 16 ? 16 - (size) % 16 : 0))
23 /* preallocate freeze image for aggregates with this estimation */
24 #define FREEZE_BYTES_PER_ITEM 9
26 /* macros/constants to handle packing/unpacking of PMC IDs and flags
27  * the 2 LSBs are used for flags, all other bits are used for PMC ID
28  */
29 #define PackID_new(id, flags)       (((UINTVAL)(id) * 4) | ((UINTVAL)(flags) & 3))
30 #define PackID_get_PMCID(id)        ((UINTVAL)(id) / 4)
31 #define PackID_set_PMCID(lv, id)    (lv) = PackID_new((id), PackID_get_FLAGS(lv))
32 #define PackID_get_FLAGS(id)        ((UINTVAL)(id) & 3)
33 #define PackID_set_FLAGS(lv, flags) (lv) = PackID_new(PackID_get_PMCID(lv), (flags))
35 enum {
36     enum_PackID_normal     = 0,
37     enum_PackID_seen       = 1,
40 /* HEADERIZER HFILE: none */
41 /* HEADERIZER BEGIN: static */
42 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
44 static void create_buffer(PARROT_INTERP,
45     ARGIN_NULLOK(PMC *pmc),
46     ARGMOD(PMC *info))
47         __attribute__nonnull__(1)
48         __attribute__nonnull__(3)
49         FUNC_MODIFIES(*info);
51 PARROT_INLINE
52 static void ensure_buffer_size(PARROT_INTERP, ARGIN(PMC *io), size_t len)
53         __attribute__nonnull__(1)
54         __attribute__nonnull__(2);
56 PARROT_INLINE
57 PARROT_CANNOT_RETURN_NULL
58 PARROT_WARN_UNUSED_RESULT
59 static opcode_t * GET_VISIT_CURSOR(ARGIN(const PMC *pmc))
60         __attribute__nonnull__(1);
62 PARROT_WARN_UNUSED_RESULT
63 PARROT_CAN_RETURN_NULL
64 PARROT_INLINE
65 static PMC* id_list_get(PARROT_INTERP, ARGIN(const PMC *io), UINTVAL id)
66         __attribute__nonnull__(1)
67         __attribute__nonnull__(2);
69 PARROT_INLINE
70 static void INC_VISIT_CURSOR(ARGMOD(PMC *pmc), UINTVAL inc)
71         __attribute__nonnull__(1)
72         FUNC_MODIFIES(*pmc);
74 PARROT_WARN_UNUSED_RESULT
75 PARROT_INLINE
76 static INTVAL INFO_HAS_DATA(ARGIN(const PMC *io))
77         __attribute__nonnull__(1);
79 PARROT_INLINE
80 static void SET_VISIT_CURSOR(ARGMOD(PMC *pmc), ARGIN(const char *cursor))
81         __attribute__nonnull__(1)
82         __attribute__nonnull__(2)
83         FUNC_MODIFIES(*pmc);
85 #define ASSERT_ARGS_create_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
86        PARROT_ASSERT_ARG(interp) \
87     , PARROT_ASSERT_ARG(info))
88 #define ASSERT_ARGS_ensure_buffer_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
89        PARROT_ASSERT_ARG(interp) \
90     , PARROT_ASSERT_ARG(io))
91 #define ASSERT_ARGS_GET_VISIT_CURSOR __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
92        PARROT_ASSERT_ARG(pmc))
93 #define ASSERT_ARGS_id_list_get __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
94        PARROT_ASSERT_ARG(interp) \
95     , PARROT_ASSERT_ARG(io))
96 #define ASSERT_ARGS_INC_VISIT_CURSOR __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
97        PARROT_ASSERT_ARG(pmc))
98 #define ASSERT_ARGS_INFO_HAS_DATA __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
99        PARROT_ASSERT_ARG(io))
100 #define ASSERT_ARGS_SET_VISIT_CURSOR __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
101        PARROT_ASSERT_ARG(pmc) \
102     , PARROT_ASSERT_ARG(cursor))
103 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
104 /* HEADERIZER END: static */
108 =item C<static opcode_t * GET_VISIT_CURSOR(const PMC *pmc)>
110 =cut
114 PARROT_INLINE
115 PARROT_CANNOT_RETURN_NULL
116 PARROT_WARN_UNUSED_RESULT
117 static opcode_t *
118 GET_VISIT_CURSOR(ARGIN(const PMC *pmc))
120     ASSERT_ARGS(GET_VISIT_CURSOR)
122     char * const buf = (char *)Buffer_bufstart(PARROT_IMAGEIO(pmc)->buffer);
123     const size_t pos = PARROT_IMAGEIO(pmc)->pos;
124     return (opcode_t *)(buf + pos);
129 =item C<static void SET_VISIT_CURSOR(PMC *pmc, const char *cursor)>
131 =cut
136 PARROT_INLINE
137 static void
138 SET_VISIT_CURSOR(ARGMOD(PMC *pmc), ARGIN(const char *cursor))
140     ASSERT_ARGS(SET_VISIT_CURSOR)
142     const char * const bufstart  = (const char *)Buffer_bufstart(PARROT_IMAGEIO(pmc)->buffer);
143     PARROT_IMAGEIO(pmc)->pos = (cursor - bufstart);
148 =item C<static void INC_VISIT_CURSOR(PMC *pmc, UINTVAL inc)>
150 =cut
155 PARROT_INLINE
156 static void
157 INC_VISIT_CURSOR(ARGMOD(PMC *pmc), UINTVAL inc)
159     ASSERT_ARGS(INC_VISIT_CURSOR)
161     PARROT_IMAGEIO(pmc)->pos += inc;
165 #define BYTECODE_SHIFT_OK(pmc) PARROT_ASSERT( \
166     PARROT_IMAGEIO(pmc)->pos <= PARROT_IMAGEIO(pmc)->input_length)
170 =item C<static void create_buffer(PARROT_INTERP, PMC *pmc, PMC *info)>
172 =cut
176 static void
177 create_buffer(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), ARGMOD(PMC *info))
179     ASSERT_ARGS(create_buffer)
181     INTVAL  len;
183     if (!PMC_IS_NULL(pmc)) {
184         STRING * const array = CONST_STRING(interp, "array");
185         STRING * const hash  = CONST_STRING(interp, "hash");
186         INTVAL         items = 1;
188         if (VTABLE_does(interp, pmc, array) || VTABLE_does(interp, pmc, hash))
189             items += VTABLE_elements(interp, pmc);
191         len = items * FREEZE_BYTES_PER_ITEM;
192     }
193     else
194         len = FREEZE_BYTES_PER_ITEM;
196     PARROT_IMAGEIO(info)->buffer =
197         Parrot_gc_new_bufferlike_header(interp, sizeof (Buffer));
198     Parrot_gc_allocate_buffer_storage_aligned(interp,
199         PARROT_IMAGEIO(info)->buffer, len);
200     SET_VISIT_CURSOR(info,
201         (const char *)Buffer_bufstart(PARROT_IMAGEIO(info)->buffer));
206 =item C<static void ensure_buffer_size(PARROT_INTERP, PMC *io, size_t len)>
208 Checks the size of the buffer to see if it can accommodate C<len> more
209 bytes. If not, expands the buffer.
211 =cut
215 PARROT_INLINE
216 static void
217 ensure_buffer_size(PARROT_INTERP, ARGIN(PMC *io), size_t len)
219     ASSERT_ARGS(ensure_buffer_size)
221     Buffer * const buf  = PARROT_IMAGEIO(io)->buffer;
222     const size_t used   = PARROT_IMAGEIO(io)->pos;
223     const int need_free = Buffer_buflen(buf) - used - len;
225     /* grow by factor 1.5 or such */
226     if (need_free <= 16) {
227         size_t new_size = (size_t) (Buffer_buflen(buf) * 1.5);
229         if (new_size < Buffer_buflen(buf) - need_free + 512)
230             new_size = Buffer_buflen(buf) - need_free + 512;
232         Parrot_gc_reallocate_buffer_storage(interp, buf, new_size);
233         PARROT_ASSERT(Buffer_buflen(buf) - used - len >= 15);
234     }
236 #ifndef DISABLE_GC_DEBUG
237     Parrot_gc_compact_memory_pool(interp);
238 #endif
243 =item C<static INTVAL INFO_HAS_DATA(const PMC *io)>
245 =cut
249 PARROT_WARN_UNUSED_RESULT
250 PARROT_INLINE
251 static INTVAL
252 INFO_HAS_DATA(ARGIN(const PMC *io))
254     ASSERT_ARGS(INFO_HAS_DATA)
256     return PARROT_IMAGEIO(io)->pos < PARROT_IMAGEIO(io)->input_length;
261 =item C<static PMC* id_list_get(PARROT_INTERP, const PMC *io, UINTVAL id)>
263 =cut
267 PARROT_WARN_UNUSED_RESULT
268 PARROT_CAN_RETURN_NULL
269 PARROT_INLINE
270 static PMC*
271 id_list_get(PARROT_INTERP, ARGIN(const PMC *io), UINTVAL id)
273     ASSERT_ARGS(id_list_get)
275     return VTABLE_get_pmc_keyed_int(interp, PARROT_IMAGEIO(io)->todo, id - 1);
278 pmclass ImageIO auto_attrs {
279     ATTR Buffer              *buffer;      /* buffer to store the image */
280     ATTR size_t               pos;         /* current read/write buf position */
281     ATTR size_t               input_length;
282     ATTR INTVAL               what;
283     ATTR PMC                 *seen;        /* seen hash */
284     ATTR PMC                 *todo;        /* todo list */
285     ATTR UINTVAL              id;          /* freze ID of PMC */
286     ATTR struct PackFile     *pf;
287     ATTR PackFile_ConstTable *pf_ct;
291 =back
293 =head1 VTABLES
295 =over 4
297 =cut
303 =item C<void init()>
305 Initializes the PMC.
307 =cut
310     VTABLE void init() {
311         PARROT_IMAGEIO(SELF)->seen = PMCNULL;
312         PARROT_IMAGEIO(SELF)->todo =
313             Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray);
315         PObj_flag_CLEAR(private1, SELF);
317         PObj_custom_mark_SET(SELF);
318     }
323 =item C<void destroy()>
325 Destroys the PMC.
327 =cut
330     VTABLE void destroy() {
331         PackFile_destroy(INTERP, PARROT_IMAGEIO(SELF)->pf);
332         PARROT_IMAGEIO(SELF)->pf = NULL;
333     }
338 =item C<void mark()>
340 Marks the PMC as alive.
342 =cut
345     VTABLE void mark() {
346         PObj * const buffer = (PObj *)(PARROT_IMAGEIO(SELF)->buffer);
347         if (buffer)
348             Parrot_gc_mark_PObj_alive(INTERP, buffer);
349         Parrot_gc_mark_PMC_alive(INTERP, PARROT_IMAGEIO(SELF)->todo);
350         Parrot_gc_mark_PMC_alive(INTERP, PARROT_IMAGEIO(SELF)->seen);
351     }
356 =item C<STRING *get_string()>
358 Returns the content of the image as a string.
360 =cut
364     VTABLE STRING *get_string() {
365         return Parrot_str_new_from_buffer(INTERP,
366                                           PARROT_IMAGEIO(SELF)->buffer,
367                                           PARROT_IMAGEIO(SELF)->pos);
368     }
373 =item C<VTABLE PMC *get_pmc()>
375 Gets the result PMC after a thaw.
377 =cut
381     VTABLE PMC *get_pmc() {
382         return VTABLE_get_pmc_keyed_int(INTERP,
383             (PARROT_IMAGEIO(SELF))->todo, 0);
384     }
389 =item C<VTABLE PMC *get_iter()>
391 Get the C<todo> list for this freeze/thaw for iterating over.
393 =cut
397     VTABLE PMC *get_iter() {
398         return PARROT_IMAGEIO(SELF)->todo;
399     }
403 =item C<VTABLE INTVAL get_integer()>
405 Returns the flags describing the visit action.
407 =cut
411     VTABLE INTVAL get_integer() {
412         return PARROT_IMAGEIO(SELF)->what;
413     }
418 =item C<VTABLE void push_integer(INTVAL v)>
420 Pushes the integer C<v> onto the end of the image.
422 =cut
426     VTABLE void push_integer(INTVAL v) {
427         const size_t len = PF_size_integer() * sizeof (opcode_t);
428         ensure_buffer_size(INTERP, SELF, len);
429         SET_VISIT_CURSOR(SELF,
430             (const char *)PF_store_integer(GET_VISIT_CURSOR(SELF), v));
431     }
436 =item C<VTABLE void push_float(FLOATVAL v)>
438 Pushes the float C<v> onto the end of the image.
440 =cut
444     VTABLE void push_float(FLOATVAL v) {
445         const size_t len = PF_size_number() * sizeof (opcode_t);
446         ensure_buffer_size(INTERP, SELF, len);
447         SET_VISIT_CURSOR(SELF,
448             (const char *)PF_store_number(GET_VISIT_CURSOR(SELF), &v));
449     }
454 =item C<VTABLE void push_string(STRING *v)>
456 Pushes the string C<*v> onto the end of the image.
458 =cut
462     VTABLE void push_string(STRING *v) {
463         if (PObj_flag_TEST(private1, SELF)) {
464             /* store a reference to constant table entry of string */
465             PMC                 * const v_pmc = key_new_string(interp, v);
466             PackFile_ConstTable * const table = PARROT_IMAGEIO(SELF)->pf_ct;
467             const int idx =
468                 PackFile_ConstTable_rlookup(INTERP, table, v_pmc, PFC_STRING);
470             if (idx >= 0) {
471                 STATICSELF.push_integer(idx);
472                 return;
473             }
475             /* XXX handle cases where the PMC has changed after
476              * Parrot_freeze_strings was called eg: :immediate subs */
477             STATICSELF.push_integer(-1);
479             /* TODO
480              * should really be:
481              * PANIC(INTERP, "string not previously in constant table "
482              *               "when freezing to packfile"); */
483         }
485         {
486             const size_t len = PF_size_string(v) * sizeof (opcode_t);
487             ensure_buffer_size(INTERP, SELF, len);
488             SET_VISIT_CURSOR(SELF,
489                 (const char *)PF_store_string(GET_VISIT_CURSOR(SELF), v));
490         }
491     }
496 =item C<VTABLE void push_pmc(PMC *v)>
498 Pushes a reference to pmc C<*v> onto the end of the image. If C<*v>
499 hasn't been seen yet, it is also pushed onto the todo list.
501 =cut
505     VTABLE void push_pmc(PMC *v) {
506         UINTVAL id;
507         int packid_type;
509         PARROT_ASSERT(PARROT_IMAGEIO(SELF)->what == VISIT_FREEZE_NORMAL);
511         if (PMC_IS_NULL(v)) {
512             id   = 0;
513             packid_type = enum_PackID_seen;
514         }
515         else {
516             Hash * const hash = (Hash *)VTABLE_get_pointer(INTERP,
517                     PARROT_IMAGEIO(SELF)->seen);
518             HashBucket * const b = parrot_hash_get_bucket(INTERP, hash, v);
520             if (b) {
521                 id = (UINTVAL)b->value;
522                 packid_type = enum_PackID_seen;
523             }
524             else {
525                 ++PARROT_IMAGEIO(SELF)->id; /* next id to freeze */
526                 id = PARROT_IMAGEIO(SELF)->id;
527                 packid_type = enum_PackID_normal;
528             }
529         }
531         SELF.push_integer(PackID_new(id, packid_type));
533         if (packid_type == enum_PackID_normal) {
534             Hash * const hash = (Hash *)VTABLE_get_pointer(INTERP,
535                     PARROT_IMAGEIO(SELF)->seen);
537             PARROT_ASSERT(v);
539             /* workaround to keep ParrotInterpreter PBC hack working */
540             if (v->vtable->base_type == enum_class_ParrotInterpreter)
541                 PObj_flag_CLEAR(private1, SELF);
543             SELF.push_integer(
544                     PObj_is_object_TEST(v)
545                     ? (INTVAL) enum_class_Object
546                     : v->vtable->base_type);
548             parrot_hash_put(INTERP, hash, v, (void *)id);
549             VTABLE_push_pmc(INTERP, PARROT_IMAGEIO(SELF)->todo, v);
550         }
551     }
556 =item C<void set_pointer(void *value)>
558 Sets the constant table of this ImageIO PMC.
560 =cut
564     VTABLE void set_pointer(void *value) {
565         PObj_flag_SET(private1, SELF);
566         PARROT_IMAGEIO(SELF)->pf_ct = (PackFile_ConstTable *)value;
567     }
572 =item C<VTABLE INTVAL shift_integer()>
574 Removes and returns an integer from the start of the image.
576 =cut
580     VTABLE INTVAL shift_integer() {
581         /* inlining PF_fetch_integer speeds up PBC thawing measurably */
582         const PackFile      *pf     = PARROT_IMAGEIO(SELF)->pf;
583         const opcode_t      *pos    = GET_VISIT_CURSOR(SELF);
584         const unsigned char *stream = (const unsigned char *)pos;
585         const INTVAL         i      = pf->fetch_iv(stream);
587         SET_VISIT_CURSOR(SELF, (const char *)pos + pf->header->wordsize);
588         BYTECODE_SHIFT_OK(SELF);
589         return i;
590     }
595 =item C<VTABLE FLOATVAL shift_float()>
597 Removes and returns an number from the start of the image.
599 =cut
603     VTABLE FLOATVAL shift_float() {
604         const opcode_t *pos = GET_VISIT_CURSOR(SELF);
605         FLOATVAL        f   = PF_fetch_number(PARROT_IMAGEIO(SELF)->pf, &pos);
606         SET_VISIT_CURSOR(SELF, (const char *)pos);
607         BYTECODE_SHIFT_OK(SELF);
608         return f;
609     }
614 =item C<VTABLE STRING* shift_string()>
616 Removes and returns a string from the start of the image.
618 =cut
622     VTABLE STRING *shift_string() {
623         if (PObj_flag_TEST(private1, SELF)) {
624             const INTVAL i = STATICSELF.shift_integer();
626             if (i >= 0) {
627                 PackFile_ConstTable *table = PARROT_IMAGEIO(SELF)->pf_ct;
629                 if (!table->constants[i].type)
630                     Parrot_ex_throw_from_c_args(interp, NULL,
631                             EXCEPTION_MALFORMED_PACKFILE,
632                             "Reference to constant not yet unpacked %d", i);
633                 return table->constants[i].u.string;
634             }
636             /* XXX
637              * only got here because constant table doesn't contain the string
638              * fallback on inline strings
639              */
640         }
642         {
643             const opcode_t * pos     = GET_VISIT_CURSOR(SELF);
644             STRING         * const s = PF_fetch_string(INTERP,
645                                     PARROT_IMAGEIO(SELF)->pf, &pos);
646             SET_VISIT_CURSOR(SELF, (const char *)pos);
647             BYTECODE_SHIFT_OK(SELF);
648             return s;
649         }
650     }
655 =item C<static PMC *shift_pmc()>
657 Removes and returns a reference to a pmc from the start of the image.
659 =cut
663     VTABLE PMC *shift_pmc() {
664         const UINTVAL  n            = SELF.shift_integer();
665         const INTVAL   id           = PackID_get_PMCID(n);
666         const int      packid_flags = PackID_get_FLAGS(n);
667         PMC           *pmc          = PMCNULL;
669         PARROT_ASSERT(PARROT_IMAGEIO(SELF)->what == VISIT_THAW_NORMAL);
671         switch (packid_flags) {
672             case enum_PackID_seen:
673                 if (id) /* got a non-NULL PMC */
674                     pmc = id_list_get(INTERP, SELF, id);
675                 break;
676             case enum_PackID_normal:
677                 {
678                     PMC * const  todo = PARROT_IMAGEIO(SELF)->todo;
679                     const INTVAL type = VTABLE_shift_integer(INTERP, SELF);
681                     PARROT_ASSERT(id - 1
682                             == VTABLE_elements(INTERP, PARROT_IMAGEIO(SELF)->todo));
684                     if (type <= 0 || type > INTERP->n_vtable_max)
685                         Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
686                                 "Unknown PMC type to thaw %d", type);
688                     /* workaround to keep ParrotInterpreter PBC hack working */
689                     if (type == enum_class_ParrotInterpreter)
690                         PObj_flag_CLEAR(private1, SELF);
692                     pmc = Parrot_pmc_new_noinit(INTERP, type);
694                     VTABLE_set_pmc_keyed_int(INTERP, todo, id - 1, pmc);
695                 }
696                 break;
697             default:
698                 Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
699                         "Unknown PMC id args thaw %d", packid_flags);
700                 break;
701         }
703         return pmc;
704     }
706     VTABLE void set_pmc(PMC *p)
707     {
708         PARROT_IMAGEIO(SELF)->what  = VISIT_FREEZE_NORMAL;
710         create_buffer(INTERP, p, SELF);
711         if (PObj_flag_TEST(private1, SELF)) {
712             PARROT_IMAGEIO(SELF)->pf = PARROT_IMAGEIO(SELF)->pf_ct->base.pf;
713         }
714         else {
715             const UINTVAL header_length =
716                 GROW_TO_16_BYTE_BOUNDARY(PACKFILE_HEADER_BYTES);
718             PARROT_IMAGEIO(SELF)->pf = PackFile_new(INTERP, 0);
719             PObj_custom_destroy_SET(SELF);
721             ensure_buffer_size(INTERP, SELF, header_length);
722             mem_sys_memcopy(GET_VISIT_CURSOR(SELF),
723                 PARROT_IMAGEIO(SELF)->pf->header, PACKFILE_HEADER_BYTES);
724             INC_VISIT_CURSOR(SELF, header_length);
725         }
727         PARROT_IMAGEIO(SELF)->seen = Parrot_pmc_new(INTERP, enum_class_Hash);
728         VTABLE_set_pointer(INTERP, PARROT_IMAGEIO(SELF)->seen,
729             parrot_new_intval_hash(INTERP));
731         STATICSELF.push_pmc(p);
732         Parrot_visit_loop_visit(INTERP, SELF);
733     }
735     VTABLE void set_string_native(STRING *image) {
736         PMC          *unused;
737         PARROT_IMAGEIO(SELF)->what   = VISIT_THAW_NORMAL;
738         PARROT_IMAGEIO(SELF)->buffer = (Buffer *)image;
740         PARROT_ASSERT(image->_bufstart == image->strstart);
742         SET_VISIT_CURSOR(SELF,
743             (const char *)Buffer_bufstart(PARROT_IMAGEIO(SELF)->buffer));
744         PARROT_IMAGEIO(SELF)->input_length = image->strlen;
746         if (PObj_flag_TEST(private1, SELF)) {
747             PARROT_IMAGEIO(SELF)->pf = PARROT_IMAGEIO(SELF)->pf_ct->base.pf;
748         }
749         else {
750             const UINTVAL header_length =
751                  GROW_TO_16_BYTE_BOUNDARY(PACKFILE_HEADER_BYTES);
752             int unpacked_length;
754             PARROT_IMAGEIO(SELF)->pf   = PackFile_new(INTERP, 0);
755             PObj_custom_destroy_SET(SELF);
757             PARROT_IMAGEIO(SELF)->pf->options |= PFOPT_PMC_FREEZE_ONLY;
758             unpacked_length = PackFile_unpack(INTERP, PARROT_IMAGEIO(SELF)->pf,
759                 GET_VISIT_CURSOR(SELF), PARROT_IMAGEIO(SELF)->input_length);
761             if (unpacked_length)
762                 INC_VISIT_CURSOR(SELF, header_length);
763             else
764                 Parrot_ex_throw_from_c_args(INTERP, NULL,
765                         EXCEPTION_INVALID_STRING_REPRESENTATION,
766                         "PackFile header failed during unpack");
767         }
769         unused = STATICSELF.shift_pmc();
770         Parrot_visit_loop_visit(INTERP, SELF);
772         /* we're done reading the image */
773         PARROT_ASSERT(!INFO_HAS_DATA(SELF));
774         Parrot_visit_loop_thawfinish(INTERP, SELF);
775     }
780 =back
782 =cut
789  * Local variables:
790  *   c-file-style: "parrot"
791  * End:
792  * vim: expandtab shiftwidth=4:
793  */