2 Copyright (C) 2001-2010, 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_CANNOT_RETURN_NULL
54 Parrot_freeze(PARROT_INTERP
, ARGIN(PMC
*pmc
))
56 ASSERT_ARGS(Parrot_freeze
)
57 PMC
* const 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<STRING * Parrot_freeze_pbc(PARROT_INTERP, PMC *pmc, const
65 PackFile_ConstTable *pf)>
74 PARROT_WARN_UNUSED_RESULT
75 PARROT_CAN_RETURN_NULL
77 Parrot_freeze_pbc(PARROT_INTERP
, ARGIN(PMC
*pmc
), ARGIN(const PackFile_ConstTable
*pf
))
79 ASSERT_ARGS(Parrot_freeze_pbc
)
82 PMC
* const pf_pmc
= Parrot_pmc_new(interp
, enum_class_UnManagedStruct
);
83 VTABLE_set_pointer(interp
, pf_pmc
, (void *)pf
);
85 visitor
= Parrot_pmc_new_init(interp
, enum_class_ImageIO
, pf_pmc
);
86 VTABLE_set_pmc(interp
, visitor
, pmc
);
88 return VTABLE_get_string(interp
, visitor
);
94 =item C<UINTVAL Parrot_freeze_size(PARROT_INTERP, PMC *pmc)>
96 Get the size of an image to be frozen without allocating a large buffer.
103 PARROT_WARN_UNUSED_RESULT
105 Parrot_freeze_size(PARROT_INTERP
, ARGIN(PMC
*pmc
))
107 ASSERT_ARGS(Parrot_freeze_size
)
110 PMC
* const visitor
= Parrot_pmc_new(interp
, enum_class_ImageIOSize
);
111 VTABLE_set_pmc(interp
, visitor
, pmc
);
112 pmc_result
= VTABLE_get_pmc(interp
, visitor
);
113 int_result
= VTABLE_get_integer(interp
, pmc_result
);
119 =item C<UINTVAL Parrot_freeze_pbc_size(PARROT_INTERP, PMC *pmc, const
120 PackFile_ConstTable *pf)>
122 Get the size of an image if it were created using C<Parrot_freeze_pbc>.
129 PARROT_WARN_UNUSED_RESULT
131 Parrot_freeze_pbc_size(PARROT_INTERP
, ARGIN(PMC
*pmc
), ARGIN(const PackFile_ConstTable
*pf
))
133 ASSERT_ARGS(Parrot_freeze_pbc_size
)
134 PMC
*pf_pmc
, *visitor
, *pmc_result
;
136 pf_pmc
= Parrot_pmc_new(interp
, enum_class_UnManagedStruct
);
137 VTABLE_set_pointer(interp
, pf_pmc
, (void *)pf
);
139 visitor
= Parrot_pmc_new_init(interp
, enum_class_ImageIOSize
, pf_pmc
);
140 VTABLE_set_pmc(interp
, visitor
, pmc
);
142 pmc_result
= VTABLE_get_pmc(interp
, visitor
);
143 return VTABLE_get_integer(interp
, pmc_result
);
149 =item C<PMC * Parrot_freeze_strings(PARROT_INTERP, PMC *pmc)>
151 Get the strings of a PMC to be frozen.
158 PARROT_WARN_UNUSED_RESULT
159 PARROT_CANNOT_RETURN_NULL
161 Parrot_freeze_strings(PARROT_INTERP
, ARGIN(PMC
*pmc
))
163 ASSERT_ARGS(Parrot_freeze_strings
)
164 PMC
* const visitor
= Parrot_pmc_new(interp
, enum_class_ImageIOStrings
);
165 VTABLE_set_pmc(interp
, visitor
, pmc
);
166 return VTABLE_get_pmc(interp
, visitor
);
172 =item C<PMC* Parrot_thaw(PARROT_INTERP, STRING *image)>
174 Thaws a PMC. Called from the C<thaw> opcode.
176 For now it seems cheaper to use a list for remembering contained
177 aggregates. We could of course decide dynamically, which strategy to
178 use, e.g.: given a big image, the first thawed item is a small
179 aggregate. This implies, it probably contains (or some big strings) more
180 nested containers, for which another approach could be a win.
187 PARROT_WARN_UNUSED_RESULT
188 PARROT_CANNOT_RETURN_NULL
190 Parrot_thaw(PARROT_INTERP
, ARGIN(STRING
*image
))
192 ASSERT_ARGS(Parrot_thaw
)
194 PMC
* const info
= Parrot_pmc_new(interp
, enum_class_ImageIO
);
199 * if we are thawing a lot of PMCs, it's cheaper to do
200 * a GC run first and then block GC - the limit should be
201 * chosen so that no more then one GC run would be triggered
205 * md5_3.pir shows a segfault during thawing the config hash
206 * info->thaw_ptr becomes invalid - seems that the hash got
207 * collected under us.
209 if (1 || (Parrot_str_byte_length(interp
, image
) > THAW_BLOCK_GC_SIZE
)) {
210 Parrot_block_GC_mark(interp
);
211 Parrot_block_GC_sweep(interp
);
215 VTABLE_set_string_native(interp
, info
, image
);
216 result
= VTABLE_get_pmc(interp
, info
);
219 Parrot_unblock_GC_mark(interp
);
220 Parrot_unblock_GC_sweep(interp
);
229 =item C<PMC* Parrot_thaw_pbc(PARROT_INTERP, STRING *image, PackFile_ConstTable
232 Thaw a pmc frozen by Parrot_freeze_pbc.
239 PARROT_WARN_UNUSED_RESULT
240 PARROT_CAN_RETURN_NULL
242 Parrot_thaw_pbc(PARROT_INTERP
, ARGIN(STRING
*image
), ARGIN(PackFile_ConstTable
*pf
))
244 ASSERT_ARGS(Parrot_thaw_pbc
)
245 PMC
*info
, *pf_pmc
, *result
;
247 pf_pmc
= Parrot_pmc_new(interp
, enum_class_UnManagedStruct
);
248 VTABLE_set_pointer(interp
, pf_pmc
, pf
);
250 info
= Parrot_pmc_new_init(interp
, enum_class_ImageIO
, pf_pmc
);
253 * Find out what broken code depends on blocking GC here and fix it, regardless of performance
256 Parrot_block_GC_mark(interp
);
257 Parrot_block_GC_sweep(interp
);
259 VTABLE_set_string_native(interp
, info
, image
);
260 result
= VTABLE_get_pmc(interp
, info
);
262 Parrot_unblock_GC_mark(interp
);
263 Parrot_unblock_GC_sweep(interp
);
270 =item C<PMC* Parrot_thaw_constants(PARROT_INTERP, STRING *image)>
272 Thaws constants, used by PackFile for unpacking PMC constants.
273 This is a lie. It does nothing different from Parrot_thaw at the moment.
280 PARROT_WARN_UNUSED_RESULT
281 PARROT_CANNOT_RETURN_NULL
283 Parrot_thaw_constants(PARROT_INTERP
, ARGIN(STRING
*image
))
285 ASSERT_ARGS(Parrot_thaw_constants
)
286 return Parrot_thaw(interp
, image
);
292 =item C<PMC* Parrot_clone(PARROT_INTERP, PMC *pmc)>
294 There are for sure shortcuts to clone faster, e.g. always thaw the image
295 immediately or use a special callback. For now we just thaw a frozen PMC.
302 PARROT_WARN_UNUSED_RESULT
303 PARROT_CAN_RETURN_NULL
305 Parrot_clone(PARROT_INTERP
, ARGIN(PMC
*pmc
))
307 ASSERT_ARGS(Parrot_clone
)
308 return VTABLE_clone(interp
, pmc
);
313 =item C<void Parrot_visit_loop_visit(PARROT_INTERP, PMC *info)>
315 Iterate a visitor PMC visiting each encountered target PMC.
322 Parrot_visit_loop_visit(PARROT_INTERP
, ARGIN(PMC
*info
))
324 ASSERT_ARGS(Parrot_visit_loop_visit
)
327 const INTVAL action
= VTABLE_get_integer(interp
, info
);
328 PMC
* const todo
= VTABLE_get_iter(interp
, info
);
330 /* can't cache upper limit, visit may append items */
331 for (i
= 0; i
< VTABLE_elements(interp
, todo
); ++i
) {
332 PMC
* const current
= VTABLE_get_pmc_keyed_int(interp
, todo
, i
);
334 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
335 "NULL current PMC in visit_loop_todo_list");
337 PARROT_ASSERT(current
->vtable
);
339 if (action
== VISIT_FREEZE_NORMAL
)
340 VTABLE_freeze(interp
, current
, info
);
342 VTABLE_thaw(interp
, current
, info
);
344 VTABLE_visit(interp
, current
, info
);
346 VISIT_PMC(interp
, info
, PMC_metadata(current
));
352 =item C<void Parrot_visit_loop_thawfinish(PARROT_INTERP, PMC *info)>
354 Iterate a visitor PMC thawfinishing each encountered target PMC.
361 Parrot_visit_loop_thawfinish(PARROT_INTERP
, ARGIN(PMC
*info
))
363 ASSERT_ARGS(Parrot_visit_loop_thawfinish
)
365 /* call thawfinish for each processed PMC */
367 * Thaw in reverse order. We have to fully thaw younger PMCs
368 * before use them in older.
370 * XXX There are no younger or older pmcs in a directed graph
371 * that allows cycles. Any code that requires a specific
372 * order here is likely broken.
375 PMC
* const todo
= VTABLE_get_iter(interp
, info
);
376 const INTVAL n
= VTABLE_elements(interp
, todo
);
379 for (i
= n
-1; i
>= 0; --i
) {
380 PMC
*current
= VTABLE_get_pmc_keyed_int(interp
, todo
, i
);
381 if (!PMC_IS_NULL(current
))
382 VTABLE_thawfinish(interp
, current
, info
);
392 The seen-hash version for freezing might go away sometime.
396 Lot of discussion on p6i and F<docs/dev/pmc_freeze.pod>.
405 * c-file-style: "parrot"
407 * vim: expandtab shiftwidth=4: