~dexter/parrot-pkg/maverick

« back to all changes in this revision

Viewing changes to src/pbc_merge.c

  • Committer: Piotr Roszatycki
  • Date: 2011-01-11 14:34:28 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: piotr.roszatycki@gmail.com-20110111143428-s7pa7qz38m61o4tw
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (C) 2005-2010, Parrot Foundation.
3
 
$Id: pbc_merge.c 48923 2010-09-10 23:34:18Z plobsing $
4
 
 
5
 
=head1 NAME
6
 
 
7
 
pbc_merge - Merge multiple Parrot bytecode (PBC) files into
8
 
                  a single PBC file.
9
 
 
10
 
=head1 SYNOPSIS
11
 
 
12
 
 pbc_merge -o out.pbc input1.pbc input2.pbc ...
13
 
 
14
 
=head1 DESCRIPTION
15
 
 
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.
19
 
 
20
 
=head2 Command-Line Options
21
 
 
22
 
=over 4
23
 
 
24
 
=item C<-o out.pbc>
25
 
 
26
 
The name of the PBC file to produce, containing the merged
27
 
segments from the input PBC files.
28
 
 
29
 
=back
30
 
 
31
 
=head2 Functions
32
 
 
33
 
=over 4
34
 
 
35
 
=cut
36
 
 
37
 
*/
38
 
 
39
 
#define PARROT_IN_EXTENSION
40
 
 
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"
46
 
 
47
 
 
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;
59
 
 
60
 
/* HEADERIZER HFILE: none */
61
 
 
62
 
/* HEADERIZER BEGIN: static */
63
 
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
64
 
 
65
 
PARROT_DOES_NOT_RETURN
66
 
static void help(PARROT_INTERP)
67
 
        __attribute__nonnull__(1);
68
 
 
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);
78
 
 
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);
87
 
 
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);
99
 
 
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);
114
 
 
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);
127
 
 
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);
136
 
 
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);
143
 
 
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);
151
 
 
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 */
188
 
 
189
 
/*
190
 
 
191
 
=item C<static void help(PARROT_INTERP)>
192
 
 
193
 
Print out the user help info.
194
 
 
195
 
=cut
196
 
 
197
 
*/
198
 
 
199
 
PARROT_DOES_NOT_RETURN
200
 
static void
201
 
help(PARROT_INTERP)
202
 
{
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);
207
 
}
208
 
 
209
 
/*
210
 
 
211
 
=item C<static PackFile* pbc_merge_loadpbc(PARROT_INTERP, const char *fullname)>
212
 
 
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.
216
 
 
217
 
=cut
218
 
 
219
 
*/
220
 
 
221
 
PARROT_WARN_UNUSED_RESULT
222
 
PARROT_CANNOT_RETURN_NULL
223
 
static PackFile*
224
 
pbc_merge_loadpbc(PARROT_INTERP, ARGIN(const char *fullname))
225
 
{
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;
235
 
 
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);
243
 
    }
244
 
 
245
 
    /* Get program size. */
246
 
    program_size = Parrot_stat_info_intval(interp, fs, STAT_FILESIZE);
247
 
 
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);
254
 
    }
255
 
 
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;
262
 
 
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);
270
 
 
271
 
        cursor = (char *)program_code + program_size;
272
 
    }
273
 
 
274
 
    if (read_result < 0) {
275
 
        Parrot_io_eprintf(interp,
276
 
                "PBC Merge: Problem reading packfile from PIO.\n");
277
 
        Parrot_exit(interp, 1);
278
 
    }
279
 
    fclose(io);
280
 
 
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);
288
 
    }
289
 
 
290
 
    /* Return the packfile. */
291
 
    return pf;
292
 
}
293
 
 
294
 
 
295
 
/*
296
 
 
297
 
=item C<static PackFile_ByteCode* pbc_merge_bytecode(PARROT_INTERP,
298
 
pbc_merge_input **inputs, int num_inputs, PackFile *pf)>
299
 
 
300
 
This function merges the bytecode from the input packfiles, storing the
301
 
offsets that each bit of bytecode now exists at.
302
 
 
303
 
=cut
304
 
 
305
 
*/
306
 
 
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))
312
 
{
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;
317
 
 
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);
322
 
 
323
 
    if (!bc_seg) {
324
 
        Parrot_io_eprintf(interp,
325
 
            "PBC Merge: Error creating bytecode segment.");
326
 
        Parrot_exit(interp, 1);
327
 
    }
328
 
 
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);
338
 
        }
339
 
 
340
 
        /* Re-allocate the current buffer. */
341
 
        bc = mem_gc_realloc_n_typed(interp, bc, cursor + in_seg->base.size, opcode_t);
342
 
 
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;
347
 
 
348
 
        /* Update cursor. */
349
 
        cursor += in_seg->base.size;
350
 
    }
351
 
 
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;
357
 
}
358
 
 
359
 
 
360
 
/*
361
 
 
362
 
=item C<static PackFile_ConstTable* pbc_merge_constants(PARROT_INTERP,
363
 
pbc_merge_input **inputs, int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
364
 
 
365
 
This function merges the constants tables from the input PBC files.
366
 
 
367
 
=cut
368
 
 
369
 
*/
370
 
 
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))
377
 
{
378
 
    ASSERT_ARGS(pbc_merge_constants)
379
 
    PackFile_Constant   *constants = mem_gc_allocate_typed(interp, PackFile_Constant);
380
 
 
381
 
    opcode_t cursor           = 0;
382
 
    opcode_t output_const_num = 0;
383
 
    opcode_t input_const_num  = 0;
384
 
    int      i, j;
385
 
 
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);
390
 
 
391
 
    if (const_seg == NULL) {
392
 
        Parrot_io_eprintf(interp,
393
 
            "PBC Merge: Error creating constant table segment.");
394
 
        Parrot_exit(interp, 1);
395
 
    }
396
 
 
397
 
    /* Loop over input files. */
398
 
    for (i = 0; i < num_inputs; ++i) {
399
 
 
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);
407
 
        }
408
 
 
409
 
        /* Store cursor as position where constant table starts. */
410
 
        inputs[i]->const_start = cursor;
411
 
        input_const_num = 0;
412
 
 
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);
417
 
 
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);
424
 
 
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:
430
 
                        {
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;
435
 
                        }
436
 
                        break;
437
 
                    default:
438
 
                        break;
439
 
                }
440
 
            }
441
 
 
442
 
            inputs[i]->const_map[input_const_num] = output_const_num;
443
 
            ++input_const_num;
444
 
            ++output_const_num;
445
 
 
446
 
            ++cursor;
447
 
        }
448
 
    }
449
 
 
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;
456
 
}
457
 
 
458
 
 
459
 
/*
460
 
 
461
 
=item C<static void pbc_merge_fixups(PARROT_INTERP, pbc_merge_input **inputs,
462
 
int num_inputs, PackFile *pf)>
463
 
 
464
 
This function merges the fixups tables from the input PBC files.
465
 
 
466
 
=cut
467
 
 
468
 
*/
469
 
 
470
 
static void
471
 
pbc_merge_fixups(PARROT_INTERP, ARGIN(pbc_merge_input **inputs),
472
 
                 int num_inputs, ARGMOD(PackFile *pf))
473
 
{
474
 
    ASSERT_ARGS(pbc_merge_fixups)
475
 
    PackFile_FixupTable  *fixup_seg;
476
 
    PackFile_FixupEntry  *fixups = NULL;
477
 
    opcode_t              cursor = 0;
478
 
    int                   i;
479
 
 
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);
487
 
    }
488
 
 
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;
494
 
 
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);
500
 
        }
501
 
 
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);
506
 
        }
507
 
 
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);
517
 
 
518
 
            /* Copy type and name. */
519
 
            copy->type = cur_entry->type;
520
 
            strcpy(name_copy, cur_entry->name);
521
 
            copy->name = name_copy;
522
 
 
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);
531
 
            }
532
 
 
533
 
            /* Slot it into the list. */
534
 
            fixups[cursor] = *copy;
535
 
            ++cursor;
536
 
        }
537
 
    }
538
 
 
539
 
    /* Stash merged fixup table and count. */
540
 
    fixup_seg->fixups      = fixups;
541
 
    fixup_seg->fixup_count = cursor;
542
 
}
543
 
 
544
 
 
545
 
/*
546
 
 
547
 
=item C<static void pbc_merge_debugs(PARROT_INTERP, pbc_merge_input **inputs,
548
 
int num_inputs, PackFile *pf, PackFile_ByteCode *bc)>
549
 
 
550
 
This function merges the debug segments from the input PBC files.
551
 
 
552
 
=cut
553
 
 
554
 
*/
555
 
 
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))
559
 
{
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);
566
 
 
567
 
    opcode_t num_mappings = 0;
568
 
    opcode_t num_lines    = 0;
569
 
 
570
 
    int i;
571
 
 
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;
578
 
 
579
 
        /* Concatenate line numbers. */
580
 
        lines = mem_gc_realloc_n_typed(interp, lines,
581
 
                num_lines + in_seg->base.size, opcode_t);
582
 
 
583
 
        memcpy(lines + num_lines, in_seg->base.data,
584
 
            in_seg->base.size * sizeof (opcode_t));
585
 
 
586
 
        /* Concatenate mappings. */
587
 
        mappings = mem_gc_realloc_n_typed(interp, mappings,
588
 
                num_mappings + in_seg->num_mappings,
589
 
                PackFile_DebugFilenameMapping);
590
 
 
591
 
        for (j = 0; j < in_seg->num_mappings; ++j) {
592
 
            PackFile_DebugFilenameMapping *mapping = mappings + num_mappings + j;
593
 
 
594
 
            STRUCT_COPY_FROM_STRUCT(mapping, in_seg->mappings[j]);
595
 
            mapping->offset   += num_lines;
596
 
            mapping->filename += inputs[i]->const_start;
597
 
        }
598
 
 
599
 
        num_lines    += in_seg->base.size - 1;
600
 
        num_mappings += in_seg->num_mappings;
601
 
    }
602
 
 
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);
609
 
 
610
 
    debug_seg->mappings     = mappings;
611
 
    debug_seg->num_mappings = num_mappings;
612
 
}
613
 
 
614
 
 
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;
623
 
 
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;
628
 
        }
629
 
    }
630
 
 
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);
636
 
 
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);
643
 
 
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];
648
 
    }
649
 
 
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;
660
 
 
661
 
    /* initialize new op mapping */
662
 
    om->n_ops++;
663
 
 
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;
670
 
        }
671
 
    }
672
 
    PARROT_ASSERT(om->lib_ops[om->n_ops - 1] || !i);
673
 
 
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;
677
 
 
678
 
    return bc->op_count - 1;
679
 
}
680
 
 
681
 
/*
682
 
 
683
 
=item C<static void pbc_fixup_bytecode(PARROT_INTERP, pbc_merge_input **inputs,
684
 
int num_inputs, PackFile_ByteCode *bc)>
685
 
 
686
 
Fixup bytecode. This includes correcting pointers into the constant table
687
 
and updating the ops mapping.
688
 
 
689
 
=cut
690
 
 
691
 
*/
692
 
 
693
 
static void
694
 
pbc_fixup_bytecode(PARROT_INTERP, ARGMOD(pbc_merge_input **inputs),
695
 
                     int num_inputs, ARGMOD(PackFile_ByteCode *bc))
696
 
{
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);
704
 
 
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;
710
 
 
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;
715
 
 
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;
721
 
 
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;
735
 
            }
736
 
 
737
 
            /* Move along the bytecode array. */
738
 
            ++cur_op;
739
 
        }
740
 
 
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;
749
 
 
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;
763
 
                }
764
 
                ++cur_op;
765
 
            }
766
 
        }
767
 
    }
768
 
}
769
 
 
770
 
 
771
 
/*
772
 
 
773
 
=item C<static PackFile* pbc_merge_begin(PARROT_INTERP, pbc_merge_input
774
 
**inputs, int num_inputs)>
775
 
 
776
 
This is the function that drives PBC merging process.
777
 
 
778
 
=cut
779
 
 
780
 
*/
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)
785
 
