2 Copyright (C) 2005-2009, 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
; /* Filename of the input file. */
49 PackFile
*pf
; /* The loaded packfile. */
50 opcode_t code_start
; /* Where the bytecode is located in the merged
52 opcode_t const_start
; /* Where the const table is located in the merged
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
),
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
),
80 __attribute__nonnull__(1)
81 __attribute__nonnull__(2)
82 __attribute__nonnull__(4)
83 FUNC_MODIFIES(*inputs
)
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
),
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
)
101 static void pbc_merge_ctpointers(PARROT_INTERP
,
102 ARGMOD(pbc_merge_input
**inputs
),
104 ARGMOD(PackFile_ByteCode
*bc
))
105 __attribute__nonnull__(1)
106 __attribute__nonnull__(2)
107 __attribute__nonnull__(4)
108 FUNC_MODIFIES(*inputs
)
111 static void pbc_merge_debugs(PARROT_INTERP
,
112 ARGMOD(pbc_merge_input
**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
)
124 static void pbc_merge_fixups(PARROT_INTERP
,
125 ARGIN(pbc_merge_input
**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)
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)
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.
199 PARROT_DOES_NOT_RETURN
203 printf("pbc_merge - merge multiple parrot bytecode files into one\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.
221 PARROT_WARN_UNUSED_RESULT
222 PARROT_CANNOT_RETURN_NULL
224 pbc_merge_loadpbc(PARROT_INTERP
, ARGIN(const char *fullname
))
226 ASSERT_ARGS(pbc_merge_loadpbc
)
227 INTVAL program_size
, wanted
;
231 INTVAL is_mapped
= 0;
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",
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");
251 Parrot_io_eprintf(interp
, "PBC Merge: Can't open %s, code %i.\n",
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
;
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
)
269 (char *)mem_sys_realloc(program_code
, program_size
+ chunk_size
);
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);
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",
293 Parrot_exit(interp
, 1);
296 /* Return the packfile. */
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.
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
)
321 opcode_t
*bc
= mem_allocate_typed(opcode_t
);
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
);
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
;
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");
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.
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
)
387 PackFile_Constant
**constants
= mem_allocate_typed(PackFile_Constant
*);
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(
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
) {
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
;
453 /* Slot it into the list. */
454 constants
[cursor
] = copy
;
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
;
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.
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
)
485 PackFile_FixupTable
*fixup_seg
;
486 PackFile_FixupEntry
**fixups
= mem_allocate_typed(PackFile_FixupEntry
*);
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
;
544 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->const_start
;
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
;
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.
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
)
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
));
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
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
)
653 opcode_t
*ops
= bc
->base
.data
;
657 /* Loop over the ops in the merged bytecode. */
658 while (cur_op
< (opcode_t
)bc
->base
.size
) {
662 /* Keep track of the current input file. */
663 if (cur_input
+ 1 < num_inputs
&&
664 cur_op
>= inputs
[cur_input
+ 1]->code_start
)
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
;
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]) {
681 ops
[cur_op
] += inputs
[cur_input
]->const_start
;
687 /* Move along the bytecode array. */
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
)) {
707 ops
[cur_op
] += inputs
[cur_input
]->const_start
;
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.
729 PARROT_WARN_UNUSED_RESULT
730 PARROT_CANNOT_RETURN_NULL
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
);
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. */
763 =item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
766 This functions writes out the merged packfile.
773 pbc_merge_write(PARROT_INTERP
, ARGMOD(PackFile
*pf
), ARGIN(const char *filename
))
775 ASSERT_ARGS(pbc_merge_write
)
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
);
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);
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.
815 static struct longopt_opt_decl options
[] = {
816 { 'o', 'o', OPTION_required_FLAG
, { "--output" } }
820 main(int argc
, const char **argv
)
823 pbc_merge_input
** input_files
;
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. */
837 while ((status
= longopt_get(interp
, argc
, argv
, options
, &opt
)) > 0) {
838 switch (opt
.opt_id
) {
840 if (output_file
== NULL
)
841 output_file
= opt
.opt_arg
;
852 if (status
== -1 || !output_file
) {
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
);
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",
877 Parrot_exit(interp
, 1);
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);
897 * c-file-style: "parrot"
899 * vim: expandtab shiftwidth=4: