[t][TT #1119] Convert t/op/bitwise.t to PIR
[parrot.git] / src / pbc_merge.c
blobbe2fe183a4741e6fb479285fabcb5645b8bc0d21
1 /*
2 Copyright (C) 2005-2009, 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; /* Filename of the input file. */
49 PackFile *pf; /* The loaded packfile. */
50 opcode_t code_start; /* Where the bytecode is located in the merged
51 bytecode. */
52 opcode_t const_start; /* Where the const table is located in the merged
53 one. */
54 } pbc_merge_input;
56 /* HEADERIZER HFILE: none */
58 /* HEADERIZER BEGIN: static */
59 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
61 PARROT_DOES_NOT_RETURN
62 static void help(PARROT_INTERP)
63 __attribute__nonnull__(1);
65 PARROT_WARN_UNUSED_RESULT
66 PARROT_CANNOT_RETURN_NULL
67 static PackFile* pbc_merge_begin(PARROT_INTERP,
68 ARGMOD(pbc_merge_input **inputs),
69 int num_inputs)
70 __attribute__nonnull__(1)
71 __attribute__nonnull__(2)
72 FUNC_MODIFIES(*inputs);
74 PARROT_WARN_UNUSED_RESULT
75 PARROT_CANNOT_RETURN_NULL
76 static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
77 ARGMOD(pbc_merge_input **inputs),
78 int num_inputs,
79 ARGMOD(PackFile *pf))
80 __attribute__nonnull__(1)
81 __attribute__nonnull__(2)
82 __attribute__nonnull__(4)
83 FUNC_MODIFIES(*inputs)
84 FUNC_MODIFIES(*pf);
86 PARROT_WARN_UNUSED_RESULT
87 PARROT_CANNOT_RETURN_NULL
88 static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
89 ARGMOD(pbc_merge_input **inputs),
90 int num_inputs,
91 ARGMOD(PackFile *pf),
92 ARGMOD(PackFile_ByteCode *bc))
93 __attribute__nonnull__(1)
94 __attribute__nonnull__(2)
95 __attribute__nonnull__(4)
96 __attribute__nonnull__(5)
97 FUNC_MODIFIES(*inputs)
98 FUNC_MODIFIES(*pf)
99 FUNC_MODIFIES(*bc);
101 static void pbc_merge_ctpointers(PARROT_INTERP,
102 ARGMOD(pbc_merge_input **inputs),
103 int num_inputs,
104 ARGMOD(PackFile_ByteCode *bc))
105 __attribute__nonnull__(1)
106 __attribute__nonnull__(2)
107 __attribute__nonnull__(4)
108 FUNC_MODIFIES(*inputs)
109 FUNC_MODIFIES(*bc);
111 static void pbc_merge_debugs(PARROT_INTERP,
112 ARGMOD(pbc_merge_input **inputs),
113 int num_inputs,
114 ARGMOD(PackFile *pf),
115 ARGMOD(PackFile_ByteCode *bc))
116 __attribute__nonnull__(1)
117 __attribute__nonnull__(2)
118 __attribute__nonnull__(4)
119 __attribute__nonnull__(5)
120 FUNC_MODIFIES(*inputs)
121 FUNC_MODIFIES(*pf)
122 FUNC_MODIFIES(*bc);
124 static void pbc_merge_fixups(PARROT_INTERP,
125 ARGIN(pbc_merge_input **inputs),
126 int num_inputs,
127 ARGMOD(PackFile *pf),
128 ARGMOD(PackFile_ByteCode *bc))
129 __attribute__nonnull__(1)
130 __attribute__nonnull__(2)
131 __attribute__nonnull__(4)
132 __attribute__nonnull__(5)
133 FUNC_MODIFIES(*pf)
134 FUNC_MODIFIES(*bc);
136 PARROT_WARN_UNUSED_RESULT
137 PARROT_CANNOT_RETURN_NULL
138 static PackFile* pbc_merge_loadpbc(PARROT_INTERP,
139 ARGIN(const char *fullname))
140 __attribute__nonnull__(1)
141 __attribute__nonnull__(2);
143 static void pbc_merge_write(PARROT_INTERP,
144 ARGMOD(PackFile *pf),
145 ARGIN(const char *filename))
146 __attribute__nonnull__(1)
147 __attribute__nonnull__(2)
148 __attribute__nonnull__(3)
149 FUNC_MODIFIES(*pf);
151 #define ASSERT_ARGS_help __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
152 PARROT_ASSERT_ARG(interp))
153 #define ASSERT_ARGS_pbc_merge_begin __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
154 PARROT_ASSERT_ARG(interp) \
155 , PARROT_ASSERT_ARG(inputs))
156 #define ASSERT_ARGS_pbc_merge_bytecode __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
157 PARROT_ASSERT_ARG(interp) \
158 , PARROT_ASSERT_ARG(inputs) \
159 , PARROT_ASSERT_ARG(pf))
160 #define ASSERT_ARGS_pbc_merge_constants __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
161 PARROT_ASSERT_ARG(interp) \
162 , PARROT_ASSERT_ARG(inputs) \
163 , PARROT_ASSERT_ARG(pf) \
164 , PARROT_ASSERT_ARG(bc))
165 #define ASSERT_ARGS_pbc_merge_ctpointers __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
166 PARROT_ASSERT_ARG(interp) \
167 , PARROT_ASSERT_ARG(inputs) \
168 , PARROT_ASSERT_ARG(bc))
169 #define ASSERT_ARGS_pbc_merge_debugs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
170 PARROT_ASSERT_ARG(interp) \
171 , PARROT_ASSERT_ARG(inputs) \
172 , PARROT_ASSERT_ARG(pf) \
173 , PARROT_ASSERT_ARG(bc))
174 #define ASSERT_ARGS_pbc_merge_fixups __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
175 PARROT_ASSERT_ARG(interp) \
176 , PARROT_ASSERT_ARG(inputs) \
177 , PARROT_ASSERT_ARG(pf) \
178 , PARROT_ASSERT_ARG(bc))
179 #define ASSERT_ARGS_pbc_merge_loadpbc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
180 PARROT_ASSERT_ARG(interp) \
181 , PARROT_ASSERT_ARG(fullname))
182 #define ASSERT_ARGS_pbc_merge_write __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
183 PARROT_ASSERT_ARG(interp) \
184 , PARROT_ASSERT_ARG(pf) \
185 , PARROT_ASSERT_ARG(filename))
186 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
187 /* HEADERIZER END: static */
191 =item C<static void help(PARROT_INTERP)>
193 Print out the user help info.
195 =cut
199 PARROT_DOES_NOT_RETURN
200 static void
201 help(PARROT_INTERP)
203 printf("pbc_merge - merge multiple parrot bytecode files into one\n");
204 printf("Usage:\n");
205 printf(" pbc_merge -o out.pbc file1.pbc file2.pbc ...\n\n");
206 Parrot_exit(interp, 0);
211 =item C<static PackFile* pbc_merge_loadpbc(PARROT_INTERP, const char *fullname)>
213 This function loads a PBC file and unpacks it. We can't
214 use Parrot_pbc_read because that is specified to also
215 fixup the segments, which we don't want.
217 =cut
221 PARROT_WARN_UNUSED_RESULT
222 PARROT_CANNOT_RETURN_NULL
223 static PackFile*
224 pbc_merge_loadpbc(PARROT_INTERP, ARGIN(const char *fullname))
226 ASSERT_ARGS(pbc_merge_loadpbc)
227 INTVAL program_size, wanted;
228 char *program_code;
229 PackFile *pf;
230 FILE * io = NULL;
231 INTVAL is_mapped = 0;
232 size_t chunk_size;
233 char *cursor;
234 INTVAL read_result;
236 /* Check the file exists. */
237 STRING * const fs = string_make(interp, fullname,
238 strlen(fullname), NULL, 0);
239 if (!Parrot_stat_info_intval(interp, fs, STAT_EXISTS)) {
240 Parrot_io_eprintf(interp, "PBC Merge: Can't stat %s, code %i.\n",
241 fullname, errno);
242 Parrot_exit(interp, 1);
245 /* Get program size. */
246 program_size = Parrot_stat_info_intval(interp, fs, STAT_FILESIZE);
248 /* Attempt to open file and handle any errors. */
249 io = fopen(fullname, "rb");
250 if (!io) {
251 Parrot_io_eprintf(interp, "PBC Merge: Can't open %s, code %i.\n",
252 fullname, errno);
253 Parrot_exit(interp, 1);
256 /* Read in program. Nabbed from Parrot_pbc_read. */
257 chunk_size = program_size > 0 ? program_size : 1024;
258 program_code = (char *)mem_sys_allocate(chunk_size);
259 wanted = program_size;
260 program_size = 0;
261 cursor = (char *)program_code;
263 while ((read_result = fread(cursor, 1, chunk_size, io)) > 0) {
264 program_size += read_result;
265 if (program_size == wanted)
266 break;
267 chunk_size = 1024;
268 program_code =
269 (char *)mem_sys_realloc(program_code, program_size + chunk_size);
271 if (!program_code) {
272 Parrot_io_eprintf(interp,
273 "PBC Merge: Could not reallocate buffer");
274 Parrot_exit(interp, 1);
277 cursor = (char *)program_code + program_size;
280 if (read_result < 0) {
281 Parrot_io_eprintf(interp,
282 "PBC Merge: Problem reading packfile from PIO.\n");
283 Parrot_exit(interp, 1);
285 fclose(io);
287 /* Now that we have the bytecode, let's unpack it. */
288 pf = PackFile_new(interp, is_mapped);
289 if (!PackFile_unpack(interp,
290 pf, (opcode_t *)program_code, program_size)) {
291 Parrot_io_eprintf(interp, "PBC Merge: Can't unpack packfile %s.\n",
292 fullname);
293 Parrot_exit(interp, 1);
296 /* Return the packfile. */
297 return pf;
303 =item C<static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
304 pbc_merge_input **inputs, int num_inputs, PackFile *pf)>
306 This function merges the bytecode from the input packfiles, storing the
307 offsets that each bit of bytecode now exists at.
309 =cut
313 PARROT_WARN_UNUSED_RESULT
314 PARROT_CANNOT_RETURN_NULL
315 static PackFile_ByteCode*
316 pbc_merge_bytecode(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
317 int num_inputs, ARGMOD(PackFile *pf))
319 ASSERT_ARGS(pbc_merge_bytecode)
320 int i;
321 opcode_t *bc = mem_allocate_typed(opcode_t);
322 opcode_t cursor = 0;
324 /* Add a bytecode segment. */
325 PackFile_ByteCode * const bc_seg =
326 (PackFile_ByteCode *)PackFile_Segment_new_seg(interp,
327 &pf->directory, PF_BYTEC_SEG, BYTE_CODE_SEGMENT_NAME, 1);
328 if (bc_seg == NULL) {
329 Parrot_io_eprintf(interp, "PBC Merge: Error creating bytecode segment.");
330 Parrot_exit(interp, 1);
333 /* Loop over input files. */
334 for (i = 0; i < num_inputs; i++) {
335 /* Get the bytecode segment from the input file. */
336 PackFile_ByteCode * const in_seg = inputs[i]->pf->cur_cs;
337 if (in_seg == NULL) {
338 Parrot_io_eprintf(interp,
339 "PBC Merge: Cannot locate bytecode segment in %s",
340 inputs[i]->filename);
341 Parrot_exit(interp, 1);
344 /* Re-allocate the current buffer. */
345 mem_realloc_n_typed(bc, cursor + in_seg->base.size, opcode_t);
346 if (bc == NULL) {
347 Parrot_io_eprintf(interp, "PBC Merge: Cannot reallocate memory\n");
348 Parrot_exit(interp, 1);
351 /* Copy data and store cursor. */
352 memcpy(bc + cursor, in_seg->base.data,
353 in_seg->base.size * sizeof (opcode_t));
354 inputs[i]->code_start = cursor;
356 /* Update cursor. */
357 cursor += in_seg->base.size;
360 /* Stash produced bytecode. */
361 bc_seg->base.data = bc;
362 bc_seg->base.size = cursor;
363 bc_seg->base.name = Parrot_str_new_constant(interp, "MERGED");
364 return bc_seg;
370 =item C<static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
371 pbc_merge_input **inputs, int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
373 This function merges the constants tables from the input PBC files.
375 =cut
379 PARROT_WARN_UNUSED_RESULT
380 PARROT_CANNOT_RETURN_NULL
381 static PackFile_ConstTable*
382 pbc_merge_constants(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
383 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
385 ASSERT_ARGS(pbc_merge_constants)
386 int i, j;
387 PackFile_Constant **constants = mem_allocate_typed(PackFile_Constant *);
388 opcode_t cursor = 0;
390 /* Add a constant table segment. */
391 PackFile_ConstTable * const const_seg = (PackFile_ConstTable*)PackFile_Segment_new_seg(
392 interp, &pf->directory, PF_CONST_SEG, CONSTANT_SEGMENT_NAME, 1);
393 if (const_seg == NULL) {
394 Parrot_io_eprintf(interp,
395 "PBC Merge: Error creating constant table segment.");
396 Parrot_exit(interp, 1);
399 /* Loop over input files. */
400 for (i = 0; i < num_inputs; i++) {
401 /* Get the constant table segment from the input file. */
402 PackFile_ConstTable * const in_seg = inputs[i]->pf->cur_cs->const_table;
403 if (in_seg == NULL) {
404 Parrot_io_eprintf(interp,
405 "PBC Merge: Cannot locate constant table segment in %s\n",
406 inputs[i]->filename);
407 Parrot_exit(interp, 1);
410 /* Store cursor as position where constant table starts. */
411 inputs[i]->const_start = cursor;
413 /* Allocate space for the constant list, provided we have some. */
414 if (in_seg->const_count > 0) {
415 constants = (PackFile_Constant **)mem_sys_realloc(constants,
416 (cursor + in_seg->const_count) * sizeof (Parrot_Pointer));
417 if (constants == NULL) {
418 Parrot_io_eprintf(interp, "PBC Merge: Out of memory");
419 Parrot_exit(interp, 1);
423 /* Loop over the constants and copy them to the output PBC. */
424 for (j = 0; j < in_seg->const_count; j++) {
425 /* Get the entry and allocate space for copy. */
426 PackFile_Constant *cur_entry = in_seg->constants[j];
427 PackFile_Constant *copy = mem_allocate_typed(
428 PackFile_Constant);
429 if (copy == NULL) {
430 Parrot_io_eprintf(interp, "PBC Merge: Out of memory");
431 Parrot_exit(interp, 1);
434 STRUCT_COPY(copy, cur_entry);
436 /* If it's a sub PMC, need to deal with offsets. */
437 if (copy->type == PFC_PMC) {
438 switch (copy->u.key->vtable->base_type) {
439 case enum_class_Sub:
440 case enum_class_Coroutine:
442 Parrot_Sub_attributes *sub;
443 PMC_get_sub(interp, copy->u.key, sub);
444 sub->start_offs += inputs[i]->code_start;
445 sub->end_offs += inputs[i]->code_start;
447 break;
448 default:
449 break;
453 /* Slot it into the list. */
454 constants[cursor] = copy;
455 cursor++;
459 /* Stash merged constants table and count and return the new segment. */
460 const_seg->constants = constants;
461 const_seg->const_count = cursor;
462 const_seg->code = bc;
463 bc->const_table = const_seg;
464 return const_seg;
470 =item C<static void pbc_merge_fixups(PARROT_INTERP, pbc_merge_input **inputs,
471 int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
473 This function merges the fixups tables from the input PBC files.
475 =cut
479 static void
480 pbc_merge_fixups(PARROT_INTERP, ARGIN(pbc_merge_input **inputs),
481 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
483 ASSERT_ARGS(pbc_merge_fixups)
484 int i, j;
485 PackFile_FixupTable *fixup_seg;
486 PackFile_FixupEntry **fixups = mem_allocate_typed(PackFile_FixupEntry *);
487 opcode_t cursor = 0;
489 /* Add a fixup table segment. */
490 fixup_seg = (PackFile_FixupTable*)PackFile_Segment_new_seg(
491 interp, &pf->directory, PF_FIXUP_SEG, FIXUP_TABLE_SEGMENT_NAME, 1);
492 if (fixup_seg == NULL) {
493 Parrot_io_eprintf(interp,
494 "PBC Merge: Error creating fixup table segment.");
495 Parrot_exit(interp, 1);
498 /* Loop over input files. */
499 for (i = 0; i < num_inputs; i++) {
500 /* Get the fixup segment from the input file. */
501 PackFile_FixupTable * const in_seg = inputs[i]->pf->cur_cs->fixups;
502 if (in_seg == NULL) {
503 Parrot_io_eprintf(interp,
504 "PBC Merge: Cannot locate fixup segment in %s",
505 inputs[i]->filename);
506 Parrot_exit(interp, 1);
509 /* Allocate space for these fixups, provided we have some. */
510 if (in_seg->fixup_count > 0) {
511 fixups = (PackFile_FixupEntry **)mem_sys_realloc(fixups,
512 (cursor + in_seg->fixup_count) * sizeof (Parrot_Pointer));
513 if (fixups == NULL) {
514 Parrot_io_eprintf(interp, "PBC Merge: Out of memory");
515 Parrot_exit(interp, 1);
519 /* Loop over the fixups and copy them to the output PBC, correcting
520 the offsets into the bytecode. */
521 for (j = 0; j < in_seg->fixup_count; j++) {
522 /* Get the entry and allocate space for copies. */
523 PackFile_FixupEntry *cur_entry = in_seg->fixups[j];
524 PackFile_FixupEntry *copy = mem_allocate_typed(
525 PackFile_FixupEntry);
526 char *name_copy = (char *)mem_sys_allocate(
527 strlen(cur_entry->name) + 1);
528 if (copy == NULL || name_copy == NULL) {
529 Parrot_io_eprintf(interp, "PBC Merge: Out of memory");
530 Parrot_exit(interp, 1);
533 /* Copy type and name. */
534 copy->type = cur_entry->type;
535 strcpy(name_copy, cur_entry->name);
536 copy->name = name_copy;
538 /* Set new offset and bytecode pointer. */
539 switch (copy->type) {
540 case enum_fixup_label:
541 copy->offset = cur_entry->offset + inputs[i]->code_start;
542 break;
543 case enum_fixup_sub:
544 copy->offset = cur_entry->offset + inputs[i]->const_start;
545 break;
546 default:
547 Parrot_io_eprintf(interp, "PBC Merge: Unknown fixup type");
548 Parrot_exit(interp, 1);
551 /* Slot it into the list. */
552 fixups[cursor] = copy;
553 cursor++;
557 /* Stash merged fixup table and count. */
558 fixup_seg->fixups = fixups;
559 fixup_seg->fixup_count = cursor;
565 =item C<static void pbc_merge_debugs(PARROT_INTERP, pbc_merge_input **inputs,
566 int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
568 This function merges the debug segments from the input PBC files.
570 =cut
574 static void
575 pbc_merge_debugs(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
576 int num_inputs, ARGMOD(PackFile *pf), ARGMOD(PackFile_ByteCode *bc))
578 ASSERT_ARGS(pbc_merge_debugs)
579 int i, j;
580 PackFile_Debug *debug_seg;
581 opcode_t *lines = mem_allocate_typed(opcode_t);
582 PackFile_DebugFilenameMapping **mappings =
583 mem_allocate_typed(PackFile_DebugFilenameMapping *);
584 opcode_t num_mappings = 0;
585 opcode_t num_lines = 0;
587 /* We need to merge both the mappings and the list of line numbers.
588 The line numbers can just be concatenated. The mappings must have
589 their offsets fixed up. */
590 for (i = 0; i < num_inputs; i++) {
591 PackFile_Debug *in_seg = inputs[i]->pf->cur_cs->debugs;
593 /* Concatenate line numbers. */
594 lines = (opcode_t *)mem_sys_realloc(lines,
595 (num_lines + in_seg->base.size) * sizeof (opcode_t));
596 if (lines == NULL) {
597 Parrot_io_eprintf(interp, "PBC Merge: Cannot reallocate memory\n");
598 Parrot_exit(interp, 1);
600 memcpy(lines + num_lines, in_seg->base.data,
601 in_seg->base.size * sizeof (opcode_t));
603 /* Concatenate mappings. */
604 mappings = (PackFile_DebugFilenameMapping **)mem_sys_realloc(mappings,
605 (num_mappings + in_seg->num_mappings) *
606 sizeof (Parrot_Pointer));
607 for (j = 0; j < in_seg->num_mappings; j++) {
608 PackFile_DebugFilenameMapping *mapping = mem_allocate_typed(
609 PackFile_DebugFilenameMapping);
610 STRUCT_COPY(mapping, in_seg->mappings[j]);
611 mapping->offset += num_lines;
612 mapping->filename += inputs[i]->const_start;
613 mappings[num_mappings + j] = mapping;
616 /* Update counts. The "- 1" allows for the fact that the size value
617 itself is included in in_seg->base.size. See RT#58660. */
618 num_lines += in_seg->base.size - 1;
619 num_mappings += in_seg->num_mappings;
622 /* Create merged debug segment. Replace created data and mappings
623 with merged ones we have created. */
624 debug_seg = Parrot_new_debug_seg(interp, bc, num_lines);
625 PackFile_add_segment(interp, &pf->directory, (PackFile_Segment*)debug_seg);
626 mem_sys_free(debug_seg->base.data);
627 debug_seg->base.data = lines;
628 mem_sys_free(debug_seg->mappings);
630 debug_seg->mappings = mappings;
631 debug_seg->num_mappings = num_mappings;
636 =item C<static void pbc_merge_ctpointers(PARROT_INTERP, pbc_merge_input
637 **inputs, int num_inputs, PackFile_ByteCode *bc)>
639 This function corrects the pointers into the constants table found in the
640 bytecode.
642 =cut
646 static void
647 pbc_merge_ctpointers(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
648 int num_inputs, ARGMOD(PackFile_ByteCode *bc))
650 ASSERT_ARGS(pbc_merge_ctpointers)
651 int cur_arg;
652 opcode_t *op_ptr;
653 opcode_t *ops = bc->base.data;
654 opcode_t cur_op = 0;
655 int cur_input = 0;
657 /* Loop over the ops in the merged bytecode. */
658 while (cur_op < (opcode_t)bc->base.size) {
659 op_info_t *op;
660 opcode_t op_num;
662 /* Keep track of the current input file. */
663 if (cur_input + 1 < num_inputs &&
664 cur_op >= inputs[cur_input + 1]->code_start)
665 cur_input++;
667 /* Get info about this op and jump over it. */
668 op_num = ops[cur_op];
669 op = &interp->op_info_table[op_num];
670 op_ptr = ops + cur_op;
671 cur_op++;
673 /* Loop over the arguments. */
674 for (cur_arg = 1; cur_arg < op->op_count; cur_arg++) {
675 /* Pick out any indexes into the constant table and correct them. */
676 switch (op->types[cur_arg - 1]) {
677 case PARROT_ARG_NC:
678 case PARROT_ARG_PC:
679 case PARROT_ARG_SC:
680 case PARROT_ARG_KC:
681 ops[cur_op] += inputs[cur_input]->const_start;
682 break;
683 default:
684 break;
687 /* Move along the bytecode array. */
688 cur_op++;
691 /* Handle special case variable argument opcodes. */
692 if (op_num == PARROT_OP_set_args_pc ||
693 op_num == PARROT_OP_get_results_pc ||
694 op_num == PARROT_OP_get_params_pc ||
695 op_num == PARROT_OP_set_returns_pc) {
696 /* Get the signature. */
697 PMC * const sig = bc->const_table->constants[op_ptr[1]]->u.key;
699 /* Loop over the arguments to locate any that need a fixup. */
700 const int sig_items = VTABLE_elements(interp, sig);
701 for (cur_arg = 0; cur_arg < sig_items; cur_arg++) {
702 switch (VTABLE_get_integer_keyed_int(interp, sig, cur_arg)) {
703 case PARROT_ARG_NC:
704 case PARROT_ARG_PC:
705 case PARROT_ARG_SC:
706 case PARROT_ARG_KC:
707 ops[cur_op] += inputs[cur_input]->const_start;
708 break;
709 default:
710 break;
712 cur_op++;
721 =item C<static PackFile* pbc_merge_begin(PARROT_INTERP, pbc_merge_input
722 **inputs, int num_inputs)>
724 This is the function that drives PBC merging process.
726 =cut
729 PARROT_WARN_UNUSED_RESULT
730 PARROT_CANNOT_RETURN_NULL
731 static PackFile*
732 pbc_merge_begin(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs), int num_inputs)
734 ASSERT_ARGS(pbc_merge_begin)
735 PackFile_ByteCode *bc;
736 PackFile_ConstTable *ct;
738 /* Create a new empty packfile. */
739 PackFile * const merged = PackFile_new(interp, 0);
740 if (merged == NULL) {
741 Parrot_io_eprintf(interp, "PBC Merge: Error creating new packfile.\n");
742 Parrot_exit(interp, 1);
745 /* Merge the various stuff. */
746 bc = pbc_merge_bytecode(interp, inputs, num_inputs, merged);
747 ct = pbc_merge_constants(interp, inputs, num_inputs, merged, bc);
748 UNUSED(ct);
750 pbc_merge_fixups(interp, inputs, num_inputs, merged, bc);
751 pbc_merge_debugs(interp, inputs, num_inputs, merged, bc);
753 /* Walk bytecode and fix ops that reference the constants table. */
754 pbc_merge_ctpointers(interp, inputs, num_inputs, bc);
756 /* Return merged result. */
757 return merged;
763 =item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
764 *filename)>
766 This functions writes out the merged packfile.
768 =cut
772 static void
773 pbc_merge_write(PARROT_INTERP, ARGMOD(PackFile *pf), ARGIN(const char *filename))
775 ASSERT_ARGS(pbc_merge_write)
776 FILE *fp;
778 /* Get size of packfile we'll write. */
779 const size_t size = PackFile_pack_size(interp, pf) * sizeof (opcode_t);
781 /* Allocate memory. */
782 opcode_t * const pack = (opcode_t*) mem_sys_allocate(size);
783 if (pack == NULL) {
784 Parrot_io_eprintf(interp, "PBC Merge: Out of memory");
785 Parrot_exit(interp, 1);
788 /* Write and clean up. */
789 PackFile_pack(interp, pf, pack);
790 if ((fp = fopen(filename, "wb")) == 0) {
791 Parrot_io_eprintf(interp, "PBC Merge: Couldn't open %s\n", filename);
792 Parrot_exit(interp, 1);
794 if ((1 != fwrite(pack, size, 1, fp))) {
795 Parrot_io_eprintf(interp, "PBC Merge: Couldn't write %s\n", filename);
796 Parrot_exit(interp, 1);
798 fclose(fp);
799 mem_sys_free(pack);
805 =item C<int main(int argc, const char **argv)>
807 The main function that grabs console input, reads in the packfiles
808 provided they exist, hands them to another function that runs the
809 merge process and finally writes out the produced packfile.
811 =cut
815 static struct longopt_opt_decl options[] = {
816 { 'o', 'o', OPTION_required_FLAG, { "--output" } }
820 main(int argc, const char **argv)
822 int status;
823 pbc_merge_input** input_files;
824 PackFile *merged;
825 int i;
826 const char *output_file = NULL;
827 struct longopt_opt_info opt = LONGOPT_OPT_INFO_INIT;
828 Interp * const interp = Parrot_new(NULL);
830 Parrot_block_GC_mark(interp);
832 /* Get options, ensuring we have at least one input
833 file and an output file. */
834 if (argc < 4) {
835 help(interp);
837 while ((status = longopt_get(interp, argc, argv, options, &opt)) > 0) {
838 switch (opt.opt_id) {
839 case 'o':
840 if (output_file == NULL)
841 output_file = opt.opt_arg;
842 else
843 help(interp);
844 break;
845 case '?':
846 help(interp);
847 break;
848 default:
849 break;
852 if (status == -1 || !output_file) {
853 help(interp);
855 argc -= opt.opt_index; /* Now the number of input files. */
856 argv += opt.opt_index; /* Now at first input filename. */
858 /* Load each packfile that we are to merge and set up an input
859 structure for each of them. */
860 input_files = (pbc_merge_input **)mem_sys_allocate(
861 argc * sizeof (Parrot_Pointer));
863 for (i = 0; i < argc; i++) {
864 /* Allocate a struct. */
865 input_files[i] = mem_allocate_typed(pbc_merge_input);
867 /* Set filename */
868 input_files[i]->filename = *argv;
870 /* Load the packfile and unpack it. */
871 input_files[i]->pf = pbc_merge_loadpbc(interp,
872 input_files[i]->filename);
873 if (input_files[i]->pf == NULL) {
874 Parrot_io_eprintf(interp,
875 "PBC Merge: Unknown error while reading and unpacking %s\n",
876 *argv);
877 Parrot_exit(interp, 1);
880 /* Next file. */
881 argv++;
884 /* Merge. */
885 merged = pbc_merge_begin(interp, input_files, argc);
887 /* Write merged packfile. */
888 pbc_merge_write(interp, merged, output_file);
890 /* Finally, we're done. */
891 Parrot_exit(interp, 0);
896 * Local variables:
897 * c-file-style: "parrot"
898 * End:
899 * vim: expandtab shiftwidth=4: