2 Copyright (C) 2005-2010, Parrot Foundation.
7 pbc_merge - Merge multiple Parrot bytecode (PBC) files into
12 pbc_merge -o out.pbc input1.pbc input2.pbc ...
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
20 =head2 Command-Line Options
26 The name of the PBC file to produce, containing the merged
27 segments from the input PBC files.
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
52 opcode_t const_start
;/* where the const table is located within the
54 opcode_t
*const_map
; /* map constants from input files to their location
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
),
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
),
82 __attribute__nonnull__(1)
83 __attribute__nonnull__(2)
84 __attribute__nonnull__(4)
85 FUNC_MODIFIES(*inputs
)
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
),
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
)
103 static void pbc_merge_ctpointers(PARROT_INTERP
,
104 ARGMOD(pbc_merge_input
**inputs
),
106 ARGMOD(PackFile_ByteCode
*bc
))
107 __attribute__nonnull__(1)
108 __attribute__nonnull__(2)
109 __attribute__nonnull__(4)
110 FUNC_MODIFIES(*inputs
)
113 static void pbc_merge_debugs(PARROT_INTERP
,
114 ARGMOD(pbc_merge_input
**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
)
126 static void pbc_merge_fixups(PARROT_INTERP
,
127 ARGIN(pbc_merge_input
**inputs
),
129 ARGMOD(PackFile
*pf
))
130 __attribute__nonnull__(1)
131 __attribute__nonnull__(2)
132 __attribute__nonnull__(4)
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)
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.
197 PARROT_DOES_NOT_RETURN
201 printf("pbc_merge - merge multiple parrot bytecode files into one\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.
219 PARROT_WARN_UNUSED_RESULT
220 PARROT_CANNOT_RETURN_NULL
222 pbc_merge_loadpbc(PARROT_INTERP
, ARGIN(const char *fullname
))
224 ASSERT_ARGS(pbc_merge_loadpbc
)
225 INTVAL program_size
, wanted
;
229 INTVAL is_mapped
= 0;
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",
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");
249 Parrot_io_eprintf(interp
, "PBC Merge: Can't open %s, code %i.\n",
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
;
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
)
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);
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",
285 Parrot_exit(interp
, 1);
288 /* Return the packfile. */
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.
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
)
313 opcode_t
*bc
= mem_gc_allocate_typed(interp
, opcode_t
);
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);
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
;
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");
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.
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
*);
380 opcode_t output_const_num
= 0;
381 opcode_t input_const_num
= 0;
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
;
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
,
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
) {
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
;
441 inputs
[i
]->const_map
[input_const_num
] = output_const_num
;
445 /* Slot it into the list. */
446 constants
[cursor
] = copy
;
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
;
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.
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
;
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
;
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
) {
527 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->const_start
;
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
;
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.
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
,
565 PackFile_DebugFilenameMapping
*mappings
=
566 mem_gc_allocate_typed(interp
, PackFile_DebugFilenameMapping
);
568 opcode_t num_mappings
= 0;
569 opcode_t num_lines
= 0;
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
;
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
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
)
635 opcode_t
*ops
= bc
->base
.data
;
639 /* Loop over the ops in the merged bytecode. */
640 while (cur_op
< (opcode_t
)bc
->base
.size
) {
644 /* Keep track of the current input file. */
645 if (cur_input
+ 1 < num_inputs
&&
646 cur_op
>= inputs
[cur_input
+ 1]->code_start
)
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
;
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]) {
662 case PARROT_ARG_NAME_SC
:
664 ops
[cur_op
] = inputs
[cur_input
]->const_map
[ ops
[cur_op
] ];
670 /* Move along the bytecode array. */
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
)) {
689 case PARROT_ARG_NAME_SC
:
691 ops
[cur_op
] = inputs
[cur_input
]->const_map
[ ops
[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.
713 PARROT_WARN_UNUSED_RESULT
714 PARROT_CANNOT_RETURN_NULL
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
;
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
;
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
);
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. */
766 =item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
769 This functions writes out the merged packfile.
776 pbc_merge_write(PARROT_INTERP
, ARGMOD(PackFile
*pf
), ARGIN(const char *filename
))
778 ASSERT_ARGS(pbc_merge_write
)
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);
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.
814 static struct longopt_opt_decl options
[] = {
815 { 'o', 'o', OPTION_required_FLAG
, { "--output" } }
819 main(int argc
, const char **argv
)
822 pbc_merge_input
** input_files
;
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. */
836 while ((status
= longopt_get(interp
, argc
, argv
, options
, &opt
)) > 0) {
837 switch (opt
.opt_id
) {
839 if (output_file
== NULL
)
840 output_file
= opt
.opt_arg
;
851 if (status
== -1 || !output_file
) {
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
);
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",
875 Parrot_exit(interp
, 1);
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);
895 * c-file-style: "parrot"
897 * vim: expandtab shiftwidth=4: