tagged release 0.6.4
[parrot.git] / src / pbc_merge.c
blob8661c64b3c20ca554a1f47b748be59622aacc8a3
1 /*
2 Copyright (C) 2005-2008, The Perl 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"
45 /* This struct describes an input file. */
46 typedef struct pbc_merge_input {
47 const char *filename; /* Filename of the input file. */
48 PackFile *pf; /* The loaded packfile. */
49 opcode_t code_start; /* Where the bytecode is located in the merged
50 bytecode. */
51 opcode_t const_start; /* Where the const table is located in the merged
52 one. */
53 } pbc_merge_input;
55 /* HEADERIZER HFILE: none */
57 /* HEADERIZER BEGIN: static */
58 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
60 PARROT_DOES_NOT_RETURN
61 static void help(PARROT_INTERP)
62 __attribute__nonnull__(1);
64 PARROT_WARN_UNUSED_RESULT
65 PARROT_CANNOT_RETURN_NULL
66 static PackFile* pbc_merge_begin(PARROT_INTERP,
67 ARGMOD(pbc_merge_input **inputs),
68 int num_inputs)
69 __attribute__nonnull__(1)
70 __attribute__nonnull__(2)
71 FUNC_MODIFIES(*inputs);
73 PARROT_WARN_UNUSED_RESULT
74 PARROT_CANNOT_RETURN_NULL
75 static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
76 ARGMOD(pbc_merge_input **inputs),
77 int num_inputs,
78 ARGMOD(PackFile *pf))
79 __attribute__nonnull__(1)
80 __attribute__nonnull__(2)
81 __attribute__nonnull__(4)
82 FUNC_MODIFIES(*inputs)
83 FUNC_MODIFIES(*pf);
85 PARROT_WARN_UNUSED_RESULT
86 PARROT_CANNOT_RETURN_NULL
87 static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
88 ARGMOD(pbc_merge_input **inputs),
89 int num_inputs,
90 ARGMOD(PackFile *pf),
91 ARGMOD(PackFile_ByteCode *bc))
92 __attribute__nonnull__(1)
93 __attribute__nonnull__(2)
94 __attribute__nonnull__(4)
95 __attribute__nonnull__(5)
96 FUNC_MODIFIES(*inputs)
97 FUNC_MODIFIES(*pf)
98 FUNC_MODIFIES(*bc);
100 static void pbc_merge_ctpointers(PARROT_INTERP,
101 ARGMOD(pbc_merge_input **inputs),
102 int num_inputs,
103 ARGMOD(PackFile_ByteCode *bc))
104 __attribute__nonnull__(1)
105 __attribute__nonnull__(2)
106 __attribute__nonnull__(4)
107 FUNC_MODIFIES(*inputs)
108 FUNC_MODIFIES(*bc);
110 static void pbc_merge_debugs(PARROT_INTERP,
111 ARGMOD(pbc_merge_input **inputs),
112 int num_inputs,
113 ARGMOD(PackFile *pf),
114 ARGMOD(PackFile_ByteCode *bc))
115 __attribute__nonnull__(1)
116 __attribute__nonnull__(2)
117 __attribute__nonnull__(4)
118 __attribute__nonnull__(5)
119 FUNC_MODIFIES(*inputs)
120 FUNC_MODIFIES(*pf)
121 FUNC_MODIFIES(*bc);
123 static void pbc_merge_fixups(PARROT_INTERP,
124 ARGIN(pbc_merge_input **inputs),
125 int num_inputs,
126 ARGMOD(PackFile *pf),
127 ARGMOD(PackFile_ByteCode *bc))
128 __attribute__nonnull__(1)
129 __attribute__nonnull__(2)
130 __attribute__nonnull__(4)
131 __attribute__nonnull__(5)
132 FUNC_MODIFIES(*pf)
133 FUNC_MODIFIES(*bc);
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_pic_index(PARROT_INTERP,
143 ARGMOD(pbc_merge_input **inputs),
144 int num_inputs,
145 ARGMOD(PackFile *pf),
146 ARGMOD(PackFile_ByteCode *bc))
147 __attribute__nonnull__(1)
148 __attribute__nonnull__(2)
149 __attribute__nonnull__(4)
150 __attribute__nonnull__(5)
151 FUNC_MODIFIES(*inputs)
152 FUNC_MODIFIES(*pf)
153 FUNC_MODIFIES(*bc);
155 static void pbc_merge_write(PARROT_INTERP,
156 ARGMOD(PackFile *pf),
157 ARGIN(const char *filename))
158 __attribute__nonnull__(1)
159 __attribute__nonnull__(2)
160 __attribute__nonnull__(3)
161 FUNC_MODIFIES(*pf);
163 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
164 /* HEADERIZER END: static */
168 =item C<static void help>
170 Print out the user help info.
172 =cut
176 PARROT_DOES_NOT_RETURN
177 static void
178 help(PARROT_INTERP)
180 printf("pbc_merge - merge multiple parrot bytecode files into one\n");
181 printf("Usage:\n");
182 printf(" pbc_merge -o out.pbc file1.pbc file2.pbc ...\n\n");
183 Parrot_exit(interp, 0);
188 =item C<static PackFile* pbc_merge_loadpbc>
190 This function loads a PBC file and unpacks it. We can't
191 use Parrot_readbc because that is specified to also
192 fixup the segments, which we don't want.
194 =cut
198 PARROT_WARN_UNUSED_RESULT
199 PARROT_CANNOT_RETURN_NULL
200 static PackFile*
201 pbc_merge_loadpbc(PARROT_INTERP, ARGIN(const char *fullname))
203 INTVAL program_size, wanted;
204 char *program_code;
205 PackFile *pf;
206 FILE * io = NULL;
207 INTVAL is_mapped = 0;
208 size_t chunk_size;
209 char *cursor;
210 INTVAL read_result;
212 /* Check the file exists. */
213 STRING * const fs = string_make(interp, fullname,
214 strlen(fullname), NULL, 0);
215 if (!Parrot_stat_info_intval(interp, fs, STAT_EXISTS)) {
216 PIO_eprintf(interp, "PBC Merge: Can't stat %s, code %i.\n",
217 fullname, errno);
218 Parrot_exit(interp, 1);
221 /* Get program size. */
222 program_size = Parrot_stat_info_intval(interp, fs, STAT_FILESIZE);
224 /* Attempt to open file and handle any errors. */
225 io = fopen(fullname, "rb");
226 if (!io) {
227 PIO_eprintf(interp, "PBC Merge: Can't open %s, code %i.\n",
228 fullname, errno);
229 Parrot_exit(interp, 1);
232 /* Read in program. Nabbed from Parrot_readpbc. */
233 chunk_size = program_size > 0 ? program_size : 1024;
234 program_code = (char *)mem_sys_allocate(chunk_size);
235 wanted = program_size;
236 program_size = 0;
237 cursor = (char *)program_code;
239 while ((read_result = fread(cursor, 1, chunk_size, io)) > 0) {
240 program_size += read_result;
241 if (program_size == wanted)
242 break;
243 chunk_size = 1024;
244 program_code =
245 (char *)mem_sys_realloc(program_code, program_size + chunk_size);
247 if (!program_code) {
248 PIO_eprintf(interp,
249 "PBC Merge: Could not reallocate buffer");
250 Parrot_exit(interp, 1);
253 cursor = (char *)program_code + program_size;
256 if (read_result < 0) {
257 PIO_eprintf(interp,
258 "PBC Merge: Problem reading packfile from PIO.\n");
259 Parrot_exit(interp, 1);
261 fclose(io);
263 /* Now that we have the bytecode, let's unpack it. */
264 pf = PackFile_new(interp, is_mapped);
265 if (!PackFile_unpack(interp,
266 pf, (opcode_t *)program_code, program_size)) {
267 PIO_eprintf(interp, "PBC Merge: Can't unpack packfile %s.\n",
268 fullname);
269 Parrot_exit(interp, 1);
272 /* Return the packfile. */
273 return pf;
279 =item C<static PackFile_ByteCode* pbc_merge_bytecode>
281 This function merges the bytecode from the input packfiles, storing the
282 offsets that each bit of bytecode now exists at.
284 =cut
288 PARROT_WARN_UNUSED_RESULT
289 PARROT_CANNOT_RETURN_NULL
290 static PackFile_ByteCode*
291 pbc_merge_bytecode(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
292 int num_inputs, ARGMOD(PackFile *pf))
294 opcode_t *bc = mem_allocate_typed(opcode_t);
295 opcode_t cursor = 0;
296 int i;
298 /* Add a bytecode segment. */
299 PackFile_ByteCode * const bc_seg =
300 (PackFile_ByteCode *)PackFile_Segment_new_seg(interp,
301 &pf->directory, PF_BYTEC_SEG, BYTE_CODE_SEGMENT_NAME, 1);
302 if (bc_seg == NULL) {
303 PIO_eprintf(interp, "PBC Merge: Error creating bytecode segment.");
304 Parrot_exit(interp, 1);
307 /* Loop over input files. */
308 for (i = 0; i < num_inputs; i++) {
309 /* Get the bytecode segment from the input file. */
310 PackFile_ByteCode * const in_seg = inputs[i]->pf->cur_cs;
311 if (in_seg == NULL) {
312 PIO_eprintf(interp,
313 "PBC Merge: Cannot locate bytecode segment in %s",
314 inputs[i]->filename);
315 Parrot_exit(interp, 1);
318 /* Re-allocate the current buffer. */
319 mem_realloc_n_typed(bc, cursor + in_seg->base.size, opcode_t);
320 if (bc == NULL) {
321 PIO_eprintf(interp, "PBC Merge: Cannot reallocate memory\n");
322 Parrot_exit(interp, 1);
325 /* Copy data and store cursor. */
326 memcpy(bc + cursor, in_seg->base.data,
327 in_seg->base.size * sizeof (opcode_t));
328 inputs[i]->code_start = cursor;
330 /* Update cursor. */
331 cursor += in_seg->base.size;
334 /* Stash produced bytecode. */
335 bc_seg->base.data = bc;
336 bc_seg->base.size = cursor;
337 bc_seg->base.name = str_dup("MERGED");
338 return bc_seg;
344 =item C<static PackFile_ConstTable* pbc_merge_constants>
346 This function merges the constants tables from the input PBC files.
348 =cut
352 PARROT_WARN_UNUSED_RESULT
353 PARROT_CANNOT_RETURN_NULL
354 static PackFile_ConstTable*
355 pbc_merge_constants(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
356 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
358 PackFile_Constant **constants = mem_allocate_typed(PackFile_Constant *);
359 opcode_t cursor = 0;
360 int i, j;
362 /* Add a constant table segment. */
363 PackFile_ConstTable * const const_seg = (PackFile_ConstTable*)PackFile_Segment_new_seg(
364 interp, &pf->directory, PF_CONST_SEG, CONSTANT_SEGMENT_NAME, 1);
365 if (const_seg == NULL) {
366 PIO_eprintf(interp,
367 "PBC Merge: Error creating constant table segment.");
368 Parrot_exit(interp, 1);
371 /* Loop over input files. */
372 for (i = 0; i < num_inputs; i++) {
373 /* Get the constant table segment from the input file. */
374 PackFile_ConstTable * const in_seg = inputs[i]->pf->cur_cs->const_table;
375 if (in_seg == NULL) {
376 PIO_eprintf(interp,
377 "PBC Merge: Cannot locate constant table segment in %s\n",
378 inputs[i]->filename);
379 Parrot_exit(interp, 1);
382 /* Store cursor as position where constant table starts. */
383 inputs[i]->const_start = cursor;
385 /* Allocate space for the constant list, provided we have some. */
386 if (in_seg->const_count > 0) {
387 constants = (PackFile_Constant **)mem_sys_realloc(constants,
388 (cursor + in_seg->const_count) * sizeof (Parrot_Pointer));
389 if (constants == NULL) {
390 PIO_eprintf(interp, "PBC Merge: Out of memory");
391 Parrot_exit(interp, 1);
395 /* Loop over the constants and copy them to the output PBC. */
396 for (j = 0; j < in_seg->const_count; j++) {
397 /* Get the entry and allocate space for copy. */
398 PackFile_Constant *cur_entry = in_seg->constants[j];
399 PackFile_Constant *copy = mem_allocate_typed(
400 PackFile_Constant);
401 if (copy == NULL) {
402 PIO_eprintf(interp, "PBC Merge: Out of memory");
403 Parrot_exit(interp, 1);
406 STRUCT_COPY(copy, cur_entry);
408 /* If it's a sub PMC, need to deal with offsets. */
409 if (copy->type == PFC_PMC) {
410 switch (copy->u.key->vtable->base_type) {
411 case enum_class_Sub:
412 case enum_class_Closure:
413 case enum_class_Coroutine:
415 Parrot_sub * const sub = PMC_sub(copy->u.key);
416 sub->start_offs += inputs[i]->code_start;
417 sub->end_offs += inputs[i]->code_start;
419 break;
420 default:
421 break;
425 /* Slot it into the list. */
426 constants[cursor] = copy;
427 cursor++;
431 /* Stash merged constants table and count and return the new segment. */
432 const_seg->constants = constants;
433 const_seg->const_count = cursor;
434 const_seg->code = bc;
435 bc->const_table = const_seg;
436 return const_seg;
442 =item C<static void pbc_merge_fixups>
444 This function merges the fixups tables from the input PBC files.
446 =cut
450 static void
451 pbc_merge_fixups(PARROT_INTERP, ARGIN(pbc_merge_input **inputs),
452 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
454 PackFile_FixupTable *fixup_seg;
455 PackFile_FixupEntry **fixups = mem_allocate_typed(PackFile_FixupEntry *);
456 opcode_t cursor = 0;
457 int i, j;
459 /* Add a fixup table segment. */
460 fixup_seg = (PackFile_FixupTable*)PackFile_Segment_new_seg(
461 interp, &pf->directory, PF_FIXUP_SEG, FIXUP_TABLE_SEGMENT_NAME, 1);
462 if (fixup_seg == NULL) {
463 PIO_eprintf(interp,
464 "PBC Merge: Error creating fixup table segment.");
465 Parrot_exit(interp, 1);
468 /* Loop over input files. */
469 for (i = 0; i < num_inputs; i++) {
470 /* Get the fixup segment from the input file. */
471 PackFile_FixupTable * const in_seg = inputs[i]->pf->cur_cs->fixups;
472 if (in_seg == NULL) {
473 PIO_eprintf(interp,
474 "PBC Merge: Cannot locate fixup segment in %s",
475 inputs[i]->filename);
476 Parrot_exit(interp, 1);
479 /* Allocate space for these fixups, provided we have some. */
480 if (in_seg->fixup_count > 0) {
481 fixups = (PackFile_FixupEntry **)mem_sys_realloc(fixups,
482 (cursor + in_seg->fixup_count) * sizeof (Parrot_Pointer));
483 if (fixups == NULL) {
484 PIO_eprintf(interp, "PBC Merge: Out of memory");
485 Parrot_exit(interp, 1);
489 /* Loop over the fixups and copy them to the output PBC, correcting
490 the offsets into the bytecode. */
491 for (j = 0; j < in_seg->fixup_count; j++) {
492 /* Get the entry and allocate space for copies. */
493 PackFile_FixupEntry *cur_entry = in_seg->fixups[j];
494 PackFile_FixupEntry *copy = mem_allocate_typed(
495 PackFile_FixupEntry);
496 char *name_copy = (char *)mem_sys_allocate(
497 strlen(cur_entry->name) + 1);
498 if (copy == NULL || name_copy == NULL) {
499 PIO_eprintf(interp, "PBC Merge: Out of memory");
500 Parrot_exit(interp, 1);
503 /* Copy type and name. */
504 copy->type = cur_entry->type;
505 strcpy(name_copy, cur_entry->name);
506 copy->name = name_copy;
508 /* Set new offset and bytecode pointer. */
509 switch (copy->type) {
510 case enum_fixup_label:
511 copy->offset = cur_entry->offset + inputs[i]->code_start;
512 break;
513 case enum_fixup_sub:
514 copy->offset = cur_entry->offset + inputs[i]->const_start;
515 break;
516 default:
517 PIO_eprintf(interp, "PBC Merge: Unknown fixup type");
518 Parrot_exit(interp, 1);
521 copy->seg = bc;
523 /* Slot it into the list. */
524 fixups[cursor] = copy;
525 cursor++;
529 /* Stash merged fixup table and count. */
530 fixup_seg->fixups = fixups;
531 fixup_seg->fixup_count = cursor;
537 =item C<static void pbc_merge_debugs>
539 This function merges the debug segments from the input PBC files.
541 =cut
545 static void
546 pbc_merge_debugs(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
547 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
549 PackFile_Debug *debug_seg;
550 opcode_t *lines = mem_allocate_typed(opcode_t);
551 PackFile_DebugMapping **mappings =
552 mem_allocate_typed(PackFile_DebugMapping *);
553 opcode_t num_mappings = 0;
554 opcode_t num_lines = 0;
555 int i, j;
557 /* We need to merge both the mappings and the list of line numbers.
558 The line numbers can just be concatenated. The mappings must have
559 their offsets fixed up. */
560 for (i = 0; i < num_inputs; i++) {
561 PackFile_Debug *in_seg = inputs[i]->pf->cur_cs->debugs;
563 /* Concatenate line numbers. */
564 lines = (opcode_t *)mem_sys_realloc(lines,
565 (num_lines + in_seg->base.size) * sizeof (opcode_t));
566 if (lines == NULL) {
567 PIO_eprintf(interp, "PBC Merge: Cannot reallocate memory\n");
568 Parrot_exit(interp, 1);
570 memcpy(lines + num_lines, in_seg->base.data,
571 in_seg->base.size * sizeof (opcode_t));
573 /* Concatenate mappings. */
574 mappings = (PackFile_DebugMapping **)mem_sys_realloc(mappings,
575 (num_mappings + in_seg->num_mappings) *
576 sizeof (Parrot_Pointer));
577 for (j = 0; j < in_seg->num_mappings; j++) {
578 PackFile_DebugMapping *mapping = mem_allocate_typed(
579 PackFile_DebugMapping);
580 STRUCT_COPY(mapping, in_seg->mappings[j]);
581 mapping->offset += num_lines;
582 if (mapping->mapping_type == PF_DEBUGMAPPINGTYPE_FILENAME)
583 mapping->u.filename += inputs[i]->const_start;
584 mappings[num_mappings + j] = mapping;
587 /* Update counts. */
588 num_lines += in_seg->base.size;
589 num_mappings += in_seg->num_mappings;
592 /* Create merged debug segment. Replace created data and mappings
593 with merged ones we have created. */
594 debug_seg = Parrot_new_debug_seg(interp, bc, num_lines);
595 PackFile_add_segment(interp, &pf->directory, (PackFile_Segment*)debug_seg);
596 mem_sys_free(debug_seg->base.data);
597 debug_seg->base.data = lines;
598 mem_sys_free(debug_seg->mappings);
600 debug_seg->mappings = mappings;
601 debug_seg->num_mappings = num_mappings;
606 =item C<static void pbc_merge_pic_index>
608 This function merges the pic_index segments from the input PBC files.
610 =cut
614 static void
615 pbc_merge_pic_index(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
616 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
618 int i;
619 PackFile_Segment *pic_index;
620 size_t size;
621 opcode_t cursor = 0;
622 opcode_t start = 0;
623 opcode_t last = 0;
625 /* calc needed size */
626 for (i = 0, size = 0; i < num_inputs; i++) {
627 PackFile_Segment * const in_seg = inputs[i]->pf->cur_cs->pic_index;
628 size += in_seg->size;
630 pic_index = PackFile_Segment_new_seg(interp,
631 &pf->directory, PF_UNKNOWN_SEG, "PIC_idx_MERGED", 1);
632 pic_index->data
633 = (opcode_t *)mem_sys_allocate_zeroed(size * sizeof (opcode_t));
634 pic_index->size = size;
636 for (i = 0, size = 0; i < num_inputs; i++) {
637 PackFile_Segment * const in_seg = inputs[i]->pf->cur_cs->pic_index;
638 size_t j;
640 * pic_index is 0 or an ever increasing (by 1) number
642 for (j = 0; j < in_seg->size; j++) {
643 const opcode_t k = in_seg->data[j];
644 if (k) {
645 pic_index->data[cursor] = k + start;
646 last = k;
648 cursor++;
650 start = last;
652 bc->pic_index = pic_index;
657 =item C<static void pbc_merge_ctpointers>
659 This function corrects the pointers into the constants table found in the
660 bytecode.
662 =cut
666 static void
667 pbc_merge_ctpointers(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
668 int num_inputs, ARGMOD(PackFile_ByteCode *bc))
670 opcode_t *op_ptr;
671 opcode_t *ops = bc->base.data;
672 opcode_t cur_op = 0;
673 int cur_input = 0;
674 int cur_arg;
676 /* Loop over the ops in the merged bytecode. */
677 while (cur_op < (opcode_t)bc->base.size) {
678 op_info_t *op;
679 opcode_t op_num;
681 /* Keep track of the current input file. */
682 if (cur_input + 1 < num_inputs &&
683 cur_op >= inputs[cur_input + 1]->code_start)
684 cur_input++;
686 /* Get info about this op and jump over it. */
687 op_num = ops[cur_op];
688 op = &interp->op_info_table[op_num];
689 op_ptr = ops + cur_op;
690 cur_op++;
692 /* Loop over the arguments. */
693 for (cur_arg = 1; cur_arg < op->op_count; cur_arg++) {
694 /* Pick out any indexes into the constant table and correct them. */
695 switch (op->types[cur_arg - 1]) {
696 case PARROT_ARG_NC:
697 case PARROT_ARG_PC:
698 case PARROT_ARG_SC:
699 case PARROT_ARG_KC:
700 ops[cur_op] += inputs[cur_input]->const_start;
701 break;
702 default:
703 break;
706 /* Move along the bytecode array. */
707 cur_op++;
710 /* Handle special case variable argument opcodes. */
711 if (op_num == PARROT_OP_set_args_pc ||
712 op_num == PARROT_OP_get_results_pc ||
713 op_num == PARROT_OP_get_params_pc ||
714 op_num == PARROT_OP_set_returns_pc) {
715 /* Get the signature. */
716 const PMC * const sig = bc->const_table->constants[op_ptr[1]]->u.key;
718 /* Loop over the arguments to locate any that need a fixup. */
719 const int sig_items = SIG_ELEMS(sig);
720 for (cur_arg = 0; cur_arg < sig_items; cur_arg++) {
721 switch (SIG_ITEM(sig, cur_arg)) {
722 case PARROT_ARG_NC:
723 case PARROT_ARG_PC:
724 case PARROT_ARG_SC:
725 case PARROT_ARG_KC:
726 ops[cur_op] += inputs[cur_input]->const_start;
727 break;
728 default:
729 break;
731 cur_op++;
740 =item C<static PackFile* pbc_merge_begin>
742 This is the function that drives PBC merging process.
744 =cut
747 PARROT_WARN_UNUSED_RESULT
748 PARROT_CANNOT_RETURN_NULL
749 static PackFile*
750 pbc_merge_begin(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs), int num_inputs)
752 PackFile_ByteCode *bc;
753 PackFile_ConstTable *ct;
755 /* Create a new empty packfile. */
756 PackFile * const merged = PackFile_new(interp, 0);
757 if (merged == NULL) {
758 PIO_eprintf(interp, "PBC Merge: Error creating new packfile.\n");
759 Parrot_exit(interp, 1);
762 /* Merge the various stuff. */
763 bc = pbc_merge_bytecode(interp, inputs, num_inputs, merged);
764 ct = pbc_merge_constants(interp, inputs, num_inputs, merged, bc);
765 UNUSED(ct);
767 pbc_merge_fixups(interp, inputs, num_inputs, merged, bc);
768 pbc_merge_debugs(interp, inputs, num_inputs, merged, bc);
769 pbc_merge_pic_index(interp, inputs, num_inputs, merged, bc);
771 /* Walk bytecode and fix ops that reference the constants table. */
772 pbc_merge_ctpointers(interp, inputs, num_inputs, bc);
774 /* Return merged result. */
775 return merged;
781 =item C<static void pbc_merge_write>
783 This functions writes out the merged packfile.
785 =cut
789 static void
790 pbc_merge_write(PARROT_INTERP, ARGMOD(PackFile *pf), ARGIN(const char *filename))
792 FILE *fp;
794 /* Get size of packfile we'll write. */
795 const size_t size = PackFile_pack_size(interp, pf) * sizeof (opcode_t);
797 /* Allocate memory. */
798 opcode_t * const pack = (opcode_t*) mem_sys_allocate(size);
799 if (pack == NULL) {
800 PIO_eprintf(interp, "PBC Merge: Out of memory");
801 Parrot_exit(interp, 1);
804 /* Write and clean up. */
805 PackFile_pack(interp, pf, pack);
806 if ((fp = fopen(filename, "wb")) == 0) {
807 PIO_eprintf(interp, "PBC Merge: Couldn't open %s\n", filename);
808 Parrot_exit(interp, 1);
810 if ((1 != fwrite(pack, size, 1, fp))) {
811 PIO_eprintf(interp, "PBC Merge: Couldn't write %s\n", filename);
812 Parrot_exit(interp, 1);
814 fclose(fp);
815 mem_sys_free(pack);
821 =item C<int main>
823 The main function that grabs console input, reads in the packfiles
824 provided they exist, hands them to another function that runs the
825 merge process and finally writes out the produced packfile.
827 =cut
831 static struct longopt_opt_decl options[] = {
832 { 'o', 'o', OPTION_required_FLAG, { "--output" } }
836 main(int argc, const char **argv)
838 int status;
839 pbc_merge_input** input_files;
840 PackFile *merged;
841 int i;
842 const char *output_file = NULL;
843 struct longopt_opt_info opt = LONGOPT_OPT_INFO_INIT;
844 Interp * const interp = Parrot_new(NULL);
846 Parrot_block_GC_mark(interp);
848 /* Get options, ensuring we have at least one input
849 file and an output file. */
850 if (argc < 4) {
851 help(interp);
853 while ((status = longopt_get(interp, argc, argv, options, &opt)) > 0) {
854 switch (opt.opt_id) {
855 case 'o':
856 if (output_file == NULL)
857 output_file = opt.opt_arg;
858 else
859 help(interp);
860 break;
861 case '?':
862 help(interp);
863 break;
864 default:
865 break;
868 if (status == -1 || !output_file) {
869 help(interp);
871 argc -= opt.opt_index; /* Now the number of input files. */
872 argv += opt.opt_index; /* Now at first input filename. */
874 /* Load each packfile that we are to merge and set up an input
875 structure for each of them. */
876 input_files = (pbc_merge_input **)mem_sys_allocate(
877 argc * sizeof (Parrot_Pointer));
879 for (i = 0; i < argc; i++) {
880 /* Allocate a struct. */
881 input_files[i] = mem_allocate_typed(pbc_merge_input);
883 /* Set filename */
884 input_files[i]->filename = *argv;
886 /* Load the packfile and unpack it. */
887 input_files[i]->pf = pbc_merge_loadpbc(interp,
888 input_files[i]->filename);
889 if (input_files[i]->pf == NULL) {
890 PIO_eprintf(interp,
891 "PBC Merge: Unknown error while reading and unpacking %s\n",
892 *argv);
893 Parrot_exit(interp, 1);
896 /* Next file. */
897 argv++;
900 /* Merge. */
901 merged = pbc_merge_begin(interp, input_files, argc);
903 /* Write merged packfile. */
904 pbc_merge_write(interp, merged, output_file);
906 /* Finally, we're done. */
907 Parrot_exit(interp, 0);
912 * Local variables:
913 * c-file-style: "parrot"
914 * End:
915 * vim: expandtab shiftwidth=4: