2
Copyright (C) 2005-2010, Parrot Foundation.
3
$Id: pbc_merge.c 48923 2010-09-10 23:34:18Z plobsing $
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: