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.
39 #define PARROT_IN_EXTENSION
41 #include "parrot/parrot.h"
42 #include "parrot/embed.h"
43 #include "parrot/oplib/ops.h"
44 #include "parrot/oplib/core_ops.h"
45 #include "pmc/pmc_sub.h"
48 /* This struct describes an input file. */
49 typedef struct pbc_merge_input
{
50 const char *filename
; /* name of the input file */
51 PackFile
*pf
; /* loaded packfile struct */
52 opcode_t code_start
; /* where the bytecode is located in the merged
54 opcode_t const_start
;/* where the const table is located within the
56 opcode_t
*const_map
; /* map constants from input files to their location
60 /* HEADERIZER HFILE: none */
62 /* HEADERIZER BEGIN: static */
63 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
65 PARROT_DOES_NOT_RETURN
66 static void help(PARROT_INTERP
)
67 __attribute__nonnull__(1);
69 static void pbc_fixup_bytecode(PARROT_INTERP
,
70 ARGMOD(pbc_merge_input
**inputs
),
72 ARGMOD(PackFile_ByteCode
*bc
))
73 __attribute__nonnull__(1)
74 __attribute__nonnull__(2)
75 __attribute__nonnull__(4)
76 FUNC_MODIFIES(*inputs
)
79 PARROT_WARN_UNUSED_RESULT
80 PARROT_CANNOT_RETURN_NULL
81 static PackFile
* pbc_merge_begin(PARROT_INTERP
,
82 ARGMOD(pbc_merge_input
**inputs
),
84 __attribute__nonnull__(1)
85 __attribute__nonnull__(2)
86 FUNC_MODIFIES(*inputs
);
88 PARROT_WARN_UNUSED_RESULT
89 PARROT_CANNOT_RETURN_NULL
90 static PackFile_ByteCode
* pbc_merge_bytecode(PARROT_INTERP
,
91 ARGMOD(pbc_merge_input
**inputs
),
94 __attribute__nonnull__(1)
95 __attribute__nonnull__(2)
96 __attribute__nonnull__(4)
97 FUNC_MODIFIES(*inputs
)
100 PARROT_WARN_UNUSED_RESULT
101 PARROT_CANNOT_RETURN_NULL
102 static PackFile_ConstTable
* pbc_merge_constants(PARROT_INTERP
,
103 ARGMOD(pbc_merge_input
**inputs
),
105 ARGMOD(PackFile
*pf
),
106 ARGMOD(PackFile_ByteCode
*bc
))
107 __attribute__nonnull__(1)
108 __attribute__nonnull__(2)
109 __attribute__nonnull__(4)
110 __attribute__nonnull__(5)
111 FUNC_MODIFIES(*inputs
)
115 static void pbc_merge_debugs(PARROT_INTERP
,
116 ARGMOD(pbc_merge_input
**inputs
),
118 ARGMOD(PackFile
*pf
),
119 ARGMOD(PackFile_ByteCode
*bc
))
120 __attribute__nonnull__(1)
121 __attribute__nonnull__(2)
122 __attribute__nonnull__(4)
123 __attribute__nonnull__(5)
124 FUNC_MODIFIES(*inputs
)
128 static void pbc_merge_fixups(PARROT_INTERP
,
129 ARGIN(pbc_merge_input
**inputs
),
131 ARGMOD(PackFile
*pf
))
132 __attribute__nonnull__(1)
133 __attribute__nonnull__(2)
134 __attribute__nonnull__(4)
137 PARROT_WARN_UNUSED_RESULT
138 PARROT_CANNOT_RETURN_NULL
139 static PackFile
* pbc_merge_loadpbc(PARROT_INTERP
,
140 ARGIN(const char *fullname
))
141 __attribute__nonnull__(1)
142 __attribute__nonnull__(2);
144 static void pbc_merge_write(PARROT_INTERP
,
145 ARGMOD(PackFile
*pf
),
146 ARGIN(const char *filename
))
147 __attribute__nonnull__(1)
148 __attribute__nonnull__(2)
149 __attribute__nonnull__(3)
152 #define ASSERT_ARGS_help __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
153 PARROT_ASSERT_ARG(interp))
154 #define ASSERT_ARGS_pbc_fixup_bytecode __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
155 PARROT_ASSERT_ARG(interp) \
156 , PARROT_ASSERT_ARG(inputs) \
157 , PARROT_ASSERT_ARG(bc))
158 #define ASSERT_ARGS_pbc_merge_begin __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
159 PARROT_ASSERT_ARG(interp) \
160 , PARROT_ASSERT_ARG(inputs))
161 #define ASSERT_ARGS_pbc_merge_bytecode __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
162 PARROT_ASSERT_ARG(interp) \
163 , PARROT_ASSERT_ARG(inputs) \
164 , PARROT_ASSERT_ARG(pf))
165 #define ASSERT_ARGS_pbc_merge_constants __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
166 PARROT_ASSERT_ARG(interp) \
167 , PARROT_ASSERT_ARG(inputs) \
168 , PARROT_ASSERT_ARG(pf) \
169 , PARROT_ASSERT_ARG(bc))
170 #define ASSERT_ARGS_pbc_merge_debugs __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
171 PARROT_ASSERT_ARG(interp) \
172 , PARROT_ASSERT_ARG(inputs) \
173 , PARROT_ASSERT_ARG(pf) \
174 , PARROT_ASSERT_ARG(bc))
175 #define ASSERT_ARGS_pbc_merge_fixups __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
176 PARROT_ASSERT_ARG(interp) \
177 , PARROT_ASSERT_ARG(inputs) \
178 , PARROT_ASSERT_ARG(pf))
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
= Parrot_str_new_init(interp
, fullname
,
238 strlen(fullname
), Parrot_default_encoding_ptr
, 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
= mem_gc_allocate_n_typed(interp
, chunk_size
, char);
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
)
268 program_code
= mem_gc_realloc_n_typed(interp
, program_code
,
269 program_size
+ chunk_size
, char);
271 cursor
= (char *)program_code
+ program_size
;
274 if (read_result
< 0) {
275 Parrot_io_eprintf(interp
,
276 "PBC Merge: Problem reading packfile from PIO.\n");
277 Parrot_exit(interp
, 1);
281 /* Now that we have the bytecode, let's unpack it. */
282 pf
= PackFile_new(interp
, is_mapped
);
283 if (!PackFile_unpack(interp
,
284 pf
, (opcode_t
*)program_code
, program_size
)) {
285 Parrot_io_eprintf(interp
, "PBC Merge: Can't unpack packfile %s.\n",
287 Parrot_exit(interp
, 1);
290 /* Return the packfile. */
297 =item C<static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
298 pbc_merge_input **inputs, int num_inputs, PackFile *pf)>
300 This function merges the bytecode from the input packfiles, storing the
301 offsets that each bit of bytecode now exists at.
307 PARROT_WARN_UNUSED_RESULT
308 PARROT_CANNOT_RETURN_NULL
309 static PackFile_ByteCode
*
310 pbc_merge_bytecode(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
311 int num_inputs
, ARGMOD(PackFile
*pf
))
313 ASSERT_ARGS(pbc_merge_bytecode
)
315 opcode_t
*bc
= mem_gc_allocate_typed(interp
, opcode_t
);
318 /* Add a bytecode segment. */
319 PackFile_ByteCode
* const bc_seg
=
320 (PackFile_ByteCode
*)PackFile_Segment_new_seg(interp
,
321 &pf
->directory
, PF_BYTEC_SEG
, BYTE_CODE_SEGMENT_NAME
, 1);
324 Parrot_io_eprintf(interp
,
325 "PBC Merge: Error creating bytecode segment.");
326 Parrot_exit(interp
, 1);
329 /* Loop over input files. */
330 for (i
= 0; i
< num_inputs
; ++i
) {
331 /* Get the bytecode segment from the input file. */
332 PackFile_ByteCode
* const in_seg
= inputs
[i
]->pf
->cur_cs
;
333 if (in_seg
== NULL
) {
334 Parrot_io_eprintf(interp
,
335 "PBC Merge: Cannot locate bytecode segment in %s",
336 inputs
[i
]->filename
);
337 Parrot_exit(interp
, 1);
340 /* Re-allocate the current buffer. */
341 bc
= mem_gc_realloc_n_typed(interp
, bc
, cursor
+ in_seg
->base
.size
, opcode_t
);
343 /* Copy data and store cursor. */
344 memcpy(bc
+ cursor
, in_seg
->base
.data
,
345 in_seg
->base
.size
* sizeof (opcode_t
));
346 inputs
[i
]->code_start
= cursor
;
349 cursor
+= in_seg
->base
.size
;
352 /* Stash produced bytecode. */
353 bc_seg
->base
.data
= bc
;
354 bc_seg
->base
.size
= cursor
;
355 bc_seg
->base
.name
= Parrot_str_new_constant(interp
, "MERGED");
362 =item C<static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
363 pbc_merge_input **inputs, int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
365 This function merges the constants tables from the input PBC files.
371 PARROT_WARN_UNUSED_RESULT
372 PARROT_CANNOT_RETURN_NULL
373 static PackFile_ConstTable
*
374 pbc_merge_constants(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
375 int num_inputs
, ARGMOD(PackFile
*pf
),
376 ARGMOD(PackFile_ByteCode
*bc
))
378 ASSERT_ARGS(pbc_merge_constants
)
379 PackFile_Constant
*constants
= mem_gc_allocate_typed(interp
, PackFile_Constant
);
382 opcode_t output_const_num
= 0;
383 opcode_t input_const_num
= 0;
386 /* Add a constant table segment. */
387 PackFile_ConstTable
* const const_seg
= (PackFile_ConstTable
*)
388 PackFile_Segment_new_seg(interp
, &pf
->directory
,
389 PF_CONST_SEG
, CONSTANT_SEGMENT_NAME
, 1);
391 if (const_seg
== NULL
) {
392 Parrot_io_eprintf(interp
,
393 "PBC Merge: Error creating constant table segment.");
394 Parrot_exit(interp
, 1);
397 /* Loop over input files. */
398 for (i
= 0; i
< num_inputs
; ++i
) {
400 /* Get the constant table segment from the input file. */
401 PackFile_ConstTable
* const in_seg
= inputs
[i
]->pf
->cur_cs
->const_table
;
402 if (in_seg
== NULL
) {
403 Parrot_io_eprintf(interp
,
404 "PBC Merge: Cannot locate constant table segment in %s\n",
405 inputs
[i
]->filename
);
406 Parrot_exit(interp
, 1);
409 /* Store cursor as position where constant table starts. */
410 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
= mem_gc_realloc_n_typed(interp
, constants
,
416 cursor
+ in_seg
->const_count
, PackFile_Constant
);
418 /* Loop over the constants and copy them to the output PBC. */
419 for (j
= 0; j
< in_seg
->const_count
; ++j
) {
420 /* Get the entry and the copy. */
421 PackFile_Constant
*cur_entry
= &in_seg
->constants
[j
];
422 PackFile_Constant
*copy
= &constants
[cursor
];
423 STRUCT_COPY(copy
, cur_entry
);
425 /* If it's a sub PMC, need to deal with offsets. */
426 if (copy
->type
== PFC_PMC
) {
427 switch (copy
->u
.key
->vtable
->base_type
) {
429 case enum_class_Coroutine
:
431 Parrot_Sub_attributes
*sub
;
432 PMC_get_sub(interp
, copy
->u
.key
, sub
);
433 sub
->start_offs
+= inputs
[i
]->code_start
;
434 sub
->end_offs
+= inputs
[i
]->code_start
;
442 inputs
[i
]->const_map
[input_const_num
] = output_const_num
;
450 /* Stash merged constants table and count and return the new segment. */
451 const_seg
->constants
= constants
;
452 const_seg
->const_count
= cursor
;
453 const_seg
->code
= bc
;
454 bc
->const_table
= const_seg
;
461 =item C<static void pbc_merge_fixups(PARROT_INTERP, pbc_merge_input **inputs,
462 int num_inputs, PackFile *pf)>
464 This function merges the fixups tables from the input PBC files.
471 pbc_merge_fixups(PARROT_INTERP
, ARGIN(pbc_merge_input
**inputs
),
472 int num_inputs
, ARGMOD(PackFile
*pf
))
474 ASSERT_ARGS(pbc_merge_fixups
)
475 PackFile_FixupTable
*fixup_seg
;
476 PackFile_FixupEntry
*fixups
= NULL
;
480 /* Add a fixup table segment. */
481 fixup_seg
= (PackFile_FixupTable
*)PackFile_Segment_new_seg(
482 interp
, &pf
->directory
, PF_FIXUP_SEG
, FIXUP_TABLE_SEGMENT_NAME
, 1);
483 if (fixup_seg
== NULL
) {
484 Parrot_io_eprintf(interp
,
485 "PBC Merge: Error creating fixup table segment.");
486 Parrot_exit(interp
, 1);
489 /* Loop over input files. */
490 for (i
= 0; i
< num_inputs
; ++i
) {
491 /* Get the fixup segment from the input file. */
492 PackFile_FixupTable
* const in_seg
= inputs
[i
]->pf
->cur_cs
->fixups
;
495 if (in_seg
== NULL
) {
496 Parrot_io_eprintf(interp
,
497 "PBC Merge: Cannot locate fixup segment in %s",
498 inputs
[i
]->filename
);
499 Parrot_exit(interp
, 1);
502 /* Allocate space for these fixups, provided we have some. */
503 if (in_seg
->fixup_count
> 0) {
504 fixups
= mem_gc_realloc_n_typed(interp
, fixups
,
505 cursor
+ in_seg
->fixup_count
, PackFile_FixupEntry
);
508 /* Loop over the fixups and copy them to the output PBC, correcting
509 the offsets into the bytecode. */
510 for (j
= 0; j
< in_seg
->fixup_count
; ++j
) {
511 /* Get the entry and allocate space for copies. */
512 const PackFile_FixupEntry
* const cur_entry
= in_seg
->fixups
+ j
;
513 PackFile_FixupEntry
* const copy
=
514 mem_gc_allocate_typed(interp
, PackFile_FixupEntry
);
515 char * const name_copy
= mem_gc_allocate_n_typed(interp
,
516 strlen(cur_entry
->name
) + 1, char);
518 /* Copy type and name. */
519 copy
->type
= cur_entry
->type
;
520 strcpy(name_copy
, cur_entry
->name
);
521 copy
->name
= name_copy
;
523 /* Set new offset and bytecode pointer. */
524 switch (copy
->type
) {
526 copy
->offset
= cur_entry
->offset
+ inputs
[i
]->const_start
;
529 Parrot_io_eprintf(interp
, "PBC Merge: Unknown fixup type");
530 Parrot_exit(interp
, 1);
533 /* Slot it into the list. */
534 fixups
[cursor
] = *copy
;
539 /* Stash merged fixup table and count. */
540 fixup_seg
->fixups
= fixups
;
541 fixup_seg
->fixup_count
= cursor
;
547 =item C<static void pbc_merge_debugs(PARROT_INTERP, pbc_merge_input **inputs,
548 int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
550 This function merges the debug segments from the input PBC files.
557 pbc_merge_debugs(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
558 int num_inputs
, ARGMOD(PackFile
*pf
), ARGMOD(PackFile_ByteCode
*bc
))
560 ASSERT_ARGS(pbc_merge_debugs
)
561 PackFile_Debug
*debug_seg
;
562 opcode_t
*lines
= mem_gc_allocate_typed(interp
,
564 PackFile_DebugFilenameMapping
*mappings
=
565 mem_gc_allocate_typed(interp
, PackFile_DebugFilenameMapping
);
567 opcode_t num_mappings
= 0;
568 opcode_t num_lines
= 0;
572 /* We need to merge both the mappings and the list of line numbers.
573 The line numbers can just be concatenated. The mappings must have
574 their offsets fixed up. */
575 for (i
= 0; i
< num_inputs
; ++i
) {
576 const PackFile_Debug
* const in_seg
= inputs
[i
]->pf
->cur_cs
->debugs
;
579 /* Concatenate line numbers. */
580 lines
= mem_gc_realloc_n_typed(interp
, lines
,
581 num_lines
+ in_seg
->base
.size
, opcode_t
);
583 memcpy(lines
+ num_lines
, in_seg
->base
.data
,
584 in_seg
->base
.size
* sizeof (opcode_t
));
586 /* Concatenate mappings. */
587 mappings
= mem_gc_realloc_n_typed(interp
, mappings
,
588 num_mappings
+ in_seg
->num_mappings
,
589 PackFile_DebugFilenameMapping
);
591 for (j
= 0; j
< in_seg
->num_mappings
; ++j
) {
592 PackFile_DebugFilenameMapping
*mapping
= mappings
+ num_mappings
+ j
;
594 STRUCT_COPY_FROM_STRUCT(mapping
, in_seg
->mappings
[j
]);
595 mapping
->offset
+= num_lines
;
596 mapping
->filename
+= inputs
[i
]->const_start
;
599 num_lines
+= in_seg
->base
.size
- 1;
600 num_mappings
+= in_seg
->num_mappings
;
603 /* Create merged debug segment. Replace created data and mappings
604 with merged ones we have created. */
605 debug_seg
= Parrot_new_debug_seg(interp
, bc
, num_lines
);
606 mem_gc_free(interp
, debug_seg
->base
.data
);
607 debug_seg
->base
.data
= lines
;
608 mem_gc_free(interp
, debug_seg
->mappings
);
610 debug_seg
->mappings
= mappings
;
611 debug_seg
->num_mappings
= num_mappings
;
616 bytecode_remap_op(PARROT_INTERP
, PackFile
*pf
, opcode_t op
) {
618 op_info_t
*info
= pf
->cur_cs
->op_info_table
[op
];
619 op_lib_t
*lib
= info
->lib
;
620 op_func_t op_func
= pf
->cur_cs
->op_func_table
[op
];
621 PackFile_ByteCode
*bc
= interp
->code
;
622 PackFile_ByteCode_OpMappingEntry
*om
;
624 for (i
= 0; i
< bc
->op_mapping
.n_libs
; i
++) {
625 if (lib
== bc
->op_mapping
.libs
[i
].lib
) {
626 om
= &bc
->op_mapping
.libs
[i
];
631 /* library not yet mapped */
632 bc
->op_mapping
.n_libs
++;
633 bc
->op_mapping
.libs
= mem_gc_realloc_n_typed_zeroed(interp
, bc
->op_mapping
.libs
,
634 bc
->op_mapping
.n_libs
, bc
->op_mapping
.n_libs
- 1,
635 PackFile_ByteCode_OpMappingEntry
);
637 /* initialize a new lib entry */
638 om
= &bc
->op_mapping
.libs
[bc
->op_mapping
.n_libs
- 1];
641 om
->lib_ops
= mem_gc_allocate_n_zeroed_typed(interp
, 0, opcode_t
);
642 om
->table_ops
= mem_gc_allocate_n_zeroed_typed(interp
, 0, opcode_t
);
645 for (i
= 0; i
< om
->n_ops
; i
++) {
646 if (bc
->op_func_table
[om
->table_ops
[i
]] == op_func
)
647 return om
->table_ops
[i
];
650 /* op not yet mapped */
653 mem_gc_realloc_n_typed_zeroed(interp
, bc
->op_func_table
, bc
->op_count
, bc
->op_count
- 1,
655 bc
->op_func_table
[bc
->op_count
- 1] = op_func
;
657 mem_gc_realloc_n_typed_zeroed(interp
, bc
->op_info_table
, bc
->op_count
, bc
->op_count
- 1,
659 bc
->op_info_table
[bc
->op_count
- 1] = info
;
661 /* initialize new op mapping */
665 mem_gc_realloc_n_typed_zeroed(interp
, om
->lib_ops
, om
->n_ops
, om
->n_ops
- 1, opcode_t
);
666 for (i
= 0; i
< lib
->op_count
; i
++) {
667 if (lib
->op_func_table
[i
] == op_func
) {
668 om
->lib_ops
[om
->n_ops
- 1] = i
;
672 PARROT_ASSERT(om
->lib_ops
[om
->n_ops
- 1] || !i
);
675 mem_gc_realloc_n_typed_zeroed(interp
, om
->table_ops
, om
->n_ops
, om
->n_ops
- 1, opcode_t
);
676 om
->table_ops
[om
->n_ops
- 1] = bc
->op_count
- 1;
678 return bc
->op_count
- 1;
683 =item C<static void pbc_fixup_bytecode(PARROT_INTERP, pbc_merge_input **inputs,
684 int num_inputs, PackFile_ByteCode *bc)>
686 Fixup bytecode. This includes correcting pointers into the constant table
687 and updating the ops mapping.
694 pbc_fixup_bytecode(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
),
695 int num_inputs
, ARGMOD(PackFile_ByteCode
*bc
))
697 ASSERT_ARGS(pbc_fixup_bytecode
)
700 opcode_t
*ops
= bc
->base
.data
;
703 op_lib_t
*core_ops
= PARROT_GET_CORE_OPLIB(interp
);
705 /* Loop over the ops in the merged bytecode. */
706 while (cur_op
< (opcode_t
)bc
->base
.size
) {
711 /* Keep track of the current input file. */
712 if (cur_input
+ 1 < num_inputs
&&
713 cur_op
>= inputs
[cur_input
+ 1]->code_start
)
716 /* Get info about this op, remap it, and jump over it. */
717 op_num
= ops
[cur_op
] = bytecode_remap_op(interp
, inputs
[cur_input
]->pf
, ops
[cur_op
]);
718 op
= bc
->op_info_table
[op_num
];
719 op_ptr
= ops
+ cur_op
;
722 /* Loop over the arguments. */
723 for (cur_arg
= 1; cur_arg
< op
->op_count
; ++cur_arg
) {
724 /* Pick out any indexes into the constant table and correct them. */
725 switch (op
->types
[cur_arg
- 1]) {
729 case PARROT_ARG_NAME_SC
:
731 ops
[cur_op
] = inputs
[cur_input
]->const_map
[ ops
[cur_op
] ];
737 /* Move along the bytecode array. */
741 /* Handle special case variable argument opcodes. */
742 op_func
= interp
->code
->op_func_table
[op_num
];
743 if (op_func
== core_ops
->op_func_table
[PARROT_OP_set_args_pc
] ||
744 op_func
== core_ops
->op_func_table
[PARROT_OP_get_results_pc
] ||
745 op_func
== core_ops
->op_func_table
[PARROT_OP_get_params_pc
] ||
746 op_func
== core_ops
->op_func_table
[PARROT_OP_set_returns_pc
]) {
747 /* Get the signature. */
748 PMC
* const sig
= bc
->const_table
->constants
[op_ptr
[1]].u
.key
;
750 /* Loop over the arguments to locate any that need a fixup. */
751 const int sig_items
= VTABLE_elements(interp
, sig
);
752 for (cur_arg
= 0; cur_arg
< sig_items
; ++cur_arg
) {
753 switch (VTABLE_get_integer_keyed_int(interp
, sig
, cur_arg
)) {
757 case PARROT_ARG_NAME_SC
:
759 ops
[cur_op
] = inputs
[cur_input
]->const_map
[ ops
[cur_op
] ];
773 =item C<static PackFile* pbc_merge_begin(PARROT_INTERP, pbc_merge_input
774 **inputs, int num_inputs)>
776 This is the function that drives PBC merging process.
781 PARROT_WARN_UNUSED_RESULT
782 PARROT_CANNOT_RETURN_NULL
784 pbc_merge_begin(PARROT_INTERP
, ARGMOD(pbc_merge_input
**inputs
), int num_inputs
)
786 ASSERT_ARGS(pbc_merge_begin
)
787 PackFile_ByteCode
*bc
;
788 PackFile_ConstTable
*ct
;
791 /* Create a new empty packfile. */
792 PackFile
* const merged
= PackFile_new(interp
, 0);
793 if (merged
== NULL
) {
794 Parrot_io_eprintf(interp
, "PBC Merge: Error creating new packfile.\n");
795 Parrot_exit(interp
, 1);
798 /* calculate how many constants are stored in the packfiles to be merged */
799 for (i
= 0; i
< num_inputs
; ++i
) {
800 PackFile_Directory
*pf_dir
= &inputs
[i
]->pf
->directory
;
802 for (j
= 0; j
< pf_dir
->num_segments
; ++j
) {
803 PackFile_Segment
*seg
= (PackFile_Segment
*)pf_dir
->segments
[j
];
804 if (seg
->type
== PF_CONST_SEG
) {
805 opcode_t const_count
= ((PackFile_ConstTable
*)seg
)->const_count
;
806 inputs
[i
]->const_map
= mem_gc_allocate_n_typed(interp
,
807 const_count
, opcode_t
);
812 /* Merge the various stuff. */
813 bc
= interp
->code
= pbc_merge_bytecode(interp
, inputs
, num_inputs
, merged
);
814 ct
= pbc_merge_constants(interp
, inputs
, num_inputs
, merged
, bc
);
817 pbc_merge_fixups(interp
, inputs
, num_inputs
, merged
);
818 pbc_merge_debugs(interp
, inputs
, num_inputs
, merged
, bc
);
820 /* Walk bytecode and fix ops that reference the constants table. */
821 pbc_fixup_bytecode(interp
, inputs
, num_inputs
, bc
);
823 for (i
= 0; i
< num_inputs
; ++i
) {
824 mem_gc_free(interp
, inputs
[i
]->const_map
);
827 /* Return merged result. */
834 =item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
837 This functions writes out the merged packfile.
844 pbc_merge_write(PARROT_INTERP
, ARGMOD(PackFile
*pf
), ARGIN(const char *filename
))
846 ASSERT_ARGS(pbc_merge_write
)
849 /* Get size of packfile we'll write. */
850 const size_t size
= PackFile_pack_size(interp
, pf
) * sizeof (opcode_t
);
852 /* Allocate memory. */
853 opcode_t
* const pack
= (opcode_t
*) Parrot_gc_allocate_memory_chunk(interp
, size
);
855 /* Write and clean up. */
856 PackFile_pack(interp
, pf
, pack
);
857 if ((fp
= fopen(filename
, "wb")) == 0) {
858 Parrot_io_eprintf(interp
, "PBC Merge: Couldn't open %s\n", filename
);
859 Parrot_exit(interp
, 1);
861 if ((1 != fwrite(pack
, size
, 1, fp
))) {
862 Parrot_io_eprintf(interp
, "PBC Merge: Couldn't write %s\n", filename
);
863 Parrot_exit(interp
, 1);
866 mem_gc_free(interp
, pack
);
872 =item C<int main(int argc, const char **argv)>
874 The main function that grabs console input, reads in the packfiles
875 provided they exist, hands them to another function that runs the
876 merge process and finally writes out the produced packfile.
882 static struct longopt_opt_decl options
[] = {
883 { 'o', 'o', OPTION_required_FLAG
, { "--output" } }
887 main(int argc
, const char **argv
)
890 pbc_merge_input
** input_files
;
893 const char *output_file
= NULL
;
894 struct longopt_opt_info opt
= LONGOPT_OPT_INFO_INIT
;
895 Interp
* const interp
= Parrot_new(NULL
);
897 Parrot_block_GC_mark(interp
);
899 /* Get options, ensuring we have at least one input
900 file and an output file. */
904 while ((status
= longopt_get(interp
, argc
, argv
, options
, &opt
)) > 0) {
905 switch (opt
.opt_id
) {
907 if (output_file
== NULL
)
908 output_file
= opt
.opt_arg
;
919 if (status
== -1 || !output_file
) {
922 argc
-= opt
.opt_index
; /* Now the number of input files. */
923 argv
+= opt
.opt_index
; /* Now at first input filename. */
925 /* Load each packfile that we are to merge and set up an input
926 structure for each of them. */
927 input_files
= mem_gc_allocate_n_typed(interp
, argc
, pbc_merge_input
*);
929 for (i
= 0; i
< argc
; ++i
) {
930 /* Allocate a struct. */
931 input_files
[i
] = mem_gc_allocate_typed(interp
, pbc_merge_input
);
934 input_files
[i
]->filename
= *argv
;
936 /* Load the packfile and unpack it. */
937 input_files
[i
]->pf
= pbc_merge_loadpbc(interp
,
938 input_files
[i
]->filename
);
939 if (input_files
[i
]->pf
== NULL
) {
940 Parrot_io_eprintf(interp
,
941 "PBC Merge: Unknown error while reading and unpacking %s\n",
943 Parrot_exit(interp
, 1);
951 merged
= pbc_merge_begin(interp
, input_files
, argc
);
953 /* Write merged packfile. */
954 pbc_merge_write(interp
, merged
, output_file
);
956 /* Finally, we're done. */
957 Parrot_exit(interp
, 0);
963 * c-file-style: "parrot"
965 * vim: expandtab shiftwidth=4: