fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc_freeze.c
blob1f892bef05a363f929a09f70a24e7077b966cc4d
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc_freeze.c - Freeze and thaw functionality
9 =head1 DESCRIPTION
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.
21 =cut
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
40 =over 4
42 =item C<STRING* Parrot_freeze(PARROT_INTERP, PMC *pmc)>
44 Freeze using either method.
46 =cut
50 PARROT_EXPORT
51 PARROT_WARN_UNUSED_RESULT
52 PARROT_CANNOT_RETURN_NULL
53 STRING*
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.
70 =cut
74 PARROT_EXPORT
75 PARROT_WARN_UNUSED_RESULT
76 PARROT_CAN_RETURN_NULL
77 opcode_t *
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)
82 PMC *visitor;
83 STRING *image;
84 DECL_CONST_CAST;
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);
94 return cursor;
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.
104 =cut
108 PARROT_EXPORT
109 PARROT_WARN_UNUSED_RESULT
110 UINTVAL
111 Parrot_freeze_size(PARROT_INTERP, ARGIN(PMC *pmc))
113 ASSERT_ARGS(Parrot_freeze_size)
114 PMC *pmc_result;
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>.
130 =cut
134 PARROT_EXPORT
135 PARROT_WARN_UNUSED_RESULT
136 UINTVAL
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;
142 DECL_CONST_CAST;
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.
161 =cut
165 PARROT_EXPORT
166 PARROT_WARN_UNUSED_RESULT
167 PARROT_CANNOT_RETURN_NULL
168 PMC *
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.
189 =cut
193 PARROT_EXPORT
194 PARROT_WARN_UNUSED_RESULT
195 PARROT_CANNOT_RETURN_NULL
196 PMC *
197 Parrot_thaw(PARROT_INTERP, ARGIN(STRING *image))
199 ASSERT_ARGS(Parrot_thaw)
201 PMC *result;
202 PMC * const info = Parrot_pmc_new(interp, enum_class_ImageIO);
203 int gc_block = 0;
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
210 * XXX
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);
219 gc_block = 1;
222 VTABLE_set_string_native(interp, info, image);
223 result = VTABLE_get_pmc(interp, info);
225 if (gc_block) {
226 Parrot_unblock_GC_mark(interp);
227 Parrot_unblock_GC_sweep(interp);
230 return result;
236 =item C<PMC* Parrot_thaw_pbc(PARROT_INTERP, PackFile_ConstTable *ct, const
237 opcode_t **cursor)>
239 Thaw a pmc frozen by Parrot_freeze_pbc.
241 =cut
245 PARROT_EXPORT
246 PARROT_WARN_UNUSED_RESULT
247 PARROT_CAN_RETURN_NULL
248 PMC*
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.
267 =cut
271 PARROT_EXPORT
272 PARROT_WARN_UNUSED_RESULT
273 PARROT_CANNOT_RETURN_NULL
274 PMC*
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.
289 =cut
293 PARROT_EXPORT
294 PARROT_WARN_UNUSED_RESULT
295 PARROT_CAN_RETURN_NULL
296 PMC*
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.
310 =cut
314 void
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);
321 INTVAL i;
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",
330 (int) i,
331 action == VISIT_FREEZE_NORMAL ? "feeze" : "thaw");
333 PARROT_ASSERT(current->vtable);
335 if (action == VISIT_FREEZE_NORMAL)
336 VTABLE_freeze(interp, current, info);
337 else
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.
353 =cut
357 void
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);
374 int i;
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);
386 =back
388 =head1 TODO
390 The seen-hash version for freezing might go away sometime.
392 =head1 SEE ALSO
394 Lot of discussion on p6i and F<docs/dev/pmc_freeze.pod>.
396 =cut
402 * Local variables:
403 * c-file-style: "parrot"
404 * End:
405 * vim: expandtab shiftwidth=4: