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