Coverage Report

Created: 2018-07-03 15:31

/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.80k
MVMCompUnit * MVM_cu_from_bytes(MVMThreadContext *tc, MVMuint8 *bytes, MVMuint32 size) {
11
2.80k
    /* Create compilation unit data structure. Allocate it in gen2 always, so
12
2.80k
     * it will never move (the JIT relies on this). */
13
2.80k
    MVMCompUnit *cu;
14
2.80k
    MVM_gc_allocate_gen2_default_set(tc);
15
2.80k
    cu = (MVMCompUnit *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTCompUnit);
16
2.80k
    cu->body.data_start = bytes;
17
2.80k
    cu->body.data_size  = size;
18
2.80k
    MVM_gc_allocate_gen2_default_clear(tc);
19
2.80k
20
2.80k
    /* Process the input. */
21
2.80k
    MVMROOT(tc, cu, {
22
2.80k
        MVM_bytecode_unpack(tc, cu);
23
2.80k
    });
24
2.80k
25
2.80k
    /* Resolve HLL config. It may contain nursery pointers, so fire write
26
2.80k
     * barrier on it. */
27
2.80k
    cu->body.hll_config = MVM_hll_get_config_for(tc, cu->body.hll_name);
28
2.80k
    MVM_gc_write_barrier_hit(tc, (MVMCollectable *)cu);
29
2.80k
30
2.80k
    return cu;
31
2.80k
}
32
33
/* Loads a compilation unit from a bytecode file, mapping it into memory. */
34
1.58k
MVMCompUnit * MVM_cu_map_from_file(MVMThreadContext *tc, const char *filename) {
35
1.58k
    MVMCompUnit *cu          = NULL;
36
1.58k
    void        *block       = NULL;
37
1.58k
    void        *handle      = NULL;
38
1.58k
    uv_file      fd;
39
1.58k
    MVMuint64    size;
40
1.58k
    uv_fs_t req;
41
1.58k
42
1.58k
    /* Ensure the file exists, and get its size. */
43
1.58k
    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.58k
47
1.58k
    size = req.statbuf.st_size;
48
1.58k
49
1.58k
    /* Map the bytecode file into memory. */
50
1.58k
    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.58k
54
1.58k
    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.58k
59
1.58k
    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.58k
63
1.58k
    /* Turn it into a compilation unit. */
64
1.58k
    cu = MVM_cu_from_bytes(tc, (MVMuint8 *)block, (MVMuint32)size);
65
1.58k
    cu->body.handle = handle;
66
1.58k
    cu->body.deallocate = MVM_DEALLOCATE_UNMAP;
67
1.58k
    return cu;
68
1.58k
}
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
837
MVMuint16 MVM_cu_callsite_add(MVMThreadContext *tc, MVMCompUnit *cu, MVMCallsite *cs) {
101
837
    MVMuint16 found = 0;
102
837
    MVMuint16 idx;
103
837
104
837
    uv_mutex_lock(cu->body.inline_tweak_mutex);
105
837
106
837
    /* See if we already know this callsite. */
107
5.84k
    for (idx = 0; idx < cu->body.num_callsites; idx++)
108
5.79k
        if (cu->body.callsites[idx] == cs) {
109
787
            found = 1;
110
787
            break;
111
787
        }
112
837
    if (!found) {
113
50
        /* Not known; let's add it. */
114
50
        size_t orig_size = cu->body.num_callsites * sizeof(MVMCallsite *);
115
50
        size_t new_size = (cu->body.num_callsites + 1) * sizeof(MVMCallsite *);
116
50
        MVMCallsite **new_callsites = MVM_fixed_size_alloc(tc, tc->instance->fsa, new_size);
117
50
        memcpy(new_callsites, cu->body.callsites, orig_size);
118
50
        idx = cu->body.num_callsites;
119
50
        new_callsites[idx] = MVM_callsite_copy(tc, cs);
120
50
        if (cu->body.callsites)
121
50
            MVM_fixed_size_free_at_safepoint(tc, tc->instance->fsa, orig_size,
122
50
                cu->body.callsites);
123
50
        cu->body.callsites = new_callsites;
124
50
        cu->body.num_callsites++;
125
50
    }
126
837
127
837
    uv_mutex_unlock(cu->body.inline_tweak_mutex);
128
837
129
837
    return idx;
130
837
}
131
132
/* Adds an extra string, needed due to an inlining, and returns its index. */
133
304
MVMuint32 MVM_cu_string_add(MVMThreadContext *tc, MVMCompUnit *cu, MVMString *str) {
134
304
    MVMuint32 found = 0;
135
304
    MVMuint32 idx;
136
304
137
304
    uv_mutex_lock(cu->body.inline_tweak_mutex);
138
304
139
304
    /* See if we already know this string; only consider those added already by
140
304
     * inline, since we don't intern and don't want this to be costly to hunt. */
141
504
    for (idx = cu->body.orig_strings; idx < cu->body.num_strings; idx++)
142
314
        if (MVM_cu_string(tc, cu, idx) == str) {
143
114
            found = 1;
144
114
            break;
145
114
        }
146
304
    if (!found) {
147
190
        /* Not known; let's add it. */
148
190
        size_t orig_size = cu->body.num_strings * sizeof(MVMString *);
149
190
        size_t new_size = (cu->body.num_strings + 1) * sizeof(MVMString *);
150
190
        MVMString **new_strings = MVM_fixed_size_alloc(tc, tc->instance->fsa, new_size);
151
190
        memcpy(new_strings, cu->body.strings, orig_size);
152
190
        idx = cu->body.num_strings;
153
190
        new_strings[idx] = str;
154
190
        if (cu->body.strings)
155
190
            MVM_fixed_size_free_at_safepoint(tc, tc->instance->fsa, orig_size,
156
190
                cu->body.strings);
157
190
        cu->body.strings = new_strings;
158
190
        cu->body.num_strings++;
159
190
    }
160
304
161
304
    uv_mutex_unlock(cu->body.inline_tweak_mutex);
162
304
163
304
    return idx;
164
304
}
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
11.4M
static MVMuint32 read_uint32(MVMuint8 *src) {
169
11.4M
#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
11.4M
    return *((MVMuint32 *)src);
178
11.4M
#endif
179
11.4M
}
180
46.9k
static void compute_fast_table_upto(MVMThreadContext *tc, MVMCompUnit *cu, MVMuint32 end_bin) {
181
46.9k
    MVMuint32  cur_bin = cu->body.string_heap_fast_table_top;
182
46.9k
    MVMuint8  *cur_pos = cu->body.string_heap_start + cu->body.string_heap_fast_table[cur_bin];
183
46.9k
    MVMuint8  *limit   = cu->body.string_heap_read_limit;
184
140k
    while (cur_bin < end_bin) {
185
93.1k
        MVMuint32 i;
186
1.58M
        for (i = 0; i < MVM_STRING_FAST_TABLE_SPAN; i++) {
187
1.49M
            if (cur_pos + 4 < limit) {
188
1.49M
                MVMuint32 bytes = read_uint32(cur_pos) >> 1;
189
1.20M
                cur_pos += 4 + bytes + (bytes & 3 ? 4 - (bytes & 3) : 0);
190
1.49M
            }
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.49M
        }
196
93.1k
        cur_bin++;
197
93.1k
        cu->body.string_heap_fast_table[cur_bin] = (MVMuint32)
198
93.1k
            (cur_pos - cu->body.string_heap_start);
199
93.1k
    }
200
46.9k
    MVM_barrier();
201
46.9k
    cu->body.string_heap_fast_table_top = end_bin;
202
46.9k
}
203
1.18M
MVMString * MVM_cu_obtain_string(MVMThreadContext *tc, MVMCompUnit *cu, MVMuint32 idx) {
204
1.18M
    MVMuint32  cur_idx;
205
1.18M
    MVMuint8  *cur_pos;
206
1.18M
    MVMuint8  *limit = cu->body.string_heap_read_limit;
207
1.18M
208
1.18M
    /* Make sure we've enough entries in the fast table to jump close to where
209
1.18M
     * the string will be. */
210
1.18M
    MVMuint32 fast_bin = idx / MVM_STRING_FAST_TABLE_SPAN;
211
1.18M
    if (fast_bin > cu->body.string_heap_fast_table_top)
212
46.9k
        compute_fast_table_upto(tc, cu, fast_bin);
213
1.18M
214
1.18M
    /* Scan from that position to find the string we need. */
215
1.18M
    cur_idx = fast_bin * MVM_STRING_FAST_TABLE_SPAN;
216
1.18M
    cur_pos = cu->body.string_heap_start + cu->body.string_heap_fast_table[fast_bin];
217
10.0M
    while (cur_idx != idx) {
218
8.82M
        if (cur_pos + 4 < limit) {
219
8.82M
            MVMuint32 bytes = read_uint32(cur_pos) >> 1;
220
7.10M
            cur_pos += 4 + bytes + (bytes & 3 ? 4 - (bytes & 3) : 0);
221
8.82M
        }
222
18.4E
        else {
223
18.4E
            MVM_exception_throw_adhoc(tc,
224
18.4E
                "Attempt to read past end of string heap when locating string");
225
18.4E
        }
226
8.82M
        cur_idx++;
227
8.82M
    }
228
1.18M
229
1.18M
    /* Read the string. */
230
1.18M
    if (cur_pos + 4 < limit) {
231
1.18M
        MVMuint32 ss = read_uint32(cur_pos);
232
1.18M
        MVMuint32 bytes = ss >> 1;
233
1.18M
        MVMuint32 decode_utf8 = ss & 1;
234
1.18M
        cur_pos += 4;
235
1.18M
        if (cur_pos + bytes < limit) {
236
1.18M
            MVMString *s;
237
1.18M
            MVM_gc_allocate_gen2_default_set(tc);
238
1.18M
            s = decode_utf8
239
6.74k
                ? MVM_string_utf8_decode(tc, tc->instance->VMString, (char *)cur_pos, bytes)
240
1.17M
                : MVM_string_latin1_decode(tc, tc->instance->VMString, (char *)cur_pos, bytes);
241
1.18M
            MVM_ASSIGN_REF(tc, &(cu->common.header), cu->body.strings[idx], s);
242
1.18M
            MVM_gc_allocate_gen2_default_clear(tc);
243
1.18M
            return s;
244
1.18M
        }
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.18M
    }
250
18.4E
    else {
251
18.4E
        MVM_exception_throw_adhoc(tc,
252
18.4E
            "Attempt to read past end of string heap when reading string length");
253
18.4E
    }
254
1.18M
}