{
786
 
    ASSERT_ARGS(pbc_merge_begin)
787
 
    PackFile_ByteCode   *bc;
788
 
    PackFile_ConstTable *ct;
789
 
    int                  i;
790
 
 
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);
796
 
    }
797
 
 
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);
808
 
            }
809
 
        }
810
 
    }
811
 
 
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);
816
 
 
817
 
    pbc_merge_fixups(interp, inputs, num_inputs, merged);
818
 
    pbc_merge_debugs(interp, inputs, num_inputs, merged, bc);
819
 
 
820
 
    /* Walk bytecode and fix ops that reference the constants table. */
821
 
    pbc_fixup_bytecode(interp, inputs, num_inputs, bc);
822
 
 
823
 
    for (i = 0; i < num_inputs; ++i) {
824
 
        mem_gc_free(interp, inputs[i]->const_map);
825
 
    }
826
 
 
827
 
    /* Return merged result. */
828
 
    return merged;
829
 
}
830
 
 
831
 
 
832
 
/*
833
 
 
834
 
=item C<static void pbc_merge_write(PARROT_INTERP, PackFile *pf, const char
835
 
*filename)>
836
 
 
837
 
This functions writes out the merged packfile.
838
 
 
839
 
=cut
840
 
 
841
 
*/
842
 
 
843
 
static void
844
 
pbc_merge_write(PARROT_INTERP, ARGMOD(PackFile *pf), ARGIN(const char *filename))
845
 
{
846
 
    ASSERT_ARGS(pbc_merge_write)
847
 
    FILE     *fp;
848
 
 
849
 
    /* Get size of packfile we'll write. */
850
 
    const size_t size = PackFile_pack_size(interp, pf) * sizeof (opcode_t);
851
 
 
852
 
    /* Allocate memory. */
853
 
    opcode_t * const pack = (opcode_t*) Parrot_gc_allocate_memory_chunk(interp, size);
854
 
 
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);
860
 
    }
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);
864
 
    }
865
 
    fclose(fp);
866
 
    mem_gc_free(interp, pack);
867
 
}
868
 
 
869
 
 
870
 
/*
871
 
 
872
 
=item C<int main(int argc, const char **argv)>
873
 
 
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.
877
 
 
878
 
=cut
879
 
 
880
 
*/
881
 
 
882
 
static struct longopt_opt_decl options[] = {
883
 
    { 'o', 'o', OPTION_required_FLAG, { "--output" } }
884
 
};
885
 
 
886
 
int
887
 
main(int argc, const char **argv)
888
 
{
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);
896
 
 
897
 
    Parrot_block_GC_mark(interp);
898
 
 
899
 
    /* Get options, ensuring we have at least one input
900
 
       file and an output file. */
901
 
    if (argc < 4) {
902
 
        help(interp);
903
 
    }
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;
917
 
        }
918
 
    }
919
 
    if (status == -1 || !output_file) {
920
 
        help(interp);
921
 
    }
922
 
    argc -= opt.opt_index;    /* Now the number of input files. */
923
 
    argv += opt.opt_index;    /* Now at first input filename. */
924
 
 
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*);
928
 
 
929
 
    for (i = 0; i < argc; ++i) {
930
 
        /* Allocate a struct. */
931
 
        input_files[i] = mem_gc_allocate_typed(interp, pbc_merge_input);
932
 
 
933
 
        /* Set filename */
934
 
        input_files[i]->filename = *argv;
935
 
 
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);
944
 
        }
945
 
 
946
 
        /* Next file. */
947
 
        ++argv;
948
 
    }
949
 
 
950
 
    /* Merge. */
951
 
    merged = pbc_merge_begin(interp, input_files, argc);
952
 
 
953
 
    /* Write merged packfile. */
954
 
    pbc_merge_write(interp, merged, output_file);
955
 
 
956
 
    /* Finally, we're done. */
957
 
    Parrot_exit(interp, 0);
958
 
}
959
 
 
960
 
 
961
 
/*
962
 
 * Local variables:
963
 
 *   c-file-style: "parrot"
964
 
 * End:
965
 
 * vim: expandtab shiftwidth=4:
966
 
 */