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