* src/pbc_merge.c:
[parrot.git] / src / pbc_merge.c
bloba02de91e0d86bae803385f8e3aa755bb353bf4a4
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. The "- 1" allows for the fact that the size value
588 itself is included in in_seg->base.size. See RT#58660. */
589 num_lines += in_seg->base.size - 1;
590 num_mappings += in_seg->num_mappings;
593 /* Create merged debug segment. Replace created data and mappings
594 with merged ones we have created. */
595 debug_seg = Parrot_new_debug_seg(interp, bc, num_lines);
596 PackFile_add_segment(interp, &pf->directory, (PackFile_Segment*)debug_seg);
597 mem_sys_free(debug_seg->base.data);
598 debug_seg->base.data = lines;
599 mem_sys_free(debug_seg->mappings);
601 debug_seg->mappings = mappings;
602 debug_seg->num_mappings = num_mappings;
607 =item C<static void pbc_merge_pic_index>
609 This function merges the pic_index segments from the input PBC files.
611 =cut
615 static void
616 pbc_merge_pic_index(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
617 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
619 int i;
620 PackFile_Segment *pic_index;
621 size_t size;
622 opcode_t cursor = 0;
623 opcode_t start = 0;
624 opcode_t last = 0;
626 /* calc needed size */
627 for (i = 0, size = 0; i < num_inputs; i++) {
628 PackFile_Segment * const in_seg = inputs[i]->pf->cur_cs->pic_index;
629 size += in_seg->size;
631 pic_index = PackFile_Segment_new_seg(interp,
632 &pf->directory, PF_UNKNOWN_SEG, "PIC_idx_MERGED", 1);
633 pic_index->data
634 = (opcode_t *)mem_sys_allocate_zeroed(size * sizeof (opcode_t));
635 pic_index->size = size;
637 for (i = 0, size = 0; i < num_inputs; i++) {
638 PackFile_Segment * const in_seg = inputs[i]->pf->cur_cs->pic_index;
639 size_t j;
641 * pic_index is 0 or an ever increasing (by 1) number
643 for (j = 0; j < in_seg->size; j++) {
644 const opcode_t k = in_seg->data[j];
645 if (k) {
646 pic_index->data[cursor] = k + start;
647 last = k;
649 cursor++;
651 start = last;
653 bc->pic_index = pic_index;
658 =item C<static void pbc_merge_ctpointers>
660 This function corrects the pointers into the constants table found in the
661 bytecode.
663 =cut
667 static void
668 pbc_merge_ctpointers(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
669 int num_inputs, ARGMOD(PackFile_ByteCode *bc))
671 opcode_t *op_ptr;
672 opcode_t *ops = bc->base.data;
673 opcode_t cur_op = 0;
674 int cur_input = 0;
675 int cur_arg;
677 /* Loop over the ops in the merged bytecode. */
678 while (cur_op < (opcode_t)bc->base.size) {
679 op_info_t *op;
680 opcode_t op_num;
682 /* Keep track of the current input file. */
683 if (cur_input + 1 < num_inputs &&
684 cur_op >= inputs[cur_input + 1]->code_start)
685 cur_input++;
687 /* Get info about this op and jump over it. */
688 op_num = ops[cur_op];
689 op = &interp->op_info_table[op_num];
690 op_ptr = ops + cur_op;
691 cur_op++;
693 /* Loop over the arguments. */
694 for (cur_arg = 1; cur_arg < op->op_count; cur_arg++) {
695 /* Pick out any indexes into the constant table and correct them. */
696 switch (op->types[cur_arg - 1]) {
697 case PARROT_ARG_NC:
698 case PARROT_ARG_PC:
699 case PARROT_ARG_SC:
700 case PARROT_ARG_KC:
701 ops[cur_op] += inputs[cur_input]->const_start;
702 break;
703 default:
704 break;
707 /* Move along the bytecode array. */
708 cur_op++;
711 /* Handle special case variable argument opcodes. */
712 if (op_num == PARROT_OP_set_args_pc ||
713 op_num == PARROT_OP_get_results_pc ||
714 op_num == PARROT_OP_get_params_pc ||
715 op_num == PARROT_OP_set_returns_pc) {
716 /* Get the signature. */
717 const PMC * const sig = bc->const_table->constants[op_ptr[1]]->u.key;
719 /* Loop over the arguments to locate any that need a fixup. */
720 const int sig_items = SIG_ELEMS(sig);
721 for (cur_arg = 0; cur_arg < sig_items; cur_arg++) {
722 switch (SIG_ITEM(sig, cur_arg)) {
723 case PARROT_ARG_NC:
724 case PARROT_ARG_PC:
725 case PARROT_ARG_SC:
726 case PARROT_ARG_KC:
727 ops[cur_op] += inputs[cur_input]->const_start;
728 break;
729 default:
730 break;
732 cur_op++;
741 =item C<static PackFile* pbc_merge_begin>
743 This is the function that drives PBC merging process.
745 =cut
748 PARROT_WARN_UNUSED_RESULT
749 PARROT_CANNOT_RETURN_NULL
750 static PackFile*
751 pbc_merge_begin(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs), int num_inputs)
753 PackFile_ByteCode *bc;
754 PackFile_ConstTable *ct;
756 /* Create a new empty packfile. */
757 PackFile * const merged = PackFile_new(interp, 0);
758 if (merged == NULL) {
759 PIO_eprintf(interp, "PBC Merge: Error creating new packfile.\n");
760 Parrot_exit(interp, 1);
763 /* Merge the various stuff. */
764 bc = pbc_merge_bytecode(interp, inputs, num_inputs, merged);
765 ct = pbc_merge_constants(interp, inputs, num_inputs, merged, bc);
766 UNUSED(ct);
768 pbc_merge_fixups(interp, inputs, num_inputs, merged, bc);
769 pbc_merge_debugs(interp, inputs, num_inputs, merged, bc);
770 pbc_merge_pic_index(interp, inputs, num_inputs, merged, bc);
772 /* Walk bytecode and fix ops that reference the constants table. */
773 pbc_merge_ctpointers(interp, inputs, num_inputs, bc);
775 /* Return merged result. */
776 return merged;
782 =item C<static void pbc_merge_write>
784 This functions writes out the merged packfile.
786 =cut
790 static void
791 pbc_merge_write(PARROT_INTERP, ARGMOD(PackFile *pf), ARGIN(const char *filename))
793 FILE *fp;
795 /* Get size of packfile we'll write. */
796 const size_t size = PackFile_pack_size(interp, pf) * sizeof (opcode_t);
798 /* Allocate memory. */
799 opcode_t * const pack = (opcode_t*) mem_sys_allocate(size);
800 if (pack == NULL) {
801 PIO_eprintf(interp, "PBC Merge: Out of memory");
802 Parrot_exit(interp, 1);
805 /* Write and clean up. */
806 PackFile_pack(interp, pf, pack);
807 if ((fp = fopen(filename, "wb")) == 0) {
808 PIO_eprintf(interp, "PBC Merge: Couldn't open %s\n", filename);
809 Parrot_exit(interp, 1);
811 if ((1 != fwrite(pack, size, 1, fp))) {
812 PIO_eprintf(interp, "PBC Merge: Couldn't write %s\n", filename);
813 Parrot_exit(interp, 1);
815 fclose(fp);
816 mem_sys_free(pack);
822 =item C<int main>
824 The main function that grabs console input, reads in the packfiles
825 provided they exist, hands them to another function that runs the
826 merge process and finally writes out the produced packfile.
828 =cut
832 static struct longopt_opt_decl options[] = {
833 { 'o', 'o', OPTION_required_FLAG, { "--output" } }
837 main(int argc, const char **argv)
839 int status;
840 pbc_merge_input** input_files;
841 PackFile *merged;
842 int i;
843 const char *output_file = NULL;
844 struct longopt_opt_info opt = LONGOPT_OPT_INFO_INIT;
845 Interp * const interp = Parrot_new(NULL);
847 Parrot_block_GC_mark(interp);
849 /* Get options, ensuring we have at least one input
850 file and an output file. */
851 if (argc < 4) {
852 help(interp);
854 while ((status = longopt_get(interp, argc, argv, options, &opt)) > 0) {
855 switch (opt.opt_id) {
856 case 'o':
857 if (output_file == NULL)
858 output_file = opt.opt_arg;
859 else
860 help(interp);
861 break;
862 case '?':
863 help(interp);
864 break;
865 default:
866 break;
869 if (status == -1 || !output_file) {
870 help(interp);
872 argc -= opt.opt_index; /* Now the number of input files. */
873 argv += opt.opt_index; /* Now at first input filename. */
875 /* Load each packfile that we are to merge and set up an input
876 structure for each of them. */
877 input_files = (pbc_merge_input **)mem_sys_allocate(
878 argc * sizeof (Parrot_Pointer));
880 for (i = 0; i < argc; i++) {
881 /* Allocate a struct. */
882 input_files[i] = mem_allocate_typed(pbc_merge_input);
884 /* Set filename */
885 input_files[i]->filename = *argv;
887 /* Load the packfile and unpack it. */
888 input_files[i]->pf = pbc_merge_loadpbc(interp,
889 input_files[i]->filename);
890 if (input_files[i]->pf == NULL) {
891 PIO_eprintf(interp,
892 "PBC Merge: Unknown error while reading and unpacking %s\n",
893 *argv);
894 Parrot_exit(interp, 1);
897 /* Next file. */
898 argv++;
901 /* Merge. */
902 merged = pbc_merge_begin(interp, input_files, argc);
904 /* Write merged packfile. */
905 pbc_merge_write(interp, merged, output_file);
907 /* Finally, we're done. */
908 Parrot_exit(interp, 0);
913 * Local variables:
914 * c-file-style: "parrot"
915 * End:
916 * vim: expandtab shiftwidth=4: