2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/pmc_freeze.c - Freeze and thaw functionality
11 Thawing PMCs uses a list with (maximum) size of the amount of PMCs to
12 keep track of retrieved PMCs.
14 The individual information of PMCs is frozen/thawed by their vtables.
16 To avoid recursion, the whole functionality is driven by
17 C<< pmc->vtable->visit >>, which is called for the first PMC initially.
18 Container PMCs call a "todo-callback" for all contained PMCs. The
19 individual action vtable (freeze/thaw) is then called for all todo-PMCs.
25 #include "parrot/parrot.h"
26 #include "pmc/pmc_callcontext.h"
27 #include "pmc_freeze.str"
29 /* when thawing a string longer then this size, we first do a GC run and then
30 * block GC - the system can't give us more headers */
32 #define THAW_BLOCK_GC_SIZE 100000
34 /* HEADERIZER HFILE: include/parrot/pmc_freeze.h */
38 =head2 Public Interface
42 =item C<STRING* Parrot_freeze(PARROT_INTERP, PMC *pmc)>
44 Freeze using either method.
51 PARROT_WARN_UNUSED_RESULT
52 PARROT_CAN_RETURN_NULL
54 Parrot_freeze(PARROT_INTERP
, ARGIN(PMC
*pmc
))
56 ASSERT_ARGS(Parrot_freeze
)
57 PMC
*image
= Parrot_pmc_new(interp
, enum_class_ImageIO
);
58 VTABLE_set_pmc(interp
, image
, pmc
);
59 return VTABLE_get_string(interp
, image
);
64 =item C<UINTVAL Parrot_freeze_size(PARROT_INTERP, PMC *pmc)>
66 Get the size of an image to be frozen without allocating a large buffer.
68 Used in C<Packfile_Constant_pack_size>.
75 PARROT_WARN_UNUSED_RESULT
76 PARROT_CAN_RETURN_NULL
78 Parrot_freeze_size(PARROT_INTERP
, ARGIN(PMC
*pmc
))
80 ASSERT_ARGS(Parrot_freeze_size
)
83 PMC
*visitor
= Parrot_pmc_new(interp
, enum_class_ImageIOSize
);
84 VTABLE_set_pmc(interp
, visitor
, pmc
);
85 pmc_result
= VTABLE_get_pmc(interp
, visitor
);
86 int_result
= VTABLE_get_integer(interp
, pmc_result
);
93 =item C<PMC* Parrot_thaw(PARROT_INTERP, STRING *image)>
95 Thaws a PMC. Called from the C<thaw> opcode.
97 For now it seems cheaper to use a list for remembering contained
98 aggregates. We could of course decide dynamically, which strategy to
99 use, e.g.: given a big image, the first thawed item is a small
100 aggregate. This implies, it probably contains (or some big strings) more
101 nested containers, for which another approach could be a win.
108 PARROT_WARN_UNUSED_RESULT
109 PARROT_CAN_RETURN_NULL
111 Parrot_thaw(PARROT_INTERP
, ARGIN(STRING
*image
))
113 ASSERT_ARGS(Parrot_thaw
)
115 PMC
*info
= Parrot_pmc_new(interp
, enum_class_ImageIO
);
120 * if we are thawing a lot of PMCs, it's cheaper to do
121 * a GC run first and then block GC - the limit should be
122 * chosen so that no more then one GC run would be triggered
126 * md5_3.pir shows a segfault during thawing the config hash
127 * info->thaw_ptr becomes invalid - seems that the hash got
128 * collected under us.
130 if (1 || (Parrot_str_byte_length(interp
, image
) > THAW_BLOCK_GC_SIZE
)) {
131 Parrot_block_GC_mark(interp
);
132 Parrot_block_GC_sweep(interp
);
136 VTABLE_set_string_native(interp
, info
, image
);
137 result
= VTABLE_get_pmc(interp
, info
);
140 Parrot_unblock_GC_mark(interp
);
141 Parrot_unblock_GC_sweep(interp
);
150 =item C<PMC* Parrot_thaw_constants(PARROT_INTERP, STRING *image)>
152 Thaws constants, used by PackFile for unpacking PMC constants.
153 This is a lie. It does nothing different from Parrot_thaw at the moment.
160 PARROT_WARN_UNUSED_RESULT
161 PARROT_CAN_RETURN_NULL
163 Parrot_thaw_constants(PARROT_INTERP
, ARGIN(STRING
*image
))
165 ASSERT_ARGS(Parrot_thaw_constants
)
166 return Parrot_thaw(interp
, image
);
172 =item C<PMC* Parrot_clone(PARROT_INTERP, PMC *pmc)>
174 There are for sure shortcuts to clone faster, e.g. always thaw the image
175 immediately or use a special callback. For now we just thaw a frozen PMC.
182 PARROT_WARN_UNUSED_RESULT
183 PARROT_CAN_RETURN_NULL
185 Parrot_clone(PARROT_INTERP
, ARGIN(PMC
*pmc
))
187 ASSERT_ARGS(Parrot_clone
)
188 return VTABLE_clone(interp
, pmc
);
193 =item C<void Parrot_visit_loop_visit(PARROT_INTERP, PMC *info)>
195 Iterate a visitor PMC visiting each encountered target PMC.
202 Parrot_visit_loop_visit(PARROT_INTERP
, ARGIN(PMC
*info
)) {
203 ASSERT_ARGS(Parrot_visit_loop_visit
)
206 PMC
* const todo
= VTABLE_get_iter(interp
, info
);
208 /* can't cache upper limit, visit may append items */
209 for (i
= 0; i
< VTABLE_elements(interp
, todo
); i
++) {
210 PMC
*current
= VTABLE_get_pmc_keyed_int(interp
, todo
, i
);
212 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
213 "NULL current PMC in visit_loop_todo_list");
215 PARROT_ASSERT(current
->vtable
);
217 VTABLE_visit(interp
, current
, info
);
219 VISIT_PMC(interp
, info
, PMC_metadata(current
));
225 =item C<void Parrot_visit_loop_thawfinish(PARROT_INTERP, PMC *info)>
227 Iterate a visitor PMC thawfinishing each encountered target PMC.
234 Parrot_visit_loop_thawfinish(PARROT_INTERP
, ARGIN(PMC
*info
)) {
235 ASSERT_ARGS(Parrot_visit_loop_thawfinish
)
237 /* call thawfinish for each processed PMC */
239 * Thaw in reverse order. We have to fully thaw younger PMCs
240 * before use them in older.
242 * XXX There are no younger or older pmcs in a directed graph
243 * that allows cycles. Any code that requires a specific
244 * order here is likely broken.
247 PMC
* const todo
= VTABLE_get_iter(interp
, info
);
248 const INTVAL n
= VTABLE_elements(interp
, todo
);
251 for (i
= n
-1; i
>= 0; --i
) {
252 PMC
*current
= VTABLE_get_pmc_keyed_int(interp
, todo
, i
);
253 if (!PMC_IS_NULL(current
))
254 VTABLE_thawfinish(interp
, current
, info
);
264 The seen-hash version for freezing might go away sometime.
268 Lot of discussion on p6i and F<docs/dev/pmc_freeze.pod>.
272 Initial version by leo 2003.11.03 - 2003.11.07.
281 * c-file-style: "parrot"
283 * vim: expandtab shiftwidth=4: