Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/core/compunit.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include "platform/mmap.h"
3
4
#ifdef _WIN32
5
#include <fcntl.h>
6
#define O_RDONLY _O_RDONLY
7
#endif
8
9
/* Creates a compilation unit from a byte array. */
10
2.61k
MVMCompUnit * MVM_cu_from_bytes(MVMThreadContext *tc, MVMuint8 *bytes, MVMuint32 size) {
11
2.61k
    /* Create compilation unit data structure. Allocate it in gen2 always, so
12
2.61k
     * it will never move (the JIT relies on this). */
13
2.61k
    MVMCompUnit *cu;
14
2.61k
    MVM_gc_allocate_gen2_default_set(tc);
15
2.61k
    cu = (MVMCompUnit *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTCompUnit);
16
2.61k
    cu->body.data_start = bytes;
17
2.61k
    cu->body.data_size  = size;
18
2.61k
    MVM_gc_allocate_gen2_default_clear(tc);
19
2.61k
20
2.61k
    /* Process the input. */
21
2.61k
    MVMROOT(tc, cu, {
22
2.61k
        MVM_bytecode_unpack(tc, cu);
23
2.61k
    });
24
2.61k
25
2.61k
    /* Resolve HLL config. It may contain nursery pointers, so fire write
26
2.61k
     * barrier on it. */
27
2.61k
    cu->body.hll_config = MVM_hll_get_config_for(tc, cu->body.hll_name);
28
2.61k
    MVM_gc_write_barrier_hit(tc, (MVMCollectable *)cu);
29
2.61k
30
2.61k
    return cu;
31
2.61k
}
32
33
/* Loads a compilation unit from a bytecode file, mapping it into memory. */
34
1.43k
MVMCompUnit * MVM_cu_map_from_file(MVMThreadContext *tc, const char *filename) {
35
1.43k
    MVMCompUnit *cu          = NULL;
36
1.43k
    void        *block       = NULL;
37
1.43k
    void        *handle      = NULL;
38
1.43k
    uv_file      fd;
39
1.43k
    MVMuint64    size;
40
1.43k
    uv_fs_t req;
41
1.43k
42
1.43k
    /* Ensure the file exists, and get its size. */
43
1.43k
    if (uv_fs_stat(tc->loop, &req, filename, NULL) < 0) {
44
0
        MVM_exception_throw_adhoc(tc, "While looking for '%s': %s", filename, uv_strerror(req.result));
45
0
    }
46
1.43k
47
1.43k
    size = req.statbuf.st_size;
48
1.43k
49
1.43k
    /* Map the bytecode file into memory. */
50
1.43k
    if ((fd = uv_fs_open(tc->loop, &req, filename, O_RDONLY, 0, NULL)) < 0) {
51
0
        MVM_exception_throw_adhoc(tc, "While trying to open '%s': %s", filename, uv_strerror(req.result));
52
0
    }
53
1.43k
54
1.43k
    if ((block = MVM_platform_map_file(fd, &handle, (size_t)size, 0)) == NULL) {
55
0
        /* FIXME: check errno or GetLastError() */
56
0
        MVM_exception_throw_adhoc(tc, "Could not map file '%s' into memory: %s", filename, "FIXME");
57
0
    }
58
1.43k
59
1.43k
    if (uv_fs_close(tc->loop, &req, fd, NULL) < 0) {
60
0
        MVM_exception_throw_adhoc(tc, "Failed to close filehandle: %s", uv_strerror(req.result));
61
0
    }
62
1.43k
63
1.43k
    /* Turn it into a compilation unit. */
64
1.43k
    cu = MVM_cu_from_bytes(tc, (MVMuint8 *)block, (MVMuint32)size);
65
1.43k
    cu->body.handle = handle;
66
1.43k
    cu->body.deallocate = MVM_DEALLOCATE_UNMAP;
67
1.43k
    return cu;
68
1.43k
}
69
70
/* Loads a compilation unit from a bytecode file handle, mapping it into memory. */
71
0
MVMCompUnit * MVM_cu_map_from_file_handle(MVMThreadContext *tc, uv_file fd, MVMuint64 pos) {
72
0
    MVMCompUnit *cu          = NULL;
73
0
    void        *block       = NULL;
74
0
    void        *handle      = NULL;
75
0
    MVMuint64    size;
76
0
    uv_fs_t req;
77
0
78
0
    /* Ensure the file exists, and get its size. */
79
0
    if (uv_fs_fstat(tc->loop, &req, fd, NULL) < 0) {
80
0
        MVM_exception_throw_adhoc(tc, "Trying to stat: %s", uv_strerror(req.result));
81
0
    }
82
0
83
0
    size = req.statbuf.st_size;
84
0
85
0
    if ((block = MVM_platform_map_file(fd, &handle, (size_t)size, 0)) == NULL) {
86
0
        /* FIXME: check errno or GetLastError() */
87
0
        MVM_exception_throw_adhoc(tc, "Could not map file into memory: %s", "FIXME");
88
0
    }
89
0
90
0
    block = ((char*)block) + pos;
91
0
92
0
    /* Turn it into a compilation unit. */
93
0
    cu = MVM_cu_from_bytes(tc, (MVMuint8 *)block, (MVMuint32)size);
94
0
    cu->body.handle = handle;
95
0
    cu->body.deallocate = MVM_DEALLOCATE_UNMAP;
96
0
    return cu;
97
0
}
98
99
/* Adds an extra callsite, needed due to an inlining, and returns its index. */
100
200
MVMuint16 MVM_cu_callsite_add(MVMThreadContext *tc, MVMCompUnit *cu, MVMCallsite *cs) {
101
200
    MVMuint16 found = 0;
102
200
    MVMuint16 idx;
103
200
104
200
    uv_mutex_lock(cu->body.inline_tweak_mutex);
105
200
106
200
    /* See if we already know this callsite. */
107
3.11k
    for (idx = 0; idx < cu->body.num_callsites; idx++)
108
3.09k
        if (cu->body.callsites[idx] == cs) {
109
188
            found = 1;
110
188
            break;
111
188
        }
112
200
    if (!found) {
113
12
        /* Not known; let's add it. */
114
12
        size_t orig_size = cu->body.num_callsites * sizeof(MVMCallsite *);
115
12
        size_t new_size = (cu->body.num_callsites + 1) * sizeof(MVMCallsite *);
116
12
        MVMCallsite **new_callsites = MVM_fixed_size_alloc(tc, tc->instance->fsa, new_size);
117
12
        memcpy(new_callsites, cu->body.callsites, orig_size);
118
12
        idx = cu->body.num_callsites;
119
12
        new_callsites[idx] = MVM_callsite_copy(tc, cs);
120
12
        if (cu->body.callsites)
121
12
            MVM_fixed_size_free_at_safepoint(tc, tc->instance->fsa, orig_size,
122
12
                cu->body.callsites);
123
12
        cu->body.callsites = new_callsites;
124
12
        cu->body.num_callsites++;
125
12
    }
126
200
127
200
    uv_mutex_unlock(cu->body.inline_tweak_mutex);
128
200
129
200
    return idx;
130
200
}
131
132
/* Adds an extra string, needed due to an inlining, and returns its index. */
133
441
MVMuint32 MVM_cu_string_add(MVMThreadContext *tc, MVMCompUnit *cu, MVMString *str) {
134
441
    MVMuint32 found = 0;
135
441
    MVMuint32 idx;
136
441
137
441
    uv_mutex_lock(cu->body.inline_tweak_mutex);
138
441
139
441
    /* See if we already know this string; only consider those added already by
140
441
     * inline, since we don't intern and don't want this to be costly to hunt. */
141
596
    for (idx = cu->body.orig_strings; idx < cu->body.num_strings; idx++)
142
493
        if (MVM_cu_string(tc, cu, idx) == str) {
143
338
            found = 1;
144
338
            break;
145
338
        }
146
441
    if (!found) {
147
103
        /* Not known; let's add it. */
148
103
        size_t orig_size = cu->body.num_strings * sizeof(MVMString *);
149
103
        size_t new_size = (cu->body.num_strings + 1) * sizeof(MVMString *);
150
103
        MVMString **new_strings = MVM_fixed_size_alloc(tc, tc->instance->fsa, new_size);
151
103
        memcpy(new_strings, cu->body.strings, orig_size);
152
103
        idx = cu->body.num_strings;
153
103
        new_strings[idx] = str;
154
103
        if (cu->body.strings)
155
103
            MVM_fixed_size_free_at_safepoint(tc, tc->instance->fsa, orig_size,
156
103
                cu->body.strings);
157
103
        cu->body.strings = new_strings;
158
103
        cu->body.num_strings++;
159
103
    }
160
441
161
441
    uv_mutex_unlock(cu->body.inline_tweak_mutex);
162
441
163
441
    return idx;
164
441
}
165
166
/* Used when we try to read a string from the string heap, but it's not there.
167
 * Decodes it "on-demand" and stores it in the string heap. */
168
9.93M
static MVMuint32 read_uint32(MVMuint8 *src) {
169
9.93M
#ifdef MVM_BIGENDIAN
170
    MVMuint32 value;
171
    size_t i;
172
    MVMuint8 *destbytes = (MVMuint8 *)&value;
173
    for (i = 0; i < 4; i++)
174
         destbytes[4 - i - 1] = src[i];
175
    return value;
176
#else
177
9.93M
    return *((MVMuint32 *)src);
178
9.93M
#endif
179
9.93M
}
180
40.6k
static void compute_fast_table_upto(MVMThreadContext *tc, MVMCompUnit *cu, MVMuint32 end_bin) {
181
40.6k
    MVMuint32  cur_bin = cu->body.string_heap_fast_table_top;
182
40.6k
    MVMuint8  *cur_pos = cu->body.string_heap_start + cu->body.string_heap_fast_table[cur_bin];
183
40.6k
    MVMuint8  *limit   = cu->body.string_heap_read_limit;
184
121k
    while (cur_bin < end_bin) {
185
81.1k
        MVMuint32 i;
186
1.37M
        for (i = 0; i < MVM_STRING_FAST_TABLE_SPAN; i++) {
187
1.29M
            if (cur_pos + 4 < limit) {
188
1.29M
                MVMuint32 bytes = read_uint32(cur_pos) >> 1;
189
1.03M
                cur_pos += 4 + bytes + (bytes & 3 ? 4 - (bytes & 3) : 0);
190
1.29M
            }
191
0
            else {
192
0
                MVM_exception_throw_adhoc(tc,
193
0
                    "Attempt to read past end of string heap when locating string");
194
0
            }
195
1.29M
        }
196
81.1k
        cur_bin++;
197
81.1k
        cu->body.string_heap_fast_table[cur_bin] = (MVMuint32)
198
81.1k
            (cur_pos - cu->body.string_heap_start);
199
81.1k
    }
200
40.6k
    MVM_barrier();
201
40.6k
    cu->body.string_heap_fast_table_top = end_bin;
202
40.6k
}
203
1.02M
MVMString * MVM_cu_obtain_string(MVMThreadContext *tc, MVMCompUnit *cu, MVMuint32 idx) {
204
1.02M
    MVMuint32  cur_idx;
205
1.02M
    MVMuint8  *cur_pos;
206
1.02M
    MVMuint8  *limit = cu->body.string_heap_read_limit;
207
1.02M
208
1.02M
    /* Make sure we've enough entries in the fast table to jump close to where
209
1.02M
     * the string will be. */
210
1.02M
    MVMuint32 fast_bin = idx / MVM_STRING_FAST_TABLE_SPAN;
211
1.02M
    if (fast_bin > cu->body.string_heap_fast_table_top)
212
40.6k
        compute_fast_table_upto(tc, cu, fast_bin);
213
1.02M
214
1.02M
    /* Scan from that position to find the string we need. */
215
1.02M
    cur_idx = fast_bin * MVM_STRING_FAST_TABLE_SPAN;
216
1.02M
    cur_pos = cu->body.string_heap_start + cu->body.string_heap_fast_table[fast_bin];
217
8.64M
    while (cur_idx != idx) {
218
7.61M
        if (cur_pos + 4 < limit) {
219
7.61M
            MVMuint32 bytes = read_uint32(cur_pos) >> 1;
220
6.03M
            cur_pos += 4 + bytes + (bytes & 3 ? 4 - (bytes & 3) : 0);
221
7.61M
        }
222
0
        else {
223
0
            MVM_exception_throw_adhoc(tc,
224
0
                "Attempt to read past end of string heap when locating string");
225
0
        }
226
7.61M
        cur_idx++;
227
7.61M
    }
228
1.02M
229
1.02M
    /* Read the string. */
230
1.02M
    if (cur_pos + 4 < limit) {
231
1.02M
        MVMuint32 ss = read_uint32(cur_pos);
232
1.02M
        MVMuint32 bytes = ss >> 1;
233
1.02M
        MVMuint32 decode_utf8 = ss & 1;
234
1.02M
        cur_pos += 4;
235
1.02M
        if (cur_pos + bytes < limit) {
236
1.02M
            MVMString *s;
237
1.02M
            MVM_gc_allocate_gen2_default_set(tc);
238
1.02M
            s = decode_utf8
239
6.01k
                ? MVM_string_utf8_decode(tc, tc->instance->VMString, (char *)cur_pos, bytes)
240
1.02M
                : MVM_string_latin1_decode(tc, tc->instance->VMString, (char *)cur_pos, bytes);
241
1.02M
            MVM_ASSIGN_REF(tc, &(cu->common.header), cu->body.strings[idx], s);
242
1.02M
            MVM_gc_allocate_gen2_default_clear(tc);
243
1.02M
            return s;
244
1.02M
        }
245
0
        else {
246
0
            MVM_exception_throw_adhoc(tc,
247
0
                "Attempt to read past end of string heap when reading string");
248
0
        }
249
1.02M
    }
250
0
    else {
251
0
        MVM_exception_throw_adhoc(tc,
252
0
            "Attempt to read past end of string heap when reading string length");
253
0
    }
254
1.02M
}