fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pbc_merge.c
blob530c3684ee610a56096c3a6f327dbbfbf62caa4e
1 /*
2 Copyright (C) 2005-2010, 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
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
53 packfile */
54 opcode_t const_start;/* where the const table is located within the
55 merged table */
56 opcode_t *const_map; /* map constants from input files to their location
57 in the output file */
58 } pbc_merge_input;
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),
71 int num_inputs,
72 ARGMOD(PackFile_ByteCode *bc))
73 __attribute__nonnull__(1)
74 __attribute__nonnull__(2)
75 __attribute__nonnull__(4)
76 FUNC_MODIFIES(*inputs)
77 FUNC_MODIFIES(*bc);
79 PARROT_WARN_UNUSED_RESULT
80 PARROT_CANNOT_RETURN_NULL
81 static PackFile* pbc_merge_begin(PARROT_INTERP,
82 ARGMOD(pbc_merge_input **inputs),
83 int num_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),
92 int num_inputs,
93 ARGMOD(PackFile *pf))
94 __attribute__nonnull__(1)
95 __attribute__nonnull__(2)
96 __attribute__nonnull__(4)
97 FUNC_MODIFIES(*inputs)
98 FUNC_MODIFIES(*pf);
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),
104 int num_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)
112 FUNC_MODIFIES(*pf)
113 FUNC_MODIFIES(*bc);
115 static void pbc_merge_debugs(PARROT_INTERP,
116 ARGMOD(pbc_merge_input **inputs),
117 int num_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)
125 FUNC_MODIFIES(*pf)
126 FUNC_MODIFIES(*bc);
128 static void pbc_merge_fixups(PARROT_INTERP,
129 ARGIN(pbc_merge_input **inputs),
130 int num_inputs,
131 ARGMOD(PackFile *pf))
132 __attribute__nonnull__(1)
133 __attribute__nonnull__(2)
134 __attribute__nonnull__(4)
135 FUNC_MODIFIES(*pf);
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)
150 FUNC_MODIFIES(*pf);
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.
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 = 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",
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 = mem_gc_allocate_n_typed(interp, chunk_size, char);
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 = 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);
279 fclose(io);
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",
286 fullname);
287 Parrot_exit(interp, 1);
290 /* Return the packfile. */
291 return pf;
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.
303 =cut
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)
314 int i;
315 opcode_t *bc = mem_gc_allocate_typed(interp, opcode_t);
316 opcode_t cursor = 0;
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);
323 if (!bc_seg) {
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;
348 /* Update 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");
356 return bc_seg;
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.
367 =cut
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);
381 opcode_t cursor = 0;
382 opcode_t output_const_num = 0;
383 opcode_t input_const_num = 0;
384 int i, j;
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;
411 input_const_num = 0;
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) {
428 case enum_class_Sub:
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;
436 break;
437 default:
438 break;
442 inputs[i]->const_map[input_const_num] = output_const_num;
443 ++input_const_num;
444 ++output_const_num;
446 ++cursor;
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;
455 return 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.
466 =cut
470 static void
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;
477 opcode_t cursor = 0;
478 int i;
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;
493 int j;
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) {
525 case enum_fixup_sub:
526 copy->offset = cur_entry->offset + inputs[i]->const_start;
527 break;
528 default:
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;
535 ++cursor;
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.
552 =cut
556 static void
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,
563 opcode_t);
564 PackFile_DebugFilenameMapping *mappings =
565 mem_gc_allocate_typed(interp, PackFile_DebugFilenameMapping);
567 opcode_t num_mappings = 0;
568 opcode_t num_lines = 0;
570 int i;
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;
577 int j;
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;
615 static opcode_t
616 bytecode_remap_op(PARROT_INTERP, PackFile *pf, opcode_t op) {
617 int i;
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];
627 goto found_lib;
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];
639 om->lib = lib;
640 om->n_ops = 0;
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);
644 found_lib:
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 */
651 bc->op_count++;
652 bc->op_func_table =
653 mem_gc_realloc_n_typed_zeroed(interp, bc->op_func_table, bc->op_count, bc->op_count - 1,
654 op_func_t);
655 bc->op_func_table[bc->op_count - 1] = op_func;
656 bc->op_info_table =
657 mem_gc_realloc_n_typed_zeroed(interp, bc->op_info_table, bc->op_count, bc->op_count - 1,
658 op_info_t *);
659 bc->op_info_table[bc->op_count - 1] = info;
661 /* initialize new op mapping */
662 om->n_ops++;
664 om->lib_ops =
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;
669 break;
672 PARROT_ASSERT(om->lib_ops[om->n_ops - 1] || !i);
674 om->table_ops =
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.
689 =cut
693 static void
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)
698 int cur_arg;
699 opcode_t *op_ptr;
700 opcode_t *ops = bc->base.data;
701 opcode_t cur_op = 0;
702 int cur_input = 0;
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) {
707 op_info_t *op;
708 opcode_t op_num;
709 op_func_t op_func;
711 /* Keep track of the current input file. */
712 if (cur_input + 1 < num_inputs &&
713 cur_op >= inputs[cur_input + 1]->code_start)
714 ++cur_input;
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;
720 ++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]) {
726 case PARROT_ARG_NC:
727 case PARROT_ARG_PC:
728 case PARROT_ARG_SC:
729 case PARROT_ARG_NAME_SC:
730 case PARROT_ARG_KC:
731 ops[cur_op] = inputs[cur_input]->const_map[ ops[cur_op] ];
732 break;
733 default:
734 break;
737 /* Move along the bytecode array. */
738 ++cur_op;
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)) {
754 case PARROT_ARG_NC:
755 case PARROT_ARG_PC:
756 case PARROT_ARG_SC:
757 case PARROT_ARG_NAME_SC:
758 case PARROT_ARG_KC:
759 ops[cur_op] = inputs[cur_input]->const_map[ ops[cur_op] ];
760 break;
761 default:
762 break;
764 ++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.
778 =cut
781 PARROT_WARN_UNUSED_RESULT
782 PARROT_CANNOT_RETURN_NULL
783 static PackFile*
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;
789 int i;
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;
801 unsigned int j = 0;
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);
815 UNUSED(ct);
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. */
828 return merged;
834 =item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
835 *filename)>
837 This functions writes out the merged packfile.
839 =cut
843 static void
844 pbc_merge_write(PARROT_INTERP, ARGMOD(PackFile *pf), ARGIN(const char *filename))
846 ASSERT_ARGS(pbc_merge_write)
847 FILE *fp;
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);
865 fclose(fp);
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.
878 =cut
882 static struct longopt_opt_decl options[] = {
883 { 'o', 'o', OPTION_required_FLAG, { "--output" } }
887 main(int argc, const char **argv)
889 int status;
890 pbc_merge_input** input_files;
891 PackFile *merged;
892 int i;
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. */
901 if (argc < 4) {
902 help(interp);
904 while ((status = longopt_get(interp, argc, argv, options, &opt)) > 0) {
905 switch (opt.opt_id) {
906 case 'o':
907 if (output_file == NULL)
908 output_file = opt.opt_arg;
909 else
910 help(interp);
911 break;
912 case '?':
913 help(interp);
914 break;
915 default:
916 break;
919 if (status == -1 || !output_file) {
920 help(interp);
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);
933 /* Set filename */
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",
942 *argv);
943 Parrot_exit(interp, 1);
946 /* Next file. */
947 ++argv;
950 /* Merge. */
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);
962 * Local variables:
963 * c-file-style: "parrot"
964 * End:
965 * vim: expandtab shiftwidth=4: