1 /*
2 Copyright (C) 2001-2015, Parrot Foundation.
3 
4 =head1 NAME
5 
6 src/packfile/output.c - Functions for writing out packfiles
7 
8 =head1 DESCRIPTION
9 
10 This file implements various functions for creating and writing packfiles.
11 
12 The C<PackFile_> functions are deprecated and will be removed with Release 7.3.0
13 
14 =head2 Functions
15 
16 =over 4
17 
18 =cut
19 
20 */
21 
22 #include "parrot/parrot.h"
23 #include "parrot/packfile.h"
24 #include "pf_private.h"
25 #include "pmc/pmc_key.h"
26 
27 /* HEADERIZER HFILE: include/parrot/packfile.h */
28 /* HEADERIZER BEGIN: static */
29 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
30 
31 PARROT_INLINE
32 static void update_backref_hash(PARROT_INTERP,
33     ARGIN(PackFile_ConstTable *ct),
34     ARGIN(Hash *seen),
35     INTVAL constno)
36         __attribute__nonnull__(1)
37         __attribute__nonnull__(2)
38         __attribute__nonnull__(3);
39 
40 #define ASSERT_ARGS_update_backref_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
41        PARROT_ASSERT_ARG(interp) \
42     , PARROT_ASSERT_ARG(ct) \
43     , PARROT_ASSERT_ARG(seen))
44 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
45 /* HEADERIZER END: static */
46 
47 /*
48 
49 =item C<size_t Parrot_pf_pack_size(PARROT_INTERP, PackFile *self)>
50 
51 Determine the size of the buffer needed in order to pack the PackFile
52 into a contiguous region of memory.
53 
54 Must be run before C<Parrot_pf_pack()>, so it will allocate an adequate
55 buffer.
56 
57 =cut
58 
59 */
60 
61 PARROT_EXPORT
62 size_t
Parrot_pf_pack_size(PARROT_INTERP,ARGMOD (PackFile * self))63 Parrot_pf_pack_size(PARROT_INTERP, ARGMOD(PackFile *self))
64 {
65     ASSERT_ARGS(Parrot_pf_pack_size)
66     size_t size;
67     size_t header_size;
68     PackFile_Directory * const dir = &self->directory;
69 
70     header_size = PACKFILE_HEADER_BYTES;
71     header_size += self->header->uuid_size;
72     header_size +=
73         header_size % 16
74             ? 16 - header_size % 16
75             : 0;
76 
77     size = header_size / sizeof (opcode_t);
78 
79     size += 4; /* directory type + 3 padding zeros */
80 
81     dir->base.file_offset = size;
82     size += pf_segment_packed_size(interp, (PackFile_Segment *) dir);
83 
84     return size;
85 }
86 
87 /*
88 
89 =item C<size_t PackFile_pack_size(PARROT_INTERP, PackFile *self)>
90 
91 Deprecated: Use C<Parrot_pf_pack_size> instead. GH #1170
92 
93 =cut
94 
95 */
96 
97 PARROT_EXPORT
98 PARROT_DEPRECATED
99 size_t
PackFile_pack_size(PARROT_INTERP,ARGMOD (PackFile * self))100 PackFile_pack_size(PARROT_INTERP, ARGMOD(PackFile *self))
101 {
102     ASSERT_ARGS(PackFile_pack_size)
103     return Parrot_pf_pack_size(interp, self);
104 }
105 
106 /*
107 
108 =item C<void Parrot_pf_pack(PARROT_INTERP, PackFile *self, opcode_t *cursor)>
109 
110 Pack the PackFile into a contiguous region of memory.
111 
112 Note that the memory block had better have at least the amount of memory
113 indicated by C<Parrot_pf_pack_size()>.
114 
115 This means that you MUST call C<Parrot_pf_pack_size()> before
116 C<Parrot_pf_pack()>
117 
118 Other pack routines are in F<src/packfile/api.c> and F<src/packfile/segments.c>.
119 
120 =cut
121 
122 */
123 
124 PARROT_EXPORT
125 void
Parrot_pf_pack(PARROT_INTERP,ARGMOD (PackFile * self),ARGOUT (opcode_t * cursor))126 Parrot_pf_pack(PARROT_INTERP, ARGMOD(PackFile *self), ARGOUT(opcode_t *cursor))
127 {
128     ASSERT_ARGS(Parrot_pf_pack)
129     opcode_t *ret;
130 
131     size_t size;
132     PackFile_Directory * const dir = &self->directory;
133     PackFile_Segment *seg;
134     int padding_size;
135     char *byte_cursor = (char*)cursor;
136 
137     self->src = cursor;
138 
139     /* Pack the fixed part of the header */
140     memcpy(cursor, self->header, PACKFILE_HEADER_BYTES);
141     byte_cursor += PACKFILE_HEADER_BYTES;
142 
143     /* Pack the UUID. */
144     if (self->header->uuid_size > 0)
145         memcpy(byte_cursor, self->header->uuid_data,
146             self->header->uuid_size);
147 
148     /* Padding. */
149     padding_size = 16 - (PACKFILE_HEADER_BYTES + self->header->uuid_size) % 16;
150     if (padding_size < 16) {
151         int i;
152         for (i = 0; i < padding_size; ++i)
153             *byte_cursor++ = 0;
154     }
155     else {
156         padding_size = 0;
157     }
158 
159     /* Set cursor. */
160     cursor += (PACKFILE_HEADER_BYTES + self->header->uuid_size + padding_size)
161         / sizeof (opcode_t);
162 
163     /* Directory format and padding. */
164     *cursor++ = PF_DIR_FORMAT;
165     *cursor++ = 0;
166     *cursor++ = 0;
167     *cursor++ = 0;
168 
169     /* pack the directory */
170     seg = (PackFile_Segment *) dir;
171 
172     /* dir size */
173     size = seg->op_count;
174     ret = pf_segment_pack(interp, seg, cursor);
175     if ((size_t)(ret - cursor) != size) {
176         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_MALFORMED_PACKFILE,
177                 "Parrot_pf_pack segment '%Ss' used size %d but reported %d",
178                 seg->name, (int)(ret-cursor), (int)size);
179     }
180 }
181 
182 /*
183 
184 =item C<void PackFile_pack(PARROT_INTERP, PackFile *self, opcode_t *cursor)>
185 
186 Deprecated: Use C<Parrot_pf_pack> instead. GH #1170
187 
188 =cut
189 
190 */
191 
192 PARROT_EXPORT
193 PARROT_DEPRECATED
194 void
PackFile_pack(PARROT_INTERP,ARGMOD (PackFile * self),ARGOUT (opcode_t * cursor))195 PackFile_pack(PARROT_INTERP, ARGMOD(PackFile *self), ARGOUT(opcode_t *cursor))
196 {
197     ASSERT_ARGS(PackFile_pack)
198     Parrot_pf_pack(interp, self, cursor);
199 }
200 
201 /*
202 
203 =item C<static void update_backref_hash(PARROT_INTERP, PackFile_ConstTable *ct,
204 Hash *seen, INTVAL constno)>
205 
206 Update C<ct>'s backref hash with new entries from C<seen>.
207 
208 =cut
209 
210 */
211 
212 PARROT_INLINE
213 static void
update_backref_hash(PARROT_INTERP,ARGIN (PackFile_ConstTable * ct),ARGIN (Hash * seen),INTVAL constno)214 update_backref_hash(PARROT_INTERP,
215                     ARGIN(PackFile_ConstTable *ct), ARGIN(Hash *seen), INTVAL constno)
216 {
217     ASSERT_ARGS(update_backref_hash)
218     parrot_hash_iterate(seen, {
219         PMC * const k = (PMC *)_bucket->key;
220         if (!Parrot_hash_get(interp, ct->pmc_hash, k)) {
221             const UINTVAL idx = (UINTVAL)_bucket->value;
222             PMC * const rec = Parrot_pmc_new_init_int(interp, enum_class_FixedIntegerArray, 2);
223 
224             VTABLE_set_integer_keyed_int(interp, rec, 0, constno);
225             VTABLE_set_integer_keyed_int(interp, rec, 1, idx);
226             Parrot_hash_put(interp, ct->pmc_hash, k, rec);
227         }
228     });
229 }
230 
231 /*
232 
233 =item C<size_t Parrot_pf_ConstTable_pack_size(PARROT_INTERP, PackFile_Segment
234 *seg)>
235 
236 Determine the size of the buffer needed in order to pack the PackFile
237 constant table into a contiguous region of memory.
238 
239 =cut
240 
241 */
242 
243 PARROT_EXPORT
244 size_t
Parrot_pf_ConstTable_pack_size(PARROT_INTERP,ARGMOD (PackFile_Segment * seg))245 Parrot_pf_ConstTable_pack_size(PARROT_INTERP, ARGMOD(PackFile_Segment *seg))
246 {
247     ASSERT_ARGS(Parrot_pf_ConstTable_pack_size)
248     opcode_t i;
249     PackFile_ConstTable* const self = (PackFile_ConstTable *) seg;
250     size_t size = 3;    /* const_counts */
251 
252     size += self->num.const_count * PF_size_number();
253 
254     for (i = 0; i < self->str.const_count; i++)
255         size += PF_size_string(self->str.constants[i]);
256 
257     self->pmc_hash = Parrot_hash_create(interp, enum_type_PMC, Hash_key_type_PMC_ptr);
258     for (i = 0; i < self->pmc.const_count; i++) {
259         Hash *seen;
260         PMC * const c = self->pmc.constants[i];
261         size += PF_size_strlen(Parrot_freeze_pbc_size(interp, c, self, &seen)) - 1;
262         update_backref_hash(interp, self, seen, i);
263     }
264     Parrot_hash_destroy(interp, self->pmc_hash);
265     self->pmc_hash = NULL;
266     size += 1 + (self->ntags * 2);
267 
268     return size;
269 }
270 
271 /*
272 
273 =item C<size_t PackFile_ConstTable_pack_size(PARROT_INTERP, PackFile_Segment
274 *seg)>
275 
276 Deprecated: Use C<Parrot_pf_ConstTable_pack_size> instead. Will not be exported
277 anymore. GH #1170
278 
279 =cut
280 
281 */
282 
283 PARROT_EXPORT
284 PARROT_DEPRECATED
285 size_t
PackFile_ConstTable_pack_size(PARROT_INTERP,ARGMOD (PackFile_Segment * seg))286 PackFile_ConstTable_pack_size(PARROT_INTERP, ARGMOD(PackFile_Segment *seg))
287 {
288     ASSERT_ARGS(PackFile_ConstTable_pack_size)
289     return Parrot_pf_ConstTable_pack_size(interp, seg);
290 }
291 
292 /*
293 
294 =item C<opcode_t * Parrot_pf_ConstTable_pack(PARROT_INTERP, PackFile_Segment
295 *seg, opcode_t *cursor)>
296 
297 Pack the PackFile ConstTable into a contiguous region of memory.
298 
299 Note that the memory block had better have at least the amount of memory
300 indicated by C<Parrot_pf_pack_size()>.
301 
302 This means that you MUST call C<Parrot_pf_pack_size()> before
303 C<Parrot_pf_ConstTable_pack()>
304 
305 =cut
306 
307 */
308 
309 PARROT_EXPORT
310 PARROT_WARN_UNUSED_RESULT
311 PARROT_CANNOT_RETURN_NULL
312 opcode_t *
Parrot_pf_ConstTable_pack(PARROT_INTERP,ARGMOD (PackFile_Segment * seg),ARGOUT (opcode_t * cursor))313 Parrot_pf_ConstTable_pack(PARROT_INTERP,
314         ARGMOD(PackFile_Segment *seg), ARGOUT(opcode_t *cursor))
315 {
316     ASSERT_ARGS(Parrot_pf_ConstTable_pack)
317     PackFile_ConstTable * const self = (PackFile_ConstTable *)seg;
318     opcode_t i;
319 
320     *cursor++ = self->num.const_count;
321     *cursor++ = self->str.const_count;
322     *cursor++ = self->pmc.const_count;
323 
324     for (i = 0; i < self->num.const_count; i++)
325         cursor = PF_store_number(cursor, &self->num.constants[i]);
326 
327     for (i = 0; i < self->str.const_count; i++)
328         cursor = PF_store_string(cursor, self->str.constants[i]);
329 
330     self->pmc_hash = Parrot_hash_create(interp, enum_type_PMC, Hash_key_type_PMC_ptr);
331     for (i = 0; i < self->pmc.const_count; i++) {
332         Hash *seen;
333         PMC * const c = self->pmc.constants[i];
334         cursor  = Parrot_freeze_pbc(interp, c, self, cursor, &seen);
335         update_backref_hash(interp, self, seen, i);
336     }
337     Parrot_hash_destroy(interp, self->pmc_hash);
338     self->pmc_hash = NULL;
339 
340     *cursor++ = self->ntags;
341     for (i = 0; i < self->ntags; i++) {
342         *cursor++ = self->tag_map[i].tag_idx;
343         *cursor++ = self->tag_map[i].const_idx;
344     }
345 
346     return cursor;
347 }
348 
349 /*
350 
351 =item C<opcode_t * PackFile_ConstTable_pack(PARROT_INTERP, PackFile_Segment
352 *seg, opcode_t *cursor)>
353 
354 Deprecated: Use C<Parrot_pf_ConstTable_pack> instead. GH #1170
355 
356 =cut
357 
358 */
359 
360 PARROT_EXPORT
361 PARROT_DEPRECATED
362 PARROT_WARN_UNUSED_RESULT
363 PARROT_CANNOT_RETURN_NULL
364 opcode_t *
PackFile_ConstTable_pack(PARROT_INTERP,ARGMOD (PackFile_Segment * seg),ARGOUT (opcode_t * cursor))365 PackFile_ConstTable_pack(PARROT_INTERP,
366         ARGMOD(PackFile_Segment *seg), ARGOUT(opcode_t *cursor))
367 {
368     ASSERT_ARGS(PackFile_ConstTable_pack)
369     return Parrot_pf_ConstTable_pack(interp, seg, cursor);
370 }
371 
372 /*
373 
374 =item C<int Parrot_pf_ConstTable_rlookup_str(PARROT_INTERP, const
375 PackFile_ConstTable *ct, STRING *s)>
376 
377 =item C<int Parrot_pf_ConstTable_rlookup_num(PARROT_INTERP, const
378 PackFile_ConstTable *ct, FLOATVAL n)>
379 
380 =item C<int Parrot_pf_ConstTable_rlookup_pmc(PARROT_INTERP, PackFile_ConstTable
381 *ct, PMC *v, INTVAL *constno, INTVAL *idx)>
382 
383 Reverse lookup a constant in the constant table.
384 
385 =item C<int PackFile_ConstTable_rlookup_str(PARROT_INTERP, const
386 PackFile_ConstTable *ct, STRING *s)>
387 
388 =item C<int PackFile_ConstTable_rlookup_num(PARROT_INTERP, const
389 PackFile_ConstTable *ct, FLOATVAL n)>
390 
391 =item C<int PackFile_ConstTable_rlookup_pmc(PARROT_INTERP, PackFile_ConstTable
392 *ct, PMC *v, INTVAL *constno, INTVAL *idx)>
393 
394 Deprecated: Use C<Parrot_pf_ConstTable_rlookup_*> instead. GH #1170
395 
396 =cut
397 
398 */
399 
400 PARROT_EXPORT
401 int
Parrot_pf_ConstTable_rlookup_str(PARROT_INTERP,ARGIN (const PackFile_ConstTable * ct),ARGIN (STRING * s))402 Parrot_pf_ConstTable_rlookup_str(PARROT_INTERP,
403     ARGIN(const PackFile_ConstTable *ct), ARGIN(STRING *s))
404 {
405     ASSERT_ARGS(Parrot_pf_ConstTable_rlookup_str)
406     int i;
407 
408     if (ct->string_hash) {
409         const HashBucket * const bucket = Parrot_hash_get_bucket(interp, ct->string_hash, s);
410         if (bucket) {
411             i = (int)PTR2INTVAL(bucket->value);
412             return i;
413         }
414         return -1;
415     }
416 
417     for (i = 0; i < ct->str.const_count; i++) {
418         STRING * const sc = ct->str.constants[i];
419         if ((s->encoding == sc->encoding) && STRING_equal(interp, s, sc)) {
420             return i;
421         }
422     }
423 
424     /* not found */
425     return -1;
426 }
427 
428 PARROT_EXPORT
429 int
Parrot_pf_ConstTable_rlookup_num(SHIM_INTERP,ARGIN (const PackFile_ConstTable * ct),FLOATVAL n)430 Parrot_pf_ConstTable_rlookup_num(SHIM_INTERP, ARGIN(const PackFile_ConstTable *ct), FLOATVAL n)
431 {
432     ASSERT_ARGS(Parrot_pf_ConstTable_rlookup_num)
433     int i;
434 
435     for (i = 0; i < ct->num.const_count; i++) {
436         if (ct->num.constants[i] == n)
437             return i;
438     }
439     /* not found */
440     return -1;
441 }
442 
443 PARROT_EXPORT
444 int
Parrot_pf_ConstTable_rlookup_pmc(PARROT_INTERP,ARGIN (PackFile_ConstTable * ct),ARGIN (PMC * v),ARGOUT (INTVAL * constno),ARGOUT (INTVAL * idx))445 Parrot_pf_ConstTable_rlookup_pmc(PARROT_INTERP,
446         ARGIN(PackFile_ConstTable *ct), ARGIN(PMC *v),
447         ARGOUT(INTVAL *constno), ARGOUT(INTVAL *idx))
448 {
449     ASSERT_ARGS(Parrot_pf_ConstTable_rlookup_pmc)
450     PMC *rec;
451 
452     PARROT_ASSERT(ct->pmc_hash);
453 
454     rec = (PMC *)Parrot_hash_get(interp, ct->pmc_hash, v);
455     if (rec) {
456         *constno = VTABLE_get_integer_keyed_int(interp, rec, 0);
457         *idx     = VTABLE_get_integer_keyed_int(interp, rec, 1);
458         return 1;
459     }
460 
461     return 0;
462 }
463 
464 PARROT_EXPORT
465 PARROT_DEPRECATED
466 int
PackFile_ConstTable_rlookup_num(SHIM_INTERP,ARGIN (const PackFile_ConstTable * ct),FLOATVAL n)467 PackFile_ConstTable_rlookup_num(SHIM_INTERP, ARGIN(const PackFile_ConstTable *ct), FLOATVAL n)
468 {
469     ASSERT_ARGS(PackFile_ConstTable_rlookup_num)
470     return Parrot_pf_ConstTable_rlookup_num(NULL, ct, n);
471 }
472 PARROT_EXPORT
473 PARROT_DEPRECATED
474 int
PackFile_ConstTable_rlookup_pmc(PARROT_INTERP,ARGIN (PackFile_ConstTable * ct),ARGIN (PMC * v),ARGOUT (INTVAL * constno),ARGOUT (INTVAL * idx))475 PackFile_ConstTable_rlookup_pmc(PARROT_INTERP,
476         ARGIN(PackFile_ConstTable *ct), ARGIN(PMC *v),
477         ARGOUT(INTVAL *constno), ARGOUT(INTVAL *idx))
478 {
479     ASSERT_ARGS(PackFile_ConstTable_rlookup_pmc)
480     return Parrot_pf_ConstTable_rlookup_pmc(interp, ct, v, constno, idx);
481 }
482 
483 PARROT_EXPORT
484 PARROT_DEPRECATED
485 int
PackFile_ConstTable_rlookup_str(PARROT_INTERP,ARGIN (const PackFile_ConstTable * ct),ARGIN (STRING * s))486 PackFile_ConstTable_rlookup_str(PARROT_INTERP,
487     ARGIN(const PackFile_ConstTable *ct), ARGIN(STRING *s))
488 {
489     ASSERT_ARGS(PackFile_ConstTable_rlookup_str)
490     return Parrot_pf_ConstTable_rlookup_str(interp, ct, s);
491 }
492 
493 /*
494 
495 =back
496 
497 =head1 HISTORY
498 
499 Rework by Melvin; new bytecode format, make bytecode portable. (Do
500 endian conversion and wordsize transforms on the fly.)
501 
502 leo: rewrite to use new directory-based format.
503 
504 rurban: api refactor and deprecations GH #1170
505 
506 =cut
507 
508 */
509 
510 
511 /*
512  * Local variables:
513  *   c-file-style: "parrot"
514  * End:
515  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
516  */
517