1 /*
2 Copyright (C) 2001-2014, Parrot Foundation.
3
4 =head1 NAME
5
6 src/pmc_freeze.c - Freeze and thaw functionality
7
8 =head1 DESCRIPTION
9
10 Thawing PMCs uses a list with (maximum) size of the amount of PMCs to
11 keep track of retrieved PMCs.
12
13 PMCs freeze and thaw their own information through their vtables.
14
15 To avoid recursion, the whole functionality is driven by
16 C<< pmc->vtable->visit >>, which is called for the first PMC initially.
17 Container PMCs call a "todo-callback" for all contained PMCs. The
18 individual action vtable (freeze/thaw) is then called for all todo-PMCs.
19
20 =cut
21
22 */
23
24 #include "parrot/parrot.h"
25 #include "pmc/pmc_callcontext.h"
26 #include "object_serialization.str"
27
28 /* when thawing a string longer then this size, we first do a GC run and then
29 * block GC - the system can't give us more headers */
30
31 #define THAW_BLOCK_GC_SIZE 100000
32
33 /* HEADERIZER HFILE: include/parrot/pmc_freeze.h */
34
35 /*
36
37 =head2 Public Interface
38
39 =over 4
40
41 =item C<STRING* Parrot_freeze(PARROT_INTERP, PMC *pmc)>
42
43 Freeze using either method.
44
45 =cut
46
47 */
48
49 PARROT_EXPORT
50 PARROT_WARN_UNUSED_RESULT
51 PARROT_CANNOT_RETURN_NULL
52 STRING*
Parrot_freeze(PARROT_INTERP,ARGIN (PMC * pmc))53 Parrot_freeze(PARROT_INTERP, ARGIN(PMC *pmc))
54 {
55 ASSERT_ARGS(Parrot_freeze)
56 PMC * const image = Parrot_pmc_new(interp, enum_class_ImageIOFreeze);
57 VTABLE_set_pmc(interp, image, pmc);
58 return VTABLE_get_string(interp, image);
59 }
60
61
62 /*
63
64 =item C<opcode_t * Parrot_freeze_pbc(PARROT_INTERP, PMC *pmc, const
65 PackFile_ConstTable *pf, opcode_t *cursor, Hash **seen)>
66
67 Freezes a PMC to a PackFile.
68
69 =cut
70
71 */
72
73 PARROT_EXPORT
74 PARROT_WARN_UNUSED_RESULT
75 PARROT_CAN_RETURN_NULL
76 opcode_t *
Parrot_freeze_pbc(PARROT_INTERP,ARGIN (PMC * pmc),ARGIN (const PackFile_ConstTable * pf),ARGOUT (opcode_t * cursor),ARGOUT (Hash ** seen))77 Parrot_freeze_pbc(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(const PackFile_ConstTable *pf),
78 ARGOUT(opcode_t *cursor), ARGOUT(Hash **seen))
79 {
80 ASSERT_ARGS(Parrot_freeze_pbc)
81 PMC *visitor;
82 STRING *image;
83 DECL_CONST_CAST;
84
85 visitor = Parrot_pmc_new(interp, enum_class_ImageIOFreeze);
86 VTABLE_set_pointer(interp, visitor,
87 PARROT_const_cast(void *, (const void *)pf));
88 VTABLE_set_pmc(interp, visitor, pmc);
89
90 image = VTABLE_get_string(interp, visitor);
91 *seen = (Hash *)VTABLE_get_pointer(interp, visitor);
92 cursor = PF_store_buf(cursor, image);
93
94 return cursor;
95 }
96
97
98 /*
99
100 =item C<UINTVAL Parrot_freeze_pbc_size(PARROT_INTERP, PMC *pmc, const
101 PackFile_ConstTable *pf, Hash **seen)>
102
103 Gets the size of an image if it were created using C<Parrot_freeze_pbc>.
104
105 =cut
106
107 */
108
109 PARROT_EXPORT
110 PARROT_WARN_UNUSED_RESULT
111 UINTVAL
Parrot_freeze_pbc_size(PARROT_INTERP,ARGIN (PMC * pmc),ARGIN (const PackFile_ConstTable * pf),ARGOUT (Hash ** seen))112 Parrot_freeze_pbc_size(PARROT_INTERP, ARGIN(PMC *pmc), ARGIN(const PackFile_ConstTable *pf),
113 ARGOUT(Hash **seen))
114 {
115 ASSERT_ARGS(Parrot_freeze_pbc_size)
116 PMC * const pf_pmc = Parrot_pmc_new(interp, enum_class_UnManagedStruct);
117 PMC *visitor, *pmc_result;
118 DECL_CONST_CAST;
119
120 VTABLE_set_pointer(interp, pf_pmc,
121 PARROT_const_cast(void *, (const void *)pf));
122
123 visitor = Parrot_pmc_new_init(interp, enum_class_ImageIOSize, pf_pmc);
124 VTABLE_set_pmc(interp, visitor, pmc);
125
126 pmc_result = VTABLE_get_pmc(interp, visitor);
127 *seen = (Hash *)VTABLE_get_pointer(interp, visitor);
128 return VTABLE_get_integer(interp, pmc_result);
129 }
130
131
132 /*
133
134 =item C<PMC * Parrot_freeze_strings(PARROT_INTERP, PMC *pmc)>
135
136 Gets the strings of a PMC to be frozen.
137
138 =cut
139
140 */
141
142 PARROT_EXPORT
143 PARROT_WARN_UNUSED_RESULT
144 PARROT_CANNOT_RETURN_NULL
145 PMC *
Parrot_freeze_strings(PARROT_INTERP,ARGIN (PMC * pmc))146 Parrot_freeze_strings(PARROT_INTERP, ARGIN(PMC *pmc))
147 {
148 ASSERT_ARGS(Parrot_freeze_strings)
149 PMC * const visitor = Parrot_pmc_new(interp, enum_class_ImageIOStrings);
150 VTABLE_set_pmc(interp, visitor, pmc);
151 return VTABLE_get_pmc(interp, visitor);
152 }
153
154 /*
155
156 =item C<void Parrot_pf_verify_image_string(PARROT_INTERP, STRING *image)>
157
158 Perform some quick sanity checks on a packfile image string to verify that it
159 is valid. Throws exceptions if not.
160
161 =cut
162
163 */
164
165 void
Parrot_pf_verify_image_string(PARROT_INTERP,ARGIN (STRING * image))166 Parrot_pf_verify_image_string(PARROT_INTERP, ARGIN(STRING *image))
167 {
168 ASSERT_ARGS(Parrot_pf_verify_image_string)
169 if (STRING_length(image) < 16)
170 Parrot_ex_throw_from_c_noargs(interp,
171 EXCEPTION_INVALID_STRING_REPRESENTATION,
172 "Cannot deserialize PMC: Incorrect Length");
173 else {
174 const char major = image->strstart[14];
175 const char minor = image->strstart[15];
176
177 if (major == PARROT_PBC_MAJOR && minor == PARROT_PBC_MINOR)
178 return;
179
180 Parrot_ex_throw_from_c_args(interp, NULL,
181 EXCEPTION_INVALID_STRING_REPRESENTATION,
182 "Version %d.%d of serialized PMC is invalid. Expected %d.%d. "
183 "You're probably linking against an incompatible libparrot.",
184 major, minor, PARROT_PBC_MAJOR, PARROT_PBC_MINOR);
185 }
186 }
187
188
189 /*
190
191 =item C<PMC * Parrot_thaw(PARROT_INTERP, STRING *image)>
192
193 Thaws a PMC. Called from the C<thaw> opcode.
194
195 For now it seems cheaper to use a list for remembering contained aggregates. We
196 could of course decide dynamically, which strategy to use: given a big image,
197 the first thawed item is a small aggregate. This implies it probably contains
198 more nested containers, for which another approach could be a win.
199
200 =cut
201
202 */
203
204 PARROT_EXPORT
205 PARROT_WARN_UNUSED_RESULT
206 PARROT_CANNOT_RETURN_NULL
207 PMC *
Parrot_thaw(PARROT_INTERP,ARGIN (STRING * image))208 Parrot_thaw(PARROT_INTERP, ARGIN(STRING *image))
209 {
210 ASSERT_ARGS(Parrot_thaw)
211
212 PMC *result;
213 PMC * const info = Parrot_pmc_new(interp, enum_class_ImageIOThaw);
214 int gc_block = 0;
215
216 /*
217 * if we are thawing a lot of PMCs, it's cheaper to do
218 * a GC run first and then block GC - the limit should be
219 * chosen so that no more then one GC run would be triggered
220 *
221 * XXX
222 *
223 * md5_3.pir shows a segfault during thawing the config hash
224 * info->thaw_ptr becomes invalid - seems that the hash got
225 * collected under us.
226 */
227 if (1 || (Parrot_str_byte_length(interp, image) > THAW_BLOCK_GC_SIZE)) {
228 Parrot_block_GC_mark(interp);
229 Parrot_block_GC_sweep(interp);
230 gc_block = 1;
231 }
232
233 VTABLE_set_string_native(interp, info, image);
234 result = VTABLE_get_pmc(interp, info);
235
236 if (gc_block) {
237 Parrot_unblock_GC_mark(interp);
238 Parrot_unblock_GC_sweep(interp);
239 }
240
241 return result;
242 }
243
244
245 /*
246
247 =item C<PMC* Parrot_thaw_pbc(PARROT_INTERP, PackFile_ConstTable *ct, const
248 opcode_t **cursor)>
249
250 Thaw a pmc frozen by Parrot_freeze_pbc.
251
252 =cut
253
254 */
255
256 PARROT_EXPORT
257 PARROT_WARN_UNUSED_RESULT
258 PARROT_CAN_RETURN_NULL
259 PMC*
Parrot_thaw_pbc(PARROT_INTERP,ARGIN (PackFile_ConstTable * ct),ARGMOD (const opcode_t ** cursor))260 Parrot_thaw_pbc(PARROT_INTERP, ARGIN(PackFile_ConstTable *ct), ARGMOD(const opcode_t **cursor))
261 {
262 ASSERT_ARGS(Parrot_thaw_pbc)
263 PackFile * const pf = ct->base.pf;
264 STRING * const image = PF_fetch_buf(interp, pf, cursor);
265 PMC * const info = Parrot_pmc_new(interp, enum_class_ImageIOThaw);
266 VTABLE_set_pointer(interp, info, ct);
267 VTABLE_set_string_native(interp, info, image);
268 return VTABLE_get_pmc(interp, info);
269 }
270
271
272 /*
273
274 =item C<PMC* Parrot_thaw_constants(PARROT_INTERP, STRING *image)>
275
276 This does nothing different from Parrot_thaw at the moment.
277
278 =cut
279
280 */
281
282 PARROT_EXPORT
283 PARROT_WARN_UNUSED_RESULT
284 PARROT_CANNOT_RETURN_NULL
285 PMC*
Parrot_thaw_constants(PARROT_INTERP,ARGIN (STRING * image))286 Parrot_thaw_constants(PARROT_INTERP, ARGIN(STRING *image))
287 {
288 ASSERT_ARGS(Parrot_thaw_constants)
289 return Parrot_thaw(interp, image);
290 }
291
292
293 /*
294
295 =item C<PMC* Parrot_clone(PARROT_INTERP, PMC *pmc)>
296
297 There are for sure shortcuts to clone faster, e.g. always thaw the image
298 immediately or use a special callback. For now we just thaw a frozen PMC.
299
300 =cut
301
302 */
303
304 PARROT_EXPORT
305 PARROT_WARN_UNUSED_RESULT
306 PARROT_CAN_RETURN_NULL
307 PMC*
Parrot_clone(PARROT_INTERP,ARGIN (PMC * pmc))308 Parrot_clone(PARROT_INTERP, ARGIN(PMC *pmc))
309 {
310 ASSERT_ARGS(Parrot_clone)
311 return VTABLE_clone(interp, pmc);
312 }
313
314
315 /*
316
317 =back
318
319 =head1 TODO
320
321 The seen-hash version for freezing might go away sometime.
322
323 =head1 SEE ALSO
324
325 Lot of discussion on p6i and F<docs/dev/pmc_freeze.pod>.
326
327 =cut
328
329 */
330
331
332 /*
333 * Local variables:
334 * c-file-style: "parrot"
335 * End:
336 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
337 */
338