remove deprecation notice for TT #449
[parrot.git] / src / pbc_merge.c
blob61816ed7e6b20220cbc9f01409a75cd2d2d71e89
1 /*
2 Copyright (C) 2005-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 pbc_merge - Merge multiple Parrot bytecode (PBC) files into
8 a single PBC file.
10 =head1 SYNOPSIS
12 pbc_merge -o out.pbc input1.pbc input2.pbc ...
14 =head1 DESCRIPTION
16 This program takes two or more PBC files and produces a single
17 merged output PBC file with a single fix-up table and constants
18 table.
20 =head2 Command-Line Options
22 =over 4
24 =item C<-o out.pbc>
26 The name of the PBC file to produce, containing the merged
27 segments from the input PBC files.
29 =back
31 =head2 Functions
33 =over 4
35 =cut
40 #include "parrot/parrot.h"
41 #include "parrot/embed.h"
42 #include "parrot/oplib/ops.h"
43 #include "pmc/pmc_sub.h"
46 /* This struct describes an input file. */
47 typedef struct pbc_merge_input {
48 const char *filename; /* name of the input file */
49 PackFile *pf; /* loaded packfile struct */
50 opcode_t code_start; /* where the bytecode is located in the merged
51 packfile */
52 opcode_t const_start;/* where the const table is located within the
53 merged table */
54 opcode_t *const_map; /* map constants from input files to their location
55 in the output file */
56 } pbc_merge_input;
58 /* HEADERIZER HFILE: none */
60 /* HEADERIZER BEGIN: static */
61 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
63 PARROT_DOES_NOT_RETURN
64 static void help(PARROT_INTERP)
65 __attribute__nonnull__(1);
67 PARROT_WARN_UNUSED_RESULT
68 PARROT_CANNOT_RETURN_NULL
69 static PackFile* pbc_merge_begin(PARROT_INTERP,
70 ARGMOD(pbc_merge_input **inputs),
71 int num_inputs)
72 __attribute__nonnull__(1)
73 __attribute__nonnull__(2)
74 FUNC_MODIFIES(*inputs);
76 PARROT_WARN_UNUSED_RESULT
77 PARROT_CANNOT_RETURN_NULL
78 static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
79 ARGMOD(pbc_merge_input **inputs),
80 int num_inputs,
81 ARGMOD(PackFile *pf))
82 __attribute__nonnull__(1)
83 __attribute__nonnull__(2)
84 __attribute__nonnull__(4)
85 FUNC_MODIFIES(*inputs)
86 FUNC_MODIFIES(*pf);
88 PARROT_WARN_UNUSED_RESULT
89 PARROT_CANNOT_RETURN_NULL
90 static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
91 ARGMOD(pbc_merge_input **inputs),
92 int num_inputs,
93 ARGMOD(PackFile *pf),
94 ARGMOD(PackFile_ByteCode *bc))
95 __attribute__nonnull__(1)
96 __attribute__nonnull__(2)
97 __attribute__nonnull__(4)
98 __attribute__nonnull__(5)
99 FUNC_MODIFIES(*inputs)
100 FUNC_MODIFIES(*pf)
101 FUNC_MODIFIES(*bc);
103 static void pbc_merge_ctpointers(PARROT_INTERP,
104 ARGMOD(pbc_merge_input **inputs),
105 int num_inputs,
106 ARGMOD(PackFile_ByteCode *bc))
107 __attribute__nonnull__(1)
108 __attribute__nonnull__(2)
109 __attribute__nonnull__(4)
110 FUNC_MODIFIES(*inputs)
111 FUNC_MODIFIES(*bc);
113 static void pbc_merge_debugs(PARROT_INTERP,
114 ARGMOD(pbc_merge_input **inputs),
115 int num_inputs,
116 ARGMOD(PackFile *pf),
117 ARGMOD(PackFile_ByteCode *bc))
118 __attribute__nonnull__(1)
119 __attribute__nonnull__(2)
120 __attribute__nonnull__(4)
121 __attribute__nonnull__(5)
122 FUNC_MODIFIES(*inputs)
123 FUNC_MODIFIES(*pf)
124 FUNC_MODIFIES(*bc);
126 static void pbc_merge_fixups(PARROT_INTERP,
127 ARGIN(pbc_merge_input **inputs),
128 int num_inputs,
129 ARGMOD(PackFile *pf))
130 __attribute__nonnull__(1)
131 __attribute__nonnull__(2)
132 __attribute__nonnull__(4)
133 FUNC_MODIFIES(*pf);
135 PARROT_WARN_UNUSED_RESULT
136 PARROT_CANNOT_RETURN_NULL
137 static PackFile* pbc_merge_loadpbc(PARROT_INTERP,
138 ARGIN(const char *fullname))
139 __attribute__nonnull__(1)
140 __attribute__nonnull__(2);
142 static void pbc_merge_write(PARROT_INTERP,
143 ARGMOD(PackFile *pf),
144 ARGIN(const char *filename))
145 __attribute__nonnull__(1)
146 __attribute__nonnull__(2)
147 __attribute__nonnull__(3)
148 FUNC_MODIFIES(*pf);
150 #define ASSERT_ARGS_help __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
151 PARROT_ASSERT_ARG(interp))
152 #define ASSERT_ARGS_pbc_merge_begin __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
153 PARROT_ASSERT_ARG(interp) \
154 , PARROT_ASSERT_ARG(inputs))
155 #define ASSERT_ARGS_pbc_merge_bytecode __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
156 PARROT_ASSERT_ARG(interp) \
157 , PARROT_ASSERT_ARG(inputs) \
158 , PARROT_ASSERT_ARG(pf))
159 #define ASSERT_ARGS_pbc_merge_constants __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
160 PARROT_ASSERT_ARG(interp) \
161 , PARROT_ASSERT_ARG(inputs) \
162 , PARROT_ASSERT_ARG(pf) \
163 , PARROT_ASSERT_ARG(bc))
164 #define ASSERT_ARGS_pbc_merge_ctpointers __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
165 PARROT_ASSERT_ARG(interp) \
166 , PARROT_ASSERT_ARG(inputs) \
167 , PARROT_ASSERT_ARG(bc))
168 #define ASSERT_ARGS_pbc_merge_debugs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
169 PARROT_ASSERT_ARG(interp) \
170 , PARROT_ASSERT_ARG(inputs) \
171 , PARROT_ASSERT_ARG(pf) \
172 , PARROT_ASSERT_ARG(bc))
173 #define ASSERT_ARGS_pbc_merge_fixups __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
174 PARROT_ASSERT_ARG(interp) \
175 , PARROT_ASSERT_ARG(inputs) \
176 , PARROT_ASSERT_ARG(pf))
177 #define ASSERT_ARGS_pbc_merge_loadpbc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
178 PARROT_ASSERT_ARG(interp) \
179 , PARROT_ASSERT_ARG(fullname))
180 #define ASSERT_ARGS_pbc_merge_write __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
181 PARROT_ASSERT_ARG(interp) \
182 , PARROT_ASSERT_ARG(pf) \
183 , PARROT_ASSERT_ARG(filename))
184 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
185 /* HEADERIZER END: static */
189 =item C<static void help(PARROT_INTERP)>
191 Print out the user help info.
193 =cut
197 PARROT_DOES_NOT_RETURN
198 static void
199 help(PARROT_INTERP)
201 printf("pbc_merge - merge multiple parrot bytecode files into one\n");
202 printf("Usage:\n");
203 printf(" pbc_merge -o out.pbc file1.pbc file2.pbc ...\n\n");
204 Parrot_exit(interp, 0);
209 =item C<static PackFile* pbc_merge_loadpbc(PARROT_INTERP, const char *fullname)>
211 This function loads a PBC file and unpacks it. We can't
212 use Parrot_pbc_read because that is specified to also
213 fixup the segments, which we don't want.
215 =cut
219 PARROT_WARN_UNUSED_RESULT
220 PARROT_CANNOT_RETURN_NULL
221 static PackFile*
222 pbc_merge_loadpbc(PARROT_INTERP, ARGIN(const char *fullname))
224 ASSERT_ARGS(pbc_merge_loadpbc)
225 INTVAL program_size, wanted;
226 char *program_code;
227 PackFile *pf;
228 FILE * io = NULL;
229 INTVAL is_mapped = 0;
230 size_t chunk_size;
231 char *cursor;
232 INTVAL read_result;
234 /* Check the file exists. */
235 STRING * const fs = string_make(interp, fullname,
236 strlen(fullname), NULL, 0);
237 if (!Parrot_stat_info_intval(interp, fs, STAT_EXISTS)) {
238 Parrot_io_eprintf(interp, "PBC Merge: Can't stat %s, code %i.\n",
239 fullname, errno);
240 Parrot_exit(interp, 1);
243 /* Get program size. */
244 program_size = Parrot_stat_info_intval(interp, fs, STAT_FILESIZE);
246 /* Attempt to open file and handle any errors. */
247 io = fopen(fullname, "rb");
248 if (!io) {
249 Parrot_io_eprintf(interp, "PBC Merge: Can't open %s, code %i.\n",
250 fullname, errno);
251 Parrot_exit(interp, 1);
254 /* Read in program. Nabbed from Parrot_pbc_read. */
255 chunk_size = program_size > 0 ? program_size : 1024;
256 program_code = mem_gc_allocate_n_typed(interp, chunk_size, char);
257 wanted = program_size;
258 program_size = 0;
259 cursor = (char *)program_code;
261 while ((read_result = fread(cursor, 1, chunk_size, io)) > 0) {
262 program_size += read_result;
263 if (program_size == wanted)
264 break;
265 chunk_size = 1024;
266 program_code = mem_gc_realloc_n_typed(interp, program_code,
267 program_size + chunk_size, char);
269 cursor = (char *)program_code + program_size;
272 if (read_result < 0) {
273 Parrot_io_eprintf(interp,
274 "PBC Merge: Problem reading packfile from PIO.\n");
275 Parrot_exit(interp, 1);
277 fclose(io);
279 /* Now that we have the bytecode, let's unpack it. */
280 pf = PackFile_new(interp, is_mapped);
281 if (!PackFile_unpack(interp,
282 pf, (opcode_t *)program_code, program_size)) {
283 Parrot_io_eprintf(interp, "PBC Merge: Can't unpack packfile %s.\n",
284 fullname);
285 Parrot_exit(interp, 1);
288 /* Return the packfile. */
289 return pf;
295 =item C<static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
296 pbc_merge_input **inputs, int num_inputs, PackFile *pf)>
298 This function merges the bytecode from the input packfiles, storing the
299 offsets that each bit of bytecode now exists at.
301 =cut
305 PARROT_WARN_UNUSED_RESULT
306 PARROT_CANNOT_RETURN_NULL
307 static PackFile_ByteCode*
308 pbc_merge_bytecode(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
309 int num_inputs, ARGMOD(PackFile *pf))
311 ASSERT_ARGS(pbc_merge_bytecode)
312 int i;
313 opcode_t *bc = mem_gc_allocate_typed(interp, opcode_t);
314 opcode_t cursor = 0;
316 /* Add a bytecode segment. */
317 PackFile_ByteCode * const bc_seg =
318 (PackFile_ByteCode *)PackFile_Segment_new_seg(interp,
319 &pf->directory, PF_BYTEC_SEG, BYTE_CODE_SEGMENT_NAME, 1);
321 if (!bc_seg) {
322 Parrot_io_eprintf(interp,
323 "PBC Merge: Error creating bytecode segment.");
324 Parrot_exit(interp, 1);
327 /* Loop over input files. */
328 for (i = 0; i < num_inputs; ++i) {
329 /* Get the bytecode segment from the input file. */
330 PackFile_ByteCode * const in_seg = inputs[i]->pf->cur_cs;
331 if (in_seg == NULL) {
332 Parrot_io_eprintf(interp,
333 "PBC Merge: Cannot locate bytecode segment in %s",
334 inputs[i]->filename);
335 Parrot_exit(interp, 1);
338 /* Re-allocate the current buffer. */
339 bc = mem_gc_realloc_n_typed(interp, bc, cursor + in_seg->base.size, opcode_t);
341 /* Copy data and store cursor. */
342 memcpy(bc + cursor, in_seg->base.data,
343 in_seg->base.size * sizeof (opcode_t));
344 inputs[i]->code_start = cursor;
346 /* Update cursor. */
347 cursor += in_seg->base.size;
350 /* Stash produced bytecode. */
351 bc_seg->base.data = bc;
352 bc_seg->base.size = cursor;
353 bc_seg->base.name = Parrot_str_new_constant(interp, "MERGED");
354 return bc_seg;
360 =item C<static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
361 pbc_merge_input **inputs, int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
363 This function merges the constants tables from the input PBC files.
365 =cut
369 PARROT_WARN_UNUSED_RESULT
370 PARROT_CANNOT_RETURN_NULL
371 static PackFile_ConstTable*
372 pbc_merge_constants(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
373 int num_inputs, ARGMOD(PackFile *pf),
374 ARGMOD(PackFile_ByteCode *bc))
376 ASSERT_ARGS(pbc_merge_constants)
377 PackFile_Constant **constants = mem_gc_allocate_typed(interp, PackFile_Constant *);
379 opcode_t cursor = 0;
380 opcode_t output_const_num = 0;
381 opcode_t input_const_num = 0;
382 int i, j;
384 /* Add a constant table segment. */
385 PackFile_ConstTable * const const_seg = (PackFile_ConstTable *)
386 PackFile_Segment_new_seg(interp, &pf->directory,
387 PF_CONST_SEG, CONSTANT_SEGMENT_NAME, 1);
389 if (const_seg == NULL) {
390 Parrot_io_eprintf(interp,
391 "PBC Merge: Error creating constant table segment.");
392 Parrot_exit(interp, 1);
395 /* Loop over input files. */
396 for (i = 0; i < num_inputs; ++i) {
398 /* Get the constant table segment from the input file. */
399 PackFile_ConstTable * const in_seg = inputs[i]->pf->cur_cs->const_table;
400 if (in_seg == NULL) {
401 Parrot_io_eprintf(interp,
402 "PBC Merge: Cannot locate constant table segment in %s\n",
403 inputs[i]->filename);
404 Parrot_exit(interp, 1);
407 /* Store cursor as position where constant table starts. */
408 inputs[i]->const_start = cursor;
409 input_const_num = 0;
411 /* Allocate space for the constant list, provided we have some. */
412 if (in_seg->const_count > 0)
413 constants = mem_gc_realloc_n_typed(interp, constants,
414 cursor + in_seg->const_count, PackFile_Constant*);
416 /* Loop over the constants and copy them to the output PBC. */
417 for (j = 0; j < in_seg->const_count; ++j) {
418 /* Get the entry and allocate space for copy. */
419 PackFile_Constant *cur_entry = in_seg->constants[j];
420 PackFile_Constant *copy = mem_gc_allocate_typed(interp,
421 PackFile_Constant);
422 STRUCT_COPY(copy, cur_entry);
424 /* If it's a sub PMC, need to deal with offsets. */
425 if (copy->type == PFC_PMC) {
426 switch (copy->u.key->vtable->base_type) {
427 case enum_class_Sub:
428 case enum_class_Coroutine:
430 Parrot_Sub_attributes *sub;
431 PMC_get_sub(interp, copy->u.key, sub);
432 sub->start_offs += inputs[i]->code_start;
433 sub->end_offs += inputs[i]->code_start;
435 break;
436 default:
437 break;
441 inputs[i]->const_map[input_const_num] = output_const_num;
442 ++input_const_num;
443 ++output_const_num;
445 /* Slot it into the list. */
446 constants[cursor] = copy;
447 ++cursor;
451 /* Stash merged constants table and count and return the new segment. */
452 const_seg->constants = constants;
453 const_seg->const_count = cursor;
454 const_seg->code = bc;
455 bc->const_table = const_seg;
456 return const_seg;
462 =item C<static void pbc_merge_fixups(PARROT_INTERP, pbc_merge_input **inputs,
463 int num_inputs, PackFile *pf)>
465 This function merges the fixups tables from the input PBC files.
467 =cut
471 static void
472 pbc_merge_fixups(PARROT_INTERP, ARGIN(pbc_merge_input **inputs),
473 int num_inputs, ARGMOD(PackFile *pf))
475 ASSERT_ARGS(pbc_merge_fixups)
476 PackFile_FixupTable *fixup_seg;
477 PackFile_FixupEntry *fixups = NULL;
478 opcode_t cursor = 0;
479 int i;
481 /* Add a fixup table segment. */
482 fixup_seg = (PackFile_FixupTable*)PackFile_Segment_new_seg(
483 interp, &pf->directory, PF_FIXUP_SEG, FIXUP_TABLE_SEGMENT_NAME, 1);
484 if (fixup_seg == NULL) {
485 Parrot_io_eprintf(interp,
486 "PBC Merge: Error creating fixup table segment.");
487 Parrot_exit(interp, 1);
490 /* Loop over input files. */
491 for (i = 0; i < num_inputs; ++i) {
492 /* Get the fixup segment from the input file. */
493 PackFile_FixupTable * const in_seg = inputs[i]->pf->cur_cs->fixups;
494 int j;
496 if (in_seg == NULL) {
497 Parrot_io_eprintf(interp,
498 "PBC Merge: Cannot locate fixup segment in %s",
499 inputs[i]->filename);
500 Parrot_exit(interp, 1);
503 /* Allocate space for these fixups, provided we have some. */
504 if (in_seg->fixup_count > 0) {
505 fixups = mem_gc_realloc_n_typed(interp, fixups,
506 cursor + in_seg->fixup_count, PackFile_FixupEntry);
509 /* Loop over the fixups and copy them to the output PBC, correcting
510 the offsets into the bytecode. */
511 for (j = 0; j < in_seg->fixup_count; ++j) {
512 /* Get the entry and allocate space for copies. */
513 const PackFile_FixupEntry * const cur_entry = in_seg->fixups + j;
514 PackFile_FixupEntry * const copy =
515 mem_gc_allocate_typed(interp, PackFile_FixupEntry);
516 char * const name_copy = mem_gc_allocate_n_typed(interp,
517 strlen(cur_entry->name) + 1, char);
519 /* Copy type and name. */
520 copy->type = cur_entry->type;
521 strcpy(name_copy, cur_entry->name);
522 copy->name = name_copy;
524 /* Set new offset and bytecode pointer. */
525 switch (copy->type) {
526 case enum_fixup_sub:
527 copy->offset = cur_entry->offset + inputs[i]->const_start;
528 break;
529 default:
530 Parrot_io_eprintf(interp, "PBC Merge: Unknown fixup type");
531 Parrot_exit(interp, 1);
534 /* Slot it into the list. */
535 fixups[cursor] = *copy;
536 ++cursor;
540 /* Stash merged fixup table and count. */
541 fixup_seg->fixups = fixups;
542 fixup_seg->fixup_count = cursor;
548 =item C<static void pbc_merge_debugs(PARROT_INTERP, pbc_merge_input **inputs,
549 int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
551 This function merges the debug segments from the input PBC files.
553 =cut
557 static void
558 pbc_merge_debugs(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
559 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
561 ASSERT_ARGS(pbc_merge_debugs)
562 PackFile_Debug *debug_seg;
563 opcode_t *lines = mem_gc_allocate_typed(interp,
564 opcode_t);
565 PackFile_DebugFilenameMapping *mappings =
566 mem_gc_allocate_typed(interp, PackFile_DebugFilenameMapping);
568 opcode_t num_mappings = 0;
569 opcode_t num_lines = 0;
571 int i;
573 /* We need to merge both the mappings and the list of line numbers.
574 The line numbers can just be concatenated. The mappings must have
575 their offsets fixed up. */
576 for (i = 0; i < num_inputs; ++i) {
577 const PackFile_Debug * const in_seg = inputs[i]->pf->cur_cs->debugs;
578 int j;
580 /* Concatenate line numbers. */
581 lines = mem_gc_realloc_n_typed(interp, lines,
582 num_lines + in_seg->base.size, opcode_t);
584 memcpy(lines + num_lines, in_seg->base.data,
585 in_seg->base.size * sizeof (opcode_t));
587 /* Concatenate mappings. */
588 mappings = mem_gc_realloc_n_typed(interp, mappings,
589 num_mappings + in_seg->num_mappings,
590 PackFile_DebugFilenameMapping);
592 for (j = 0; j < in_seg->num_mappings; ++j) {
593 PackFile_DebugFilenameMapping *mapping = mappings + num_mappings + j;
595 STRUCT_COPY_FROM_STRUCT(mapping, in_seg->mappings[j]);
596 mapping->offset += num_lines;
597 mapping->filename += inputs[i]->const_start;
600 num_lines += in_seg->base.size - 1;
601 num_mappings += in_seg->num_mappings;
604 /* Create merged debug segment. Replace created data and mappings
605 with merged ones we have created. */
606 debug_seg = Parrot_new_debug_seg(interp, bc, num_lines);
607 PackFile_add_segment(interp, &pf->directory, (PackFile_Segment*)debug_seg);
608 mem_gc_free(interp, debug_seg->base.data);
609 debug_seg->base.data = lines;
610 mem_gc_free(interp, debug_seg->mappings);
612 debug_seg->mappings = mappings;
613 debug_seg->num_mappings = num_mappings;
618 =item C<static void pbc_merge_ctpointers(PARROT_INTERP, pbc_merge_input
619 **inputs, int num_inputs, PackFile_ByteCode *bc)>
621 This function corrects the pointers into the constants table found in the
622 bytecode.
624 =cut
628 static void
629 pbc_merge_ctpointers(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
630 int num_inputs, ARGMOD(PackFile_ByteCode *bc))
632 ASSERT_ARGS(pbc_merge_ctpointers)
633 int cur_arg;
634 opcode_t *op_ptr;
635 opcode_t *ops = bc->base.data;
636 opcode_t cur_op = 0;
637 int cur_input = 0;
639 /* Loop over the ops in the merged bytecode. */
640 while (cur_op < (opcode_t)bc->base.size) {
641 op_info_t *op;
642 opcode_t op_num;
644 /* Keep track of the current input file. */
645 if (cur_input + 1 < num_inputs &&
646 cur_op >= inputs[cur_input + 1]->code_start)
647 ++cur_input;
649 /* Get info about this op and jump over it. */
650 op_num = ops[cur_op];
651 op = &interp->op_info_table[op_num];
652 op_ptr = ops + cur_op;
653 ++cur_op;
655 /* Loop over the arguments. */
656 for (cur_arg = 1; cur_arg < op->op_count; ++cur_arg) {
657 /* Pick out any indexes into the constant table and correct them. */
658 switch (op->types[cur_arg - 1]) {
659 case PARROT_ARG_NC:
660 case PARROT_ARG_PC:
661 case PARROT_ARG_SC:
662 case PARROT_ARG_NAME_SC:
663 case PARROT_ARG_KC:
664 ops[cur_op] = inputs[cur_input]->const_map[ ops[cur_op] ];
665 break;
666 default:
667 break;
670 /* Move along the bytecode array. */
671 ++cur_op;
674 /* Handle special case variable argument opcodes. */
675 if (op_num == PARROT_OP_set_args_pc ||
676 op_num == PARROT_OP_get_results_pc ||
677 op_num == PARROT_OP_get_params_pc ||
678 op_num == PARROT_OP_set_returns_pc) {
679 /* Get the signature. */
680 PMC * const sig = bc->const_table->constants[op_ptr[1]]->u.key;
682 /* Loop over the arguments to locate any that need a fixup. */
683 const int sig_items = VTABLE_elements(interp, sig);
684 for (cur_arg = 0; cur_arg < sig_items; ++cur_arg) {
685 switch (VTABLE_get_integer_keyed_int(interp, sig, cur_arg)) {
686 case PARROT_ARG_NC:
687 case PARROT_ARG_PC:
688 case PARROT_ARG_SC:
689 case PARROT_ARG_NAME_SC:
690 case PARROT_ARG_KC:
691 ops[cur_op] = inputs[cur_input]->const_map[ ops[cur_op] ];
692 break;
693 default:
694 break;
696 ++cur_op;
705 =item C<static PackFile* pbc_merge_begin(PARROT_INTERP, pbc_merge_input
706 **inputs, int num_inputs)>
708 This is the function that drives PBC merging process.
710 =cut
713 PARROT_WARN_UNUSED_RESULT
714 PARROT_CANNOT_RETURN_NULL
715 static PackFile*
716 pbc_merge_begin(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs), int num_inputs)
718 ASSERT_ARGS(pbc_merge_begin)
719 PackFile_ByteCode *bc;
720 PackFile_ConstTable *ct;
721 int i;
723 /* Create a new empty packfile. */
724 PackFile * const merged = PackFile_new(interp, 0);
725 if (merged == NULL) {
726 Parrot_io_eprintf(interp, "PBC Merge: Error creating new packfile.\n");
727 Parrot_exit(interp, 1);
730 /* calculate how many constants are stored in the packfiles to be merged */
731 for (i = 0; i < num_inputs; ++i) {
732 PackFile_Directory *pf_dir = &inputs[i]->pf->directory;
733 unsigned int j = 0;
734 for (j = 0; j < pf_dir->num_segments; ++j) {
735 PackFile_Segment *seg = (PackFile_Segment *)pf_dir->segments[j];
736 if (seg->type == PF_CONST_SEG) {
737 opcode_t const_count = ((PackFile_ConstTable *)seg)->const_count;
738 inputs[i]->const_map = mem_gc_allocate_n_typed(interp,
739 const_count, opcode_t);
744 /* Merge the various stuff. */
745 bc = pbc_merge_bytecode(interp, inputs, num_inputs, merged);
746 ct = pbc_merge_constants(interp, inputs, num_inputs, merged, bc);
747 UNUSED(ct);
749 pbc_merge_fixups(interp, inputs, num_inputs, merged);
750 pbc_merge_debugs(interp, inputs, num_inputs, merged, bc);
752 /* Walk bytecode and fix ops that reference the constants table. */
753 pbc_merge_ctpointers(interp, inputs, num_inputs, bc);
755 for (i = 0; i < num_inputs; ++i) {
756 mem_gc_free(interp, inputs[i]->const_map);
759 /* Return merged result. */
760 return merged;
766 =item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
767 *filename)>
769 This functions writes out the merged packfile.
771 =cut
775 static void
776 pbc_merge_write(PARROT_INTERP, ARGMOD(PackFile *pf), ARGIN(const char *filename))
778 ASSERT_ARGS(pbc_merge_write)
779 FILE *fp;
781 /* Get size of packfile we'll write. */
782 const size_t size = PackFile_pack_size(interp, pf) * sizeof (opcode_t);
784 /* Allocate memory. */
785 opcode_t * const pack = (opcode_t*) Parrot_gc_allocate_memory_chunk(interp, size);
787 /* Write and clean up. */
788 PackFile_pack(interp, pf, pack);
789 if ((fp = fopen(filename, "wb")) == 0) {
790 Parrot_io_eprintf(interp, "PBC Merge: Couldn't open %s\n", filename);
791 Parrot_exit(interp, 1);
793 if ((1 != fwrite(pack, size, 1, fp))) {
794 Parrot_io_eprintf(interp, "PBC Merge: Couldn't write %s\n", filename);
795 Parrot_exit(interp, 1);
797 fclose(fp);
798 mem_gc_free(interp, pack);
804 =item C<int main(int argc, const char **argv)>
806 The main function that grabs console input, reads in the packfiles
807 provided they exist, hands them to another function that runs the
808 merge process and finally writes out the produced packfile.
810 =cut
814 static struct longopt_opt_decl options[] = {
815 { 'o', 'o', OPTION_required_FLAG, { "--output" } }
819 main(int argc, const char **argv)
821 int status;
822 pbc_merge_input** input_files;
823 PackFile *merged;
824 int i;
825 const char *output_file = NULL;
826 struct longopt_opt_info opt = LONGOPT_OPT_INFO_INIT;
827 Interp * const interp = Parrot_new(NULL);
829 Parrot_block_GC_mark(interp);
831 /* Get options, ensuring we have at least one input
832 file and an output file. */
833 if (argc < 4) {
834 help(interp);
836 while ((status = longopt_get(interp, argc, argv, options, &opt)) > 0) {
837 switch (opt.opt_id) {
838 case 'o':
839 if (output_file == NULL)
840 output_file = opt.opt_arg;
841 else
842 help(interp);
843 break;
844 case '?':
845 help(interp);
846 break;
847 default:
848 break;
851 if (status == -1 || !output_file) {
852 help(interp);
854 argc -= opt.opt_index; /* Now the number of input files. */
855 argv += opt.opt_index; /* Now at first input filename. */
857 /* Load each packfile that we are to merge and set up an input
858 structure for each of them. */
859 input_files = mem_gc_allocate_n_typed(interp, argc, pbc_merge_input*);
861 for (i = 0; i < argc; ++i) {
862 /* Allocate a struct. */
863 input_files[i] = mem_gc_allocate_typed(interp, pbc_merge_input);
865 /* Set filename */
866 input_files[i]->filename = *argv;
868 /* Load the packfile and unpack it. */
869 input_files[i]->pf = pbc_merge_loadpbc(interp,
870 input_files[i]->filename);
871 if (input_files[i]->pf == NULL) {
872 Parrot_io_eprintf(interp,
873 "PBC Merge: Unknown error while reading and unpacking %s\n",
874 *argv);
875 Parrot_exit(interp, 1);
878 /* Next file. */
879 ++argv;
882 /* Merge. */
883 merged = pbc_merge_begin(interp, input_files, argc);
885 /* Write merged packfile. */
886 pbc_merge_write(interp, merged, output_file);
888 /* Finally, we're done. */
889 Parrot_exit(interp, 0);
894 * Local variables:
895 * c-file-style: "parrot"
896 * End:
897 * vim: expandtab shiftwidth=4: