1/* 2Copyright (C) 2010-2014, Parrot Foundation. 3 4=head1 NAME 5 6src/pmc/imageiothaw.pmc - ImageIOThaw PMC 7 8=head1 DESCRIPTION 9 10Thaws PMCs from packfile images. 11 12=head1 VTABLES 13 14=over 4 15 16=cut 17 18*/ 19 20#include "parrot/imageio.h" 21 22#define BYTECODE_SHIFT_OK(interp, pmc) PARROT_ASSERT( \ 23 PARROT_IMAGEIOTHAW(pmc)->curs <= (opcode_t *) \ 24 (PARROT_IMAGEIOTHAW(pmc)->img->strstart + \ 25 Parrot_str_byte_length((interp), PARROT_IMAGEIOTHAW(pmc)->img))) 26 27 28/* HEADERIZER HFILE: none */ 29 30pmclass ImageIOThaw auto_attrs { 31 ATTR STRING *img; 32 ATTR opcode_t *curs; 33 ATTR PMC *seen; 34 ATTR PMC *todo; 35 ATTR PackFile *pf; 36 ATTR PackFile_ConstTable *pf_ct; 37 38/* 39 40=item C<void init()> 41 42Initializes the PMC. 43 44=cut 45 46*/ 47 48 VTABLE void init() { 49 PARROT_IMAGEIOTHAW(SELF)->seen = 50 Parrot_pmc_new(INTERP, enum_class_ResizablePMCArray); 51 PARROT_IMAGEIOTHAW(SELF)->todo = 52 Parrot_pmc_new(INTERP, enum_class_ResizableIntegerArray); 53 54 PObj_flag_CLEAR(private1, SELF); 55 56 PObj_custom_mark_SET(SELF); 57 } 58 59 60/* 61 62=item C<void destroy()> 63 64Destroys the PMC. 65 66=cut 67 68*/ 69 70 VTABLE void destroy() :no_wb { 71 Parrot_pf_destroy(INTERP, PARROT_IMAGEIOTHAW(SELF)->pf); 72 PARROT_IMAGEIOTHAW(SELF)->pf = NULL; 73 } 74 75 76/* 77 78=item C<void mark()> 79 80Marks the PMC as alive. 81 82=cut 83 84*/ 85 86 VTABLE void mark() :no_wb { 87 Parrot_gc_mark_STRING_alive(INTERP, PARROT_IMAGEIOTHAW(SELF)->img); 88 Parrot_gc_mark_PMC_alive(INTERP, PARROT_IMAGEIOTHAW(SELF)->seen); 89 Parrot_gc_mark_PMC_alive(INTERP, PARROT_IMAGEIOTHAW(SELF)->todo); 90 } 91 92 93/* 94 95=item C<void set_string_native(STRING *image)> 96 97Thaws the PMC contained in C<image>. 98 99=cut 100 101*/ 102 103 VTABLE void set_string_native(STRING *image) { 104 if (!PObj_external_TEST(image)) 105 Parrot_str_pin(INTERP, image); 106 107 PARROT_IMAGEIOTHAW(SELF)->img = image; 108 PARROT_IMAGEIOTHAW(SELF)->curs = (opcode_t *)image->strstart; 109 110 if (PObj_flag_TEST(private1, SELF)) { 111 PARROT_IMAGEIOTHAW(SELF)->pf = PARROT_IMAGEIOTHAW(SELF)->pf_ct->base.pf; 112 } 113 else { 114 const UINTVAL header_length = 115 GROW_TO_16_BYTE_BOUNDARY(PACKFILE_HEADER_BYTES); 116 int unpacked_length; 117 118 PARROT_IMAGEIOTHAW(SELF)->pf = Parrot_pf_new(INTERP, 0); 119 PObj_custom_destroy_SET(SELF); 120 121 PARROT_IMAGEIOTHAW(SELF)->pf->options |= PFOPT_PMC_FREEZE_ONLY; 122 unpacked_length = Parrot_pf_unpack(INTERP, PARROT_IMAGEIOTHAW(SELF)->pf, 123 PARROT_IMAGEIOTHAW(SELF)->curs, 124 Parrot_str_byte_length(interp, image)); 125 126 if (unpacked_length) 127 PARROT_IMAGEIOTHAW(SELF)->curs += header_length / sizeof (opcode_t*); 128 else 129 Parrot_ex_throw_from_c_noargs(INTERP, 130 EXCEPTION_INVALID_STRING_REPRESENTATION, 131 "PackFile header failed during unpack"); 132 } 133 134 STATICSELF.shift_pmc(); 135 136 { 137 PMC * const seen = PARROT_IMAGEIOTHAW(SELF)->seen; 138 PMC * const todo = PARROT_IMAGEIOTHAW(SELF)->todo; 139 INTVAL i, n; 140 141 for (i = 0; i < VTABLE_elements(INTERP, todo); i++) { 142 const INTVAL idx = VTABLE_get_integer_keyed_int(INTERP, todo, i); 143 PMC * const current = VTABLE_get_pmc_keyed_int(INTERP, seen, idx); 144 if (PMC_IS_NULL(current)) 145 Parrot_ex_throw_from_c_args(interp, NULL, 146 EXCEPTION_MALFORMED_PACKFILE, 147 "NULL current PMC at %d in thaw", 148 (int)i); 149 150 VTABLE_thaw(INTERP, current, SELF); 151 VTABLE_visit(INTERP, current, SELF); 152 PMC_metadata(current) = SELF.shift_pmc(); 153 } 154 155 n = i; 156 157 /* we're done reading the image */ 158 PARROT_ASSERT(image->strstart + Parrot_str_byte_length(interp, image) == 159 (char *)PARROT_IMAGEIOTHAW(SELF)->curs); 160 161 for (i = 0; i < n; i++) { 162 const INTVAL idx = VTABLE_get_integer_keyed_int(INTERP, todo, i); 163 PMC * const current = VTABLE_get_pmc_keyed_int(INTERP, seen, idx); 164 VTABLE_thawfinish(INTERP, current, SELF); 165 } 166 } 167 168 if (!PObj_external_TEST(image)) 169 Parrot_str_unpin(INTERP, image); 170 } 171 172 173/* 174 175=item C<PMC *get_pmc()> 176 177Get the thawed PMC. 178 179=cut 180 181*/ 182 183 VTABLE PMC *get_pmc() :no_wb { 184 if (PObj_flag_TEST(private1, SELF)) 185 return PARROT_IMAGEIOTHAW(SELF)->seen; 186 else 187 return VTABLE_get_pmc_keyed_int(INTERP, (PARROT_IMAGEIOTHAW(SELF))->seen, 0); 188 } 189 190 191/* 192 193=item C<INTVAL get_integer()> 194 195Get the visit action. 196 197=cut 198 199*/ 200 201 VTABLE INTVAL get_integer() :no_wb { 202 UNUSED(INTERP) 203 UNUSED(SELF) 204 return VISIT_THAW_NORMAL; 205 } 206 207 208/* 209 210=item C<void set_pointer(void *value)> 211 212Set an exterior constant table to use for cross-referencing constants. 213 214=cut 215 216*/ 217 218 VTABLE void set_pointer(void *value) { 219 PObj_flag_SET(private1, SELF); 220 PARROT_IMAGEIOTHAW(SELF)->pf_ct = (PackFile_ConstTable *)value; 221 } 222 223 224/* 225 226=item C<INTVAL shift_integer()> 227 228Retrieve an integer as the next item from the image. 229 230=cut 231 232*/ 233 234 VTABLE INTVAL shift_integer() :manual_wb { 235 /* inlining PF_fetch_integer speeds up PBC thawing measurably */ 236 PackFile * const pf = PARROT_IMAGEIOTHAW(SELF)->pf; 237 const unsigned char *stream = (const unsigned char *)PARROT_IMAGEIOTHAW(SELF)->curs; 238 const INTVAL i = pf->fetch_iv(stream); 239 DECL_CONST_CAST; 240 PARROT_IMAGEIOTHAW(SELF)->curs = (opcode_t *)PARROT_const_cast(unsigned char *, 241 stream + pf->header->wordsize); 242 BYTECODE_SHIFT_OK(INTERP, SELF); 243 RETURN(INTVAL i); 244 } 245 246 247/* 248 249=item C<FLOATVAL shift_float()> 250 251Retrieve a float as the next item from the image. 252 253=cut 254 255*/ 256 257 VTABLE FLOATVAL shift_float() :manual_wb { 258 PackFile * const pf = PARROT_IMAGEIOTHAW(SELF)->pf; 259 const opcode_t *curs = PARROT_IMAGEIOTHAW(SELF)->curs; 260 const FLOATVAL f = PF_fetch_number(pf, &curs); 261 DECL_CONST_CAST; 262 PARROT_IMAGEIOTHAW(SELF)->curs = PARROT_const_cast(opcode_t *, curs); 263 BYTECODE_SHIFT_OK(INTERP, SELF); 264 RETURN(FLOATVAL f); 265 } 266 267 268/* 269 270=item C<STRING *shift_string()> 271 272Retrieve a string as the next item from the image. 273 274=cut 275 276*/ 277 278 VTABLE STRING *shift_string() :manual_wb { 279 if (PObj_flag_TEST(private1, SELF)) { 280 const INTVAL i = STATICSELF.shift_integer(); 281 BYTECODE_SHIFT_OK(INTERP, SELF); 282 283 if (i >= 0) { 284 PackFile_ConstTable *table = PARROT_IMAGEIOTHAW(SELF)->pf_ct; 285 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 286 return table->str.constants[i]; 287 } 288 289 /* XXX 290 * only got here because constant table doesn't contain the string 291 * fallback on inline strings 292 */ 293 } 294 295 { 296 PackFile * const pf = PARROT_IMAGEIOTHAW(SELF)->pf; 297 const opcode_t *curs = PARROT_IMAGEIOTHAW(SELF)->curs; 298 STRING *s = PF_fetch_string(INTERP, pf, &curs); 299 DECL_CONST_CAST; 300 PARROT_IMAGEIOTHAW(SELF)->curs = PARROT_const_cast(opcode_t *, curs); 301 BYTECODE_SHIFT_OK(INTERP, SELF); 302 PARROT_GC_WRITE_BARRIER(INTERP, SELF); 303 return s; 304 } 305 } 306 307 308/* 309 310=item C<PMC *shift_pmc()> 311 312Retrieve a PMC as the next item from the image. 313 314=cut 315 316*/ 317 318 VTABLE PMC *shift_pmc() :manual_wb { 319 const UINTVAL n = SELF.shift_integer(); 320 const INTVAL id = PackID_get_PMCID(n); 321 const int packid_flags = PackID_get_FLAGS(n); 322 323 PMC *pmc = PMCNULL; 324 PMC *seen = PARROT_IMAGEIOTHAW(SELF)->seen; 325 PMC *todo = PARROT_IMAGEIOTHAW(SELF)->todo; 326 327 switch (packid_flags) { 328 case enum_PackID_seen: 329 if (id) /* got a non-NULL PMC */ 330 pmc = VTABLE_get_pmc_keyed_int(INTERP, seen, id - 1); 331 break; 332 case enum_PackID_pbc_backref: 333 { 334 PackFile_ConstTable *table = PARROT_IMAGEIOTHAW(SELF)->pf_ct; 335 INTVAL constno = SELF.shift_integer(); 336 INTVAL idx = SELF.shift_integer(); 337 PMC *olist = table->pmc.constants[constno]; 338 pmc = VTABLE_get_pmc_keyed_int(INTERP, olist, idx); 339 PARROT_ASSERT(id - 1 == VTABLE_elements(INTERP, seen)); 340 VTABLE_set_pmc_keyed_int(INTERP, seen, id - 1, pmc); 341 break; 342 } 343 case enum_PackID_normal: 344 { 345 const INTVAL type = SELF.shift_integer(); 346 347 PARROT_ASSERT(id - 1 == VTABLE_elements(INTERP, seen)); 348 349 if (type <= 0 || type > INTERP->n_vtable_max) 350 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 351 "Unknown PMC type to thaw %d", type); 352 353 pmc = Parrot_pmc_new_noinit(INTERP, type); 354 355 VTABLE_set_pmc_keyed_int(INTERP, seen, id - 1, pmc); 356 VTABLE_push_integer(INTERP, todo, id - 1); 357 } 358 break; 359 default: 360 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION, 361 "Unknown PMC id args thaw %d", packid_flags); 362 break; 363 } 364 365 RETURN(PMC *pmc); 366 } 367 368} 369 370/* 371 372=back 373 374=cut 375 376*/ 377 378/* 379 * Local variables: 380 * c-file-style: "parrot" 381 * End: 382 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' : 383 */ 384 385