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 PMCs freeze and thaw their own information through 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
);
65 =item C<opcode_t * Parrot_freeze_pbc(PARROT_INTERP, PMC *pmc, const
66 PackFile_ConstTable *pf, opcode_t *cursor)>
68 Freezes a PMC to a PackFile.
75 PARROT_WARN_UNUSED_RESULT
76 PARROT_CAN_RETURN_NULL
78 Parrot_freeze_pbc(PARROT_INTERP
, ARGIN(PMC
*pmc
), ARGIN(const PackFile_ConstTable
*pf
),
79 ARGIN(opcode_t
*cursor
))
81 ASSERT_ARGS(Parrot_freeze_pbc
)
86 visitor
= Parrot_pmc_new(interp
, enum_class_ImageIO
);
87 VTABLE_set_pointer(interp
, visitor
,
88 PARROT_const_cast(void *, (const void *)pf
));
89 VTABLE_set_pmc(interp
, visitor
, pmc
);
91 image
= VTABLE_get_string(interp
, visitor
);
92 cursor
= PF_store_buf(cursor
, image
);
100 =item C<UINTVAL Parrot_freeze_size(PARROT_INTERP, PMC *pmc)>
102 Gets the size of an image to be frozen without allocating a large buffer.
109 PARROT_WARN_UNUSED_RESULT
111 Parrot_freeze_size(PARROT_INTERP
, ARGIN(PMC
*pmc
))
113 ASSERT_ARGS(Parrot_freeze_size
)
115 PMC
* const visitor
= Parrot_pmc_new(interp
, enum_class_ImageIOSize
);
116 VTABLE_set_pmc(interp
, visitor
, pmc
);
117 pmc_result
= VTABLE_get_pmc(interp
, visitor
);
119 return VTABLE_get_integer(interp
, pmc_result
);
125 =item C<UINTVAL Parrot_freeze_pbc_size(PARROT_INTERP, PMC *pmc, const
126 PackFile_ConstTable *pf)>
128 Gets the size of an image if it were created using C<Parrot_freeze_pbc>.
135 PARROT_WARN_UNUSED_RESULT
137 Parrot_freeze_pbc_size(PARROT_INTERP
, ARGIN(PMC
*pmc
), ARGIN(const PackFile_ConstTable
*pf
))
139 ASSERT_ARGS(Parrot_freeze_pbc_size
)
140 PMC
*pf_pmc
= Parrot_pmc_new(interp
, enum_class_UnManagedStruct
);
141 PMC
*visitor
, *pmc_result
;
144 VTABLE_set_pointer(interp
, pf_pmc
,
145 PARROT_const_cast(void *, (const void *)pf
));
147 visitor
= Parrot_pmc_new_init(interp
, enum_class_ImageIOSize
, pf_pmc
);
148 VTABLE_set_pmc(interp
, visitor
, pmc
);
150 pmc_result
= VTABLE_get_pmc(interp
, visitor
);
151 return VTABLE_get_integer(interp
, pmc_result
);
157 =item C<PMC * Parrot_freeze_strings(PARROT_INTERP, PMC *pmc)>
159 Gets the strings of a PMC to be frozen.
166 PARROT_WARN_UNUSED_RESULT
167 PARROT_CANNOT_RETURN_NULL
169 Parrot_freeze_strings(PARROT_INTERP
, ARGIN(PMC
*pmc
))
171 ASSERT_ARGS(Parrot_freeze_strings
)
172 PMC
* const visitor
= Parrot_pmc_new(interp
, enum_class_ImageIOStrings
);
173 VTABLE_set_pmc(interp
, visitor
, pmc
);
174 return VTABLE_get_pmc(interp
, visitor
);
180 =item C<PMC * Parrot_thaw(PARROT_INTERP, STRING *image)>
182 Thaws a PMC. Called from the C<thaw> opcode.
184 For now it seems cheaper to use a list for remembering contained aggregates. We
185 could of course decide dynamically, which strategy to use: given a big image,
186 the first thawed item is a small aggregate. This implies it probably contains
187 more nested containers, for which another approach could be a win.
194 PARROT_WARN_UNUSED_RESULT
195 PARROT_CANNOT_RETURN_NULL
197 Parrot_thaw(PARROT_INTERP
, ARGIN(STRING
*image
))
199 ASSERT_ARGS(Parrot_thaw
)
202 PMC
* const info
= Parrot_pmc_new(interp
, enum_class_ImageIO
);
206 * if we are thawing a lot of PMCs, it's cheaper to do
207 * a GC run first and then block GC - the limit should be
208 * chosen so that no more then one GC run would be triggered
212 * md5_3.pir shows a segfault during thawing the config hash
213 * info->thaw_ptr becomes invalid - seems that the hash got
214 * collected under us.
216 if (1 || (Parrot_str_byte_length(interp
, image
) > THAW_BLOCK_GC_SIZE
)) {
217 Parrot_block_GC_mark(interp
);
218 Parrot_block_GC_sweep(interp
);
222 VTABLE_set_string_native(interp
, info
, image
);
223 result
= VTABLE_get_pmc(interp
, info
);
226 Parrot_unblock_GC_mark(interp
);
227 Parrot_unblock_GC_sweep(interp
);
236 =item C<PMC* Parrot_thaw_pbc(PARROT_INTERP, PackFile_ConstTable *ct, const
239 Thaw a pmc frozen by Parrot_freeze_pbc.
246 PARROT_WARN_UNUSED_RESULT
247 PARROT_CAN_RETURN_NULL
249 Parrot_thaw_pbc(PARROT_INTERP
, ARGIN(PackFile_ConstTable
*ct
), ARGMOD(const opcode_t
**cursor
))
251 ASSERT_ARGS(Parrot_thaw_pbc
)
252 PackFile
* const pf
= ct
->base
.pf
;
253 STRING
*image
= PF_fetch_buf(interp
, pf
, cursor
);
254 PMC
*info
= Parrot_pmc_new(interp
, enum_class_ImageIO
);
255 VTABLE_set_pointer(interp
, info
, ct
);
256 VTABLE_set_string_native(interp
, info
, image
);
257 return VTABLE_get_pmc(interp
, info
);
263 =item C<PMC* Parrot_thaw_constants(PARROT_INTERP, STRING *image)>
265 This does nothing different from Parrot_thaw at the moment.
272 PARROT_WARN_UNUSED_RESULT
273 PARROT_CANNOT_RETURN_NULL
275 Parrot_thaw_constants(PARROT_INTERP
, ARGIN(STRING
*image
))
277 ASSERT_ARGS(Parrot_thaw_constants
)
278 return Parrot_thaw(interp
, image
);
284 =item C<PMC* Parrot_clone(PARROT_INTERP, PMC *pmc)>
286 There are for sure shortcuts to clone faster, e.g. always thaw the image
287 immediately or use a special callback. For now we just thaw a frozen PMC.
294 PARROT_WARN_UNUSED_RESULT
295 PARROT_CAN_RETURN_NULL
297 Parrot_clone(PARROT_INTERP
, ARGIN(PMC
*pmc
))
299 ASSERT_ARGS(Parrot_clone
)
300 return VTABLE_clone(interp
, pmc
);
306 =item C<void Parrot_visit_loop_visit(PARROT_INTERP, PMC *info)>
308 Iterate a visitor PMC visiting each encountered target PMC.
315 Parrot_visit_loop_visit(PARROT_INTERP
, ARGIN(PMC
*info
))
317 ASSERT_ARGS(Parrot_visit_loop_visit
)
319 PMC
* const todo
= VTABLE_get_iter(interp
, info
);
320 const INTVAL action
= VTABLE_get_integer(interp
, info
);
323 /* can't cache upper limit, visit may append items */
324 for (i
= 0; i
< VTABLE_elements(interp
, todo
); ++i
) {
325 PMC
* const current
= VTABLE_get_pmc_keyed_int(interp
, todo
, i
);
326 if (PMC_IS_NULL(current
))
327 Parrot_ex_throw_from_c_args(interp
, NULL
,
328 EXCEPTION_MALFORMED_PACKFILE
,
329 "NULL current PMC at %d in visit_loop_todo_list - %s",
331 action
== VISIT_FREEZE_NORMAL
? "feeze" : "thaw");
333 PARROT_ASSERT(current
->vtable
);
335 if (action
== VISIT_FREEZE_NORMAL
)
336 VTABLE_freeze(interp
, current
, info
);
338 VTABLE_thaw(interp
, current
, info
);
340 VTABLE_visit(interp
, current
, info
);
342 VISIT_PMC(interp
, info
, PMC_metadata(current
));
349 =item C<void Parrot_visit_loop_thawfinish(PARROT_INTERP, PMC *info)>
351 Iterates a visitor PMC, thawfinishing each encountered target PMC.
358 Parrot_visit_loop_thawfinish(PARROT_INTERP
, ARGIN(PMC
*info
))
360 ASSERT_ARGS(Parrot_visit_loop_thawfinish
)
362 /* call thawfinish for each processed PMC */
364 * Thaw in reverse order. We have to fully thaw younger PMCs
365 * before use them in older.
367 * XXX There are no younger or older pmcs in a directed graph
368 * that allows cycles. Any code that requires a specific
369 * order here is likely broken.
372 PMC
* const todo
= VTABLE_get_iter(interp
, info
);
373 const INTVAL n
= VTABLE_elements(interp
, todo
);
376 for (i
= n
- 1; i
>= 0; --i
) {
377 PMC
*current
= VTABLE_get_pmc_keyed_int(interp
, todo
, i
);
378 if (!PMC_IS_NULL(current
))
379 VTABLE_thawfinish(interp
, current
, info
);
390 The seen-hash version for freezing might go away sometime.
394 Lot of discussion on p6i and F<docs/dev/pmc_freeze.pod>.
403 * c-file-style: "parrot"
405 * vim: expandtab shiftwidth=4: