[svn:parrot] r43434 - in trunk: . compilers/pirc/src config/auto/sizes docs/book/draft docs/book/pct docs/dev docs/pdds examples/embed examples/languages/abc examples/languages/squaak examples/pge include/parrot lib/Parrot/Configure/Step ports/cpan ports/cygwin ports/debian ports/fedora ports/mandriva ports/suse runtime/parrot/languages runtime/parrot/library/Math runtime/parrot/library/Math/Random src src/call src/gc src/interp src/pmc src/runcore src/string t/compilers/tge t/library t/oo t/pmc t/src t/steps/init/hints tools/dev tools/util

plobsing at svn.parrot.org plobsing at svn.parrot.org
Wed Jan 13 01:39:01 UTC 2010


Author: plobsing
Date: Wed Jan 13 01:38:58 2010
New Revision: 43434
URL: https://trac.parrot.org/parrot/changeset/43434

Log:
merge branch pmc_freeze_cleanup

Modified:
   trunk/   (props changed)
   trunk/PBC_COMPAT
   trunk/compilers/pirc/src/bcgen.h
   trunk/config/auto/sizes/intval_maxmin_c.in   (props changed)
   trunk/docs/book/draft/README   (props changed)
   trunk/docs/book/draft/appa_glossary.pod   (props changed)
   trunk/docs/book/draft/appb_patch_submission.pod   (props changed)
   trunk/docs/book/draft/appc_command_line_options.pod   (props changed)
   trunk/docs/book/draft/appd_build_options.pod   (props changed)
   trunk/docs/book/draft/appe_source_code.pod   (props changed)
   trunk/docs/book/draft/ch01_introduction.pod   (props changed)
   trunk/docs/book/draft/ch02_getting_started.pod   (props changed)
   trunk/docs/book/draft/ch07_dynpmcs.pod   (props changed)
   trunk/docs/book/draft/ch08_dynops.pod   (props changed)
   trunk/docs/book/draft/ch10_opcode_reference.pod   (props changed)
   trunk/docs/book/draft/ch11_directive_reference.pod   (props changed)
   trunk/docs/book/draft/ch12_operator_reference.pod   (props changed)
   trunk/docs/book/draft/chXX_hlls.pod   (props changed)
   trunk/docs/book/draft/chXX_library.pod   (props changed)
   trunk/docs/book/draft/chXX_testing_and_debugging.pod   (props changed)
   trunk/docs/book/pct/ch01_introduction.pod   (props changed)
   trunk/docs/book/pct/ch02_getting_started.pod   (props changed)
   trunk/docs/book/pct/ch03_compiler_tools.pod   (props changed)
   trunk/docs/book/pct/ch04_pge.pod   (props changed)
   trunk/docs/book/pct/ch05_nqp.pod   (props changed)
   trunk/docs/dev/c_functions.pod   (props changed)
   trunk/docs/pdds/pdd30_install.pod   (props changed)
   trunk/examples/embed/cotorra.c   (props changed)
   trunk/examples/languages/abc/   (props changed)
   trunk/examples/languages/squaak/   (props changed)
   trunk/examples/pge/demo.pir   (props changed)
   trunk/include/parrot/call.h   (props changed)
   trunk/include/parrot/gc_api.h   (props changed)
   trunk/include/parrot/list.h
   trunk/include/parrot/packfile.h
   trunk/include/parrot/parrot.h
   trunk/include/parrot/pmc_freeze.h
   trunk/include/parrot/runcore_api.h   (props changed)
   trunk/include/parrot/runcore_profiling.h   (props changed)
   trunk/include/parrot/runcore_trace.h   (props changed)
   trunk/include/parrot/string_funcs.h
   trunk/lib/Parrot/Configure/Step/Test.pm   (props changed)
   trunk/ports/cpan/pause_guide.pod   (props changed)
   trunk/ports/cygwin/parrot-1.0.0-1.cygport   (props changed)
   trunk/ports/debian/libparrot-dev.install.in   (props changed)
   trunk/ports/debian/libparrot.install.in   (props changed)
   trunk/ports/debian/parrot-doc.install.in   (props changed)
   trunk/ports/debian/parrot.install.in   (props changed)
   trunk/ports/fedora/parrot.spec.fedora   (props changed)
   trunk/ports/mandriva/parrot.spec.mandriva   (props changed)
   trunk/ports/suse/parrot.spec.suse   (props changed)
   trunk/runtime/parrot/languages/   (props changed)
   trunk/runtime/parrot/library/Math/Rand.pir   (props changed)
   trunk/runtime/parrot/library/Math/Random/mt19937ar.pir   (props changed)
   trunk/src/call/ops.c   (props changed)
   trunk/src/call/pcc.c   (props changed)
   trunk/src/frame_builder.h
   trunk/src/gc/alloc_memory.c   (props changed)
   trunk/src/gc/alloc_resources.c   (props changed)
   trunk/src/gc/api.c   (props changed)
   trunk/src/gc/malloc.c   (props changed)
   trunk/src/gc/malloc_trace.c   (props changed)
   trunk/src/gc/mark_sweep.c   (props changed)
   trunk/src/gc/system.c   (props changed)
   trunk/src/hash.c
   trunk/src/interp/inter_cb.c   (props changed)
   trunk/src/interp/inter_create.c   (props changed)
   trunk/src/interp/inter_misc.c   (props changed)
   trunk/src/list.c
   trunk/src/packfile.c
   trunk/src/pmc/array.pmc
   trunk/src/pmc/class.pmc
   trunk/src/pmc/default.pmc
   trunk/src/pmc/eval.pmc
   trunk/src/pmc/fixedbooleanarray.pmc
   trunk/src/pmc/fixedintegerarray.pmc
   trunk/src/pmc/fixedpmcarray.pmc
   trunk/src/pmc/fixedstringarray.pmc
   trunk/src/pmc/float.pmc
   trunk/src/pmc/hash.pmc
   trunk/src/pmc/integer.pmc
   trunk/src/pmc/key.pmc
   trunk/src/pmc/lexinfo.pmc
   trunk/src/pmc/object.pmc
   trunk/src/pmc/orderedhash.pmc
   trunk/src/pmc/parrotinterpreter.pmc
   trunk/src/pmc/resizablebooleanarray.pmc
   trunk/src/pmc/resizableintegerarray.pmc
   trunk/src/pmc/scheduler.pmc
   trunk/src/pmc/schedulermessage.pmc
   trunk/src/pmc/string.pmc
   trunk/src/pmc/sub.pmc
   trunk/src/pmc/task.pmc
   trunk/src/pmc_freeze.c
   trunk/src/runcore/cores.c   (props changed)
   trunk/src/runcore/main.c   (props changed)
   trunk/src/runcore/profiling.c   (props changed)
   trunk/src/runcore/trace.c   (props changed)
   trunk/src/string/api.c
   trunk/t/compilers/tge/NoneGrammar.tg   (props changed)
   trunk/t/library/mt19937ar.t   (props changed)
   trunk/t/library/mt19937ar.txt   (props changed)
   trunk/t/oo/root_new.t   (props changed)
   trunk/t/pmc/eval.t
   trunk/t/pmc/namespace-old.t   (props changed)
   trunk/t/src/embed.t   (props changed)
   trunk/t/steps/init/hints/linux-01.t   (props changed)
   trunk/tools/dev/fetch_languages.pl   (props changed)
   trunk/tools/dev/mk_gitignore.pl   (props changed)
   trunk/tools/util/perlcritic-cage.conf   (props changed)

Modified: trunk/PBC_COMPAT
==============================================================================
--- trunk/PBC_COMPAT	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/PBC_COMPAT	Wed Jan 13 01:38:58 2010	(r43434)
@@ -28,6 +28,7 @@
 # please insert tab separated entries at the top of the list
 
 5.6	2009.12.12	bacek	merge CallSignature and Context
+5.5	2010.01.01	plobsing	change prophash handling
 5.4	2009.12.02	bacek	remove CallSignatureReturns
 5.3	2009.10.23	bacek	add CallSignatureReturns
 5.2	2009.09.16	darbelo	remove pic.ops

Modified: trunk/compilers/pirc/src/bcgen.h
==============================================================================
--- trunk/compilers/pirc/src/bcgen.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/compilers/pirc/src/bcgen.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -162,6 +162,10 @@
 emit_opcode(ARGIN(bytecode * const bc), opcode_t op)
         __attribute__nonnull__(1);
 
+int emit_pbc_key(ARGIN(bytecode * const bc), ARGIN(key * const k))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
 FLOATVAL get_num_const(ARGIN(bytecode * const bc), unsigned index)
         __attribute__nonnull__(1);
 

Modified: trunk/include/parrot/list.h
==============================================================================
--- trunk/include/parrot/list.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/include/parrot/list.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -220,11 +220,11 @@
 PARROT_EXPORT
 void Parrot_pmc_array_visit(PARROT_INTERP,
     ARGIN(List *list),
-    ARGMOD(void *pinfo))
+    ARGMOD(visit_info *info))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(3)
-        FUNC_MODIFIES(*pinfo);
+        FUNC_MODIFIES(*info);
 
 PARROT_WARN_UNUSED_RESULT
 PARROT_PURE_FUNCTION
@@ -284,7 +284,7 @@
 #define ASSERT_ARGS_Parrot_pmc_array_visit __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(list) \
-    , PARROT_ASSERT_ARG(pinfo))
+    , PARROT_ASSERT_ARG(info))
 #define ASSERT_ARGS_Parrot_pmc_array_length __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(list))
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */

Modified: trunk/include/parrot/packfile.h
==============================================================================
--- trunk/include/parrot/packfile.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/include/parrot/packfile.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -67,6 +67,7 @@
 #  define PFOPT_ALIGN 8
 #  define PFOPT_VALUE 16
 #endif
+#define PFOPT_PMC_FREEZE_ONLY 32
 
 #if TRACE_PACKFILE
 /* Here we pass multipe args to a macro so the args may not be bracketed here! */

Modified: trunk/include/parrot/parrot.h
==============================================================================
--- trunk/include/parrot/parrot.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/include/parrot/parrot.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -259,8 +259,8 @@
 #include "parrot/string.h"
 #include "parrot/string_primitives.h"
 #include "parrot/hash.h"
-#include "parrot/list.h"
 #include "parrot/pmc_freeze.h"
+#include "parrot/list.h"
 #include "parrot/vtable.h"
 #include "parrot/context.h"
 #include "parrot/exceptions.h"

Modified: trunk/include/parrot/pmc_freeze.h
==============================================================================
--- trunk/include/parrot/pmc_freeze.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/include/parrot/pmc_freeze.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -11,69 +11,137 @@
  */
 
 #ifndef PARROT_PMC_FREEZE_H_GUARD
-#define      PARROT_PMC_FREEZE_H_GUARD
+#define PARROT_PMC_FREEZE_H_GUARD
 
 struct _visit_info;
 typedef void (*visit_f)(PARROT_INTERP, ARGIN_NULLOK(PMC*), ARGIN(struct _visit_info*));
 
 typedef enum {
-    VISIT_FREEZE_NORMAL,
-    VISIT_FREEZE_AT_DESTRUCT,
-    VISIT_FREEZE_SIZE,
-    VISIT_THAW_NORMAL,
-    VISIT_THAW_CONSTANTS,
-    VISIT_CLONE,
-    VISIT_DESTRUCTION_ORDER
-} visit_enum_type;
-
-struct _image_io;
-#define IMAGE_IO struct _image_io
-typedef void (*push_integer_f)       (PARROT_INTERP, IMAGE_IO*, INTVAL);
-typedef void (*push_string_f)        (PARROT_INTERP, IMAGE_IO*, STRING*);
-typedef void (*push_number_f)        (PARROT_INTERP, IMAGE_IO*, FLOATVAL);
-typedef INTVAL (*shift_integer_f)    (PARROT_INTERP, IMAGE_IO*);
-typedef STRING* (*shift_string_f)    (PARROT_INTERP, IMAGE_IO*);
-typedef FLOATVAL (*shift_number_f)   (PARROT_INTERP, IMAGE_IO*);
+    VISIT_HOW_PMC_TO_VISITOR     = 0x00, /* push to visitor */
+    VISIT_HOW_VISITOR_TO_PMC     = 0x01, /* shift from visitor */
+    VISIT_HOW_PMC_TO_PMC         = 0x02, /* push to visitor; then shift from visitor */
+    VISIT_HOW_VISITOR_TO_VISITOR = 0x03, /* shift from visitor; then push to visitor */
+} visit_how_enum_t;
+
+#define VISIT_HOW_MASK 0x03
+
+typedef enum {
+    VISIT_WHAT_PMC      = 0x04,
+    VISIT_WHAT_STRING   = 0x08,
+    VISIT_WHAT_FLOATVAL = 0x10,
+    VISIT_WHAT_INTVAL   = 0x20,
+} visit_what_enum_t;
+
+#define VISIT_WHAT_MASK 0x3c
+
+/* backwards-compat defns */
+#define visit_enum_type      INTVAL
+#define VISIT_FREEZE_NORMAL  (VISIT_HOW_PMC_TO_VISITOR | VISIT_WHAT_PMC)
+#define VISIT_THAW_NORMAL    (VISIT_HOW_VISITOR_TO_PMC | VISIT_WHAT_PMC)
+#define VISIT_THAW_CONSTANTS VISIT_THAW_NORMAL
+
+struct _visit_info;
+typedef INTVAL   (*get_integer_f)   (PARROT_INTERP, struct _visit_info*);
+typedef void     (*push_integer_f)  (PARROT_INTERP, struct _visit_info*, INTVAL);
+typedef void     (*push_string_f)   (PARROT_INTERP, struct _visit_info*, STRING*);
+typedef void     (*push_number_f)   (PARROT_INTERP, struct _visit_info*, FLOATVAL);
+typedef void     (*push_pmc_f)      (PARROT_INTERP, struct _visit_info*, PMC*);
+typedef INTVAL   (*shift_integer_f) (PARROT_INTERP, struct _visit_info*);
+typedef STRING*  (*shift_string_f)  (PARROT_INTERP, struct _visit_info*);
+typedef FLOATVAL (*shift_number_f)  (PARROT_INTERP, struct _visit_info*);
+typedef PMC*     (*shift_pmc_f)     (PARROT_INTERP, struct _visit_info*);
 
 typedef struct _image_funcs {
+    get_integer_f       get_integer;
     push_integer_f      push_integer;
     push_string_f       push_string;
     push_number_f       push_float;
+    push_pmc_f          push_pmc;
     shift_integer_f     shift_integer;
     shift_string_f      shift_string;
     shift_number_f      shift_float;
+    shift_pmc_f         shift_pmc;
 } image_funcs;
 
-typedef struct _image_io {
-    STRING *image;
-    struct PackFile *pf;
-    const image_funcs *vtable;
-} image_io;
-
 typedef enum {
     EXTRA_IS_NULL,
-    EXTRA_IS_UNUSED,
     EXTRA_IS_PROP_HASH,
-    EXTRA_CLASS_EXISTS
 } extra_flags_enum;
 
 typedef struct _visit_info {
     visit_f             visit_pmc_now;
-    visit_f             visit_action;   /* freeze, thaw ... */
+    size_t              pos;            /* current read/write position in buffer */
+    Buffer             *buffer;
+    size_t              input_length;   /* */
     INTVAL              what;
-    STRING             *image;
     PMC               **thaw_ptr;       /* where to thaw a new PMC */
-    INTVAL              last_type;
     PMC                *seen;           /* seen hash */
     PMC                *todo;           /* todo list */
     PMC                *id_list;        /* seen list used by thaw */
     UINTVAL             id;             /* freze ID of PMC */
-    void               *extra;          /* PMC specific */
     INTVAL              extra_flags;    /* concerning to extra */
-    PMC                *thaw_result;    /* 1st thawed */
-    IMAGE_IO           *image_io;
+    struct PackFile    *pf;
+    const image_funcs  *vtable;
+    struct _visit_info *image_io;       /* dummy backwards-compat pointer. */
 } visit_info;
 
+#define IMAGE_IO visit_info
+
+#define VISIT_PMC(interp, visit, pmc) do {\
+    const INTVAL _visit_pmc_flags = VTABLE_get_integer((interp), (visit)); \
+    if (_visit_pmc_flags & VISIT_WHAT_PMC) { \
+        switch (_visit_pmc_flags & VISIT_HOW_MASK) { \
+          case VISIT_HOW_PMC_TO_VISITOR: \
+            VTABLE_push_pmc((interp), (visit), (pmc)); \
+            break; \
+          case VISIT_HOW_VISITOR_TO_PMC: \
+            (pmc) = VTABLE_shift_pmc((interp), (visit)); \
+            break; \
+          case VISIT_HOW_PMC_TO_PMC: \
+            VTABLE_push_pmc((interp), (visit), (pmc)); \
+            (pmc) = VTABLE_shift_pmc((interp), (visit)); \
+            break; \
+          case VISIT_HOW_VISITOR_TO_VISITOR: \
+            (pmc) = VTABLE_shift_pmc((interp), (visit)); \
+            VTABLE_push_pmc((interp), (visit), (pmc)); \
+            break; \
+          default: \
+            do_panic((interp), "Bad VISIT_HOW in VISIT_PMC", __FILE__, __LINE__); \
+        } \
+    } \
+} while (0)
+
+#define VISIT_PMC_ATTR(interp, visit, self, pmclass, attr_name) do {\
+    const INTVAL _visit_pmc_attr_flags = VTABLE_get_integer((interp), (visit)); \
+    if (_visit_pmc_attr_flags & VISIT_WHAT_PMC) { \
+        PMC *_visit_pmc_attr; \
+        switch (_visit_pmc_attr_flags & VISIT_HOW_MASK) { \
+          case VISIT_HOW_PMC_TO_VISITOR: \
+            GETATTR_ ## pmclass ## _ ## attr_name((interp), (self), _visit_pmc_attr); \
+            VTABLE_push_pmc((interp), (visit), _visit_pmc_attr); \
+            break; \
+          case VISIT_HOW_VISITOR_TO_PMC: \
+            _visit_pmc_attr = VTABLE_shift_pmc((interp), (visit)); \
+            SETATTR_ ## pmclass ## _ ## attr_name((interp), (self), _visit_pmc_attr); \
+            break; \
+          case VISIT_HOW_PMC_TO_PMC: \
+            GETATTR_ ## pmclass ## _ ## attr_name((interp), (self), _visit_pmc_attr); \
+            VTABLE_push_pmc((interp), (visit), _visit_pmc_attr); \
+            _visit_pmc_attr = VTABLE_shift_pmc((interp), (visit)); \
+            SETATTR_ ## pmclass ## _ ## attr_name((interp), (self), _visit_pmc_attr); \
+            break; \
+          case VISIT_HOW_VISITOR_TO_VISITOR: \
+            _visit_pmc_attr = VTABLE_shift_pmc((interp), (visit)); \
+            SETATTR_ ## pmclass ## _ ## attr_name((interp), (self), _visit_pmc_attr); \
+            GETATTR_ ## pmclass ## _ ## attr_name((interp), (self), _visit_pmc_attr); \
+            VTABLE_push_pmc((interp), (visit), _visit_pmc_attr); \
+            break; \
+          default: \
+            do_panic((interp), "Bad VISIT_HOW in VISIT_PMC_ATTR", __FILE__, __LINE__); \
+        } \
+    } \
+} while (0)
+
 /*
  * public interfaces
  */

Modified: trunk/include/parrot/string_funcs.h
==============================================================================
--- trunk/include/parrot/string_funcs.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/include/parrot/string_funcs.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -291,6 +291,17 @@
 
 PARROT_EXPORT
 PARROT_WARN_UNUSED_RESULT
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+STRING * Parrot_str_new_from_buffer(PARROT_INTERP,
+    ARGMOD(Buffer *buffer),
+    const UINTVAL len)
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*buffer);
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
 PARROT_CANNOT_RETURN_NULL
 STRING * Parrot_str_new_init(PARROT_INTERP,
     ARGIN_NULLOK(const char *buffer),
@@ -629,6 +640,9 @@
 #define ASSERT_ARGS_Parrot_str_new_COW __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(s))
+#define ASSERT_ARGS_Parrot_str_new_from_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(buffer))
 #define ASSERT_ARGS_Parrot_str_new_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(encoding) \

Modified: trunk/src/frame_builder.h
==============================================================================
--- trunk/src/frame_builder.h	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/frame_builder.h	Wed Jan 13 01:38:58 2010	(r43434)
@@ -647,19 +647,19 @@
 #else /* NUMVAL_SIZE */
 
 #  define jit_emit_fload_m_n(interp, pc, address) \
-      emitm_fldt((pc), emit_None, emit_None, emit_None, (address))
+      emitm_fldt((interp), (pc), emit_None, emit_None, emit_None, (address))
 
 #  define jit_emit_fload_mb_n(interp, pc, base, offs) \
-      emitm_fldt((pc), (base), emit_None, 1, (offs))
+      emitm_fldt((interp), (pc), (base), emit_None, 1, (offs))
 
 #  define jit_emit_fstore_m_n(pc, address) \
-      emitm_fstpt((pc), emit_None, emit_None, emit_None, (address))
+      emitm_fstpt((interp), (pc), emit_None, emit_None, emit_None, (address))
 
 #  define jit_emit_fstore_mb_n(interp, pc, base, offs) \
-      emitm_fstpt((pc), (base), emit_None, 1, (offs))
+      emitm_fstpt((interp), (pc), (base), emit_None, 1, (offs))
 
 #  define jit_emit_fst_mb_n(interp, pc, base, offs) \
-      emitm_fstt((pc), (base), emit_None, 1, (offs))
+      emitm_fstt((interp), (pc), (base), emit_None, 1, (offs))
 
 #endif /* NUMVAL_SIZE */
 

Modified: trunk/src/hash.c
==============================================================================
--- trunk/src/hash.c	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/hash.c	Wed Jan 13 01:38:58 2010	(r43434)
@@ -555,7 +555,6 @@
 hash_thaw(PARROT_INTERP, ARGMOD(Hash *hash), ARGMOD(visit_info *info))
 {
     ASSERT_ARGS(hash_thaw)
-    IMAGE_IO * const io         = info->image_io;
 
     /* during thaw, info->extra is the key/value count */
     const size_t     num_entries = (size_t) hash->entries;
@@ -569,13 +568,13 @@
         switch (hash->key_type) {
           case Hash_key_type_STRING:
             {
-                STRING * const s_key = VTABLE_shift_string(interp, io);
+                STRING * const s_key = VTABLE_shift_string(interp, info);
                 b = parrot_hash_put(interp, hash, s_key, NULL);
             }
             break;
           case Hash_key_type_int:
             {
-                const INTVAL i_key = VTABLE_shift_integer(interp, io);
+                const INTVAL i_key = VTABLE_shift_integer(interp, info);
                 b = parrot_hash_put(interp, hash, (void*)i_key, NULL);
             }
             break;
@@ -588,15 +587,13 @@
         switch (hash->entry_type) {
           case enum_hash_pmc:
             {
-                /* this looks awful, but it avoids type-punning warnings */
-                void **ptr     = &b->value;
-                info->thaw_ptr = (PMC **)ptr;
-                (info->visit_pmc_now)(interp, NULL, info);
+                PMC *p   = VTABLE_shift_pmc(interp, info);
+                b->value = (void *)p;
                 break;
             }
           case enum_hash_int:
             {
-                const INTVAL i = VTABLE_shift_integer(interp, io);
+                const INTVAL i = VTABLE_shift_integer(interp, info);
                 b->value       = (void *)i;
                 break;
             }
@@ -629,7 +626,6 @@
 hash_freeze(PARROT_INTERP, ARGIN(const Hash * const hash), ARGMOD(visit_info *info))
 {
     ASSERT_ARGS(hash_freeze)
-    IMAGE_IO * const io = info->image_io;
     size_t           i;
 
     for (i = 0; i < hash->entries; i++) {
@@ -637,10 +633,10 @@
 
         switch (hash->key_type) {
           case Hash_key_type_STRING:
-            VTABLE_push_string(interp, io, (STRING *)b->key);
+            VTABLE_push_string(interp, info, (STRING *)b->key);
             break;
           case Hash_key_type_int:
-            VTABLE_push_integer(interp, io, (INTVAL)b->key);
+            VTABLE_push_integer(interp, info, (INTVAL)b->key);
             break;
           default:
             Parrot_ex_throw_from_c_args(interp, NULL, 1,
@@ -650,10 +646,10 @@
 
         switch (hash->entry_type) {
           case enum_hash_pmc:
-            (info->visit_pmc_now)(interp, (PMC *)b->value, info);
+            VTABLE_push_pmc(interp, info, (PMC *)b->value);
             break;
           case enum_hash_int:
-            VTABLE_push_integer(interp, io, (INTVAL)b->value);
+            VTABLE_push_integer(interp, info, (INTVAL)b->value);
             break;
           default:
             Parrot_ex_throw_from_c_args(interp, NULL, 1,
@@ -683,13 +679,11 @@
     ASSERT_ARGS(parrot_hash_visit)
     visit_info* const info = (visit_info*) pinfo;
 
-    switch (info->what) {
+    switch (VTABLE_get_integer(interp, info)) {
       case VISIT_THAW_NORMAL:
-      case VISIT_THAW_CONSTANTS:
         hash_thaw(interp, hash, info);
         break;
       case VISIT_FREEZE_NORMAL:
-      case VISIT_FREEZE_AT_DESTRUCT:
         hash_freeze(interp, hash, info);
         break;
       default:

Modified: trunk/src/list.c
==============================================================================
--- trunk/src/list.c	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/list.c	Wed Jan 13 01:38:58 2010	(r43434)
@@ -1635,7 +1635,8 @@
 
 /*
 
-=item C<void Parrot_pmc_array_visit(PARROT_INTERP, List *list, void *pinfo)>
+=item C<void Parrot_pmc_array_visit(PARROT_INTERP, List *list, visit_info
+*info)>
 
 This is used by freeze/thaw to visit the contents of the list.
 
@@ -1647,11 +1648,10 @@
 
 PARROT_EXPORT
 void
-Parrot_pmc_array_visit(PARROT_INTERP, ARGIN(List *list), ARGMOD(void *pinfo))
+Parrot_pmc_array_visit(PARROT_INTERP, ARGIN(List *list), ARGMOD(visit_info *info))
 {
     ASSERT_ARGS(Parrot_pmc_array_visit)
     List_chunk        *chunk;
-    visit_info * const info = (visit_info*) pinfo;
     UINTVAL            idx;
 
     const UINTVAL n = Parrot_pmc_array_length(interp, list);
@@ -1662,9 +1662,7 @@
         if (!(chunk->flags & sparse)) {
             UINTVAL i;
             for (i = 0; i < chunk->items && idx < n; i++, idx++) {
-                PMC ** const pos = ((PMC **) Buffer_bufstart(&chunk->data)) + i;
-                info->thaw_ptr   = pos;
-                (info->visit_pmc_now)(interp, *pos, info);
+                VISIT_PMC(interp, info, ((PMC **)Buffer_bufstart(&chunk->data))[i]);
             }
         }
         /*

Modified: trunk/src/packfile.c
==============================================================================
--- trunk/src/packfile.c	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/packfile.c	Wed Jan 13 01:38:58 2010	(r43434)
@@ -981,6 +981,13 @@
     PackFile        * const pf  = self;
 #endif
 
+    if (packed_size < PACKFILE_HEADER_BYTES) {
+        Parrot_io_eprintf(NULL, "PackFile_unpack: "
+            "Buffer length %d is shorter than PACKFILE_HEADER_BYTES %d\n",
+            packed_size, PACKFILE_HEADER_BYTES);
+        return 0;
+    }
+
     self->src  = packed;
     self->size = packed_size;
 
@@ -1045,13 +1052,21 @@
         /* No UUID; fine, nothing more to do. */
     }
     else if (header->uuid_type == 1) {
+        if (packed_size < PACKFILE_HEADER_BYTES + header->uuid_size) {
+            Parrot_io_eprintf(NULL, "PackFile_unpack: "
+                    "Buffer length %d is shorter than PACKFILE_HEADER_BYTES + uuid_size %d\n",
+                    packed_size, PACKFILE_HEADER_BYTES + header->uuid_size);
+            return 0;
+        }
+
+
         /* Read in the UUID. We'll put it in a NULL-terminated string, just in
          * case people use it that way. */
         header->uuid_data = (unsigned char *)
             mem_sys_allocate(header->uuid_size + 1);
 
         memcpy(header->uuid_data, packed + PACKFILE_HEADER_BYTES,
-            header->uuid_size);
+                header->uuid_size);
 
         /* NULL terminate */
         header->uuid_data[header->uuid_size] = '\0';
@@ -1072,6 +1087,9 @@
     /* Set what transforms we need to do when reading the rest of the file. */
     PackFile_assign_transforms(self);
 
+    if (self->options & PFOPT_PMC_FREEZE_ONLY)
+        return cursor - packed;
+
     /* Directory format. */
     header->dir_format = PF_fetch_opcode(self, &cursor);
 

Modified: trunk/src/pmc/array.pmc
==============================================================================
--- trunk/src/pmc/array.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/array.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -1184,9 +1184,8 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        VTABLE_push_integer(INTERP, io, VTABLE_elements(INTERP, SELF));
+        VTABLE_push_integer(INTERP, info, VTABLE_elements(INTERP, SELF));
     }
 
 /*
@@ -1200,13 +1199,9 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
         SUPER(info);
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            SELF.set_integer_native(VTABLE_shift_integer(INTERP, io));
+        SELF.set_integer_native(VTABLE_shift_integer(INTERP, info));
     }
-}
 
 /*
 

Modified: trunk/src/pmc/class.pmc
==============================================================================
--- trunk/src/pmc/class.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/class.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -1432,38 +1432,23 @@
 */
 
     VTABLE void visit(visit_info *info) {
-        Parrot_Class_attributes * const class_data = PARROT_CLASS(SELF);
-        PMC **pos;
-
         /* 1) visit the attribute description hash */
-        pos            = &class_data->attrib_metadata;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Class, attrib_metadata);
 
         /* 2) visit list of parents */
-        pos            = &class_data->parents;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Class, parents);
 
         /* 3) visit list of roles */
-        pos            = &class_data->roles;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Class, roles);
 
         /* 4) visit hash of methods */
-        pos            = &class_data->methods;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Class, methods);
 
         /* 5) visit hash of vtable overrides */
-        pos            = &class_data->vtable_overrides;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Class, vtable_overrides);
 
         /* 6) visit list of resolve methods */
-        pos            = &class_data->resolve_method;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Class, resolve_method);
     }
 
 /*
@@ -1477,15 +1462,14 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO     * const io         = info->image_io;
         Parrot_Class_attributes * const class_data = PARROT_CLASS(SELF);
         STRING       *serial_namespace = CONST_STRING(interp, "");
 
         /* 1) freeze class id */
-        VTABLE_push_integer(INTERP, io, class_data->id);
+        VTABLE_push_integer(INTERP, info, class_data->id);
 
         /* 2) freeze class name */
-        VTABLE_push_string(INTERP, io, class_data->name);
+        VTABLE_push_string(INTERP, info, class_data->name);
 
         /* 3) serialize namespace name, including HLL */
         if (!PMC_IS_NULL(class_data->_namespace)) {
@@ -1494,7 +1478,7 @@
             if (!PMC_IS_NULL(names))
                 serial_namespace = Parrot_str_join(interp, CONST_STRING(interp, ";"), names);
         }
-        VTABLE_push_string(INTERP, io, serial_namespace);
+        VTABLE_push_string(INTERP, info, serial_namespace);
     }
 
 /*
@@ -1512,46 +1496,39 @@
          * anonymous class and later decide whether to link it into the
          * namespace.  */
 
-        if (info->extra_flags == EXTRA_IS_PROP_HASH) {
-            SUPER(info);
-        }
-        else if (info->extra_flags == EXTRA_IS_NULL) {
-            IMAGE_IO * const io = info->image_io;
-
-            /* 1) thaw class id */
-            const INTVAL id = VTABLE_shift_integer(INTERP, io);
+        /* 1) thaw class id */
+        const INTVAL id = VTABLE_shift_integer(INTERP, info);
 
-            /* 2) thaw class name */
-            STRING * const name = VTABLE_shift_string(INTERP, io);
+        /* 2) thaw class name */
+        STRING * const name = VTABLE_shift_string(INTERP, info);
 
-            /* 3) deserialize namespace name, including HLL */
-            STRING * const serial_namespace = VTABLE_shift_string(INTERP, io);
-            STRING * const semicolon_str = CONST_STRING(INTERP, ";");
-            PMC    * const namespace_array =
-                Parrot_str_split(INTERP, semicolon_str, serial_namespace);
-            PMC *ns = Parrot_get_namespace_keyed(interp,
+        /* 3) deserialize namespace name, including HLL */
+        STRING * const serial_namespace = VTABLE_shift_string(INTERP, info);
+        STRING * const semicolon_str = CONST_STRING(INTERP, ";");
+        PMC    * const namespace_array =
+            Parrot_str_split(INTERP, semicolon_str, serial_namespace);
+        PMC *ns = Parrot_get_namespace_keyed(interp,
+                INTERP->root_namespace, namespace_array);
+
+        /* If the namespace doesn't exist, we create it, and initialize
+         * ourselves in it */
+        if (PMC_IS_NULL(ns)) {
+            ns = Parrot_make_namespace_keyed(interp,
                     INTERP->root_namespace, namespace_array);
+            SELF.init_pmc(ns);
+        }
+        /* If the namespace exists already, we point to it, but otherwise
+         * act as an anonymous class. */
+        else {
+            SELF.init();
+            PARROT_CLASS(SELF)->_namespace = ns;
+        }
 
-            /* If the namespace doesn't exist, we create it, and initialize
-             * ourselves in it */
-            if (PMC_IS_NULL(ns)) {
-                ns = Parrot_make_namespace_keyed(interp,
-                        INTERP->root_namespace, namespace_array);
-                SELF.init_pmc(ns);
-            }
-            /* If the namespace exists already, we point to it, but otherwise
-             * act as an anonymous class. */
-            else {
-                SELF.init();
-                PARROT_CLASS(SELF)->_namespace = ns;
-            }
-
-            /* Set the class's short name to the frozen name */
-            PARROT_CLASS(SELF)->name = name;
+        /* Set the class's short name to the frozen name */
+        PARROT_CLASS(SELF)->name = name;
 
-            /* Set the class's id the frozen id */
-            PARROT_CLASS(SELF)->id = id;
-        }
+        /* Set the class's id the frozen id */
+        PARROT_CLASS(SELF)->id = id;
     }
 
 /*

Modified: trunk/src/pmc/default.pmc
==============================================================================
--- trunk/src/pmc/default.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/default.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -370,10 +370,10 @@
 */
 
     VTABLE PMC *getprop(STRING *key) {
-        if (PMC_metadata(SELF))
-            return VTABLE_get_pmc_keyed_str(INTERP, PMC_metadata(SELF), key);
-        else
+        if (PMC_IS_NULL(PMC_metadata(SELF)))
             return check_get_std_props(interp, SELF, key);
+        else
+            return VTABLE_get_pmc_keyed_str(INTERP, PMC_metadata(SELF), key);
     }
 
 /*
@@ -390,13 +390,10 @@
         if (check_set_std_props(INTERP, SELF, key, value))
             return;
 
-        if (PMC_metadata(SELF))
-            VTABLE_set_pmc_keyed_str(INTERP, PMC_metadata(SELF), key, value);
-        else {
-            PMC * const prop = make_prop_hash(INTERP, SELF);
+        if (PMC_IS_NULL(PMC_metadata(SELF)))
+            make_prop_hash(INTERP, SELF);
 
-            VTABLE_set_pmc_keyed_str(INTERP, prop, key, value);
-        }
+        VTABLE_set_pmc_keyed_str(INTERP, PMC_metadata(SELF), key, value);
     }
 
 /*
@@ -410,7 +407,7 @@
 */
 
     VTABLE void delprop(STRING *key) {
-        if (PMC_metadata(SELF))
+        if (!PMC_IS_NULL(PMC_metadata(SELF)))
             VTABLE_delete_keyed_str(INTERP, PMC_metadata(SELF), key);
     }
 
@@ -425,7 +422,7 @@
 */
 
     VTABLE PMC *getprops() {
-        if (!PMC_metadata(SELF)) {
+        if (PMC_IS_NULL(PMC_metadata(SELF))) {
             if (has_pending_std_props(SELF))
                 return make_prop_hash(INTERP, SELF);
             else
@@ -1055,18 +1052,6 @@
 */
 
     VTABLE void visit(visit_info *info) {
-        /* default - mark prop hash */
-        if (PMC_metadata(SELF) &&
-            info->extra_flags != EXTRA_IS_PROP_HASH) {
-            info->extra_flags = EXTRA_IS_PROP_HASH;
-            info->extra       = PMC_metadata(SELF);
-
-            /* place escape mark */
-            (info->visit_pmc_now)(INTERP, SELF, info);
-
-            /* place and the prop hash */
-            (info->visit_pmc_now)(INTERP, PMC_metadata(SELF), info);
-        }
     }
 
 /*
@@ -1110,12 +1095,7 @@
 
     VTABLE void thaw(visit_info *info) {
         /* default - initialize the PMC */
-        if (info->extra_flags == EXTRA_IS_PROP_HASH) {
-            info->thaw_ptr  = &PMC_metadata(SELF);
-            (info->visit_pmc_now)(INTERP, PMC_metadata(SELF), info);
-        }
-        else
-            SELF.init();
+        SELF.init();
     }
 
 /*

Modified: trunk/src/pmc/eval.pmc
==============================================================================
--- trunk/src/pmc/eval.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/eval.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -333,16 +333,14 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO *io     = info->image_io;
         STRING   *packed = SELF.get_string();
-        VTABLE_push_string(INTERP, io, packed);
+        VTABLE_push_string(INTERP, info, packed);
 
         SUPER(info);
     }
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO         *io     = info->image_io;
-        STRING           *packed = VTABLE_shift_string(INTERP, io);
+        STRING           *packed = VTABLE_shift_string(INTERP, info);
         PackFile         *pf;
         PackFile_Segment *seg;
         Parrot_Sub_attributes *sub;

Modified: trunk/src/pmc/fixedbooleanarray.pmc
==============================================================================
--- trunk/src/pmc/fixedbooleanarray.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/fixedbooleanarray.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -516,7 +516,6 @@
     VTABLE void freeze(visit_info *info) {
         UINTVAL          size, resize_threshold;
         unsigned char  * bit_array;
-        IMAGE_IO * const io = info->image_io;
         STRING   *       s;
         GET_ATTR_size(INTERP, SELF, size);
         GET_ATTR_resize_threshold(INTERP, SELF, resize_threshold);
@@ -525,8 +524,8 @@
         s = Parrot_str_new(INTERP, (char*)bit_array,
                 (resize_threshold / BITS_PER_CHAR));
 
-        VTABLE_push_integer(INTERP, io, size);
-        VTABLE_push_string(INTERP, io, s);
+        VTABLE_push_integer(INTERP, info, size);
+        VTABLE_push_string(INTERP, info, s);
     }
 
 /*
@@ -539,14 +538,13 @@
 
 */
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
 
-        if (info->extra_flags == EXTRA_IS_NULL) {
+        {
             unsigned char * bit_array;
             UINTVAL         threshold;
-            const INTVAL    size      = VTABLE_shift_integer(INTERP, io);
-            STRING * const  s         = VTABLE_shift_string(INTERP, io);
+            const INTVAL    size      = VTABLE_shift_integer(INTERP, info);
+            STRING * const  s         = VTABLE_shift_string(INTERP, info);
 
             bit_array = (unsigned char *)Parrot_str_to_cstring(INTERP, s);
             threshold = Parrot_str_byte_length(interp, s) * BITS_PER_CHAR;

Modified: trunk/src/pmc/fixedintegerarray.pmc
==============================================================================
--- trunk/src/pmc/fixedintegerarray.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/fixedintegerarray.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -560,43 +560,37 @@
     }*/
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO *io = info->image_io;
         INTVAL   *int_array;
         INTVAL    i, n;
 
         SUPER(info);
 
         GET_ATTR_size(INTERP, SELF, n);
-        VTABLE_push_integer(INTERP, io, n);
+        VTABLE_push_integer(INTERP, info, n);
         GET_ATTR_int_array(INTERP, SELF, int_array);
 
         for (i = 0; i < n; ++i)
-            VTABLE_push_integer(INTERP, io, int_array[i]);
+            VTABLE_push_integer(INTERP, info, int_array[i]);
     }
 
     VTABLE void thaw(visit_info *info) {
-        PObj_custom_destroy_SET(SELF);
+        INTVAL n;
 
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            IMAGE_IO * const io = info->image_io;
-            const INTVAL n = VTABLE_shift_integer(INTERP, io);
+        SUPER(info);
 
-            SET_ATTR_size(INTERP, SELF, 0);
-            SET_ATTR_int_array(INTERP, SELF, NULL);
+        SET_ATTR_size(INTERP, SELF, 0);
+        SET_ATTR_int_array(INTERP, SELF, NULL);
 
-            if (n) {
-                INTVAL  i;
-                INTVAL *int_array;
+        if ((n = VTABLE_shift_integer(INTERP, info))) {
+            INTVAL  i;
+            INTVAL *int_array;
 
-                SELF.set_integer_native(n);
-                GET_ATTR_int_array(INTERP, SELF, int_array);
+            SELF.set_integer_native(n);
+            GET_ATTR_int_array(INTERP, SELF, int_array);
 
-                for (i = 0; i < n; ++i)
-                    int_array[i] = VTABLE_shift_integer(INTERP, io);
-            }
+            for (i = 0; i < n; ++i)
+                int_array[i] = VTABLE_shift_integer(INTERP, info);
         }
-        else
-            SUPER(info);
     }
 }
 

Modified: trunk/src/pmc/fixedpmcarray.pmc
==============================================================================
--- trunk/src/pmc/fixedpmcarray.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/fixedpmcarray.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -721,16 +721,13 @@
     }
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        VTABLE_push_integer(INTERP, io, VTABLE_elements(INTERP, SELF));
+        VTABLE_push_integer(INTERP, info, VTABLE_elements(INTERP, SELF));
     }
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        if (info->extra_flags == EXTRA_IS_NULL)
-            SELF.set_integer_native(VTABLE_shift_integer(INTERP, io));
+        SELF.set_integer_native(VTABLE_shift_integer(INTERP, info));
     }
 
 /*

Modified: trunk/src/pmc/fixedstringarray.pmc
==============================================================================
--- trunk/src/pmc/fixedstringarray.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/fixedstringarray.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -567,16 +567,15 @@
 
 */
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const   io  = info->image_io;
         STRING           **str_array;
         UINTVAL            size, i;
 
         GET_ATTR_size(INTERP, SELF, size);
         GET_ATTR_str_array(INTERP, SELF, str_array);
-        VTABLE_push_integer(INTERP, io, size);
+        VTABLE_push_integer(INTERP, info, size);
 
         for (i = 0; i < size; ++i)
-            VTABLE_push_string(INTERP, io, str_array[i]);
+            VTABLE_push_string(INTERP, info, str_array[i]);
     }
 
 /*
@@ -589,22 +588,18 @@
 
 */
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
+        UINTVAL  i, size;
+        STRING **str_array;
+
+        SELF.init();
         SUPER(info);
 
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            UINTVAL  i, size;
-            STRING **str_array;
-
-            SELF.init();
-
-            size   = VTABLE_shift_integer(INTERP, io);
-            SELF.set_integer_native((INTVAL)size);
-            GET_ATTR_str_array(INTERP, SELF, str_array);
-
-            for (i = 0; i < size; ++i)
-                str_array[i] = VTABLE_shift_string(INTERP, io);
-        }
+        size   = VTABLE_shift_integer(INTERP, info);
+        SELF.set_integer_native((INTVAL)size);
+        GET_ATTR_str_array(INTERP, SELF, str_array);
+
+        for (i = 0; i < size; ++i)
+            str_array[i] = VTABLE_shift_string(INTERP, info);
     }
 }
 

Modified: trunk/src/pmc/float.pmc
==============================================================================
--- trunk/src/pmc/float.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/float.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -352,9 +352,8 @@
 
 */
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        VTABLE_push_float(INTERP, io, SELF.get_number());
+        VTABLE_push_float(INTERP, info, SELF.get_number());
     }
 
 /*
@@ -367,10 +366,8 @@
 
 */
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        if (info->extra_flags == EXTRA_IS_NULL)
-            SET_ATTR_fv(INTERP, SELF, VTABLE_shift_float(INTERP, io));
+        SET_ATTR_fv(INTERP, SELF, VTABLE_shift_float(INTERP, info));
     }
 /*
 

Modified: trunk/src/pmc/hash.pmc
==============================================================================
--- trunk/src/pmc/hash.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/hash.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -1102,13 +1102,12 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io   = info->image_io;
         Hash     * const hash = (Hash *)SELF.get_pointer();;
 
         SUPER(info);
-        VTABLE_push_integer(INTERP, io, VTABLE_elements(INTERP, SELF));
-        VTABLE_push_integer(INTERP, io, (INTVAL)hash->key_type);
-        VTABLE_push_integer(INTERP, io, hash->entry_type);
+        VTABLE_push_integer(INTERP, info, VTABLE_elements(INTERP, SELF));
+        VTABLE_push_integer(INTERP, info, (INTVAL)hash->key_type);
+        VTABLE_push_integer(INTERP, info, hash->entry_type);
     }
 
 /*
@@ -1122,13 +1121,12 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
         SUPER(info);
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            const INTVAL elems  = VTABLE_shift_integer(INTERP, io);
-            const INTVAL k_type = VTABLE_shift_integer(INTERP, io);
-            const INTVAL v_type = VTABLE_shift_integer(INTERP, io);
+
+        {
+            const INTVAL elems  = VTABLE_shift_integer(INTERP, info);
+            const INTVAL k_type = VTABLE_shift_integer(INTERP, info);
+            const INTVAL v_type = VTABLE_shift_integer(INTERP, info);
             Hash        *hash;
 
             if (k_type == Hash_key_type_int && v_type == enum_hash_int) {

Modified: trunk/src/pmc/integer.pmc
==============================================================================
--- trunk/src/pmc/integer.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/integer.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -1312,9 +1312,8 @@
 
 */
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        VTABLE_push_integer(INTERP, io, SELF.get_integer());
+        VTABLE_push_integer(INTERP, info, SELF.get_integer());
     }
 
 
@@ -1328,10 +1327,8 @@
 
 */
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        if (info->extra_flags == EXTRA_IS_NULL)
-            SELF.set_integer_native(VTABLE_shift_integer(INTERP, io));
+        SELF.set_integer_native(VTABLE_shift_integer(INTERP, info));
     }
 }
 

Modified: trunk/src/pmc/key.pmc
==============================================================================
--- trunk/src/pmc/key.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/key.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -304,43 +304,34 @@
 */
 
     VTABLE void visit(visit_info *info) {
-
-        Parrot_Key_attributes *attrs;
-        /* at end a PMCNULL is written during thaw, which should stop visiting
-         * the key */
-
         /* Sometimes visit gets an uninitialized Key.  Initialize it. */
         if (!PMC_data(SELF))
             SELF.init();
 
-        attrs = (Parrot_Key_attributes *)PMC_data(SELF);
-        info->thaw_ptr  = &attrs->next_key;
-        (info->visit_pmc_now)(INTERP, attrs->next_key, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Key, next_key);
     }
 
     void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
         /* write flags */
         const INTVAL flags  = (PObj_get_FLAGS(SELF) & KEY_type_FLAGS);
 
         /* write the contents of a register - else thaw can't restore
          * the register state */
-        VTABLE_push_integer(INTERP, io, flags & ~KEY_register_FLAG);
+        VTABLE_push_integer(INTERP, info, flags & ~KEY_register_FLAG);
 
         /* and contents of this key component */
         switch (flags) {
           case KEY_integer_FLAG:
           case KEY_integer_FLAG | KEY_register_FLAG:
-            VTABLE_push_integer(INTERP, io, key_integer(INTERP, SELF));
+            VTABLE_push_integer(INTERP, info, key_integer(INTERP, SELF));
             break;
           case KEY_number_FLAG:
           case KEY_number_FLAG | KEY_register_FLAG:
-            VTABLE_push_float(INTERP, io, key_number(INTERP, SELF));
+            VTABLE_push_float(INTERP, info, key_number(INTERP, SELF));
             break;
           case KEY_string_FLAG:
           case KEY_string_FLAG | KEY_register_FLAG:
-            VTABLE_push_string(INTERP, io, key_string(INTERP, SELF));
+            VTABLE_push_string(INTERP, info, key_string(INTERP, SELF));
             break;
           default:
             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_KEY_NOT_FOUND,
@@ -350,8 +341,7 @@
     }
 
     void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-        const INTVAL flags  = VTABLE_shift_integer(INTERP, io) & KEY_type_FLAGS;
+        const INTVAL flags  = VTABLE_shift_integer(INTERP, info) & KEY_type_FLAGS;
 
         PObj_get_FLAGS(SELF) |= flags;
         PObj_custom_mark_SET(SELF);
@@ -362,13 +352,13 @@
         /* get contents */
         switch (flags) {
           case KEY_integer_FLAG:
-            SET_ATTR_int_key(INTERP, SELF, VTABLE_shift_integer(INTERP, io));
+            SET_ATTR_int_key(INTERP, SELF, VTABLE_shift_integer(INTERP, info));
             break;
           case KEY_number_FLAG:
-            VTABLE_set_number_native(INTERP, SELF, VTABLE_shift_float(INTERP, io));
+            VTABLE_set_number_native(INTERP, SELF, VTABLE_shift_float(INTERP, info));
             break;
           case KEY_string_FLAG:
-            VTABLE_set_string_native(INTERP, SELF, VTABLE_shift_string(INTERP, io));
+            VTABLE_set_string_native(INTERP, SELF, VTABLE_shift_string(INTERP, info));
             break;
           default:
             Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_KEY_NOT_FOUND,

Modified: trunk/src/pmc/lexinfo.pmc
==============================================================================
--- trunk/src/pmc/lexinfo.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/lexinfo.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -140,29 +140,22 @@
 
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            const INTVAL elems  = VTABLE_shift_integer(INTERP, io);
-            const INTVAL k_type = VTABLE_shift_integer(INTERP, io);
-            const INTVAL v_type = VTABLE_shift_integer(INTERP, io);
-            Hash        *hash;
-
-            UNUSED(k_type);
-            UNUSED(v_type);
-
-            PARROT_ASSERT(v_type == enum_hash_int);
-            /* TODO make a better interface for hash creation
-             * TODO create hash with needed types in the first place
-             */
-
-            SELF.init_pmc(NULL);
-            hash          = (Hash *)SELF.get_pointer();
-            hash->entries = elems;
-        }
-        else {
-            SUPER(info);
-        }
+        const INTVAL elems  = VTABLE_shift_integer(INTERP, info);
+        const INTVAL k_type = VTABLE_shift_integer(INTERP, info);
+        const INTVAL v_type = VTABLE_shift_integer(INTERP, info);
+        Hash        *hash;
+
+        UNUSED(k_type);
+        UNUSED(v_type);
+
+        PARROT_ASSERT(v_type == enum_hash_int);
+        /* TODO make a better interface for hash creation
+         * TODO create hash with needed types in the first place
+         */
+
+        SELF.init_pmc(NULL);
+        hash          = (Hash *)SELF.get_pointer();
+        hash->entries = elems;
     }
 }
 

Modified: trunk/src/pmc/object.pmc
==============================================================================
--- trunk/src/pmc/object.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/object.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -761,9 +761,7 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        if (info->extra_flags == EXTRA_IS_PROP_HASH) {
-            SUPER(info);
-        }
+        return;
     }
 
 /*

Modified: trunk/src/pmc/orderedhash.pmc
==============================================================================
--- trunk/src/pmc/orderedhash.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/orderedhash.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -627,17 +627,14 @@
 */
 
     VTABLE void visit(visit_info *info) {
-        switch (info->what) {
+        switch (VTABLE_get_integer(INTERP, info)) {
           case VISIT_THAW_NORMAL:
-          case VISIT_THAW_CONSTANTS:
             SUPER(info);
             break;
 
           case VISIT_FREEZE_NORMAL:
-          case VISIT_FREEZE_AT_DESTRUCT:
             {
                 Hash     * const hash = (Hash *)SELF.get_pointer();
-                IMAGE_IO * const io   = info->image_io;
                 const UINTVAL entries = hash->entries;
                 UINTVAL i;
 
@@ -647,7 +644,7 @@
                     if (b) {
                         STRING * const key = (STRING *)b->key;
                         if (key) {
-                            VTABLE_push_string(interp, io, key);
+                            VTABLE_push_string(interp, info, key);
                             (info->visit_pmc_now)(interp, (PMC *)b->value, info);
                         }
                     }
@@ -657,7 +654,7 @@
           default:
             Parrot_ex_throw_from_c_args(interp, NULL,
                     EXCEPTION_INVALID_OPERATION,
-                    "unhandled visit action (%d)", info->what);
+                    "unhandled visit action (%d)", VTABLE_get_integer(INTERP, info));
         }
     }
 }

Modified: trunk/src/pmc/parrotinterpreter.pmc
==============================================================================
--- trunk/src/pmc/parrotinterpreter.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/parrotinterpreter.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -708,8 +708,8 @@
          */
 
         /*  HLL_info */
-        if (info->what == VISIT_THAW_NORMAL ||
-                info->what == VISIT_THAW_CONSTANTS) {
+        if (VTABLE_get_integer(INTERP, info) == VISIT_THAW_NORMAL ||
+            VTABLE_get_integer(INTERP, info) == VISIT_THAW_CONSTANTS) {
             pos = &PMC_args(SELF);
         }
         else
@@ -720,21 +720,14 @@
     }
 
     VTABLE void thaw(visit_info *info) {
-        if (info->extra_flags == EXTRA_IS_PROP_HASH) {
-            SUPER(info);
+        if (!PMC_data(SELF)) {
+            Parrot_ParrotInterpreter_attributes *attrs =
+                mem_allocate_zeroed_typed(Parrot_ParrotInterpreter_attributes);
+            PMC_data(SELF) = attrs;
+            PObj_custom_destroy_SET(SELF);
         }
-        else if (info->extra_flags == EXTRA_IS_NULL) {
 
-            if (!PMC_data(SELF)) {
-                Parrot_ParrotInterpreter_attributes *attrs =
-                    mem_allocate_zeroed_typed(Parrot_ParrotInterpreter_attributes);
-                PMC_data(SELF) = attrs;
-                PObj_custom_destroy_SET(SELF);
-            }
-
-            PMC_interp(SELF) = INTERP;
-            info->what       = VISIT_THAW_CONSTANTS;
-        }
+        PMC_interp(SELF) = INTERP;
     }
 
     VTABLE void thawfinish(visit_info *info) {

Modified: trunk/src/pmc/resizablebooleanarray.pmc
==============================================================================
--- trunk/src/pmc/resizablebooleanarray.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/resizablebooleanarray.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -422,19 +422,18 @@
         STRING           *s;
         UINTVAL           tail_pos, rounded_size, head_pos;
         unsigned char    *bit_array;
-        IMAGE_IO * const  io = info->image_io;
 
         GET_ATTR_size(INTERP, SELF, tail_pos);
         GET_ATTR_resize_threshold(INTERP, SELF, head_pos);
         GET_ATTR_bit_array(INTERP, SELF, bit_array);
         rounded_size = ROUND_BYTES(tail_pos);
 
-        VTABLE_push_integer(INTERP, io, head_pos);
-        VTABLE_push_integer(INTERP, io, tail_pos);
+        VTABLE_push_integer(INTERP, info, head_pos);
+        VTABLE_push_integer(INTERP, info, tail_pos);
 
         s = Parrot_str_new(INTERP, (char*)bit_array, rounded_size);
 
-        VTABLE_push_string(INTERP, io, s);
+        VTABLE_push_string(INTERP, info, s);
     }
 
 /*
@@ -448,10 +447,9 @@
 */
     VTABLE void thaw(visit_info *info) {
         unsigned char   *bit_array;
-        IMAGE_IO * const io       = info->image_io;
-        const UINTVAL    head_pos = VTABLE_shift_integer(INTERP, io);
-        const UINTVAL    tail_pos = VTABLE_shift_integer(INTERP, io);
-        STRING * const   s        = VTABLE_shift_string(INTERP, io);
+        const UINTVAL    head_pos = VTABLE_shift_integer(INTERP, info);
+        const UINTVAL    tail_pos = VTABLE_shift_integer(INTERP, info);
+        STRING * const   s        = VTABLE_shift_string(INTERP, info);
 
         bit_array      = (unsigned char*)Parrot_str_to_cstring(INTERP, s);
         SET_ATTR_size(INTERP, SELF, tail_pos);

Modified: trunk/src/pmc/resizableintegerarray.pmc
==============================================================================
--- trunk/src/pmc/resizableintegerarray.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/resizableintegerarray.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -292,7 +292,6 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO *io = info->image_io;
         INTVAL   *int_array;
         INTVAL    i, n, rt;
 
@@ -300,38 +299,33 @@
 
         n  = SELF.get_integer();
         GET_ATTR_resize_threshold(INTERP, SELF, rt);
-        VTABLE_push_integer(INTERP, io, n);
-        VTABLE_push_integer(INTERP, io, rt);
+        VTABLE_push_integer(INTERP, info, n);
+        VTABLE_push_integer(INTERP, info, rt);
 
         GET_ATTR_int_array(INTERP, SELF, int_array);
 
         for (i = 0; i < n; ++i)
-            VTABLE_push_integer(INTERP, io, int_array[i]);
+            VTABLE_push_integer(INTERP, info, int_array[i]);
     }
 
     VTABLE void thaw(visit_info *info) {
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            IMAGE_IO * const io = info->image_io;
-            const INTVAL n = VTABLE_shift_integer(INTERP, io);
-            const INTVAL rt = VTABLE_shift_integer(INTERP, io);
-
-            SET_ATTR_size(INTERP, SELF, 0);
-            SET_ATTR_resize_threshold(INTERP, SELF, rt);
-            SET_ATTR_int_array(INTERP, SELF, NULL);
-
-            if (n) {
-                INTVAL  i;
-                INTVAL *int_array;
-
-                SELF.set_integer_native(n);
-                GET_ATTR_int_array(INTERP, SELF, int_array);
-
-                for (i = 0; i < n; ++i)
-                    int_array[i] = VTABLE_shift_integer(INTERP, io);
-            }
+        const INTVAL n = VTABLE_shift_integer(INTERP, info);
+        const INTVAL rt = VTABLE_shift_integer(INTERP, info);
+
+        SET_ATTR_size(INTERP, SELF, 0);
+        SET_ATTR_resize_threshold(INTERP, SELF, rt);
+        SET_ATTR_int_array(INTERP, SELF, NULL);
+
+        if (n) {
+            INTVAL  i;
+            INTVAL *int_array;
+
+            SELF.set_integer_native(n);
+            GET_ATTR_int_array(INTERP, SELF, int_array);
+
+            for (i = 0; i < n; ++i)
+                int_array[i] = VTABLE_shift_integer(INTERP, info);
         }
-        else
-            SUPER(info);
     }
 
 

Modified: trunk/src/pmc/scheduler.pmc
==============================================================================
--- trunk/src/pmc/scheduler.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/scheduler.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -288,18 +288,11 @@
 */
 
     VTABLE void visit(visit_info *info) {
-        Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF);
-        PMC **pos;
-
         /* 1) visit task list */
-        pos            = &core_struct->task_list;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, task_list);
 
         /* 2) visit the handlers */
-        pos            = &core_struct->handlers;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Scheduler, handlers);
     }
 
 
@@ -314,14 +307,13 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO *io = info->image_io;
         Parrot_Scheduler_attributes * const core_struct = PARROT_SCHEDULER(SELF);
 
         /* 1) freeze scheduler id */
-        VTABLE_push_integer(INTERP, io, core_struct->id);
+        VTABLE_push_integer(INTERP, info, core_struct->id);
 
         /* 2) freeze maximum task id */
-        VTABLE_push_integer(INTERP, io, core_struct->max_tid);
+        VTABLE_push_integer(INTERP, info, core_struct->max_tid);
     }
 
 
@@ -336,13 +328,11 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
         /* 1. thaw scheduler id */
-        const INTVAL id = VTABLE_shift_integer(INTERP, io);
+        const INTVAL id = VTABLE_shift_integer(INTERP, info);
 
         /* 2. thaw maximum task id */
-        const INTVAL max_tid = VTABLE_shift_integer(INTERP, io);
+        const INTVAL max_tid = VTABLE_shift_integer(INTERP, info);
 
         /* Allocate the scheduler's core data struct and set custom flags. */
         SELF.init();

Modified: trunk/src/pmc/schedulermessage.pmc
==============================================================================
--- trunk/src/pmc/schedulermessage.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/schedulermessage.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -238,15 +238,14 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO *io = info->image_io;
         Parrot_SchedulerMessage_attributes * const core_struct =
             PARROT_SCHEDULERMESSAGE(SELF);
 
         /* 1) freeze message id */
-        VTABLE_push_integer(INTERP, io, core_struct->id);
+        VTABLE_push_integer(INTERP, info, core_struct->id);
 
         /* 2) freeze message type */
-        VTABLE_push_string(INTERP, io, core_struct->type);
+        VTABLE_push_string(INTERP, info, core_struct->type);
     }
 
 /*
@@ -260,13 +259,11 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
         /* 1. thaw message id */
-        const INTVAL id = VTABLE_shift_integer(INTERP, io);
+        const INTVAL id = VTABLE_shift_integer(INTERP, info);
 
         /* 2. thaw message type */
-        STRING * const type = VTABLE_shift_string(INTERP, io);
+        STRING * const type = VTABLE_shift_string(INTERP, info);
 
         /* Allocate the message's core data struct and set custom flags. */
         SELF.init();

Modified: trunk/src/pmc/string.pmc
==============================================================================
--- trunk/src/pmc/string.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/string.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -786,9 +786,8 @@
 
 */
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        VTABLE_push_string(INTERP, io, VTABLE_get_string(INTERP, SELF));
+        VTABLE_push_string(INTERP, info, VTABLE_get_string(INTERP, SELF));
     }
 
 /*
@@ -801,10 +800,8 @@
 
 */
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         SUPER(info);
-        if (info->extra_flags == EXTRA_IS_NULL)
-            SET_ATTR_str_val(INTERP, SELF, VTABLE_shift_string(INTERP, io));
+        SET_ATTR_str_val(INTERP, SELF, VTABLE_shift_string(INTERP, info));
     }
 /*
 

Modified: trunk/src/pmc/sub.pmc
==============================================================================
--- trunk/src/pmc/sub.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/sub.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -632,18 +632,11 @@
 */
 
     VTABLE void visit(visit_info *info) {
-        Parrot_Sub_attributes *sub;
-
-        PMC_get_sub(INTERP, SELF, sub);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Sub, namespace_name);
 
-        info->thaw_ptr = &sub->namespace_name;
-        (info->visit_pmc_now)(INTERP, sub->namespace_name, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Sub, multi_signature);
 
-        info->thaw_ptr = &sub->multi_signature;
-        (info->visit_pmc_now)(INTERP, sub->multi_signature, info);
-
-        info->thaw_ptr = &sub->outer_sub;
-        (info->visit_pmc_now)(INTERP, sub->outer_sub, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Sub, outer_sub);
 
         /*
          * XXX visit_pmc_now is wrong, because it breaks
@@ -653,13 +646,12 @@
          *
          * Therefore the hash must be last during visit for now.
          */
-        info->thaw_ptr = &sub->lex_info;
-        (info->visit_pmc_now)(INTERP, sub->lex_info, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Sub, lex_info);
+
         SUPER(info);
     }
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO       * const io  = info->image_io;
         Parrot_Sub_attributes *sub;
         STRING                *hll_name;
         int i;
@@ -684,35 +676,35 @@
          * - subid
          */
 
-        VTABLE_push_integer(INTERP, io, (INTVAL) sub->start_offs);
-        VTABLE_push_integer(INTERP, io, (INTVAL) sub->end_offs);
-        VTABLE_push_integer(INTERP, io,
+        VTABLE_push_integer(INTERP, info, (INTVAL) sub->start_offs);
+        VTABLE_push_integer(INTERP, info, (INTVAL) sub->end_offs);
+        VTABLE_push_integer(INTERP, info,
             (INTVAL)(PObj_get_FLAGS(pmc) & SUB_FLAG_PF_MASK));
 
-        VTABLE_push_string(INTERP, io, sub->name);
+        VTABLE_push_string(INTERP, info, sub->name);
 
         if (!sub->method_name)
             sub->method_name = CONST_STRING(INTERP, "");
-        VTABLE_push_string(INTERP, io, sub->method_name);
+        VTABLE_push_string(INTERP, info, sub->method_name);
 
         if (!sub->ns_entry_name)
             sub->ns_entry_name = CONST_STRING(INTERP, "");
-        VTABLE_push_string(INTERP, io, sub->ns_entry_name);
+        VTABLE_push_string(INTERP, info, sub->ns_entry_name);
 
         hll_name = Parrot_get_HLL_name(INTERP, sub->HLL_id);
         if (!hll_name)
             hll_name = CONST_STRING(INTERP, "");
-        VTABLE_push_string(INTERP, io, hll_name);
+        VTABLE_push_string(INTERP, info, hll_name);
 
-        VTABLE_push_integer(INTERP, io, (INTVAL)sub->comp_flags);
-        VTABLE_push_integer(INTERP, io, sub->vtable_index);
+        VTABLE_push_integer(INTERP, info, (INTVAL)sub->comp_flags);
+        VTABLE_push_integer(INTERP, info, sub->vtable_index);
 
         for (i = 0; i < 4; ++i)
-            VTABLE_push_integer(INTERP, io, sub->n_regs_used[i]);
+            VTABLE_push_integer(INTERP, info, sub->n_regs_used[i]);
 
         if (!sub->subid)
             sub->subid = CONST_STRING(INTERP, "");
-        VTABLE_push_string(INTERP, io, sub->subid);
+        VTABLE_push_string(INTERP, info, sub->subid);
     }
 
 /*
@@ -726,36 +718,33 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
+        Parrot_Sub_attributes *sub;
+        INTVAL flags;
+        int    i;
+
         SUPER(info);
 
-        if (info->extra_flags == EXTRA_IS_NULL) {
-            Parrot_Sub_attributes *sub;
-            INTVAL flags;
-            int    i;
-
-            PMC_get_sub(INTERP, SELF, sub);
-
-            /* we get relative offsets */
-            sub->start_offs   = (size_t) VTABLE_shift_integer(INTERP, io);
-            sub->end_offs     = (size_t) VTABLE_shift_integer(INTERP, io);
-            flags             = VTABLE_shift_integer(INTERP, io);
-
-            PObj_get_FLAGS(SELF) |= flags & SUB_FLAG_PF_MASK;
-
-            sub->name           = VTABLE_shift_string(INTERP, io);
-            sub->method_name    = VTABLE_shift_string(INTERP, io);
-            sub->ns_entry_name  = VTABLE_shift_string(INTERP, io);
-            sub->HLL_id         = Parrot_get_HLL_id(INTERP,
-                VTABLE_shift_string(INTERP, io));
-            sub->comp_flags     = VTABLE_shift_integer(INTERP, io);
-            sub->vtable_index   = VTABLE_shift_integer(INTERP, io);
+        PMC_get_sub(INTERP, SELF, sub);
 
-            for (i = 0; i < 4; ++i)
-                sub->n_regs_used[i] = VTABLE_shift_integer(INTERP, io);
+        /* we get relative offsets */
+        sub->start_offs   = (size_t) VTABLE_shift_integer(INTERP, info);
+        sub->end_offs     = (size_t) VTABLE_shift_integer(INTERP, info);
+        flags             = VTABLE_shift_integer(INTERP, info);
+
+        PObj_get_FLAGS(SELF) |= flags & SUB_FLAG_PF_MASK;
+
+        sub->name           = VTABLE_shift_string(INTERP, info);
+        sub->method_name    = VTABLE_shift_string(INTERP, info);
+        sub->ns_entry_name  = VTABLE_shift_string(INTERP, info);
+        sub->HLL_id         = Parrot_get_HLL_id(INTERP,
+            VTABLE_shift_string(INTERP, info));
+        sub->comp_flags     = VTABLE_shift_integer(INTERP, info);
+        sub->vtable_index   = VTABLE_shift_integer(INTERP, info);
 
-            sub->subid        = VTABLE_shift_string(INTERP, io);
-        }
+        for (i = 0; i < 4; ++i)
+            sub->n_regs_used[i] = VTABLE_shift_integer(INTERP, info);
+
+        sub->subid        = VTABLE_shift_string(INTERP, info);
     }
 
 /*

Modified: trunk/src/pmc/task.pmc
==============================================================================
--- trunk/src/pmc/task.pmc	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc/task.pmc	Wed Jan 13 01:38:58 2010	(r43434)
@@ -396,13 +396,8 @@
 */
 
     VTABLE void visit(visit_info *info) {
-        Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
-        PMC **pos;
-
         /* 1) visit code block */
-        pos            = &core_struct->codeblock;
-        info->thaw_ptr = pos;
-        (info->visit_pmc_now)(INTERP, *pos, info);
+        VISIT_PMC_ATTR(INTERP, info, SELF, Task, codeblock);
     }
 
 /*
@@ -416,26 +411,25 @@
 */
 
     VTABLE void freeze(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
         const Parrot_Task_attributes * const core_struct = PARROT_TASK(SELF);
 
         /* 1) freeze task id */
-        VTABLE_push_integer(INTERP, io, core_struct->id);
+        VTABLE_push_integer(INTERP, info, core_struct->id);
 
         /* 2) freeze task birthtime */
-        VTABLE_push_float(INTERP, io, core_struct->birthtime);
+        VTABLE_push_float(INTERP, info, core_struct->birthtime);
 
         /* 3) freeze task priority */
-        VTABLE_push_integer(INTERP, io, core_struct->priority);
+        VTABLE_push_integer(INTERP, info, core_struct->priority);
 
         /* 4) freeze task type */
-        VTABLE_push_string(INTERP, io, core_struct->type);
+        VTABLE_push_string(INTERP, info, core_struct->type);
 
         /* 5) freeze task subtype */
-        VTABLE_push_string(INTERP, io, core_struct->subtype);
+        VTABLE_push_string(INTERP, info, core_struct->subtype);
 
         /* 6) freeze task status */
-        VTABLE_push_string(INTERP, io, core_struct->status);
+        VTABLE_push_string(INTERP, info, core_struct->status);
     }
 
 /*
@@ -449,25 +443,23 @@
 */
 
     VTABLE void thaw(visit_info *info) {
-        IMAGE_IO * const io = info->image_io;
-
         /* 1. thaw task id */
-        const INTVAL id = VTABLE_shift_integer(INTERP, io);
+        const INTVAL id = VTABLE_shift_integer(INTERP, info);
 
         /* 2. thaw task birthtime */
-        const FLOATVAL birthtime = VTABLE_shift_float(INTERP, io);
+        const FLOATVAL birthtime = VTABLE_shift_float(INTERP, info);
 
         /* 3. thaw task priority */
-        const INTVAL priority = VTABLE_shift_integer(INTERP, io);
+        const INTVAL priority = VTABLE_shift_integer(INTERP, info);
 
         /* 4. thaw task type */
-        STRING * const type = VTABLE_shift_string(INTERP, io);
+        STRING * const type = VTABLE_shift_string(INTERP, info);
 
         /* 5. thaw task subtype */
-        STRING * const subtype = VTABLE_shift_string(INTERP, io);
+        STRING * const subtype = VTABLE_shift_string(INTERP, info);
 
         /* 6. thaw task status */
-        STRING * const status = VTABLE_shift_string(INTERP, io);
+        STRING * const status = VTABLE_shift_string(INTERP, info);
 
         /* Allocate the task's core data struct and set custom flags. */
         SELF.init();

Modified: trunk/src/pmc_freeze.c
==============================================================================
--- trunk/src/pmc_freeze.c	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/pmc_freeze.c	Wed Jan 13 01:38:58 2010	(r43434)
@@ -18,7 +18,7 @@
 Container PMCs call a "todo-callback" for all contained PMCs. The
 individual action vtable (freeze/thaw) is then called for all todo-PMCs.
 
-In the current implementation C<IMAGE_IO> is a stand-in for some kind of
+In the current implementation C<visit_info> is a stand-in for some kind of
 serializer PMC which will eventually be written. It associates a Parrot
 C<STRING> with a vtable.
 
@@ -34,7 +34,7 @@
 /* HEADERIZER BEGIN: static */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
-static void create_image(PARROT_INTERP,
+static void create_buffer(PARROT_INTERP,
     ARGIN_NULLOK(PMC *pmc),
     ARGMOD(visit_info *info))
         __attribute__nonnull__(1)
@@ -42,152 +42,98 @@
         FUNC_MODIFIES(*info);
 
 PARROT_INLINE
-static void do_action(PARROT_INTERP,
-    ARGIN_NULLOK(PMC *pmc),
-    ARGIN(visit_info *info),
-    int seen,
-    UINTVAL id)
+static void ensure_buffer_size(PARROT_INTERP,
+    ARGIN(visit_info *io),
+    size_t len)
         __attribute__nonnull__(1)
-        __attribute__nonnull__(3);
+        __attribute__nonnull__(2);
 
-PARROT_INLINE
-static void do_thaw(PARROT_INTERP,
-    ARGIN_NULLOK(PMC *pmc),
-    ARGIN(visit_info *info))
+static INTVAL get_visit_integer(PARROT_INTERP, ARGIN(visit_info *io))
         __attribute__nonnull__(1)
-        __attribute__nonnull__(3);
+        __attribute__nonnull__(2);
 
 PARROT_INLINE
-static void freeze_pmc(PARROT_INTERP,
-    ARGIN_NULLOK(PMC *pmc),
-    ARGIN(visit_info *info),
-    int seen,
-    UINTVAL id)
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(3);
-
-static void ft_init(PARROT_INTERP, ARGIN(visit_info *info))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
+static INTVAL INFO_HAS_DATA(ARGIN(visit_info *io))
+        __attribute__nonnull__(1);
 
 PARROT_INLINE
-static void op_check_size(PARROT_INTERP, ARGIN(STRING *s), size_t len)
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
+static INTVAL OUTPUT_LENGTH(ARGIN(visit_info *io))
+        __attribute__nonnull__(1);
 
 static void push_opcode_integer(PARROT_INTERP,
-    ARGIN(IMAGE_IO *io),
+    ARGIN(visit_info *io),
     INTVAL v)
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
 static void push_opcode_number(PARROT_INTERP,
-    ARGIN(IMAGE_IO *io),
+    ARGIN(visit_info *io),
     FLOATVAL v)
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
 static void push_opcode_string(PARROT_INTERP,
-    ARGIN(IMAGE_IO *io),
+    ARGIN(visit_info *io),
     ARGIN(STRING *v))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
         __attribute__nonnull__(3);
 
-PARROT_WARN_UNUSED_RESULT
-PARROT_CAN_RETURN_NULL
-static PMC* run_thaw(PARROT_INTERP,
-    ARGIN(STRING* image),
-    visit_enum_type what)
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
-
-static INTVAL shift_opcode_integer(SHIM_INTERP, ARGIN(IMAGE_IO *io))
+static INTVAL shift_opcode_integer(SHIM_INTERP, ARGIN(visit_info *io))
         __attribute__nonnull__(2);
 
-static FLOATVAL shift_opcode_number(SHIM_INTERP, ARGIN(IMAGE_IO *io))
+static FLOATVAL shift_opcode_number(SHIM_INTERP, ARGIN(visit_info *io))
         __attribute__nonnull__(2);
 
 PARROT_WARN_UNUSED_RESULT
 PARROT_CANNOT_RETURN_NULL
-static STRING* shift_opcode_string(PARROT_INTERP, ARGIN(IMAGE_IO *io))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
-
-PARROT_INLINE
-PARROT_CANNOT_RETURN_NULL
-static PMC* thaw_create_pmc(PARROT_INTERP,
-    ARGIN(const visit_info *info),
-    INTVAL type)
+static STRING* shift_opcode_string(PARROT_INTERP, ARGIN(visit_info *io))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
-PARROT_INLINE
-static int thaw_pmc(PARROT_INTERP,
-    ARGMOD(visit_info *info),
-    ARGOUT(UINTVAL *id),
-    ARGOUT(INTVAL *type))
+static void visit_info_init(PARROT_INTERP,
+    ARGOUT(visit_info *info),
+    visit_enum_type what,
+    ARGIN(STRING *input),
+    ARGIN(PMC *pmc))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
-        __attribute__nonnull__(3)
         __attribute__nonnull__(4)
-        FUNC_MODIFIES(*info)
-        FUNC_MODIFIES(*id)
-        FUNC_MODIFIES(*type);
-
-static void todo_list_init(PARROT_INTERP, ARGOUT(visit_info *info))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2)
+        __attribute__nonnull__(5)
         FUNC_MODIFIES(*info);
 
-PARROT_INLINE
-static int todo_list_seen(PARROT_INTERP,
-    ARGIN(PMC *pmc),
-    ARGMOD(visit_info *info),
-    ARGOUT(UINTVAL *id))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2)
-        __attribute__nonnull__(3)
-        __attribute__nonnull__(4)
-        FUNC_MODIFIES(*info)
-        FUNC_MODIFIES(*id);
-
 static void visit_loop_todo_list(PARROT_INTERP,
     ARGIN_NULLOK(PMC *current),
     ARGIN(visit_info *info))
         __attribute__nonnull__(1)
         __attribute__nonnull__(3);
 
-static void visit_todo_list(PARROT_INTERP,
+static void visit_todo_list_freeze(PARROT_INTERP,
     ARGIN_NULLOK(PMC* pmc),
     ARGIN(visit_info* info))
         __attribute__nonnull__(1)
         __attribute__nonnull__(3);
 
+PARROT_INLINE
 static void visit_todo_list_thaw(PARROT_INTERP,
-    ARGIN_NULLOK(PMC* old),
+    SHIM(PMC* pmc_not_used),
     ARGIN(visit_info* info))
         __attribute__nonnull__(1)
         __attribute__nonnull__(3);
 
-#define ASSERT_ARGS_create_image __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_create_buffer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_do_action __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_ensure_buffer_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_do_thaw __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_freeze_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_ft_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_op_check_size __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+    , PARROT_ASSERT_ARG(io))
+#define ASSERT_ARGS_get_visit_integer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(s))
+    , PARROT_ASSERT_ARG(io))
+#define ASSERT_ARGS_INFO_HAS_DATA __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(io))
+#define ASSERT_ARGS_OUTPUT_LENGTH __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(io))
 #define ASSERT_ARGS_push_opcode_integer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(io))
@@ -198,9 +144,6 @@
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(io) \
     , PARROT_ASSERT_ARG(v))
-#define ASSERT_ARGS_run_thaw __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(image))
 #define ASSERT_ARGS_shift_opcode_integer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(io))
 #define ASSERT_ARGS_shift_opcode_number __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -208,26 +151,15 @@
 #define ASSERT_ARGS_shift_opcode_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(io))
-#define ASSERT_ARGS_thaw_create_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_thaw_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_visit_info_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(info) \
-    , PARROT_ASSERT_ARG(id) \
-    , PARROT_ASSERT_ARG(type))
-#define ASSERT_ARGS_todo_list_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_todo_list_seen __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(pmc) \
-    , PARROT_ASSERT_ARG(info) \
-    , PARROT_ASSERT_ARG(id))
+    , PARROT_ASSERT_ARG(input) \
+    , PARROT_ASSERT_ARG(pmc))
 #define ASSERT_ARGS_visit_loop_todo_list __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(info))
-#define ASSERT_ARGS_visit_todo_list __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+#define ASSERT_ARGS_visit_todo_list_freeze __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(info))
 #define ASSERT_ARGS_visit_todo_list_thaw __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
@@ -256,8 +188,6 @@
 enum {
     enum_PackID_normal     = 0,
     enum_PackID_seen       = 1,
-    enum_PackID_prev_type  = 2,
-    enum_PackID_extra_info = 3
 };
 
 /*
@@ -266,7 +196,8 @@
 
 =over 4
 
-=item C<static void op_check_size(PARROT_INTERP, STRING *s, size_t len)>
+=item C<static void ensure_buffer_size(PARROT_INTERP, visit_info *io, size_t
+len)>
 
 Checks the size of the "stream" buffer to see if it can accommodate
 C<len> more bytes. If not, expands the buffer.
@@ -275,21 +206,35 @@
 
 */
 
+#define GET_VISIT_CURSOR(io) \
+    ((opcode_t *)(((char *)Buffer_bufstart((io)->buffer) + (io)->pos)))
+#define SET_VISIT_CURSOR(io, x) do {\
+    (io)->pos = ((char *)(x) - (char *)Buffer_bufstart((io)->buffer)); \
+} while (0)
+#define INC_VISIT_CURSOR(io, x) do {\
+    (io)->pos += (x); \
+} while (0)
+
+#define BYTECODE_SHIFT_OK(io) PARROT_ASSERT((io)->pos <= (io)->input_length)
+
+
 PARROT_INLINE
 static void
-op_check_size(PARROT_INTERP, ARGIN(STRING *s), size_t len)
+ensure_buffer_size(PARROT_INTERP, ARGIN(visit_info *io), size_t len)
 {
-    ASSERT_ARGS(op_check_size)
-    const size_t used      = s->bufused;
-    const int    need_free = (int)Buffer_buflen(s) - used - len;
+    ASSERT_ARGS(ensure_buffer_size)
+    Buffer *buf         = io->buffer;
+    const size_t used   = io->pos;
+    const int need_free = Buffer_buflen(buf) - used - len;
 
     /* grow by factor 1.5 or such */
     if (need_free <= 16) {
-        size_t new_size = (size_t) (Buffer_buflen(s) * 1.5);
-        if (new_size < Buffer_buflen(s) - need_free + 512)
-            new_size = Buffer_buflen(s) - need_free + 512;
-        Parrot_gc_reallocate_string_storage(interp, s, new_size);
-        PARROT_ASSERT(Buffer_buflen(s) - used - len >= 15);
+        size_t new_size = (size_t) (Buffer_buflen(buf) * 1.5);
+        if (new_size < Buffer_buflen(buf) - need_free + 512)
+            new_size = Buffer_buflen(buf) - need_free + 512;
+        Parrot_gc_reallocate_buffer_storage(interp, buf, new_size);
+
+        PARROT_ASSERT(Buffer_buflen(buf) - used - len >= 15);
     }
 
 #ifndef DISABLE_GC_DEBUG
@@ -298,10 +243,61 @@
 
 }
 
+/*
+
+=item C<static INTVAL OUTPUT_LENGTH(visit_info *io)>
+
+XXX TODO
+
+=cut
+
+*/
+
+PARROT_INLINE
+static INTVAL
+OUTPUT_LENGTH(ARGIN(visit_info *io)) {
+    ASSERT_ARGS(OUTPUT_LENGTH)
+    return io->pos;
+}
 
 /*
 
-=item C<static void push_opcode_integer(PARROT_INTERP, IMAGE_IO *io, INTVAL v)>
+=item C<static INTVAL INFO_HAS_DATA(visit_info *io)>
+
+XXX TODO
+
+=cut
+
+*/
+
+PARROT_INLINE
+static INTVAL
+INFO_HAS_DATA(ARGIN(visit_info *io)) {
+    ASSERT_ARGS(INFO_HAS_DATA)
+    return io->pos < io->input_length;
+}
+
+
+/*
+
+=item C<static INTVAL get_visit_integer(PARROT_INTERP, visit_info *io)>
+
+get the flags describing the visit action
+
+=cut
+
+*/
+
+static INTVAL
+get_visit_integer(PARROT_INTERP, ARGIN(visit_info *io)) {
+    ASSERT_ARGS(get_visit_integer)
+    return io->what;
+}
+
+/*
+
+=item C<static void push_opcode_integer(PARROT_INTERP, visit_info *io, INTVAL
+v)>
 
 Pushes the integer C<v> onto the end of the C<*io> "stream".
 
@@ -312,21 +308,19 @@
 */
 
 static void
-push_opcode_integer(PARROT_INTERP, ARGIN(IMAGE_IO *io), INTVAL v)
+push_opcode_integer(PARROT_INTERP, ARGIN(visit_info *io), INTVAL v)
 {
     ASSERT_ARGS(push_opcode_integer)
-    UINTVAL size = sizeof (opcode_t);
-    STRING   *op = Parrot_str_new_init(interp, (char *)&v, size,
-        Parrot_fixed_8_encoding_ptr, Parrot_binary_charset_ptr, 0);
-
-    PARROT_ASSERT(sizeof (opcode_t) == sizeof (INTVAL));
-    io->image = Parrot_str_append(interp, io->image, op);
+    size_t len = PF_size_integer() * sizeof (opcode_t);
+    ensure_buffer_size(interp, io, len);
+    SET_VISIT_CURSOR(io, PF_store_integer(GET_VISIT_CURSOR(io), v));
 }
 
 
 /*
 
-=item C<static void push_opcode_number(PARROT_INTERP, IMAGE_IO *io, FLOATVAL v)>
+=item C<static void push_opcode_number(PARROT_INTERP, visit_info *io, FLOATVAL
+v)>
 
 Pushes the number C<v> onto the end of the C<*io> "stream".
 
@@ -335,24 +329,19 @@
 */
 
 static void
-push_opcode_number(PARROT_INTERP, ARGIN(IMAGE_IO *io), FLOATVAL v)
+push_opcode_number(PARROT_INTERP, ARGIN(visit_info *io), FLOATVAL v)
 {
     ASSERT_ARGS(push_opcode_number)
-    UINTVAL   len    = PF_size_number() * sizeof (opcode_t);
-    opcode_t *buffer = (opcode_t *)mem_sys_allocate(len);
-    opcode_t *ignore = PF_store_number(buffer, &v);
-    STRING   *number = Parrot_str_new_init(interp, (char *)buffer, len,
-        Parrot_fixed_8_encoding_ptr, Parrot_binary_charset_ptr, 0);
-
-    UNUSED(ignore);
-    io->image = Parrot_str_append(interp, io->image, number);
-    mem_sys_free(buffer);
+    size_t len = PF_size_number() * sizeof (opcode_t);
+    ensure_buffer_size(interp, io, len);
+    SET_VISIT_CURSOR(io, PF_store_number(GET_VISIT_CURSOR(io), &v));
 }
 
 
 /*
 
-=item C<static void push_opcode_string(PARROT_INTERP, IMAGE_IO *io, STRING *v)>
+=item C<static void push_opcode_string(PARROT_INTERP, visit_info *io, STRING
+*v)>
 
 Pushes the string C<*v> onto the end of the C<*io> "stream".
 
@@ -361,25 +350,34 @@
 */
 
 static void
-push_opcode_string(PARROT_INTERP, ARGIN(IMAGE_IO *io), ARGIN(STRING *v))
+push_opcode_string(PARROT_INTERP, ARGIN(visit_info *io), ARGIN(STRING *v))
 {
     ASSERT_ARGS(push_opcode_string)
+    size_t len = PF_size_string(v) * sizeof (opcode_t);
+    ensure_buffer_size(interp, io, len);
+    SET_VISIT_CURSOR(io, PF_store_string(GET_VISIT_CURSOR(io), v));
+}
+
+/*
 
-    size_t    len    = PF_size_string(v) * sizeof (opcode_t);
-    opcode_t *buffer = (opcode_t *)mem_sys_allocate(len);
-    opcode_t *ignore = PF_store_string(buffer, v);
-    STRING   *number = Parrot_str_new_init(interp, (char *)buffer, len,
-        Parrot_fixed_8_encoding_ptr, Parrot_binary_charset_ptr, 0);
+=item C<static void push_opcode_pmc(PARROT_INTERP, visit_info *io, PMC *v)>
 
-    UNUSED(ignore);
-    io->image = Parrot_str_append(interp, io->image, number);
-    mem_sys_free(buffer);
-}
+Pushes a reference to pmc C<*v> onto the end of the C<*io> "stream". If C<*v>
+hasn't been seen yet, it is also pushed onto the todo list.
 
+=cut
+
+*/
+
+static void
+push_opcode_pmc(PARROT_INTERP, ARGIN(visit_info *io), ARGIN(PMC *v)) {
+    io->thaw_ptr = &v;
+    (io->visit_pmc_now)(interp, v, io);
+}
 
 /*
 
-=item C<static INTVAL shift_opcode_integer(PARROT_INTERP, IMAGE_IO *io)>
+=item C<static INTVAL shift_opcode_integer(PARROT_INTERP, visit_info *io)>
 
 Removes and returns an integer from the start of the C<*io> "stream".
 
@@ -388,26 +386,20 @@
 */
 
 static INTVAL
-shift_opcode_integer(SHIM_INTERP, ARGIN(IMAGE_IO *io))
+shift_opcode_integer(SHIM_INTERP, ARGIN(visit_info *io))
 {
     ASSERT_ARGS(shift_opcode_integer)
-    const char * const   start  = (char *)io->image->strstart;
-    char               **opcode = &io->image->strstart;
-    const INTVAL i              = PF_fetch_integer(io->pf,
-                                    (const opcode_t **)opcode);
-
-    io->image->bufused -= ((char *)io->image->strstart - start);
-    io->image->strlen  -= ((char *)io->image->strstart - start);
-
-    PARROT_ASSERT((int)io->image->bufused >= 0);
-
+    opcode_t *pos  = GET_VISIT_CURSOR(io);
+    const INTVAL i = PF_fetch_integer(io->pf, (const opcode_t **)&pos);
+    SET_VISIT_CURSOR(io, pos);
+    BYTECODE_SHIFT_OK(io);
     return i;
 }
 
 
 /*
 
-=item C<static FLOATVAL shift_opcode_number(PARROT_INTERP, IMAGE_IO *io)>
+=item C<static FLOATVAL shift_opcode_number(PARROT_INTERP, visit_info *io)>
 
 Removes and returns an number from the start of the C<*io> "stream".
 
@@ -416,27 +408,20 @@
 */
 
 static FLOATVAL
-shift_opcode_number(SHIM_INTERP, ARGIN(IMAGE_IO *io))
+shift_opcode_number(SHIM_INTERP, ARGIN(visit_info *io))
 {
     ASSERT_ARGS(shift_opcode_number)
-
-    const char * const   start  = (const char *)io->image->strstart;
-    char               **opcode = &io->image->strstart;
-    const FLOATVAL       f      = PF_fetch_number(io->pf,
-                                    (const opcode_t **)opcode);
-
-    io->image->bufused -= ((char *)io->image->strstart - start);
-    io->image->strlen  -= ((char *)io->image->strstart - start);
-
-    PARROT_ASSERT((int)io->image->bufused >= 0);
-
+    opcode_t *pos     = GET_VISIT_CURSOR(io);
+    const FLOATVAL f  = PF_fetch_number(io->pf, (const opcode_t **)&pos);
+    SET_VISIT_CURSOR(io, pos);
+    BYTECODE_SHIFT_OK(io);
     return f;
 }
 
 
 /*
 
-=item C<static STRING* shift_opcode_string(PARROT_INTERP, IMAGE_IO *io)>
+=item C<static STRING* shift_opcode_string(PARROT_INTERP, visit_info *io)>
 
 Removes and returns a string from the start of the C<*io> "stream".
 
@@ -444,27 +429,39 @@
 
 */
 
+
 PARROT_WARN_UNUSED_RESULT
 PARROT_CANNOT_RETURN_NULL
 static STRING*
-shift_opcode_string(PARROT_INTERP, ARGIN(IMAGE_IO *io))
+shift_opcode_string(PARROT_INTERP, ARGIN(visit_info *io))
 {
     ASSERT_ARGS(shift_opcode_string)
+    opcode_t *pos    = GET_VISIT_CURSOR(io);
+    STRING * const s = PF_fetch_string(interp, io->pf, (const opcode_t **)&pos);
+    SET_VISIT_CURSOR(io, pos);
+    BYTECODE_SHIFT_OK(io);
+    return s;
+}
+
+/*
 
-    char * const   start  = (char*)io->image->strstart;
-    char *         opcode = io->image->strstart;
-    STRING * const s      = PF_fetch_string(interp, io->pf,
-                                (const opcode_t **)&opcode);
-
-    io->image->strstart = opcode;
-    io->image->bufused -= (opcode - start);
-    io->image->strlen  -= (opcode - start);
+=item C<static PMC *shift_opcode_pmc(PARROT_INTERP, visit_info *io)>
 
-    PARROT_ASSERT((int)io->image->bufused >= 0);
+Removes and returns a reference to a pmc from the start of the C<*io> "stream".
 
-    return s;
-}
+=cut
+
+*/
 
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+static PMC *
+shift_opcode_pmc(PARROT_INTERP, ARGIN(visit_info *io)) {
+    PMC *result;
+    io->thaw_ptr = &result;
+    (io->visit_pmc_now)(interp, NULL, io);
+    return result;
+}
 
 /*
 
@@ -485,115 +482,101 @@
  */
 
 static image_funcs opcode_funcs = {
+    get_visit_integer,
     push_opcode_integer,
     push_opcode_string,
     push_opcode_number,
+    push_opcode_pmc,
     shift_opcode_integer,
     shift_opcode_string,
-    shift_opcode_number
+    shift_opcode_number,
+    shift_opcode_pmc
 };
 
 /*
 
-=item C<static void ft_init(PARROT_INTERP, visit_info *info)>
+=item C<static void visit_info_init(PARROT_INTERP, visit_info *info,
+visit_enum_type what, STRING *input, PMC *pmc)>
 
-Initializes the freeze/thaw subsystem.
+Initializes the C<*info> lists.
 
 =cut
 
 */
+#define GROW_TO_16_BYTE_BOUNDARY(size) ((size) + ((size) % 16 ? 16 - (size) % 16 : 0))
 
 static void
-ft_init(PARROT_INTERP, ARGIN(visit_info *info))
+visit_info_init(PARROT_INTERP, ARGOUT(visit_info *info),
+  visit_enum_type what, ARGIN(STRING *input), ARGIN(PMC *pmc))
 {
-    ASSERT_ARGS(ft_init)
-    STRING   *s = info->image;
-    PackFile *pf;
-
-    /* We want to store a 16-byte aligned header, but the actual
-     * header may be shorter. */
-    const unsigned int header_length = PACKFILE_HEADER_BYTES +
-        (PACKFILE_HEADER_BYTES % 16 ?
-         16 - PACKFILE_HEADER_BYTES % 16 : 0);
-
-    info->image_io         = mem_allocate_typed(IMAGE_IO);
-    info->image_io->image  = s = info->image;
-
-    info->image_io->vtable = &opcode_funcs;
-
-    pf = info->image_io->pf = PackFile_new(interp, 0);
-
-    if (info->what == VISIT_FREEZE_NORMAL
-    ||  info->what == VISIT_FREEZE_AT_DESTRUCT) {
-
-        op_check_size(interp, s, header_length);
-        mem_sys_memcopy(s->strstart, pf->header, PACKFILE_HEADER_BYTES);
-        s->bufused += header_length;
-        s->strlen  += header_length;
-    }
-    else {
-        if (Parrot_str_byte_length(interp, s) < header_length) {
-            Parrot_ex_throw_from_c_args(interp, NULL,
-                EXCEPTION_INVALID_STRING_REPRESENTATION,
-                "bad string to thaw");
-        }
-
-        /* TT #749: use the validation logic from Packfile_unpack */
-        if (pf->header->bc_major != PARROT_PBC_MAJOR
-        ||  pf->header->bc_minor != PARROT_PBC_MINOR)
+    ASSERT_ARGS(visit_info_init)
+    /* We want to store a 16-byte aligned header, but the actual * header may be shorter. */
+    const unsigned int header_length = GROW_TO_16_BYTE_BOUNDARY(PACKFILE_HEADER_BYTES);
+
+    PackFile *pf = info->pf = PackFile_new(interp, 0);
+    info->what = what;
+    info->vtable = &opcode_funcs;
+    info->image_io = info; /* backwards-compat hack */
+
+    if (info->what == VISIT_FREEZE_NORMAL) {
+        info->visit_pmc_now  = visit_todo_list_freeze;
+        create_buffer(interp, pmc, info);
+        ensure_buffer_size(interp, info, header_length);
+        mem_sys_memcopy(GET_VISIT_CURSOR(info), pf->header, PACKFILE_HEADER_BYTES);
+        INC_VISIT_CURSOR(info, header_length);
+    }
+    else { /* VISIT_THAW_ */
+        int unpacked_length;
+        info->visit_pmc_now    = visit_todo_list_thaw;
+        info->buffer = (Buffer *)input;
+        PARROT_ASSERT(input->_bufstart == input->strstart);
+        SET_VISIT_CURSOR(info, Buffer_bufstart(info->buffer));
+        info->input_length = input->strlen;
+
+        pf->options |= PFOPT_PMC_FREEZE_ONLY;
+        unpacked_length = PackFile_unpack(interp, pf, GET_VISIT_CURSOR(info), info->input_length);
+        if (!unpacked_length) {
+            PackFile_destroy(interp, info->pf);
             Parrot_ex_throw_from_c_args(interp, NULL,
                     EXCEPTION_INVALID_STRING_REPRESENTATION,
-                    "can't thaw a PMC from Parrot %d.%d", pf->header->bc_major,
-                    pf->header->bc_minor);
-
-        mem_sys_memcopy(pf->header, s->strstart, PACKFILE_HEADER_BYTES);
-        PackFile_assign_transforms(pf);
-
-        s->bufused -= header_length;
-        s->strlen  -= header_length;
-
-        LVALUE_CAST(char *, s->strstart) += header_length;
+                    "PackFile header failed during unpack");
+        }
+        else {
+            INC_VISIT_CURSOR(info, header_length);
+        }
     }
 
-    info->last_type   = -1;
+    /* we must use PMCs here so that they get marked properly */
+    info->todo        = pmc_new(interp, enum_class_Array);
+    info->seen        = pmc_new(interp, enum_class_Hash);
+    VTABLE_set_pointer(interp, info->seen, parrot_new_intval_hash(interp));
     info->id_list     = pmc_new(interp, enum_class_Array);
     info->id          = 0;
     info->extra_flags = EXTRA_IS_NULL;
-}
-
-
-/*
-
-=item C<static void todo_list_init(PARROT_INTERP, visit_info *info)>
-
-Initializes the C<*info> lists.
-
-=cut
 
-*/
+    visit_loop_todo_list(interp, pmc, info);
+    PackFile_destroy(interp, info->pf);
+}
 
-static void
-todo_list_init(PARROT_INTERP, ARGOUT(visit_info *info))
-{
-    ASSERT_ARGS(todo_list_init)
-    info->visit_pmc_now   = visit_todo_list;
 
-    /* we must use PMCs here so that they get marked properly */
-    info->todo = pmc_new(interp, enum_class_Array);
-    info->seen = pmc_new(interp, enum_class_Hash);
-    VTABLE_set_pointer(interp, info->seen, parrot_new_intval_hash(interp));
+PARROT_INLINE
+static PMC*
+id_list_get(PARROT_INTERP, ARGIN(visit_info *info), UINTVAL id) {
+    List * const id_list = (List *)PMC_data(info->id_list);
+    PMC **pos = (PMC **)Parrot_pmc_array_get(interp, id_list, id, enum_type_PMC);
 
-    ft_init(interp, info);
+    if (pos && pos != ((void *)-1))
+        return *pos;
+    return NULL;
 }
 
-
 /*
 
-=item C<static void freeze_pmc(PARROT_INTERP, PMC *pmc, visit_info *info, int
-seen, UINTVAL id)>
+=item C<static void visit_todo_list_thaw(PARROT_INTERP, PMC* pmc_not_used,
+visit_info* info)>
 
-Freeze PMC, setting type, seen, and "same-as-last" indicators as
-appropriate.
+Callback for thaw - action first.
+thaws and return a PMC.
 
 =cut
 
@@ -601,361 +584,98 @@
 
 PARROT_INLINE
 static void
-freeze_pmc(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), ARGIN(visit_info *info),
-        int seen, UINTVAL id)
+visit_todo_list_thaw(PARROT_INTERP, SHIM(PMC* pmc_not_used), ARGIN(visit_info* info))
 {
-    ASSERT_ARGS(freeze_pmc)
-    IMAGE_IO * const io = info->image_io;
-    INTVAL           type;
-
-    if (PMC_IS_NULL(pmc)) {
-        /* NULL + seen bit */
-        VTABLE_push_integer(interp, io, PackID_new(NULL, enum_PackID_seen));
-        return;
-    }
-
-    type = pmc->vtable->base_type;
-
-    if (PObj_is_object_TEST(pmc))
-        type = enum_class_Object;
-
-    if (seen) {
-        if (info->extra_flags) {
-            PackID_set_FLAGS(id, enum_PackID_extra_info);
-            VTABLE_push_integer(interp, io, id);
-            VTABLE_push_integer(interp, io, info->extra_flags);
-            return;
-        }
-
-        PackID_set_FLAGS(id, enum_PackID_seen);
-    }
-    else if (type == info->last_type)
-        PackID_set_FLAGS(id, enum_PackID_prev_type);
-
-    VTABLE_push_integer(interp, io, id);
-
-    if (PackID_get_FLAGS(id) == enum_PackID_normal) {
-        /* write type */
-        VTABLE_push_integer(interp, io, type);
-        info->last_type = type;
-    }
-}
-
-
-/*
-
-=item C<static int thaw_pmc(PARROT_INTERP, visit_info *info, UINTVAL *id, INTVAL
-*type)>
-
-Freeze and thaw a PMC (id).
-
-For example, the ASCII representation of the C<Array>
-
-    P0 = [P1=666, P2=777, P0]
-
-may look like this:
-
-    0xdf4 30 3 0xdf8 33 666 0xdf2 777 0xdf5
-
-where 30 is C<class_enum_Array>, 33 is C<class_enum_Integer>, the
-type of the second C<Integer> is suppressed, the repeated P0 has bit 0
-set.
+    ASSERT_ARGS(visit_todo_list_thaw)
 
-=cut
+    UINTVAL  n            = VTABLE_shift_integer(interp, info);
+    UINTVAL  id           = PackID_get_PMCID(n);
+    int      packid_flags = PackID_get_FLAGS(n);
+    PMC     *pmc          = PMCNULL;
 
-*/
+    PARROT_ASSERT(info->what == VISIT_THAW_NORMAL);
 
-PARROT_INLINE
-static int
-thaw_pmc(PARROT_INTERP, ARGMOD(visit_info *info),
-        ARGOUT(UINTVAL *id), ARGOUT(INTVAL *type))
-{
-    ASSERT_ARGS(thaw_pmc)
-    IMAGE_IO * const io   = info->image_io;
-    UINTVAL          n    = VTABLE_shift_integer(interp, io);
-    int              seen = 0;
-
-    info->extra_flags     = EXTRA_IS_NULL;
-
-    switch (PackID_get_FLAGS(n)) {
-      case enum_PackID_extra_info:
-        /* pmc has extra data */
-        info->extra_flags = VTABLE_shift_integer(interp, io);
-        break;
+    switch (packid_flags) {
       case enum_PackID_seen:
-        seen = 1;
-        break;
-      case enum_PackID_prev_type:
-        /* prev PMC was same type */
-        *type = info->last_type;
+        if (id) /* got a non-NULL PMC */
+            pmc = id_list_get(interp, info, id);
         break;
-      default:
-        /* type follows */
+      case enum_PackID_normal:
         {
-            *type           = VTABLE_shift_integer(interp, io);
-            info->last_type = *type;
-
-            if (*type <= 0)
-                Parrot_ex_throw_from_c_args(interp, NULL, 1,
-                    "Unknown PMC type to thaw %d", (int) *type);
-
-            /* that ought to be a class */
-            if (*type >= interp->n_vtable_max || !interp->vtables[*type])
-                *type = enum_class_Class;
+            INTVAL type = VTABLE_shift_integer(interp, info);
+            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 = pmc_new_noinit(interp, type);
+            VTABLE_thaw(interp, pmc, info);
+
+            {
+                List * const todo    = (List *)PMC_data(info->todo);
+                List * const id_list = (List *)PMC_data(info->id_list);
+                Parrot_pmc_array_assign(interp, id_list, id, pmc, enum_type_PMC);
+                /* remember nested aggregates depth first */
+                Parrot_pmc_array_unshift(interp, todo, pmc, enum_type_PMC);
+            }
         }
         break;
-    }
-
-    *id = n;
-    return seen;
-}
-
-
-/*
-
-=item C<static void do_action(PARROT_INTERP, PMC *pmc, visit_info *info, int
-seen, UINTVAL id)>
-
-Called from C<visit_todo_list()> to perform the action specified in
-C<< info->what >>.
-
-Currently only C<VISIT_FREEZE_NORMAL> and C<VISIT_FREEZE_AT_DESTRUCT> are
-implemented.
-
-=cut
-
-*/
-
-PARROT_INLINE
-static void
-do_action(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), ARGIN(visit_info *info),
-        int seen, UINTVAL id)
-{
-    ASSERT_ARGS(do_action)
-    switch (info->what) {
-      case VISIT_FREEZE_AT_DESTRUCT:
-      case VISIT_FREEZE_NORMAL:
-        freeze_pmc(interp, pmc, info, seen, id);
-        if (pmc)
-            info->visit_action = pmc->vtable->freeze;
-        break;
       default:
-        Parrot_ex_throw_from_c_args(interp, NULL, 1, "Illegal action %ld",
-                (long)info->what);
-    }
-}
-
-
-/*
-
-=item C<static PMC* thaw_create_pmc(PARROT_INTERP, const visit_info *info,
-INTVAL type)>
-
-Called from C<do_thaw()> to attach the vtable etc. to C<*pmc>.
-
-=cut
-
-*/
-
-PARROT_INLINE
-PARROT_CANNOT_RETURN_NULL
-static PMC*
-thaw_create_pmc(PARROT_INTERP, ARGIN(const visit_info *info),
-        INTVAL type)
-{
-    ASSERT_ARGS(thaw_create_pmc)
-    PMC *pmc;
-    switch (info->what) {
-      case VISIT_THAW_NORMAL:
-        pmc = pmc_new_noinit(interp, type);
+        Parrot_ex_throw_from_c_args(interp, NULL, 1, "Unknown PMC id args thaw %d", packid_flags);
         break;
-      case VISIT_THAW_CONSTANTS:
-        pmc = constant_pmc_new_noinit(interp, type);
-        break;
-      default:
-        Parrot_ex_throw_from_c_args(interp, NULL, 1,
-                "Illegal visit_next type");
     }
 
-    return pmc;
+    *info->thaw_ptr = pmc;
 }
 
 
 /*
 
-=item C<static void do_thaw(PARROT_INTERP, PMC *pmc, visit_info *info)>
-
-Called by C<visit_todo_list_thaw()> to thaw and return a PMC.
+=item C<static void visit_todo_list_freeze(PARROT_INTERP, PMC* pmc, visit_info*
+info)>
 
-C<seen> is false if this is the first time the PMC has been encountered.
+Checks the seen PMC via the todo list.
 
 =cut
 
 */
 
-PARROT_INLINE
 static void
-do_thaw(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), ARGIN(visit_info *info))
+visit_todo_list_freeze(PARROT_INTERP, ARGIN_NULLOK(PMC* pmc), ARGIN(visit_info* info))
 {
-    ASSERT_ARGS(do_thaw)
-    PMC **pos;
-
-    /* set below, but avoid compiler warning */
-    UINTVAL id             = 0;
-    INTVAL  type           = 0;
-    int     must_have_seen = thaw_pmc(interp, info, &id, &type);
-
-    id = PackID_get_PMCID(id);
-
-    if (!id) {
-        /* got a NULL PMC */
-        pmc = PMCNULL;
-        if (!info->thaw_result)
-            info->thaw_result = pmc;
-        else
-            *info->thaw_ptr = pmc;
-        return;
-    }
+    ASSERT_ARGS(visit_todo_list_freeze)
+    UINTVAL id;
+    int packid_type;
 
-    pos = (PMC **)Parrot_pmc_array_get(interp, (List *)PMC_data(info->id_list),
-        id, enum_type_PMC);
+    PARROT_ASSERT(info->what == VISIT_FREEZE_NORMAL);
 
-    if (pos == (void *)-1)
-        pos = NULL;
-    else if (pos) {
-        pmc = *(PMC **)pos;
-        if (!pmc)
-            pos = NULL;
+    if (PMC_IS_NULL(pmc)) {
+        id   = 0;
+        packid_type = enum_PackID_seen;
     }
-
-    if (pos) {
-        if (info->extra_flags == EXTRA_IS_PROP_HASH) {
-            interp->vtables[enum_class_default]->thaw(interp, pmc, info);
-            return;
+    else {
+        Hash *hash = (Hash *)VTABLE_get_pointer(interp, info->seen);
+        HashBucket * const b = parrot_hash_get_bucket(interp, hash, pmc);
+        if (b) {
+            id = (UINTVAL) b->value;
+            packid_type = enum_PackID_seen;
+        }
+        else {
+            info->id++; /* next id to freeze */
+            id = info->id;
+            packid_type = enum_PackID_normal;
         }
-
-        /* else maybe VTABLE_thaw ... but there is no other extra stuff */
-
-        PARROT_ASSERT(must_have_seen);
-
-        *info->thaw_ptr = pmc;
-        return;
-    }
-
-    PARROT_ASSERT(!must_have_seen);
-    pmc = thaw_create_pmc(interp, info, type);
-
-    VTABLE_thaw(interp, pmc, info);
-
-    if (info->extra_flags == EXTRA_CLASS_EXISTS) {
-        pmc               = (PMC *)info->extra;
-        info->extra       = NULL;
-        info->extra_flags = 0;
-    }
-
-    if (!info->thaw_result)
-        info->thaw_result = pmc;
-    else
-        *info->thaw_ptr = pmc;
-
-
-    Parrot_pmc_array_assign(interp, (List *)PMC_data(info->id_list), id, pmc, enum_type_PMC);
-
-    /* remember nested aggregates depth first */
-    Parrot_pmc_array_unshift(interp, (List *)PMC_data(info->todo), pmc, enum_type_PMC);
-}
-
-/*
-
-=item C<static int todo_list_seen(PARROT_INTERP, PMC *pmc, visit_info *info,
-UINTVAL *id)>
-
-Returns true if the PMC was seen, otherwise it put it on the todo list.
-Generates an ID (tag) for PMC, offset by 4 as are addresses.  Low bits are
-flags.
-
-=cut
-
-*/
-
-PARROT_INLINE
-static int
-todo_list_seen(PARROT_INTERP, ARGIN(PMC *pmc), ARGMOD(visit_info *info),
-        ARGOUT(UINTVAL *id))
-{
-    ASSERT_ARGS(todo_list_seen)
-    HashBucket * const b =
-        parrot_hash_get_bucket(interp,
-                (Hash *)VTABLE_get_pointer(interp, info->seen), pmc);
-
-    if (b) {
-        *id = (UINTVAL) b->value;
-        return 1;
     }
 
-    /* next id to freeze */
-    info->id++;
-    *id = PackID_new(info->id, enum_PackID_normal);
-
-    parrot_hash_put(interp,
-            (Hash *)VTABLE_get_pointer(interp, info->seen), pmc, (void *)*id);
-
-    /* remember containers */
-    Parrot_pmc_array_unshift(interp, (List *)PMC_data(info->todo), pmc, enum_type_PMC);
-
-    return 0;
-}
-
-
-/*
-
-=item C<static void visit_todo_list(PARROT_INTERP, PMC* pmc, visit_info* info)>
-
-Checks the seen PMC via the todo list.
+    VTABLE_push_integer(interp, info, PackID_new(id, packid_type));
 
-=cut
-
-*/
-
-static void
-visit_todo_list(PARROT_INTERP, ARGIN_NULLOK(PMC* pmc), ARGIN(visit_info* info))
-{
-    ASSERT_ARGS(visit_todo_list)
-    int     seen;
-    UINTVAL id = 0;
-
-    if (PMC_IS_NULL(pmc)) {
-        seen = 1;
-        id   = 0;
+    if (packid_type == enum_PackID_normal) {
+        Hash *hash = (Hash *)VTABLE_get_pointer(interp, info->seen);
+        PARROT_ASSERT(pmc);
+        VTABLE_push_integer(interp, info,
+                PObj_is_object_TEST(pmc) ? enum_class_Object : pmc->vtable->base_type);
+        parrot_hash_put(interp, hash, pmc, (void *)id);
+        Parrot_pmc_array_unshift(interp, (List *)PMC_data(info->todo), pmc, enum_type_PMC);
+        VTABLE_freeze(interp, pmc, info);
     }
-    else
-        seen = todo_list_seen(interp, pmc, info, &id);
-
-    do_action(interp, pmc, info, seen, id);
-
-    if (!seen)
-        (info->visit_action)(interp, pmc, info);
-}
-
-
-/*
-
-=item C<static void visit_todo_list_thaw(PARROT_INTERP, PMC* old, visit_info*
-info)>
-
-Callback for thaw - action first.
-
-Todo-list and seen handling is all in C<do_thaw()>.
-
-=cut
-
-*/
-
-static void
-visit_todo_list_thaw(PARROT_INTERP, ARGIN_NULLOK(PMC* old), ARGIN(visit_info* info))
-{
-    ASSERT_ARGS(visit_todo_list_thaw)
-    do_thaw(interp, old, info);
 }
 
 
@@ -976,59 +696,34 @@
 {
     ASSERT_ARGS(visit_loop_todo_list)
     PMC        **list_item;
-    List        *finish_list    = NULL;
     List * const todo           = (List *)PMC_data(info->todo);
-    int          finished_first = 0;
-    const int    thawing        = info->what == VISIT_THAW_CONSTANTS
-                               || info->what == VISIT_THAW_NORMAL;
-    int          i;
-
-    /* create a list that contains PMCs that need thawfinish */
-    if (thawing) {
-        PMC * const finish_list_pmc = pmc_new(interp, enum_class_Array);
-        finish_list                 = (List *)PMC_data(finish_list_pmc);
-    }
+    const int    thawing        = info->what == VISIT_THAW_NORMAL;
 
     (info->visit_pmc_now)(interp, current, info);
 
     /* can't cache upper limit, visit may append items */
-again:
     while ((list_item = (PMC **)Parrot_pmc_array_shift(interp, todo, enum_type_PMC))) {
         current = *list_item;
         if (!current)
             Parrot_ex_throw_from_c_args(interp, NULL, 1,
-                "NULL current PMC in visit_loop_todo_list");
+                    "NULL current PMC in visit_loop_todo_list");
 
         PARROT_ASSERT(current->vtable);
 
-        /* Workaround for thawing constants. Clear constant flag */
-        /* See src/packfile.c:3999 */
-        if (thawing)
-            PObj_constant_CLEAR(current);
-
         VTABLE_visit(interp, current, info);
 
-        if (thawing) {
-            if (current == info->thaw_result)
-                finished_first = 1;
-            if (current->vtable->thawfinish != interp->vtables[enum_class_default]->thawfinish)
-                Parrot_pmc_array_unshift(interp, finish_list, current, enum_type_PMC);
-        }
+        VISIT_PMC(interp, info, PMC_metadata(current));
     }
 
-    if (thawing) {
-        INTVAL n;
-        /* if image isn't consumed, there are some extra data to thaw */
-        if (info->image->bufused > 0) {
-            (info->visit_pmc_now)(interp, NULL, info);
-            goto again;
-        }
+    if (thawing)
+        /* we're done reading the image */
+        PARROT_ASSERT(!INFO_HAS_DATA(info));
 
+    if (thawing) {
         /* on thawing call thawfinish for each processed PMC */
-        if (!finished_first)
-            Parrot_pmc_array_unshift(interp, finish_list, info->thaw_result, enum_type_PMC);
-
-        n = Parrot_pmc_array_length(interp, finish_list);
+        List        *finish_list = (List *)PMC_data(info->id_list);
+        const INTVAL n           = Parrot_pmc_array_length(interp, finish_list);
+        int          i;
 
         for (i = 0; i < n ; ++i) {
             current = *(PMC**)Parrot_pmc_array_get(interp, finish_list, i, enum_type_PMC);
@@ -1041,18 +736,18 @@
 
 /*
 
-=item C<static void create_image(PARROT_INTERP, PMC *pmc, visit_info *info)>
+=item C<static void create_buffer(PARROT_INTERP, PMC *pmc, visit_info *info)>
 
-Allocate image to some estimated size.
+Allocate buffer to some estimated size.
 
 =cut
 
 */
 
 static void
-create_image(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), ARGMOD(visit_info *info))
+create_buffer(PARROT_INTERP, ARGIN_NULLOK(PMC *pmc), ARGMOD(visit_info *info))
 {
-    ASSERT_ARGS(create_image)
+    ASSERT_ARGS(create_buffer)
     STRING *array = CONST_STRING(interp, "array");
     STRING *hash  = CONST_STRING(interp, "hash");
     INTVAL  len;
@@ -1061,91 +756,14 @@
     && (VTABLE_does(interp, pmc, array) || VTABLE_does(interp, pmc, hash))) {
         const INTVAL items = VTABLE_elements(interp, pmc);
         /* TODO check e.g. first item of aggregate and estimate size */
-        len = items * FREEZE_BYTES_PER_ITEM;
+        len = (items ? items : 1) * FREEZE_BYTES_PER_ITEM;
     }
     else
         len = FREEZE_BYTES_PER_ITEM;
 
-    info->image = Parrot_str_new_init(interp, NULL, len,
-         Parrot_fixed_8_encoding_ptr, Parrot_binary_charset_ptr, 0);
-}
-
-
-/*
-
-=item C<static PMC* run_thaw(PARROT_INTERP, STRING* image, visit_enum_type
-what)>
-
-Performs thawing. C<what> indicates what to be thawed.
-
-For now it seems cheaper to use a list for remembering contained
-aggregates. We could of course decide dynamically, which strategy to
-use, e.g.: given a big image, the first thawed item is a small
-aggregate. This implies, it probably contains (or some big strings) more
-nested containers, for which another approach could be a win.
-
-=cut
-
-*/
-
-PARROT_WARN_UNUSED_RESULT
-PARROT_CAN_RETURN_NULL
-static PMC*
-run_thaw(PARROT_INTERP, ARGIN(STRING* image), visit_enum_type what)
-{
-    ASSERT_ARGS(run_thaw)
-    visit_info    info;
-    int           gc_block = 0;
-    const UINTVAL bufused  = image->bufused;
-
-    info.image = image;
-    /*
-     * if we are thawing a lot of PMCs, it's cheaper to do
-     * a GC run first and then block GC - the limit should be
-     * chosen so that no more then one GC run would be triggered
-     *
-     * XXX
-     *
-     * md5_3.pir shows a segfault during thawing the config hash
-     * info->thaw_ptr becomes invalid - seems that the hash got
-     * collected under us.
-     */
-    if (1 || (Parrot_str_byte_length(interp, image) > THAW_BLOCK_GC_SIZE)) {
-        Parrot_block_GC_mark(interp);
-        Parrot_block_GC_sweep(interp);
-        gc_block = 1;
-    }
-
-    /* _NORMAL or _CONSTANTS */
-    info.what = what;
-
-    todo_list_init(interp, &info);
-    info.visit_pmc_now   = visit_todo_list_thaw;
-
-    info.thaw_result = NULL;
-
-    /* run thaw loop */
-    visit_loop_todo_list(interp, NULL, &info);
-
-    /*
-     * thaw consumes the image string by incrementing strstart
-     * and decrementing bufused - restore that
-     */
-    LVALUE_CAST(char *, image->strstart) -= bufused;
-    image->bufused = bufused;
-    image->strlen += bufused;
-
-    PARROT_ASSERT(image->strstart >= (char *)Buffer_bufstart(image));
-
-    if (gc_block) {
-        Parrot_unblock_GC_mark(interp);
-        Parrot_unblock_GC_sweep(interp);
-    }
-
-    PackFile_destroy(interp, info.image_io->pf);
-    mem_sys_free(info.image_io);
-    info.image_io = NULL;
-    return info.thaw_result;
+    info->buffer = (Buffer *)Parrot_gc_new_bufferlike_header(interp, sizeof (Buffer));
+    Parrot_gc_allocate_buffer_storage_aligned(interp, info->buffer, len);
+    SET_VISIT_CURSOR(info, Buffer_bufstart(info->buffer));
 }
 
 
@@ -1172,22 +790,10 @@
 Parrot_freeze(PARROT_INTERP, ARGIN(PMC *pmc))
 {
     ASSERT_ARGS(Parrot_freeze)
-    /*
-     * freeze using a todo list and seen hash
-     * Please note that both have to be PMCs, so that trace_system_stack
-     * can call mark on the PMCs
-     */
     visit_info info;
 
-    info.what = VISIT_FREEZE_NORMAL;
-    create_image(interp, pmc, &info);
-    todo_list_init(interp, &info);
-
-    visit_loop_todo_list(interp, pmc, &info);
-
-    PackFile_destroy(interp, info.image_io->pf);
-    mem_sys_free(info.image_io);
-    return info.image;
+    visit_info_init(interp, &info, VISIT_FREEZE_NORMAL, STRINGNULL, pmc);
+    return Parrot_str_new_from_buffer(interp, info.buffer, OUTPUT_LENGTH(&info));
 }
 
 
@@ -1197,6 +803,12 @@
 
 Thaws a PMC.  Called from the C<thaw> opcode.
 
+For now it seems cheaper to use a list for remembering contained
+aggregates. We could of course decide dynamically, which strategy to
+use, e.g.: given a big image, the first thawed item is a small
+aggregate. This implies, it probably contains (or some big strings) more
+nested containers, for which another approach could be a win.
+
 =cut
 
 */
@@ -1208,7 +820,38 @@
 Parrot_thaw(PARROT_INTERP, ARGIN(STRING *image))
 {
     ASSERT_ARGS(Parrot_thaw)
-    return run_thaw(interp, image, VISIT_THAW_NORMAL);
+
+    visit_info  info;
+    int         gc_block = 0;
+    PMC        *result;
+
+    /*
+     * if we are thawing a lot of PMCs, it's cheaper to do
+     * a GC run first and then block GC - the limit should be
+     * chosen so that no more then one GC run would be triggered
+     *
+     * XXX
+     *
+     * md5_3.pir shows a segfault during thawing the config hash
+     * info->thaw_ptr becomes invalid - seems that the hash got
+     * collected under us.
+     */
+    if (1 || (Parrot_str_byte_length(interp, image) > THAW_BLOCK_GC_SIZE)) {
+        Parrot_block_GC_mark(interp);
+        Parrot_block_GC_sweep(interp);
+        gc_block = 1;
+    }
+
+    info.thaw_ptr = &result;
+    visit_info_init(interp, &info, VISIT_THAW_NORMAL, image, PMCNULL);
+    BYTECODE_SHIFT_OK(&info);
+
+    if (gc_block) {
+        Parrot_unblock_GC_mark(interp);
+        Parrot_unblock_GC_sweep(interp);
+    }
+
+    return result;
 }
 
 
@@ -1217,6 +860,7 @@
 =item C<PMC* Parrot_thaw_constants(PARROT_INTERP, STRING *image)>
 
 Thaws constants, used by PackFile for unpacking PMC constants.
+This is a lie. It does nothing different from Parrot_thaw at the moment.
 
 =cut
 
@@ -1229,7 +873,7 @@
 Parrot_thaw_constants(PARROT_INTERP, ARGIN(STRING *image))
 {
     ASSERT_ARGS(Parrot_thaw_constants)
-    return run_thaw(interp, image, VISIT_THAW_CONSTANTS);
+    return Parrot_thaw(interp, image);
 }
 
 

Modified: trunk/src/string/api.c
==============================================================================
--- trunk/src/string/api.c	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/src/string/api.c	Wed Jan 13 01:38:58 2010	(r43434)
@@ -648,6 +648,45 @@
                                      point? */
 }
 
+
+/*
+
+=item C<STRING * Parrot_str_new_from_buffer(PARROT_INTERP, Buffer *buffer, const
+UINTVAL len)>
+
+Make a Parrot string from a Buffer.
+
+The Buffer is nulled afterwards - only one PObj can point at a given string pool object.
+
+=cut
+
+*/
+
+PARROT_EXPORT
+PARROT_WARN_UNUSED_RESULT
+PARROT_MALLOC
+PARROT_CANNOT_RETURN_NULL
+STRING *
+Parrot_str_new_from_buffer(PARROT_INTERP, ARGMOD(Buffer *buffer), const UINTVAL len)
+{
+    ASSERT_ARGS(Parrot_str_new_from_buffer)
+    STRING *result;
+
+    result = Parrot_gc_new_string_header(interp, 0);
+    Buffer_bufstart(result) = Buffer_bufstart(buffer);
+    Buffer_buflen(result)   = Buffer_buflen(buffer);
+    result->strstart        = (char *) Buffer_bufstart(result);
+    result->bufused         = len;
+    result->strlen          = len;
+    result->encoding        = Parrot_fixed_8_encoding_ptr;
+    result->charset         = Parrot_binary_charset_ptr;
+
+    Buffer_bufstart(buffer) = NULL;
+    Buffer_buflen(buffer)   = 0;
+
+    return result;
+}
+
 /*
 
 =item C<const char* string_primary_encoding_for_representation(PARROT_INTERP,

Modified: trunk/t/pmc/eval.t
==============================================================================
--- trunk/t/pmc/eval.t	Tue Jan 12 19:47:47 2010	(r43433)
+++ trunk/t/pmc/eval.t	Wed Jan 13 01:38:58 2010	(r43434)
@@ -394,7 +394,8 @@
 written
 OUTPUT
 
-pir_output_is( <<"CODE", <<'OUTPUT', "eval.thaw" );
+TODO: {
+pir_output_is( <<"CODE", <<'OUTPUT', "eval.thaw", todo => 'TT #1142 not yet fixed' );
 .sub main :main
     .local pmc io, e
     .local string file
@@ -414,6 +415,7 @@
 hello from foo_1
 hello from foo_1
 OUTPUT
+}
 
 pir_output_is( <<"CODE", <<'OUTPUT', "eval.freeze+thaw" );
 .sub main :main


More information about the parrot-commits mailing list