/home/travis/build/MoarVM/MoarVM/src/core/bytecode.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Some constants. */ |
4 | 2.61k | #define HEADER_SIZE 92 |
5 | 2.61k | #define MIN_BYTECODE_VERSION 5 |
6 | 2.61k | #define MAX_BYTECODE_VERSION 5 |
7 | 661k | #define FRAME_HEADER_SIZE (11 * 4 + 3 * 2) |
8 | 288k | #define FRAME_HANDLER_SIZE (4 * 4 + 2 * 2) |
9 | 651k | #define FRAME_SLV_SIZE (2 * 2 + 2 * 4) |
10 | 5.22k | #define SCDEP_HEADER_OFFSET 12 |
11 | 5.22k | #define EXTOP_HEADER_OFFSET 20 |
12 | 5.22k | #define FRAME_HEADER_OFFSET 28 |
13 | 5.22k | #define CALLSITE_HEADER_OFFSET 36 |
14 | 5.22k | #define STRING_HEADER_OFFSET 44 |
15 | 5.22k | #define SCDATA_HEADER_OFFSET 52 |
16 | 5.22k | #define BYTECODE_HEADER_OFFSET 60 |
17 | 5.22k | #define ANNOTATION_HEADER_OFFSET 68 |
18 | 2.61k | #define HLL_NAME_HEADER_OFFSET 76 |
19 | 7.83k | #define SPECIAL_FRAME_HEADER_OFFSET 80 |
20 | | |
21 | | /* Frame flags. */ |
22 | 279k | #define FRAME_FLAG_EXIT_HANDLER 1 |
23 | 279k | #define FRAME_FLAG_IS_THUNK 2 |
24 | | |
25 | | /* Describes the current reader state. */ |
26 | | typedef struct { |
27 | | /* General info. */ |
28 | | MVMuint32 version; |
29 | | |
30 | | /* The string heap. */ |
31 | | MVMuint8 *string_seg; |
32 | | MVMuint32 expected_strings; |
33 | | |
34 | | /* The SC dependencies segment. */ |
35 | | MVMuint32 expected_scs; |
36 | | MVMuint8 *sc_seg; |
37 | | |
38 | | /* The extension ops segment. */ |
39 | | MVMuint8 *extop_seg; |
40 | | MVMuint32 expected_extops; |
41 | | |
42 | | /* The frame segment. */ |
43 | | MVMuint32 expected_frames; |
44 | | MVMuint8 *frame_seg; |
45 | | MVMuint16 *frame_outer_fixups; |
46 | | |
47 | | /* The callsites segment. */ |
48 | | MVMuint8 *callsite_seg; |
49 | | MVMuint32 expected_callsites; |
50 | | |
51 | | /* The bytecode segment. */ |
52 | | MVMuint32 bytecode_size; |
53 | | MVMuint8 *bytecode_seg; |
54 | | |
55 | | /* The annotations segment */ |
56 | | MVMuint8 *annotation_seg; |
57 | | MVMuint32 annotation_size; |
58 | | |
59 | | /* HLL name string index */ |
60 | | MVMuint32 hll_str_idx; |
61 | | |
62 | | /* The limit we can not read beyond. */ |
63 | | MVMuint8 *read_limit; |
64 | | |
65 | | /* Array of frames. */ |
66 | | MVMStaticFrame **frames; |
67 | | |
68 | | /* Special frame indexes */ |
69 | | MVMuint32 main_frame; |
70 | | MVMuint32 load_frame; |
71 | | MVMuint32 deserialize_frame; |
72 | | |
73 | | } ReaderState; |
74 | | |
75 | | /* copies memory dependent on endianness */ |
76 | 6.68M | static void memcpy_endian(void *dest, MVMuint8 *src, size_t size) { |
77 | 6.68M | #ifdef MVM_BIGENDIAN |
78 | | size_t i; |
79 | | MVMuint8 *destbytes = (MVMuint8 *)dest; |
80 | | for (i = 0; i < size; i++) |
81 | | destbytes[size - i - 1] = src[i]; |
82 | | #else |
83 | 6.68M | memcpy(dest, src, size); |
84 | 6.68M | #endif |
85 | 6.68M | } |
86 | | |
87 | | /* Reads a uint32 from a buffer. */ |
88 | 3.65M | static MVMuint32 read_int32(MVMuint8 *buffer, size_t offset) { |
89 | 3.65M | MVMuint32 value; |
90 | 3.65M | memcpy_endian(&value, buffer + offset, 4); |
91 | 3.65M | return value; |
92 | 3.65M | } |
93 | | |
94 | | /* Reads an uint16 from a buffer. */ |
95 | 3.02M | static MVMuint16 read_int16(MVMuint8 *buffer, size_t offset) { |
96 | 3.02M | MVMuint16 value; |
97 | 3.02M | memcpy_endian(&value, buffer + offset, 2); |
98 | 3.02M | return value; |
99 | 3.02M | } |
100 | | |
101 | | /* Reads an uint8 from a buffer. */ |
102 | 227k | static MVMuint8 read_int8(MVMuint8 *buffer, size_t offset) { |
103 | 227k | return buffer[offset]; |
104 | 227k | } |
105 | | |
106 | | /* Cleans up reader state. */ |
107 | 2.61k | static void cleanup_all(MVMThreadContext *tc, ReaderState *rs) { |
108 | 2.61k | MVM_free(rs->frames); |
109 | 2.61k | MVM_free(rs->frame_outer_fixups); |
110 | 2.61k | MVM_free(rs); |
111 | 2.61k | } |
112 | | |
113 | | /* Ensures we can read a certain amount of bytes without overrunning the end |
114 | | * of the stream. */ |
115 | 1.13M | MVM_STATIC_INLINE void ensure_can_read(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs, MVMuint8 *pos, MVMuint32 size) { |
116 | 1.13M | if (pos + size > rs->read_limit) { |
117 | 0 | cleanup_all(tc, rs); |
118 | 0 | MVM_exception_throw_adhoc(tc, "Read past end of bytecode stream"); |
119 | 0 | } |
120 | 1.13M | } |
121 | | |
122 | | /* Reads a string index, looks up the string and returns it. Bounds |
123 | | * checks the string heap index too. */ |
124 | 744k | static MVMString * get_heap_string(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs, MVMuint8 *buffer, size_t offset) { |
125 | 744k | MVMuint32 heap_index = read_int32(buffer, offset); |
126 | 744k | if (heap_index >= cu->body.num_strings) { |
127 | 0 | if (rs) |
128 | 0 | cleanup_all(tc, rs); |
129 | 0 | MVM_exception_throw_adhoc(tc, "String heap index beyond end of string heap"); |
130 | 0 | } |
131 | 744k | return MVM_cu_string(tc, cu, heap_index); |
132 | 744k | } |
133 | | |
134 | | /* Dissects the bytecode stream and hands back a reader pointing to the |
135 | | * various parts of it. */ |
136 | 2.61k | static ReaderState * dissect_bytecode(MVMThreadContext *tc, MVMCompUnit *cu) { |
137 | 2.61k | MVMCompUnitBody *cu_body = &cu->body; |
138 | 2.61k | ReaderState *rs = NULL; |
139 | 2.61k | MVMuint32 version, offset, size; |
140 | 2.61k | |
141 | 2.61k | /* Sanity checks. */ |
142 | 2.61k | if (cu_body->data_size < HEADER_SIZE) |
143 | 0 | MVM_exception_throw_adhoc(tc, "Bytecode stream shorter than header"); |
144 | 2.61k | if (memcmp(cu_body->data_start, "MOARVM\r\n", 8) != 0) |
145 | 0 | MVM_exception_throw_adhoc(tc, "Bytecode stream corrupt (missing magic string)"); |
146 | 2.61k | version = read_int32(cu_body->data_start, 8); |
147 | 2.61k | if (version < MIN_BYTECODE_VERSION) |
148 | 0 | MVM_exception_throw_adhoc(tc, "Bytecode stream version too low"); |
149 | 2.61k | if (version > MAX_BYTECODE_VERSION) |
150 | 0 | MVM_exception_throw_adhoc(tc, "Bytecode stream version too high"); |
151 | 2.61k | |
152 | 2.61k | /* Allocate reader state. */ |
153 | 2.61k | rs = (ReaderState *)MVM_calloc(1, sizeof(ReaderState)); |
154 | 2.61k | rs->version = version; |
155 | 2.61k | rs->read_limit = cu_body->data_start + cu_body->data_size; |
156 | 2.61k | cu->body.bytecode_version = version; |
157 | 2.61k | |
158 | 2.61k | /* Locate SC dependencies segment. */ |
159 | 2.61k | offset = read_int32(cu_body->data_start, SCDEP_HEADER_OFFSET); |
160 | 2.61k | if (offset > cu_body->data_size) { |
161 | 0 | cleanup_all(tc, rs); |
162 | 0 | MVM_exception_throw_adhoc(tc, "Serialization contexts segment starts after end of stream"); |
163 | 0 | } |
164 | 2.61k | rs->sc_seg = cu_body->data_start + offset; |
165 | 2.61k | rs->expected_scs = read_int32(cu_body->data_start, SCDEP_HEADER_OFFSET + 4); |
166 | 2.61k | |
167 | 2.61k | /* Locate extension ops segment. */ |
168 | 2.61k | offset = read_int32(cu_body->data_start, EXTOP_HEADER_OFFSET); |
169 | 2.61k | if (offset > cu_body->data_size) { |
170 | 0 | cleanup_all(tc, rs); |
171 | 0 | MVM_exception_throw_adhoc(tc, "Extension ops segment starts after end of stream"); |
172 | 0 | } |
173 | 2.61k | rs->extop_seg = cu_body->data_start + offset; |
174 | 2.61k | rs->expected_extops = read_int32(cu_body->data_start, EXTOP_HEADER_OFFSET + 4); |
175 | 2.61k | |
176 | 2.61k | /* Locate frames segment. */ |
177 | 2.61k | offset = read_int32(cu_body->data_start, FRAME_HEADER_OFFSET); |
178 | 2.61k | if (offset > cu_body->data_size) { |
179 | 0 | cleanup_all(tc, rs); |
180 | 0 | MVM_exception_throw_adhoc(tc, "Frames segment starts after end of stream"); |
181 | 0 | } |
182 | 2.61k | rs->frame_seg = cu_body->data_start + offset; |
183 | 2.61k | rs->expected_frames = read_int32(cu_body->data_start, FRAME_HEADER_OFFSET + 4); |
184 | 2.61k | |
185 | 2.61k | /* Locate callsites segment. */ |
186 | 2.61k | offset = read_int32(cu_body->data_start, CALLSITE_HEADER_OFFSET); |
187 | 2.61k | if (offset > cu_body->data_size) { |
188 | 0 | cleanup_all(tc, rs); |
189 | 0 | MVM_exception_throw_adhoc(tc, "Callsites segment starts after end of stream"); |
190 | 0 | } |
191 | 2.61k | rs->callsite_seg = cu_body->data_start + offset; |
192 | 2.61k | rs->expected_callsites = read_int32(cu_body->data_start, CALLSITE_HEADER_OFFSET + 4); |
193 | 2.61k | |
194 | 2.61k | /* Locate strings segment. */ |
195 | 2.61k | offset = read_int32(cu_body->data_start, STRING_HEADER_OFFSET); |
196 | 2.61k | if (offset > cu_body->data_size) { |
197 | 0 | cleanup_all(tc, rs); |
198 | 0 | MVM_exception_throw_adhoc(tc, "Strings segment starts after end of stream"); |
199 | 0 | } |
200 | 2.61k | rs->string_seg = cu_body->data_start + offset; |
201 | 2.61k | rs->expected_strings = read_int32(cu_body->data_start, STRING_HEADER_OFFSET + 4); |
202 | 2.61k | |
203 | 2.61k | /* Get SC data, if any. */ |
204 | 2.61k | offset = read_int32(cu_body->data_start, SCDATA_HEADER_OFFSET); |
205 | 2.61k | size = read_int32(cu_body->data_start, SCDATA_HEADER_OFFSET + 4); |
206 | 2.61k | if (offset > cu_body->data_size || offset + size > cu_body->data_size) { |
207 | 0 | cleanup_all(tc, rs); |
208 | 0 | MVM_exception_throw_adhoc(tc, "Serialized data segment overflows end of stream"); |
209 | 0 | } |
210 | 2.61k | if (offset) { |
211 | 1.43k | cu_body->serialized = cu_body->data_start + offset; |
212 | 1.43k | cu_body->serialized_size = size; |
213 | 1.43k | } |
214 | 2.61k | |
215 | 2.61k | /* Locate bytecode segment. */ |
216 | 2.61k | offset = read_int32(cu_body->data_start, BYTECODE_HEADER_OFFSET); |
217 | 2.61k | size = read_int32(cu_body->data_start, BYTECODE_HEADER_OFFSET + 4); |
218 | 2.61k | if (offset > cu_body->data_size || offset + size > cu_body->data_size) { |
219 | 0 | cleanup_all(tc, rs); |
220 | 0 | MVM_exception_throw_adhoc(tc, "Bytecode segment overflows end of stream"); |
221 | 0 | } |
222 | 2.61k | rs->bytecode_seg = cu_body->data_start + offset; |
223 | 2.61k | rs->bytecode_size = size; |
224 | 2.61k | |
225 | 2.61k | /* Locate annotations segment. */ |
226 | 2.61k | offset = read_int32(cu_body->data_start, ANNOTATION_HEADER_OFFSET); |
227 | 2.61k | size = read_int32(cu_body->data_start, ANNOTATION_HEADER_OFFSET + 4); |
228 | 2.61k | if (offset > cu_body->data_size || offset + size > cu_body->data_size) { |
229 | 0 | cleanup_all(tc, rs); |
230 | 0 | MVM_exception_throw_adhoc(tc, "Annotation segment overflows end of stream"); |
231 | 0 | } |
232 | 2.61k | rs->annotation_seg = cu_body->data_start + offset; |
233 | 2.61k | rs->annotation_size = size; |
234 | 2.61k | |
235 | 2.61k | /* Locate HLL name */ |
236 | 2.61k | rs->hll_str_idx = read_int32(cu_body->data_start, HLL_NAME_HEADER_OFFSET); |
237 | 2.61k | |
238 | 2.61k | /* Locate special frame indexes. Note, they are 0 for none, and the |
239 | 2.61k | * index + 1 if there is one. */ |
240 | 2.61k | rs->main_frame = read_int32(cu_body->data_start, SPECIAL_FRAME_HEADER_OFFSET); |
241 | 2.61k | rs->load_frame = read_int32(cu_body->data_start, SPECIAL_FRAME_HEADER_OFFSET + 4); |
242 | 2.61k | rs->deserialize_frame = read_int32(cu_body->data_start, SPECIAL_FRAME_HEADER_OFFSET + 8); |
243 | 2.61k | if (rs->main_frame > rs->expected_frames |
244 | 2.61k | || rs->load_frame > rs->expected_frames |
245 | 2.61k | || rs->deserialize_frame > rs->expected_frames) { |
246 | 0 | MVM_exception_throw_adhoc(tc, "Special frame index out of bounds"); |
247 | 0 | } |
248 | 2.61k | |
249 | 2.61k | return rs; |
250 | 2.61k | } |
251 | | |
252 | | /* Loads the SC dependencies list. */ |
253 | 2.61k | static void deserialize_sc_deps(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { |
254 | 2.61k | MVMCompUnitBody *cu_body = &cu->body; |
255 | 2.61k | MVMuint32 i, sh_idx; |
256 | 2.61k | MVMuint8 *pos; |
257 | 2.61k | |
258 | 2.61k | /* Allocate SC lists in compilation unit. */ |
259 | 2.61k | cu_body->scs = MVM_malloc(rs->expected_scs * sizeof(MVMSerializationContext *)); |
260 | 2.61k | cu_body->scs_to_resolve = MVM_malloc(rs->expected_scs * sizeof(MVMSerializationContextBody *)); |
261 | 2.61k | cu_body->sc_handle_idxs = MVM_malloc(rs->expected_scs * sizeof(MVMint32)); |
262 | 2.61k | cu_body->num_scs = rs->expected_scs; |
263 | 2.61k | |
264 | 2.61k | /* Resolve all the things. */ |
265 | 2.61k | pos = rs->sc_seg; |
266 | 9.73k | for (i = 0; i < rs->expected_scs; i++) { |
267 | 7.11k | MVMSerializationContextBody *scb; |
268 | 7.11k | MVMString *handle; |
269 | 7.11k | |
270 | 7.11k | /* Grab string heap index. */ |
271 | 7.11k | ensure_can_read(tc, cu, rs, pos, 4); |
272 | 7.11k | sh_idx = read_int32(pos, 0); |
273 | 7.11k | pos += 4; |
274 | 7.11k | |
275 | 7.11k | /* Resolve to string. */ |
276 | 7.11k | if (sh_idx >= cu_body->num_strings) { |
277 | 0 | cleanup_all(tc, rs); |
278 | 0 | MVM_exception_throw_adhoc(tc, "String heap index beyond end of string heap"); |
279 | 0 | } |
280 | 7.11k | cu_body->sc_handle_idxs[i] = sh_idx; |
281 | 7.11k | handle = MVM_cu_string(tc, cu, sh_idx); |
282 | 7.11k | |
283 | 7.11k | /* See if we can resolve it. */ |
284 | 7.11k | uv_mutex_lock(&tc->instance->mutex_sc_weakhash); |
285 | 7.11k | MVM_HASH_GET(tc, tc->instance->sc_weakhash, handle, scb); |
286 | 7.11k | if (scb && scb->sc) { |
287 | 3.73k | cu_body->scs_to_resolve[i] = NULL; |
288 | 3.73k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->scs[i], scb->sc); |
289 | 3.73k | scb->claimed = 1; |
290 | 3.73k | } |
291 | 3.38k | else { |
292 | 3.38k | if (!scb) { |
293 | 1.43k | scb = MVM_calloc(1, sizeof(MVMSerializationContextBody)); |
294 | 1.43k | scb->handle = handle; |
295 | 1.43k | MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, scb); |
296 | 1.43k | MVM_sc_add_all_scs_entry(tc, scb); |
297 | 1.43k | } |
298 | 3.38k | cu_body->scs_to_resolve[i] = scb; |
299 | 3.38k | cu_body->scs[i] = NULL; |
300 | 3.38k | } |
301 | 7.11k | uv_mutex_unlock(&tc->instance->mutex_sc_weakhash); |
302 | 7.11k | } |
303 | 2.61k | } |
304 | | |
305 | | /* Loads the extension op records. */ |
306 | 2.61k | static MVMExtOpRecord * deserialize_extop_records(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { |
307 | 2.61k | MVMExtOpRecord *extops; |
308 | 2.61k | MVMuint32 num = rs->expected_extops; |
309 | 2.61k | MVMuint8 *pos; |
310 | 2.61k | MVMuint32 i; |
311 | 2.61k | |
312 | 2.61k | if (num == 0) |
313 | 2.61k | return NULL; |
314 | 2.61k | |
315 | 0 | extops = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, |
316 | 0 | num * sizeof(MVMExtOpRecord)); |
317 | 0 |
|
318 | 0 | pos = rs->extop_seg; |
319 | 0 | for (i = 0; i < num; i++) { |
320 | 0 | MVMuint32 name_idx; |
321 | 0 | MVMuint16 operand_bytes = 0; |
322 | 0 | MVMuint8 *operand_descriptor = extops[i].operand_descriptor; |
323 | 0 |
|
324 | 0 | /* Read name string index. */ |
325 | 0 | ensure_can_read(tc, cu, rs, pos, 4); |
326 | 0 | name_idx = read_int32(pos, 0); |
327 | 0 | pos += 4; |
328 | 0 |
|
329 | 0 | /* Lookup name string. */ |
330 | 0 | if (name_idx >= cu->body.num_strings) { |
331 | 0 | cleanup_all(tc, rs); |
332 | 0 | MVM_exception_throw_adhoc(tc, |
333 | 0 | "String heap index beyond end of string heap"); |
334 | 0 | } |
335 | 0 | extops[i].name = MVM_cu_string(tc, cu, name_idx); |
336 | 0 |
|
337 | 0 | /* Read operand descriptor. */ |
338 | 0 | ensure_can_read(tc, cu, rs, pos, 8); |
339 | 0 | memcpy(operand_descriptor, pos, 8); |
340 | 0 | pos += 8; |
341 | 0 |
|
342 | 0 | /* Validate operand descriptor. |
343 | 0 | * TODO: Unify with validation in MVM_ext_register_extop? */ |
344 | 0 | { |
345 | 0 | MVMuint8 j = 0; |
346 | 0 |
|
347 | 0 | for(; j < 8; j++) { |
348 | 0 | MVMuint8 flags = operand_descriptor[j]; |
349 | 0 |
|
350 | 0 | if (!flags) |
351 | 0 | break; |
352 | 0 |
|
353 | 0 | switch (flags & MVM_operand_rw_mask) { |
354 | 0 | case MVM_operand_literal: |
355 | 0 | goto check_literal; |
356 | 0 |
|
357 | 0 | case MVM_operand_read_reg: |
358 | 0 | case MVM_operand_write_reg: |
359 | 0 | operand_bytes += 2; |
360 | 0 | goto check_reg; |
361 | 0 |
|
362 | 0 | case MVM_operand_read_lex: |
363 | 0 | case MVM_operand_write_lex: |
364 | 0 | operand_bytes += 4; |
365 | 0 | goto check_reg; |
366 | 0 |
|
367 | 0 | default: |
368 | 0 | goto fail; |
369 | 0 | } |
370 | 0 |
|
371 | 0 | check_literal: |
372 | 0 | switch (flags & MVM_operand_type_mask) { |
373 | 0 | case MVM_operand_int8: |
374 | 0 | operand_bytes += 1; |
375 | 0 | continue; |
376 | 0 |
|
377 | 0 | case MVM_operand_int16: |
378 | 0 | operand_bytes += 2; |
379 | 0 | continue; |
380 | 0 |
|
381 | 0 | case MVM_operand_int32: |
382 | 0 | operand_bytes += 4; |
383 | 0 | continue; |
384 | 0 |
|
385 | 0 | case MVM_operand_int64: |
386 | 0 | operand_bytes += 8; |
387 | 0 | continue; |
388 | 0 |
|
389 | 0 | case MVM_operand_num32: |
390 | 0 | operand_bytes += 4; |
391 | 0 | continue; |
392 | 0 |
|
393 | 0 | case MVM_operand_num64: |
394 | 0 | operand_bytes += 8; |
395 | 0 | continue; |
396 | 0 |
|
397 | 0 | case MVM_operand_str: |
398 | 0 | operand_bytes += 2; |
399 | 0 | continue; |
400 | 0 |
|
401 | 0 | case MVM_operand_coderef: |
402 | 0 | operand_bytes += 2; |
403 | 0 | continue; |
404 | 0 |
|
405 | 0 | case MVM_operand_ins: |
406 | 0 | case MVM_operand_callsite: |
407 | 0 | default: |
408 | 0 | goto fail; |
409 | 0 | } |
410 | 0 |
|
411 | 0 | check_reg: |
412 | 0 | switch (flags & MVM_operand_type_mask) { |
413 | 0 | case MVM_operand_int8: |
414 | 0 | case MVM_operand_int16: |
415 | 0 | case MVM_operand_int32: |
416 | 0 | case MVM_operand_int64: |
417 | 0 | case MVM_operand_num32: |
418 | 0 | case MVM_operand_num64: |
419 | 0 | case MVM_operand_str: |
420 | 0 | case MVM_operand_obj: |
421 | 0 | case MVM_operand_type_var: |
422 | 0 | case MVM_operand_uint8: |
423 | 0 | case MVM_operand_uint16: |
424 | 0 | case MVM_operand_uint32: |
425 | 0 | case MVM_operand_uint64: |
426 | 0 | continue; |
427 | 0 |
|
428 | 0 | default: |
429 | 0 | goto fail; |
430 | 0 | } |
431 | 0 |
|
432 | 0 | fail: |
433 | 0 | cleanup_all(tc, rs); |
434 | 0 | MVM_exception_throw_adhoc(tc, "Invalid operand descriptor"); |
435 | 0 | } |
436 | 0 | } |
437 | 0 |
|
438 | 0 | extops[i].operand_bytes = operand_bytes; |
439 | 0 | } |
440 | 0 |
|
441 | 0 | return extops; |
442 | 0 | } |
443 | | |
444 | | /* Loads the static frame information (what locals we have, bytecode offset, |
445 | | * lexicals, etc.) and returns a list of them. */ |
446 | 2.61k | static MVMStaticFrame ** deserialize_frames(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { |
447 | 2.61k | MVMStaticFrame **frames; |
448 | 2.61k | MVMuint8 *pos; |
449 | 2.61k | MVMuint32 bytecode_pos, bytecode_size, i, j; |
450 | 2.61k | |
451 | 2.61k | /* Allocate frames array. */ |
452 | 2.61k | if (rs->expected_frames == 0) { |
453 | 0 | cleanup_all(tc, rs); |
454 | 0 | MVM_exception_throw_adhoc(tc, "Bytecode file must have at least one frame"); |
455 | 0 | } |
456 | 2.61k | frames = MVM_malloc(sizeof(MVMStaticFrame *) * rs->expected_frames); |
457 | 2.61k | |
458 | 2.61k | /* Allocate outer fixup list for frames. */ |
459 | 2.61k | rs->frame_outer_fixups = MVM_malloc(sizeof(MVMuint16) * rs->expected_frames); |
460 | 2.61k | |
461 | 2.61k | /* Load frames. */ |
462 | 2.61k | pos = rs->frame_seg; |
463 | 282k | for (i = 0; i < rs->expected_frames; i++) { |
464 | 279k | MVMStaticFrame *static_frame; |
465 | 279k | MVMStaticFrameBody *static_frame_body; |
466 | 279k | |
467 | 279k | /* Ensure we can read a frame here. */ |
468 | 279k | ensure_can_read(tc, cu, rs, pos, FRAME_HEADER_SIZE); |
469 | 279k | |
470 | 279k | /* Allocate frame and get/check bytecode start/length. */ |
471 | 279k | static_frame = (MVMStaticFrame *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTStaticFrame); |
472 | 279k | MVM_ASSIGN_REF(tc, &(cu->common.header), frames[i], static_frame); |
473 | 279k | static_frame_body = &static_frame->body; |
474 | 279k | bytecode_pos = read_int32(pos, 0); |
475 | 279k | bytecode_size = read_int32(pos, 4); |
476 | 279k | if (bytecode_pos >= rs->bytecode_size) { |
477 | 0 | cleanup_all(tc, rs); |
478 | 0 | MVM_exception_throw_adhoc(tc, "Frame has invalid bytecode start point"); |
479 | 0 | } |
480 | 279k | if (bytecode_pos + bytecode_size > rs->bytecode_size) { |
481 | 0 | cleanup_all(tc, rs); |
482 | 0 | MVM_exception_throw_adhoc(tc, "Frame bytecode overflows bytecode stream"); |
483 | 0 | } |
484 | 279k | static_frame_body->bytecode = rs->bytecode_seg + bytecode_pos; |
485 | 279k | static_frame_body->bytecode_size = bytecode_size; |
486 | 279k | static_frame_body->orig_bytecode = static_frame_body->bytecode; |
487 | 279k | |
488 | 279k | /* Get number of locals and lexicals. */ |
489 | 279k | static_frame_body->num_locals = read_int32(pos, 8); |
490 | 279k | static_frame_body->num_lexicals = read_int32(pos, 12); |
491 | 279k | |
492 | 279k | /* Get compilation unit unique ID and name. */ |
493 | 279k | MVM_ASSIGN_REF(tc, &(static_frame->common.header), static_frame_body->cuuid, get_heap_string(tc, cu, rs, pos, 16)); |
494 | 279k | MVM_ASSIGN_REF(tc, &(static_frame->common.header), static_frame_body->name, get_heap_string(tc, cu, rs, pos, 20)); |
495 | 279k | |
496 | 279k | /* Add frame outer fixup to fixup list. */ |
497 | 279k | rs->frame_outer_fixups[i] = read_int16(pos, 24); |
498 | 279k | |
499 | 279k | /* Get annotations details */ |
500 | 279k | { |
501 | 279k | MVMuint32 annot_offset = read_int32(pos, 26); |
502 | 279k | MVMuint32 num_annotations = read_int32(pos, 30); |
503 | 279k | if (annot_offset + num_annotations * 12 > rs->annotation_size) { |
504 | 0 | cleanup_all(tc, rs); |
505 | 0 | MVM_exception_throw_adhoc(tc, "Frame annotation segment overflows bytecode stream"); |
506 | 0 | } |
507 | 279k | static_frame_body->annotations_data = rs->annotation_seg + annot_offset; |
508 | 279k | static_frame_body->num_annotations = num_annotations; |
509 | 279k | } |
510 | 279k | |
511 | 279k | /* Read number of handlers. */ |
512 | 279k | static_frame_body->num_handlers = read_int32(pos, 34); |
513 | 279k | |
514 | 279k | /* Read exit handler flag (version 2 and higher). */ |
515 | 279k | if (rs->version >= 2) { |
516 | 279k | MVMint16 flags = read_int16(pos, 38); |
517 | 279k | static_frame_body->has_exit_handler = flags & FRAME_FLAG_EXIT_HANDLER; |
518 | 279k | static_frame_body->is_thunk = flags & FRAME_FLAG_IS_THUNK; |
519 | 279k | } |
520 | 279k | |
521 | 279k | /* Read code object SC indexes (version 4 and higher). */ |
522 | 279k | if (rs->version >= 4) { |
523 | 279k | static_frame_body->code_obj_sc_dep_idx = read_int32(pos, 42); |
524 | 279k | static_frame_body->code_obj_sc_idx = read_int32(pos, 46); |
525 | 279k | } |
526 | 279k | |
527 | 279k | /* Associate frame with compilation unit. */ |
528 | 279k | MVM_ASSIGN_REF(tc, &(static_frame->common.header), static_frame_body->cu, cu); |
529 | 279k | |
530 | 279k | /* Stash position for lazy deserialization of the rest. */ |
531 | 279k | static_frame_body->frame_data_pos = pos; |
532 | 279k | |
533 | 279k | /* Skip over the rest, making sure it's readable. */ |
534 | 279k | { |
535 | 279k | MVMuint32 skip = 2 * static_frame_body->num_locals + |
536 | 279k | 6 * static_frame_body->num_lexicals; |
537 | 279k | MVMuint16 slvs = read_int16(pos, 40); |
538 | 279k | pos += FRAME_HEADER_SIZE; |
539 | 279k | ensure_can_read(tc, cu, rs, pos, skip); |
540 | 279k | pos += skip; |
541 | 398k | for (j = 0; j < static_frame_body->num_handlers; j++) { |
542 | 118k | ensure_can_read(tc, cu, rs, pos, FRAME_HANDLER_SIZE); |
543 | 118k | if (read_int32(pos, 8) & MVM_EX_CAT_LABELED) { |
544 | 23 | pos += FRAME_HANDLER_SIZE; |
545 | 23 | ensure_can_read(tc, cu, rs, pos, 2); |
546 | 23 | pos += 2; |
547 | 23 | } |
548 | 118k | else { |
549 | 118k | pos += FRAME_HANDLER_SIZE; |
550 | 118k | } |
551 | 118k | } |
552 | 279k | ensure_can_read(tc, cu, rs, pos, slvs * FRAME_SLV_SIZE); |
553 | 279k | pos += slvs * FRAME_SLV_SIZE; |
554 | 279k | } |
555 | 279k | } |
556 | 2.61k | |
557 | 2.61k | /* Fixup outers. */ |
558 | 282k | for (i = 0; i < rs->expected_frames; i++) { |
559 | 279k | if (rs->frame_outer_fixups[i] != i) { |
560 | 271k | if (rs->frame_outer_fixups[i] < rs->expected_frames) { |
561 | 271k | MVM_ASSIGN_REF(tc, &(frames[i]->common.header), frames[i]->body.outer, frames[rs->frame_outer_fixups[i]]); |
562 | 271k | } |
563 | 0 | else { |
564 | 0 | cleanup_all(tc, rs); |
565 | 0 | MVM_exception_throw_adhoc(tc, "Invalid frame outer index; cannot fixup"); |
566 | 0 | } |
567 | 271k | } |
568 | 279k | } |
569 | 2.61k | |
570 | 2.61k | return frames; |
571 | 2.61k | } |
572 | | |
573 | | /* Finishes up reading and exploding of a frame. */ |
574 | | void MVM_bytecode_finish_frame(MVMThreadContext *tc, MVMCompUnit *cu, |
575 | 102k | MVMStaticFrame *sf, MVMint32 dump_only) { |
576 | 102k | MVMuint32 j; |
577 | 102k | MVMuint8 *pos; |
578 | 102k | MVMuint16 slvs; |
579 | 102k | |
580 | 102k | /* Ensure we've not already done this. */ |
581 | 102k | if (sf->body.fully_deserialized) |
582 | 0 | return; |
583 | 102k | |
584 | 102k | /* Acquire the update mutex on the CompUnit. */ |
585 | 102k | MVM_reentrantmutex_lock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex); |
586 | 102k | |
587 | 102k | /* Ensure no other thread has done this for us in the mean time. */ |
588 | 102k | if (sf->body.fully_deserialized) { |
589 | 0 | MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex); |
590 | 0 | return; |
591 | 0 | } |
592 | 102k | |
593 | 102k | /* Locate start of frame body. */ |
594 | 102k | pos = sf->body.frame_data_pos; |
595 | 102k | |
596 | 102k | /* Get the number of static lex values we'll need to apply. */ |
597 | 102k | slvs = read_int16(pos, 40); |
598 | 102k | |
599 | 102k | /* Skip past header. */ |
600 | 102k | pos += FRAME_HEADER_SIZE; |
601 | 102k | |
602 | 102k | /* Read the local types. */ |
603 | 102k | if (sf->body.num_locals) { |
604 | 102k | sf->body.local_types = MVM_malloc(sizeof(MVMuint16) * sf->body.num_locals); |
605 | 1.75M | for (j = 0; j < sf->body.num_locals; j++) |
606 | 1.65M | sf->body.local_types[j] = read_int16(pos, 2 * j); |
607 | 102k | pos += 2 * sf->body.num_locals; |
608 | 102k | } |
609 | 102k | |
610 | 102k | /* Read the lexical types. */ |
611 | 102k | if (sf->body.num_lexicals) { |
612 | 34.6k | /* Allocate names hash and types list. */ |
613 | 34.6k | sf->body.lexical_types = MVM_malloc(sizeof(MVMuint16) * sf->body.num_lexicals); |
614 | 34.6k | |
615 | 34.6k | /* Read in data. */ |
616 | 34.6k | if (sf->body.num_lexicals) { |
617 | 34.6k | sf->body.lexical_names_list = MVM_malloc(sizeof(MVMLexicalRegistry *) * sf->body.num_lexicals); |
618 | 34.6k | } |
619 | 147k | for (j = 0; j < sf->body.num_lexicals; j++) { |
620 | 112k | MVMString *name = get_heap_string(tc, cu, NULL, pos, 6 * j + 2); |
621 | 112k | MVMLexicalRegistry *entry = MVM_calloc(1, sizeof(MVMLexicalRegistry)); |
622 | 112k | |
623 | 112k | MVM_ASSIGN_REF(tc, &(sf->common.header), entry->key, name); |
624 | 112k | sf->body.lexical_names_list[j] = entry; |
625 | 112k | entry->value = j; |
626 | 112k | |
627 | 112k | sf->body.lexical_types[j] = read_int16(pos, 6 * j); |
628 | 112k | MVM_HASH_BIND(tc, sf->body.lexical_names, name, entry) |
629 | 112k | } |
630 | 34.6k | pos += 6 * sf->body.num_lexicals; |
631 | 34.6k | } |
632 | 102k | |
633 | 102k | /* Read in handlers. */ |
634 | 102k | if (sf->body.num_handlers) { |
635 | 13.1k | /* Allocate space for handler data. */ |
636 | 13.1k | sf->body.handlers = MVM_malloc(sf->body.num_handlers * sizeof(MVMFrameHandler)); |
637 | 13.1k | |
638 | 13.1k | /* Read each handler. */ |
639 | 63.5k | for (j = 0; j < sf->body.num_handlers; j++) { |
640 | 50.3k | sf->body.handlers[j].start_offset = read_int32(pos, 0); |
641 | 50.3k | sf->body.handlers[j].end_offset = read_int32(pos, 4); |
642 | 50.3k | sf->body.handlers[j].category_mask = read_int32(pos, 8); |
643 | 50.3k | sf->body.handlers[j].action = read_int16(pos, 12); |
644 | 50.3k | sf->body.handlers[j].block_reg = read_int16(pos, 14); |
645 | 50.3k | sf->body.handlers[j].goto_offset = read_int32(pos, 16); |
646 | 50.3k | pos += FRAME_HANDLER_SIZE; |
647 | 50.3k | if (sf->body.handlers[j].category_mask & MVM_EX_CAT_LABELED) { |
648 | 23 | sf->body.handlers[j].label_reg = read_int16(pos, 0); |
649 | 23 | pos += 2; |
650 | 23 | } |
651 | 50.3k | sf->body.handlers[j].inlined_and_not_lexical = 0; |
652 | 50.3k | } |
653 | 13.1k | } |
654 | 102k | |
655 | 102k | /* Allocate default lexical environment storage. */ |
656 | 102k | sf->body.env_size = sf->body.num_lexicals * sizeof(MVMRegister); |
657 | 102k | sf->body.static_env = MVM_calloc(1, sf->body.env_size); |
658 | 102k | sf->body.static_env_flags = MVM_calloc(1, sf->body.num_lexicals); |
659 | 102k | |
660 | 102k | /* Stash static lexical segment offset, so we can easily locate it to |
661 | 102k | * resolve them later. */ |
662 | 18.0k | sf->body.frame_static_lex_pos = slvs ? pos : NULL; |
663 | 102k | |
664 | 102k | /* Read in static lexical flags. */ |
665 | 149k | for (j = 0; j < slvs; j++) { |
666 | 46.9k | MVMuint16 lex_idx = read_int16(pos, 0); |
667 | 46.9k | MVMuint16 flags = read_int16(pos, 2); |
668 | 46.9k | |
669 | 46.9k | if (lex_idx >= sf->body.num_lexicals) { |
670 | 0 | MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex); |
671 | 0 | MVM_exception_throw_adhoc(tc, "Lexical index out of bounds: %d > %d", lex_idx, sf->body.num_lexicals); |
672 | 0 | } |
673 | 46.9k | |
674 | 46.9k | sf->body.static_env_flags[lex_idx] = flags; |
675 | 46.9k | if (flags == 2 && !dump_only) { |
676 | 2 | /* State variable; need to resolve wval immediately. Other kinds |
677 | 2 | * can wait. */ |
678 | 2 | MVMSerializationContext *sc = MVM_sc_get_sc(tc, cu, read_int32(pos, 4)); |
679 | 2 | if (sc == NULL) { |
680 | 0 | MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex); |
681 | 0 | MVM_exception_throw_adhoc(tc, "SC not yet resolved; lookup failed"); |
682 | 0 | } |
683 | 2 | MVM_ASSIGN_REF(tc, &(sf->common.header), sf->body.static_env[lex_idx].o, |
684 | 2 | MVM_sc_get_object(tc, sc, read_int32(pos, 8))); |
685 | 2 | } |
686 | 46.9k | pos += FRAME_SLV_SIZE; |
687 | 46.9k | } |
688 | 102k | |
689 | 102k | /* Mark the frame fully deserialized. */ |
690 | 102k | sf->body.fully_deserialized = 1; |
691 | 102k | |
692 | 102k | /* Release the update mutex again */ |
693 | 102k | MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex); |
694 | 102k | } |
695 | | |
696 | | /* Gets the SC reference for a given static lexical var for |
697 | | * vivification purposes */ |
698 | 5.88k | MVMuint8 MVM_bytecode_find_static_lexical_scref(MVMThreadContext *tc, MVMCompUnit *cu, MVMStaticFrame *sf, MVMuint16 index, MVMint32 *sc, MVMint32 *id) { |
699 | 5.88k | MVMuint16 slvs, i; |
700 | 5.88k | |
701 | 5.88k | MVMuint8 *pos = sf->body.frame_static_lex_pos; |
702 | 5.88k | if (!pos) |
703 | 130 | return 0; |
704 | 5.88k | |
705 | 5.75k | slvs = read_int16(sf->body.frame_data_pos, 40); |
706 | 51.6k | for (i = 0; i < slvs; i++) { |
707 | 51.6k | if (read_int16(pos, 0) == index) { |
708 | 5.75k | *sc = read_int32(pos, 4); |
709 | 5.75k | *id = read_int32(pos, 8); |
710 | 5.75k | return 1; |
711 | 5.75k | } |
712 | 45.9k | pos += FRAME_SLV_SIZE; |
713 | 45.9k | } |
714 | 5.75k | |
715 | 0 | return 0; |
716 | 5.75k | } |
717 | | |
718 | | /* Loads the callsites. */ |
719 | 2.61k | static MVMCallsite ** deserialize_callsites(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { |
720 | 2.61k | MVMCallsite **callsites; |
721 | 2.61k | MVMuint8 *pos; |
722 | 2.61k | MVMuint32 i, j, elems; |
723 | 2.61k | MVMCompUnitBody *cu_body = &cu->body; |
724 | 2.61k | |
725 | 2.61k | /* Allocate space for callsites. */ |
726 | 2.61k | if (rs->expected_callsites == 0) |
727 | 78 | return NULL; |
728 | 2.53k | callsites = MVM_fixed_size_alloc(tc, tc->instance->fsa, |
729 | 2.53k | sizeof(MVMCallsite *) * rs->expected_callsites); |
730 | 2.53k | |
731 | 2.53k | /* Load callsites. */ |
732 | 2.53k | pos = rs->callsite_seg; |
733 | 69.6k | for (i = 0; i < rs->expected_callsites; i++) { |
734 | 67.1k | MVMuint8 has_flattening = 0; |
735 | 67.1k | MVMuint32 positionals = 0; |
736 | 67.1k | MVMuint32 nameds_slots = 0; |
737 | 67.1k | MVMuint32 nameds_non_flattening = 0; |
738 | 67.1k | |
739 | 67.1k | /* Ensure we can read at least an element count. */ |
740 | 67.1k | ensure_can_read(tc, cu, rs, pos, 2); |
741 | 67.1k | elems = read_int16(pos, 0); |
742 | 67.1k | pos += 2; |
743 | 67.1k | |
744 | 67.1k | /* Allocate space for the callsite. */ |
745 | 67.1k | callsites[i] = MVM_malloc(sizeof(MVMCallsite)); |
746 | 67.1k | callsites[i]->flag_count = elems; |
747 | 67.1k | if (elems) |
748 | 65.5k | callsites[i]->arg_flags = MVM_malloc(elems * sizeof(MVMCallsiteEntry)); |
749 | 67.1k | else |
750 | 1.57k | callsites[i]->arg_flags = NULL; |
751 | 67.1k | |
752 | 67.1k | /* Ensure we can read in a callsite of this size, and do so. */ |
753 | 67.1k | ensure_can_read(tc, cu, rs, pos, elems); |
754 | 294k | for (j = 0; j < elems; j++) |
755 | 227k | callsites[i]->arg_flags[j] = read_int8(pos, j); |
756 | 67.1k | pos += elems; |
757 | 67.1k | |
758 | 67.1k | /* Add alignment. */ |
759 | 67.1k | pos += elems % 2; |
760 | 67.1k | |
761 | 67.1k | /* Count positional arguments, and validate that all positionals come |
762 | 67.1k | * before all nameds (flattening named counts as named). */ |
763 | 294k | for (j = 0; j < elems; j++) { |
764 | 227k | if (callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_FLAT) { |
765 | 4.68k | if (!(callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_OBJ)) |
766 | 0 | MVM_exception_throw_adhoc(tc, "Flattened positional args must be objects"); |
767 | 4.68k | if (nameds_slots) |
768 | 0 | MVM_exception_throw_adhoc(tc, "Flattened positional args must appear before named args"); |
769 | 4.68k | has_flattening = 1; |
770 | 4.68k | positionals++; |
771 | 4.68k | } |
772 | 222k | else if (callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_FLAT_NAMED) { |
773 | 2.73k | if (!(callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_OBJ)) |
774 | 0 | MVM_exception_throw_adhoc(tc, "Flattened named args must be objects"); |
775 | 2.73k | has_flattening = 1; |
776 | 2.73k | nameds_slots++; |
777 | 2.73k | } |
778 | 219k | else if (callsites[i]->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) { |
779 | 72.5k | nameds_slots += 2; |
780 | 72.5k | nameds_non_flattening++; |
781 | 72.5k | } |
782 | 147k | else if (nameds_slots) { |
783 | 0 | MVM_exception_throw_adhoc(tc, "All positional args must appear before named args"); |
784 | 0 | } |
785 | 147k | else { |
786 | 147k | positionals++; |
787 | 147k | } |
788 | 227k | } |
789 | 67.1k | callsites[i]->num_pos = positionals; |
790 | 67.1k | callsites[i]->arg_count = positionals + nameds_slots; |
791 | 67.1k | callsites[i]->has_flattening = has_flattening; |
792 | 67.1k | callsites[i]->is_interned = 0; |
793 | 67.1k | callsites[i]->with_invocant = NULL; |
794 | 67.1k | |
795 | 67.1k | if (rs->version >= 3 && nameds_non_flattening) { |
796 | 37.6k | ensure_can_read(tc, cu, rs, pos, nameds_non_flattening * 4); |
797 | 37.6k | callsites[i]->arg_names = MVM_malloc(nameds_non_flattening * sizeof(MVMString*)); |
798 | 110k | for (j = 0; j < nameds_non_flattening; j++) { |
799 | 72.5k | callsites[i]->arg_names[j] = get_heap_string(tc, cu, rs, pos, 0); |
800 | 72.5k | pos += 4; |
801 | 72.5k | } |
802 | 29.4k | } else { |
803 | 29.4k | callsites[i]->arg_names = NULL; |
804 | 29.4k | } |
805 | 67.1k | |
806 | 67.1k | /* Track maximum callsite size we've seen. (Used for now, though |
807 | 67.1k | * in the end we probably should calculate it by frame.) */ |
808 | 67.1k | if (callsites[i]->arg_count > cu_body->max_callsite_size) |
809 | 3.99k | cu_body->max_callsite_size = callsites[i]->arg_count; |
810 | 67.1k | |
811 | 67.1k | /* Try to intern the callsite (that is, see if it matches one the |
812 | 67.1k | * VM already knows about). If it does, it will free the memory |
813 | 67.1k | * associated and replace it with the interned one. Otherwise it |
814 | 67.1k | * will store this one, provided it meets the interning rules. */ |
815 | 67.1k | MVM_callsite_try_intern(tc, &(callsites[i])); |
816 | 67.1k | } |
817 | 2.53k | |
818 | 2.53k | /* Add one on to the maximum, to allow space for unshifting an extra |
819 | 2.53k | * arg in the "supply invoked code object" case. */ |
820 | 2.53k | cu_body->max_callsite_size++; |
821 | 2.53k | |
822 | 2.53k | return callsites; |
823 | 2.61k | } |
824 | | |
825 | | /* Creates code objects to go with each of the static frames. */ |
826 | 2.61k | static void create_code_objects(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { |
827 | 2.61k | MVMuint32 i; |
828 | 2.61k | MVMObject *code_type; |
829 | 2.61k | MVMCompUnitBody *cu_body = &cu->body; |
830 | 2.61k | |
831 | 2.61k | cu_body->coderefs = MVM_malloc(cu_body->num_frames * sizeof(MVMObject *)); |
832 | 2.61k | |
833 | 2.61k | code_type = tc->instance->boot_types.BOOTCode; |
834 | 282k | for (i = 0; i < cu_body->num_frames; i++) { |
835 | 279k | MVMCode *coderef = (MVMCode *)REPR(code_type)->allocate(tc, STABLE(code_type)); |
836 | 279k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->coderefs[i], coderef); |
837 | 279k | MVM_ASSIGN_REF(tc, &(coderef->common.header), coderef->body.sf, rs->frames[i]); |
838 | 279k | MVM_ASSIGN_REF(tc, &(coderef->common.header), coderef->body.name, rs->frames[i]->body.name); |
839 | 279k | MVM_ASSIGN_REF(tc, &(rs->frames[i]->common.header), rs->frames[i]->body.static_code, coderef); |
840 | 279k | } |
841 | 2.61k | } |
842 | | |
843 | | /* Takes a compilation unit pointing at a bytecode stream (which actually |
844 | | * has more than just the executive bytecode, but also various declarations, |
845 | | * like frames). Unpacks it and populates the compilation unit. */ |
846 | 2.61k | void MVM_bytecode_unpack(MVMThreadContext *tc, MVMCompUnit *cu) { |
847 | 2.61k | ReaderState *rs; |
848 | 2.61k | MVMCompUnitBody *cu_body = &cu->body; |
849 | 2.61k | /* Allocate directly in generation 2 so the object is not moving around. */ |
850 | 2.61k | MVM_gc_allocate_gen2_default_set(tc); |
851 | 2.61k | |
852 | 2.61k | /* Dissect the bytecode into its parts. */ |
853 | 2.61k | rs = dissect_bytecode(tc, cu); |
854 | 2.61k | |
855 | 2.61k | /* Allocate space for the strings heap; we deserialize it lazily. */ |
856 | 2.61k | cu_body->strings = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, |
857 | 2.61k | rs->expected_strings * sizeof(MVMString *)); |
858 | 2.61k | cu_body->num_strings = rs->expected_strings; |
859 | 2.61k | cu_body->orig_strings = rs->expected_strings; |
860 | 2.61k | cu_body->string_heap_fast_table = MVM_calloc( |
861 | 2.61k | (rs->expected_strings / MVM_STRING_FAST_TABLE_SPAN) + 1, |
862 | 2.61k | sizeof(MVMuint32)); |
863 | 2.61k | cu_body->string_heap_start = rs->string_seg; |
864 | 2.61k | cu_body->string_heap_read_limit = rs->read_limit; |
865 | 2.61k | |
866 | 2.61k | /* Load SC dependencies. */ |
867 | 2.61k | deserialize_sc_deps(tc, cu, rs); |
868 | 2.61k | |
869 | 2.61k | /* Load the extension op records. */ |
870 | 2.61k | cu_body->extops = deserialize_extop_records(tc, cu, rs); |
871 | 2.61k | cu_body->num_extops = rs->expected_extops; |
872 | 2.61k | |
873 | 2.61k | /* Load the static frame info and give each one a code reference. */ |
874 | 2.61k | rs->frames = deserialize_frames(tc, cu, rs); |
875 | 2.61k | cu_body->num_frames = rs->expected_frames; |
876 | 2.61k | cu_body->orig_frames = rs->expected_frames; |
877 | 2.61k | create_code_objects(tc, cu, rs); |
878 | 2.61k | |
879 | 2.61k | /* Load callsites. */ |
880 | 2.61k | cu_body->max_callsite_size = MVM_MIN_CALLSITE_SIZE; |
881 | 2.61k | cu_body->callsites = deserialize_callsites(tc, cu, rs); |
882 | 2.61k | cu_body->num_callsites = rs->expected_callsites; |
883 | 2.61k | cu_body->orig_callsites = rs->expected_callsites; |
884 | 2.61k | |
885 | 2.61k | if (rs->hll_str_idx > rs->expected_strings) |
886 | 0 | MVM_exception_throw_adhoc(tc, "Unpacking bytecode: HLL name string index out of range: %d > %d", rs->hll_str_idx, rs->expected_strings); |
887 | 2.61k | |
888 | 2.61k | /* Resolve HLL name. */ |
889 | 2.61k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->hll_name, |
890 | 2.61k | MVM_cu_string(tc, cu, rs->hll_str_idx)); |
891 | 2.61k | |
892 | 2.61k | /* Resolve special frames. */ |
893 | 2.61k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->main_frame, |
894 | 2.61k | rs->main_frame ? rs->frames[rs->main_frame - 1] : rs->frames[0]); |
895 | 2.61k | if (rs->load_frame) |
896 | 1.56k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->load_frame, rs->frames[rs->load_frame - 1]); |
897 | 2.61k | if (rs->deserialize_frame) |
898 | 2.50k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu_body->deserialize_frame, rs->frames[rs->deserialize_frame - 1]); |
899 | 2.61k | |
900 | 2.61k | /* Clean up reader state. */ |
901 | 2.61k | cleanup_all(tc, rs); |
902 | 2.61k | |
903 | 2.61k | /* Restore normal GC allocation. */ |
904 | 2.61k | MVM_gc_allocate_gen2_default_clear(tc); |
905 | 2.61k | } |
906 | | |
907 | | /* returns the annotation for that bytecode offset */ |
908 | 0 | MVMBytecodeAnnotation * MVM_bytecode_resolve_annotation(MVMThreadContext *tc, MVMStaticFrameBody *sfb, MVMuint32 offset) { |
909 | 0 | MVMBytecodeAnnotation *ba = NULL; |
910 | 0 | MVMuint32 i; |
911 | 0 |
|
912 | 0 | if (sfb->num_annotations && offset < sfb->bytecode_size) { |
913 | 0 | MVMuint8 *cur_anno = sfb->annotations_data; |
914 | 0 | for (i = 0; i < sfb->num_annotations; i++) { |
915 | 0 | MVMint32 ann_offset = read_int32(cur_anno, 0); |
916 | 0 | if (ann_offset > offset) |
917 | 0 | break; |
918 | 0 | cur_anno += 12; |
919 | 0 | } |
920 | 0 | if (i) |
921 | 0 | cur_anno -= 12; |
922 | 0 | ba = MVM_malloc(sizeof(MVMBytecodeAnnotation)); |
923 | 0 | ba->bytecode_offset = read_int32(cur_anno, 0); |
924 | 0 | ba->filename_string_heap_index = read_int32(cur_anno, 4); |
925 | 0 | ba->line_number = read_int32(cur_anno, 8); |
926 | 0 | } |
927 | 0 |
|
928 | 0 | return ba; |
929 | 0 | } |