Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/core/frame.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* This allows the dynlex cache to be disabled when bug hunting, if needed. */
4
#define MVM_DYNLEX_CACHE_ENABLED 1
5
6
/* Computes the initial work area for a frame or a specialization of a frame. */
7
MVMRegister * MVM_frame_initial_work(MVMThreadContext *tc, MVMuint16 *local_types,
8
102k
                                     MVMuint16 num_locals) {
9
102k
    MVMuint16 i;
10
102k
    MVMRegister *work_initial = MVM_calloc(num_locals, sizeof(MVMRegister));
11
1.75M
    for (i = 0; i < num_locals; i++)
12
1.65M
        if (local_types[i] == MVM_reg_obj)
13
1.19M
            work_initial[i].o = tc->instance->VMNull;
14
102k
    return work_initial;
15
102k
}
16
17
/* Takes a static frame and does various one-off calculations about what
18
 * space it shall need. Also triggers bytecode verification of the frame's
19
 * bytecode. */
20
102k
static void prepare_and_verify_static_frame(MVMThreadContext *tc, MVMStaticFrame *static_frame) {
21
102k
    MVMStaticFrameBody *static_frame_body = &static_frame->body;
22
102k
    MVMCompUnit        *cu                = static_frame_body->cu;
23
102k
24
102k
    /* Ensure the frame is fully deserialized. */
25
102k
    if (!static_frame_body->fully_deserialized)
26
102k
        MVM_bytecode_finish_frame(tc, cu, static_frame, 0);
27
102k
28
102k
    /* Take compilation unit lock, to make sure we don't race to do the
29
102k
     * frame preparation/verification work. */
30
102k
    MVM_reentrantmutex_lock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
31
102k
    if (static_frame->body.instrumentation_level == 0) {
32
102k
        /* Work size is number of locals/registers plus size of the maximum
33
102k
        * call site argument list. */
34
102k
        static_frame_body->work_size = sizeof(MVMRegister) *
35
102k
            (static_frame_body->num_locals + static_frame_body->cu->body.max_callsite_size);
36
102k
37
102k
        /* Validate the bytecode. */
38
102k
        MVM_validate_static_frame(tc, static_frame);
39
102k
40
102k
        /* Obtain an index to each threadcontext's lexotic pool table */
41
102k
        static_frame_body->pool_index = MVM_incr(&tc->instance->num_frames_run);
42
102k
43
102k
        /* Compute work area initial state that we can memcpy into place each
44
102k
         * time. */
45
102k
        if (static_frame_body->num_locals)
46
102k
            static_frame_body->work_initial = MVM_frame_initial_work(tc,
47
102k
                static_frame_body->local_types,
48
102k
                static_frame_body->num_locals);
49
102k
50
102k
        /* Check if we have any state var lexicals. */
51
102k
        if (static_frame_body->static_env_flags) {
52
102k
            MVMuint8 *flags  = static_frame_body->static_env_flags;
53
102k
            MVMint64  numlex = static_frame_body->num_lexicals;
54
102k
            MVMint64  i;
55
214k
            for (i = 0; i < numlex; i++)
56
112k
                if (flags[i] == 2) {
57
2
                    static_frame_body->has_state_vars = 1;
58
2
                    break;
59
2
                }
60
102k
        }
61
102k
62
102k
        /* Set its spesh threshold. */
63
102k
        static_frame_body->spesh_threshold = MVM_spesh_threshold(tc, static_frame);
64
102k
    }
65
102k
66
102k
    /* Unlock, now we're finished. */
67
102k
    MVM_reentrantmutex_unlock(tc, (MVMReentrantMutex *)cu->body.deserialize_frame_mutex);
68
102k
}
69
70
/* When we don't match the current instrumentation level, we hit this. It may
71
 * simply be that we never invoked the frame, in which case we prepare and
72
 * verify it. It may also be because we need to instrument the code for
73
 * profiling. */
74
102k
static void instrumentation_level_barrier(MVMThreadContext *tc, MVMStaticFrame *static_frame) {
75
102k
    /* Prepare and verify if needed. */
76
102k
    if (static_frame->body.instrumentation_level == 0)
77
102k
        prepare_and_verify_static_frame(tc, static_frame);
78
102k
79
102k
    /* Mark frame as being at the current instrumentation level. */
80
102k
    static_frame->body.instrumentation_level = tc->instance->instrumentation_level;
81
102k
82
102k
    /* Add profiling instrumentation if needed. */
83
102k
    if (tc->instance->profiling)
84
0
        MVM_profile_instrument(tc, static_frame);
85
102k
    else if (tc->instance->cross_thread_write_logging)
86
0
        MVM_cross_thread_write_instrument(tc, static_frame);
87
102k
    else if (tc->instance->coverage_logging)
88
0
        MVM_line_coverage_instrument(tc, static_frame);
89
102k
    else
90
102k
        MVM_profile_ensure_uninstrumented(tc, static_frame);
91
102k
}
92
93
/* Called when the GC destroys a frame. Since the frame may have been alive as
94
 * part of a continuation that was taken but never invoked, we should check
95
 * things normally cleaned up on return don't need cleaning up also. */
96
552k
void MVM_frame_destroy(MVMThreadContext *tc, MVMFrame *frame) {
97
552k
    if (frame->work) {
98
0
        MVM_args_proc_cleanup(tc, &frame->params);
99
0
        MVM_fixed_size_free(tc, tc->instance->fsa, frame->allocd_work,
100
0
            frame->work);
101
0
    }
102
552k
    if (frame->env)
103
240k
        MVM_fixed_size_free(tc, tc->instance->fsa, frame->allocd_env, frame->env);
104
552k
    if (frame->continuation_tags)
105
0
        MVM_continuation_free_tags(tc, frame);
106
552k
}
107
108
/* Creates a frame for usage as a context only, possibly forcing all of the
109
 * static lexicals to be deserialized if it's used for auto-close purposes. */
110
static MVMFrame * create_context_only(MVMThreadContext *tc, MVMStaticFrame *static_frame,
111
1.31k
        MVMObject *code_ref, MVMint32 autoclose) {
112
1.31k
    MVMFrame *frame;
113
1.31k
114
1.31k
    MVMROOT(tc, static_frame, {
115
1.31k
    MVMROOT(tc, code_ref, {
116
1.31k
        /* If the frame was never invoked before, need initial calculations
117
1.31k
         * and verification. */
118
1.31k
         if (static_frame->body.instrumentation_level == 0)
119
1.31k
             instrumentation_level_barrier(tc, static_frame);
120
1.31k
121
1.31k
        frame = MVM_gc_allocate_frame(tc);
122
1.31k
    });
123
1.31k
    });
124
1.31k
125
1.31k
    /* Set static frame, code ref, and handlers. */
126
1.31k
    MVM_ASSIGN_REF(tc, &(frame->header), frame->static_info, static_frame);
127
1.31k
    MVM_ASSIGN_REF(tc, &(frame->header), frame->code_ref, code_ref);
128
1.31k
    frame->effective_handlers = static_frame->body.handlers;
129
1.31k
130
1.31k
    /* Allocate space for lexicals, copying the default lexical environment
131
1.31k
     * into place and, if we're auto-closing, making sure anything we'd clone
132
1.31k
     * is vivified to prevent the clone (which is what creates the correct
133
1.31k
     * BEGIN/INIT semantics). */
134
1.31k
    if (static_frame->body.env_size) {
135
1.31k
        frame->env = MVM_fixed_size_alloc(tc, tc->instance->fsa, static_frame->body.env_size);
136
1.31k
        frame->allocd_env = static_frame->body.env_size;
137
1.31k
        if (autoclose) {
138
5
            MVMuint16 i, num_lexicals = static_frame->body.num_lexicals;
139
5
140
5
            MVM_gc_root_temp_push(tc, (MVMCollectable **)&static_frame);
141
5
142
102
            for (i = 0; i < num_lexicals; i++) {
143
97
                if (!static_frame->body.static_env[i].o && static_frame->body.static_env_flags[i] == 1) {
144
0
                    MVMint32 scid, objid;
145
0
                    if (MVM_bytecode_find_static_lexical_scref(tc, static_frame->body.cu,
146
0
                            static_frame, i, &scid, &objid)) {
147
0
                        MVMObject *resolved;
148
0
                        MVMSerializationContext *sc = MVM_sc_get_sc(tc, static_frame->body.cu, scid);
149
0
150
0
                        if (sc == NULL)
151
0
                            MVM_exception_throw_adhoc(tc,
152
0
                                "SC not yet resolved; lookup failed");
153
0
154
0
                        resolved = MVM_sc_get_object(tc, sc, objid);
155
0
156
0
                        MVM_ASSIGN_REF(tc, &(static_frame->common.header),
157
0
                            static_frame->body.static_env[i].o,
158
0
                            resolved);
159
0
                    }
160
0
                }
161
97
            }
162
5
            MVM_gc_root_temp_pop(tc);
163
5
        }
164
1.31k
        memcpy(frame->env, static_frame->body.static_env, static_frame->body.env_size);
165
1.31k
    }
166
1.31k
167
1.31k
    return frame;
168
1.31k
}
169
170
/* Creates a frame that is suitable for deserializing a context into. Starts
171
 * with a ref count of 1 due to being held by an SC. */
172
MVMFrame * MVM_frame_create_context_only(MVMThreadContext *tc, MVMStaticFrame *static_frame,
173
1.31k
        MVMObject *code_ref) {
174
1.31k
    return create_context_only(tc, static_frame, code_ref, 0);
175
1.31k
}
176
177
/* Provides auto-close functionality, for the handful of cases where we have
178
 * not ever been in the outer frame of something we're invoking. In this case,
179
 * we fake up a frame based on the static lexical environment. */
180
26
static MVMFrame * autoclose(MVMThreadContext *tc, MVMStaticFrame *needed) {
181
26
    MVMFrame *result;
182
26
183
26
    /* First, see if we can find one on the call stack; return it if so. */
184
26
    MVMFrame *candidate = tc->cur_frame;
185
86
    while (candidate) {
186
81
        if (candidate->static_info->body.bytecode == needed->body.bytecode)
187
21
            return candidate;
188
60
        candidate = candidate->caller;
189
60
    }
190
26
191
26
    /* If not, fake up a frame See if it also needs an outer. */
192
5
    MVMROOT(tc, needed, {
193
5
        result = create_context_only(tc, needed, (MVMObject *)needed->body.static_code, 1);
194
5
    });
195
5
    if (needed->body.outer) {
196
4
        /* See if the static code object has an outer. */
197
4
        MVMCode *outer_code = needed->body.outer->body.static_code;
198
4
        if (outer_code->body.outer &&
199
3
                outer_code->body.outer->static_info->body.bytecode == needed->body.bytecode) {
200
0
            /* Yes, just take it. */
201
0
            MVM_ASSIGN_REF(tc, &(result->header), result->outer, outer_code->body.outer);
202
0
        }
203
4
        else {
204
4
            /* Otherwise, recursively auto-close. */
205
4
            MVMROOT(tc, result, {
206
4
                MVMFrame *ac = autoclose(tc, needed->body.outer);
207
4
                MVM_ASSIGN_REF(tc, &(result->header), result->outer, ac);
208
4
            });
209
4
        }
210
4
    }
211
5
    return result;
212
26
}
213
214
/* Obtains memory for a frame on the thread-local call stack. */
215
static MVMFrame * allocate_frame(MVMThreadContext *tc, MVMStaticFrame *static_frame,
216
12.4M
                                 MVMSpeshCandidate *spesh_cand) {
217
12.4M
    MVMFrame *frame;
218
12.4M
    MVMint32  env_size, work_size;
219
12.4M
    MVMStaticFrameBody *static_frame_body;
220
12.4M
221
12.4M
    /* Allocate the frame. */
222
12.4M
    MVMCallStackRegion *stack = tc->stack_current;
223
12.4M
    if (stack->alloc + sizeof(MVMFrame) >= stack->alloc_limit)
224
0
        stack = MVM_callstack_region_next(tc);
225
12.4M
    frame = (MVMFrame *)stack->alloc;
226
12.4M
    stack->alloc += sizeof(MVMFrame);
227
12.4M
    memset(frame, 0, sizeof(MVMFrame));
228
12.4M
229
12.4M
    /* Allocate space for lexicals and work area. */
230
12.4M
    static_frame_body = &(static_frame->body);
231
8.62M
    env_size = spesh_cand ? spesh_cand->env_size : static_frame_body->env_size;
232
12.4M
    if (env_size) {
233
953k
        frame->env = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, env_size);
234
953k
        frame->allocd_env = env_size;
235
953k
    }
236
8.62M
    work_size = spesh_cand ? spesh_cand->work_size : static_frame_body->work_size;
237
12.4M
    if (work_size) {
238
12.4M
        if (spesh_cand) {
239
8.62M
            /* Allocate zeroed memory. Spesh makes sure we have VMNull setup in
240
8.62M
             * the places we need it. */
241
8.62M
            frame->work = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, work_size);
242
8.62M
        }
243
3.84M
        else {
244
3.84M
            /* Copy frame template with VMNulls in to place. */
245
3.84M
            frame->work = MVM_fixed_size_alloc(tc, tc->instance->fsa, work_size);
246
3.84M
            memcpy(frame->work, static_frame_body->work_initial,
247
3.84M
                sizeof(MVMRegister) * static_frame_body->num_locals);
248
3.84M
        }
249
12.4M
        frame->allocd_work = work_size;
250
12.4M
251
12.4M
        /* Calculate args buffer position. */
252
12.4M
        frame->args = frame->work + (spesh_cand
253
8.62M
            ? spesh_cand->num_locals
254
3.84M
            : static_frame_body->num_locals);
255
12.4M
    }
256
12.4M
257
12.4M
    /* Assign a sequence nr */
258
12.4M
    frame->sequence_nr = tc->next_frame_nr++;
259
12.4M
260
12.4M
    return frame;
261
12.4M
}
262
263
/* Obtains memory for a frame on the heap. */
264
static MVMFrame * allocate_heap_frame(MVMThreadContext *tc, MVMStaticFrame *static_frame,
265
1.66k
                                      MVMSpeshCandidate *spesh_cand) {
266
1.66k
    MVMFrame *frame;
267
1.66k
    MVMint32  env_size, work_size;
268
1.66k
    MVMStaticFrameBody *static_frame_body;
269
1.66k
270
1.66k
    /* Allocate the frame. */
271
1.66k
    MVMROOT(tc, static_frame, {
272
1.66k
        frame = MVM_gc_allocate_frame(tc);
273
1.66k
    });
274
1.66k
275
1.66k
    /* Allocate space for lexicals and work area. */
276
1.66k
    static_frame_body = &(static_frame->body);
277
1.66k
    env_size = spesh_cand ? spesh_cand->env_size : static_frame_body->env_size;
278
1.66k
    if (env_size) {
279
0
        frame->env = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, env_size);
280
0
        frame->allocd_env = env_size;
281
0
    }
282
1.66k
    work_size = spesh_cand ? spesh_cand->work_size : static_frame_body->work_size;
283
1.66k
    if (work_size) {
284
1.66k
        /* Fill up all object registers with a pointer to our VMNull object */
285
1.66k
        if (spesh_cand && spesh_cand->local_types) {
286
0
            MVMuint32 num_locals = spesh_cand->num_locals;
287
0
            MVMuint16 *local_types = spesh_cand->local_types;
288
0
            MVMuint32 i;
289
0
            frame->work = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, work_size);
290
0
            for (i = 0; i < num_locals; i++)
291
0
                if (local_types[i] == MVM_reg_obj)
292
0
                    frame->work[i].o = tc->instance->VMNull;
293
0
        }
294
1.66k
        else {
295
1.66k
            frame->work = MVM_fixed_size_alloc(tc, tc->instance->fsa, work_size);
296
1.66k
            memcpy(frame->work, static_frame_body->work_initial,
297
1.66k
                sizeof(MVMRegister) * static_frame_body->num_locals);
298
1.66k
        }
299
1.66k
        frame->allocd_work = work_size;
300
1.66k
301
1.66k
        /* Calculate args buffer position. */
302
1.66k
        frame->args = frame->work + (spesh_cand
303
0
            ? spesh_cand->num_locals
304
1.66k
            : static_frame_body->num_locals);
305
1.66k
    }
306
1.66k
307
1.66k
    return frame;
308
1.66k
}
309
310
/* This exists to reduce the amount of pointer-fiddling that has to be
311
 * done by the JIT */
312
void MVM_frame_invoke_code(MVMThreadContext *tc, MVMCode *code,
313
983k
                           MVMCallsite *callsite, MVMint32 spesh_cand) {
314
983k
    MVM_frame_invoke(tc, code->body.sf, callsite,  tc->cur_frame->args,
315
983k
        code->body.outer, (MVMObject*)code, spesh_cand);
316
983k
}
317
318
/* Takes a static frame and a thread context. Invokes the static frame. */
319
void MVM_frame_invoke(MVMThreadContext *tc, MVMStaticFrame *static_frame,
320
                      MVMCallsite *callsite, MVMRegister *args,
321
12.4M
                      MVMFrame *outer, MVMObject *code_ref, MVMint32 spesh_cand) {
322
12.4M
    MVMFrame *frame;
323
12.4M
    MVMuint32 found_spesh;
324
12.4M
325
12.4M
    /* If the frame was never invoked before, or never before at the current
326
12.4M
     * instrumentation level, we need to trigger the instrumentation level
327
12.4M
     * barrier. */
328
12.4M
    if (static_frame->body.instrumentation_level != tc->instance->instrumentation_level) {
329
102k
        MVMROOT(tc, static_frame, {
330
102k
        MVMROOT(tc, code_ref, {
331
102k
        MVMROOT(tc, outer, {
332
102k
            instrumentation_level_barrier(tc, static_frame);
333
102k
        });
334
102k
        });
335
102k
        });
336
102k
    }
337
12.4M
338
12.4M
    /* Ensure we have an outer if needed. This is done ahead of allocating the
339
12.4M
     * new frame, since an autoclose will force the callstack on to the heap. */
340
12.4M
    if (outer) {
341
12.4M
        /* We were provided with an outer frame and it will already have had
342
12.4M
         * its reference count incremented; just ensure that it is based on the
343
12.4M
         * correct static frame (compare on bytecode address to cope with
344
12.4M
         * nqp::freshcoderef). */
345
12.4M
        if (outer->static_info->body.orig_bytecode != static_frame->body.outer->body.orig_bytecode) {
346
0
            char *frame_cuuid = MVM_string_utf8_encode_C_string(tc, static_frame->body.cuuid);
347
0
            char *frame_name;
348
0
            char *outer_cuuid = MVM_string_utf8_encode_C_string(tc, outer->static_info->body.cuuid);
349
0
            char *outer_name;
350
0
            char *frame_outer_cuuid = MVM_string_utf8_encode_C_string(tc, static_frame->body.outer->body.cuuid);
351
0
            char *frame_outer_name;
352
0
353
0
            char *waste[7] = { frame_cuuid, outer_cuuid, frame_outer_cuuid, NULL, NULL, NULL, NULL };
354
0
            int waste_counter = 3;
355
0
356
0
            if (static_frame->body.name) {
357
0
                frame_name = MVM_string_utf8_encode_C_string(tc, static_frame->body.name);
358
0
                waste[waste_counter++] = frame_name;
359
0
            }
360
0
            else {
361
0
                frame_name = "<anonymous static frame>";
362
0
            }
363
0
364
0
            if (outer->static_info->body.name) {
365
0
                outer_name = MVM_string_utf8_encode_C_string(tc, outer->static_info->body.name);
366
0
                waste[waste_counter++] = outer_name;
367
0
            }
368
0
            else {
369
0
                outer_name = "<anonymous static frame>";
370
0
            }
371
0
372
0
            if (static_frame->body.outer->body.name) {
373
0
                frame_outer_name = MVM_string_utf8_encode_C_string(tc, static_frame->body.outer->body.name);
374
0
                waste[waste_counter++] = frame_outer_name;
375
0
            }
376
0
            else {
377
0
                frame_outer_name = "<anonymous static frame>";
378
0
            }
379
0
380
0
            MVM_exception_throw_adhoc_free(tc, waste,
381
0
                "When invoking %s '%s', provided outer frame %p (%s '%s') does not match expected static frame %p (%s '%s')",
382
0
                frame_cuuid,
383
0
                frame_name,
384
0
                outer->static_info,
385
0
                outer_cuuid,
386
0
                outer_name,
387
0
                static_frame->body.outer,
388
0
                frame_outer_cuuid,
389
0
                frame_outer_name);
390
0
        }
391
12.4M
    }
392
5.40k
    else if (static_frame->body.static_code) {
393
5.40k
        MVMCode *static_code = static_frame->body.static_code;
394
5.40k
        if (static_code->body.outer) {
395
1
            /* We're lacking an outer, but our static code object may have one.
396
1
            * This comes up in the case of cloned protoregexes, for example. */
397
1
            outer = static_code->body.outer;
398
1
        }
399
5.40k
        else if (static_frame->body.outer) {
400
22
            /* Auto-close, and cache it in the static frame. */
401
22
            MVMROOT(tc, static_frame, {
402
22
            MVMROOT(tc, code_ref, {
403
22
                MVM_frame_force_to_heap(tc, tc->cur_frame);
404
22
                outer = autoclose(tc, static_frame->body.outer);
405
22
                MVM_ASSIGN_REF(tc, &(static_code->common.header),
406
22
                    static_code->body.outer, outer);
407
22
            });
408
22
            });
409
22
        }
410
5.40k
    }
411
12.4M
412
12.4M
    /* See if any specializations apply. */
413
12.4M
    found_spesh = 0;
414
12.4M
    if (spesh_cand >= 0 && spesh_cand < static_frame->body.num_spesh_candidates) {
415
1.44M
        MVMSpeshCandidate *chosen_cand = &static_frame->body.spesh_candidates[spesh_cand];
416
1.44M
        if (!chosen_cand->sg) {
417
1.44M
            frame = allocate_frame(tc, static_frame, chosen_cand);
418
1.44M
            frame->effective_bytecode    = chosen_cand->bytecode;
419
1.44M
            frame->effective_handlers    = chosen_cand->handlers;
420
1.44M
            frame->effective_spesh_slots = chosen_cand->spesh_slots;
421
1.44M
            frame->spesh_cand            = chosen_cand;
422
1.44M
            frame->spesh_log_idx         = -1;
423
1.44M
            found_spesh                  = 1;
424
1.44M
        }
425
1.44M
    }
426
12.4M
    if (!found_spesh && ++static_frame->body.invocations >= static_frame->body.spesh_threshold && callsite->is_interned) {
427
7.85M
        /* Look for specialized bytecode. */
428
7.85M
        MVMint32 num_spesh = static_frame->body.num_spesh_candidates;
429
7.85M
        MVMSpeshCandidate *chosen_cand = NULL;
430
7.85M
        MVMint32 i, j;
431
12.6M
        for (i = 0; i < num_spesh; i++) {
432
11.9M
            MVMSpeshCandidate *cand = &static_frame->body.spesh_candidates[i];
433
11.9M
            if (cand->cs == callsite) {
434
10.1M
                MVMint32 match = 1;
435
22.8M
                for (j = 0; j < cand->num_guards; j++) {
436
15.6M
                    MVMint32   pos = cand->guards[j].slot;
437
15.6M
                    MVMSTable *st  = (MVMSTable *)cand->guards[j].match;
438
15.6M
                    MVMObject *arg = args[pos].o;
439
15.6M
                    if (!arg) {
440
0
                        match = 0;
441
0
                        break;
442
0
                    }
443
15.6M
                    switch (cand->guards[j].kind) {
444
13.6M
                    case MVM_SPESH_GUARD_CONC:
445
13.6M
                        if (!IS_CONCRETE(arg) || STABLE(arg) != st)
446
2.37M
                            match = 0;
447
13.6M
                        break;
448
2.05M
                    case MVM_SPESH_GUARD_TYPE:
449
2.05M
                        if (IS_CONCRETE(arg) || STABLE(arg) != st)
450
649k
                            match = 0;
451
2.05M
                        break;
452
0
                    case MVM_SPESH_GUARD_DC_CONC: {
453
0
                        MVMRegister dc;
454
0
                        STABLE(arg)->container_spec->fetch(tc, arg, &dc);
455
0
                        if (!dc.o || !IS_CONCRETE(dc.o) || STABLE(dc.o) != st)
456
0
                            match = 0;
457
0
                        break;
458
13.6M
                    }
459
0
                    case MVM_SPESH_GUARD_DC_TYPE: {
460
0
                        MVMRegister dc;
461
0
                        STABLE(arg)->container_spec->fetch(tc, arg, &dc);
462
0
                        if (!dc.o || IS_CONCRETE(dc.o) || STABLE(dc.o) != st)
463
0
                            match = 0;
464
0
                        break;
465
13.6M
                    }
466
0
                    case MVM_SPESH_GUARD_DC_CONC_RW: {
467
0
                        if (STABLE(arg)->container_spec->can_store(tc, arg)) {
468
0
                            MVMRegister dc;
469
0
                            STABLE(arg)->container_spec->fetch(tc, arg, &dc);
470
0
                            if (!dc.o || !IS_CONCRETE(dc.o) || STABLE(dc.o) != st)
471
0
                                match = 0;
472
0
                        }
473
0
                        else {
474
0
                            match = 0;
475
0
                        }
476
0
                        break;
477
13.6M
                    }
478
0
                    case MVM_SPESH_GUARD_DC_TYPE_RW: {
479
0
                        if (STABLE(arg)->container_spec->can_store(tc, arg)) {
480
0
                            MVMRegister dc;
481
0
                            STABLE(arg)->container_spec->fetch(tc, arg, &dc);
482
0
                            if (!dc.o || IS_CONCRETE(dc.o) || STABLE(dc.o) != st)
483
0
                                match = 0;
484
0
                        }
485
0
                        else {
486
0
                            match = 0;
487
0
                        }
488
0
                        break;
489
13.6M
                    }
490
15.6M
                    }
491
15.6M
                    if (!match)
492
3.02M
                        break;
493
15.6M
                }
494
10.1M
                if (match) {
495
7.15M
                    chosen_cand = cand;
496
7.15M
                    break;
497
7.15M
                }
498
10.1M
            }
499
11.9M
        }
500
7.85M
501
7.85M
        /* If we didn't find any, and we're below the limit, can set up a
502
7.85M
         * specialization. */
503
7.85M
        if (!chosen_cand && num_spesh < MVM_SPESH_LIMIT && tc->instance->spesh_enabled)
504
17.0k
            chosen_cand = MVM_spesh_candidate_setup(tc, static_frame,
505
17.0k
                callsite, args, 0);
506
7.85M
507
7.85M
        /* Now try to use specialized bytecode. We may need to compete to
508
7.85M
         * be a logging run of it. */
509
7.85M
        if (chosen_cand) {
510
7.17M
            if (chosen_cand->sg) {
511
123k
                /* In the logging phase. Try to get a logging index; ensure it
512
123k
                 * is not being used as an OSR logging candidate elsewhere. */
513
123k
                AO_t cur_idx = MVM_load(&(chosen_cand->log_enter_idx));
514
123k
                if (!chosen_cand->osr_logging && cur_idx < MVM_SPESH_LOG_RUNS) {
515
120k
                    if (MVM_cas(&(chosen_cand->log_enter_idx), cur_idx, cur_idx + 1) == cur_idx) {
516
120k
                        /* We get to log. */
517
120k
                        frame = allocate_frame(tc, static_frame, chosen_cand);
518
120k
                        frame->effective_bytecode    = chosen_cand->bytecode;
519
120k
                        frame->effective_handlers    = chosen_cand->handlers;
520
120k
                        frame->effective_spesh_slots = chosen_cand->spesh_slots;
521
120k
                        frame->spesh_log_slots       = chosen_cand->log_slots;
522
120k
                        frame->spesh_cand            = chosen_cand;
523
120k
                        frame->spesh_log_idx         = (MVMint8)cur_idx;
524
120k
                        found_spesh                  = 1;
525
120k
                    }
526
120k
                }
527
123k
            }
528
7.05M
            else {
529
7.05M
                /* In the post-specialize phase; can safely used the code. */
530
7.05M
                frame = allocate_frame(tc, static_frame, chosen_cand);
531
7.05M
                if (chosen_cand->jitcode) {
532
6.65M
                    frame->effective_bytecode = chosen_cand->jitcode->bytecode;
533
6.65M
                    frame->jit_entry_label    = chosen_cand->jitcode->labels[0];
534
6.65M
                }
535
394k
                else {
536
394k
                    frame->effective_bytecode = chosen_cand->bytecode;
537
394k
                }
538
7.05M
                frame->effective_handlers    = chosen_cand->handlers;
539
7.05M
                frame->effective_spesh_slots = chosen_cand->spesh_slots;
540
7.05M
                frame->spesh_cand            = chosen_cand;
541
7.05M
                frame->spesh_log_idx         = -1;
542
7.05M
                found_spesh                  = 1;
543
7.05M
            }
544
7.17M
        }
545
7.85M
    }
546
12.4M
    if (!found_spesh) {
547
3.84M
        frame = allocate_frame(tc, static_frame, NULL);
548
3.84M
        frame->effective_bytecode = static_frame->body.bytecode;
549
3.84M
        frame->effective_handlers = static_frame->body.handlers;
550
3.84M
    }
551
12.4M
552
12.4M
    /* Set static frame. */
553
12.4M
    frame->static_info = static_frame;
554
12.4M
555
12.4M
    /* Store the code ref (NULL at the top-level). */
556
12.4M
    frame->code_ref = code_ref;
557
12.4M
558
12.4M
    /* Outer. */
559
12.4M
    frame->outer = outer;
560
12.4M
561
12.4M
    /* Caller is current frame in the thread context. */
562
12.4M
    frame->caller = tc->cur_frame;
563
12.4M
564
12.4M
    /* Initialize argument processing. */
565
12.4M
    MVM_args_proc_init(tc, &frame->params, callsite, args);
566
12.4M
567
12.4M
    /* Update interpreter and thread context, so next execution will use this
568
12.4M
     * frame. */
569
12.4M
    tc->cur_frame = frame;
570
12.4M
    tc->current_frame_nr = frame->sequence_nr;
571
12.4M
572
12.4M
    *(tc->interp_cur_op) = frame->effective_bytecode;
573
12.4M
    *(tc->interp_bytecode_start) = frame->effective_bytecode;
574
12.4M
    *(tc->interp_reg_base) = frame->work;
575
12.4M
    *(tc->interp_cu) = static_frame->body.cu;
576
12.4M
577
12.4M
578
12.4M
579
12.4M
    /* If we need to do so, make clones of things in the lexical environment
580
12.4M
     * that need it. Note that we do this after tc->cur_frame became the
581
12.4M
     * current frame, to make sure these new objects will certainly get
582
12.4M
     * marked if GC is triggered along the way. */
583
12.4M
    if (static_frame->body.has_state_vars) {
584
18
        /* Drag everything out of static_frame_body before we start,
585
18
         * as GC action may invalidate it. */
586
18
        MVMRegister *env       = static_frame->body.static_env;
587
18
        MVMuint8    *flags     = static_frame->body.static_env_flags;
588
18
        MVMint64     numlex    = static_frame->body.num_lexicals;
589
18
        MVMRegister *state     = NULL;
590
18
        MVMint64     state_act = 0; /* 0 = none so far, 1 = first time, 2 = later */
591
18
        MVMint64 i;
592
18
        MVMROOT(tc, frame, {
593
18
            for (i = 0; i < numlex; i++) {
594
18
                if (flags[i] == 2) {
595
18
                    redo_state:
596
18
                    switch (state_act) {
597
18
                    case 0:
598
18
                        if (!frame->code_ref)
599
18
                            MVM_exception_throw_adhoc(tc,
600
18
                                "Frame must have code-ref to have state variables");
601
18
                        state = ((MVMCode *)frame->code_ref)->body.state_vars;
602
18
                        if (state) {
603
18
                            /* Already have state vars; pull them from this. */
604
18
                            state_act = 2;
605
18
                        }
606
18
                        else {
607
18
                            /* Allocate storage for state vars. */
608
18
                            state = (MVMRegister *)MVM_calloc(1, frame->static_info->body.env_size);
609
18
                            ((MVMCode *)frame->code_ref)->body.state_vars = state;
610
18
                            state_act = 1;
611
18
612
18
                            /* Note that this frame should run state init code. */
613
18
                            frame->flags |= MVM_FRAME_FLAG_STATE_INIT;
614
18
                        }
615
18
                        goto redo_state;
616
18
                    case 1: {
617
18
                        MVMObject *cloned = MVM_repr_clone(tc, env[i].o);
618
18
                        frame->env[i].o = cloned;
619
18
                        MVM_ASSIGN_REF(tc, &(frame->code_ref->header), state[i].o, cloned);
620
18
                        break;
621
18
                    }
622
18
                    case 2:
623
18
                        frame->env[i].o = state[i].o;
624
18
                        break;
625
18
                    }
626
18
                }
627
18
            }
628
18
        });
629
18
    }
630
12.4M
}
631
632
/* Forces the specified frame from the stack and on to the heap, if it's not
633
 * already there. */
634
605k
MVMFrame * MVM_frame_force_to_heap(MVMThreadContext *tc, MVMFrame *frame) {
635
605k
    if (MVM_FRAME_IS_ON_CALLSTACK(tc, frame)) {
636
347k
        /* To keep things simple, we'll promote the entire stack. */
637
347k
        MVMFrame *cur_to_promote = tc->cur_frame;
638
347k
        MVMFrame *new_cur_frame = NULL;
639
347k
        MVMFrame *update_caller = NULL;
640
347k
        MVMFrame *result = NULL;
641
347k
        MVMROOT(tc, new_cur_frame, {
642
347k
        MVMROOT(tc, update_caller, {
643
347k
        MVMROOT(tc, result, {
644
347k
            while (cur_to_promote) {
645
347k
                /* Allocate a heap frame. */
646
347k
                MVMFrame *promoted = MVM_gc_allocate_frame(tc);
647
347k
648
347k
                /* Copy current frame's body to it. */
649
347k
                memcpy(
650
347k
                    (char *)promoted + sizeof(MVMCollectable),
651
347k
                    (char *)cur_to_promote + sizeof(MVMCollectable),
652
347k
                    sizeof(MVMFrame) - sizeof(MVMCollectable));
653
347k
654
347k
                /* Update caller of previously promtoed frame, if any. This is the
655
347k
                 * only reference that might point to a non-heap frame. */
656
347k
                if (update_caller) {
657
347k
                    MVM_ASSIGN_REF(tc, &(update_caller->header),
658
347k
                        update_caller->caller, promoted);
659
347k
                }
660
347k
661
347k
                /* If we're the first time through the lopo, then we're instead
662
347k
                 * replacing the current stack top. Note we do it at the end,
663
347k
                 * so that the GC can still walk unpromoted frames if it runs
664
347k
                 * in this loop. */
665
347k
                else {
666
347k
                    new_cur_frame = promoted;
667
347k
                }
668
347k
669
347k
                /* If the frame we're promoting was in the active handlers list,
670
347k
                 * update the address there. */
671
347k
                if (tc->active_handlers) {
672
347k
                    MVMActiveHandler *ah = tc->active_handlers;
673
347k
                    while (ah) {
674
347k
                        if (ah->frame == cur_to_promote)
675
347k
                            ah->frame = promoted;
676
347k
                        ah = ah->next_handler;
677
347k
                    }
678
347k
                }
679
347k
680
347k
                /* If we're replacing the frame we were asked to promote, that will
681
347k
                 * become our result. */
682
347k
                if (cur_to_promote == frame)
683
347k
                    result = promoted;
684
347k
685
347k
                /* Check if there's a caller, or if we reached the end of the
686
347k
                 * chain. */
687
347k
                if (cur_to_promote->caller) {
688
347k
                    /* If the caller is on the stack then it needs promotion too.
689
347k
                     * If not, we're done. */
690
347k
                    if (MVM_FRAME_IS_ON_CALLSTACK(tc, cur_to_promote->caller)) {
691
347k
                        /* Clear caller in promoted frame, to avoid a heap -> stack
692
347k
                         * reference if we GC during this loop. */
693
347k
                        promoted->caller = NULL;
694
347k
                        update_caller = promoted;
695
347k
                        cur_to_promote = cur_to_promote->caller;
696
347k
                    }
697
347k
                    else {
698
347k
                        if (cur_to_promote == tc->thread_entry_frame)
699
347k
                            tc->thread_entry_frame = promoted;
700
347k
                        cur_to_promote = NULL;
701
347k
                    }
702
347k
                }
703
347k
                else {
704
347k
                    /* End of caller chain; check if we promoted the entry
705
347k
                     * frame */
706
347k
                    if (cur_to_promote == tc->thread_entry_frame)
707
347k
                        tc->thread_entry_frame = promoted;
708
347k
                    cur_to_promote = NULL;
709
347k
                }
710
347k
            }
711
347k
        });
712
347k
        });
713
347k
        });
714
347k
715
347k
        /* All is promoted. Update thread's current frame and reset the thread
716
347k
         * local callstack. */
717
347k
        tc->cur_frame = new_cur_frame;
718
347k
        MVM_callstack_reset(tc);
719
347k
720
347k
        /* Hand back new location of promoted frame. */
721
347k
        if (!result)
722
0
            MVM_panic(1, "Failed to find frame to promote on call stack");
723
347k
        return result;
724
347k
    }
725
257k
    else {
726
257k
        return frame;
727
257k
    }
728
605k
}
729
730
/* Creates a frame for de-optimization purposes. */
731
MVMFrame * MVM_frame_create_for_deopt(MVMThreadContext *tc, MVMStaticFrame *static_frame,
732
1.66k
                                      MVMCode *code_ref) {
733
1.66k
    MVMFrame *frame;
734
1.66k
    MVMROOT(tc, static_frame, {
735
1.66k
    MVMROOT(tc, code_ref, {
736
1.66k
        frame = allocate_heap_frame(tc, static_frame, NULL);
737
1.66k
    });
738
1.66k
    });
739
1.66k
    frame->effective_bytecode       = static_frame->body.bytecode;
740
1.66k
    frame->effective_handlers       = static_frame->body.handlers;
741
1.66k
    MVM_ASSIGN_REF(tc, &(frame->header), frame->static_info, static_frame);
742
1.66k
    MVM_ASSIGN_REF(tc, &(frame->header), frame->code_ref, code_ref);
743
1.66k
    MVM_ASSIGN_REF(tc, &(frame->header), frame->outer, code_ref->body.outer);
744
1.66k
    return frame;
745
1.66k
}
746
747
/* Removes a single frame, as part of a return or unwind. Done after any exit
748
 * handler has already been run. */
749
12.4M
static MVMuint64 remove_one_frame(MVMThreadContext *tc, MVMuint8 unwind) {
750
12.4M
    MVMFrame *returner = tc->cur_frame;
751
12.4M
    MVMFrame *caller   = returner->caller;
752
12.4M
753
12.4M
    /* See if we were in a logging spesh frame, and need to complete the
754
12.4M
     * specialization. */
755
12.4M
    if (returner->spesh_cand && returner->spesh_log_idx >= 0) {
756
120k
        if (returner->spesh_cand->osr_logging) {
757
1
            /* Didn't achieve enough log entries to complete the OSR, but
758
1
             * clearly hot, so specialize anyway. This also avoids races
759
1
             * when the candidate is called again later and still has
760
1
             * sp_osrfinalize instructions in it. */
761
1
            returner->spesh_cand->osr_logging = 0;
762
1
            MVM_spesh_candidate_specialize(tc, returner->static_info,
763
1
                returner->spesh_cand);
764
1
        }
765
120k
        else if (MVM_decr(&(returner->spesh_cand->log_exits_remaining)) == 1) {
766
13.7k
            MVM_spesh_candidate_specialize(tc, returner->static_info,
767
13.7k
                returner->spesh_cand);
768
13.7k
        }
769
120k
    }
770
12.4M
771
12.4M
    /* Clear up any continuation tags. */
772
12.4M
    if (returner->continuation_tags)
773
0
        MVM_continuation_free_tags(tc, returner);
774
12.4M
775
12.4M
    /* Clean up frame working space. */
776
12.4M
    if (returner->work) {
777
12.4M
        MVM_args_proc_cleanup(tc, &returner->params);
778
12.4M
        MVM_fixed_size_free(tc, tc->instance->fsa, returner->allocd_work,
779
12.4M
            returner->work);
780
12.4M
    }
781
12.4M
782
12.4M
    /* If it's a call stack frame, remove it from the stack. */
783
12.4M
    if (MVM_FRAME_IS_ON_CALLSTACK(tc, returner)) {
784
11.4M
        MVMCallStackRegion *stack = tc->stack_current;
785
11.4M
        stack->alloc = (char *)returner;
786
11.4M
        if ((char *)stack->alloc - sizeof(MVMCallStackRegion) == (char *)stack)
787
2.55M
            MVM_callstack_region_prev(tc);
788
11.4M
        if (returner->env)
789
500k
            MVM_fixed_size_free(tc, tc->instance->fsa, returner->allocd_env, returner->env);
790
11.4M
    }
791
12.4M
792
12.4M
    /* Otherwise, NULL  out ->work, to indicate the frame is no longer in
793
12.4M
     * dynamic scope. This is used by the GC to avoid marking stuff (this is
794
12.4M
     * needed for safety as otherwise we'd read freed memory), as well as by
795
12.4M
     * exceptions to ensure the target of an exception throw is indeed still
796
12.4M
     * in dynamic scope. */
797
982k
    else {
798
982k
        returner->work = NULL;
799
982k
    }
800
12.4M
801
12.4M
    /* Switch back to the caller frame if there is one. */
802
12.4M
    if (caller && returner != tc->thread_entry_frame) {
803
12.4M
        tc->cur_frame = caller;
804
12.4M
        tc->current_frame_nr = caller->sequence_nr;
805
12.4M
806
12.4M
        *(tc->interp_cur_op) = caller->return_address;
807
12.4M
        *(tc->interp_bytecode_start) = caller->effective_bytecode;
808
12.4M
        *(tc->interp_reg_base) = caller->work;
809
12.4M
        *(tc->interp_cu) = caller->static_info->body.cu;
810
12.4M
811
12.4M
812
12.4M
        /* Handle any special return hooks. */
813
12.4M
        if (caller->special_return || caller->special_unwind) {
814
75.6k
            MVMSpecialReturn  sr  = caller->special_return;
815
75.6k
            MVMSpecialReturn  su  = caller->special_unwind;
816
75.6k
            void             *srd = caller->special_return_data;
817
75.6k
            caller->special_return           = NULL;
818
75.6k
            caller->special_unwind           = NULL;
819
75.6k
            caller->special_return_data      = NULL;
820
75.6k
            caller->mark_special_return_data = NULL;
821
75.6k
            if (unwind && su)
822
3
                su(tc, srd);
823
75.6k
            else if (!unwind && sr)
824
75.6k
                sr(tc, srd);
825
75.6k
        }
826
12.4M
827
12.4M
        return 1;
828
12.4M
    }
829
260
    else {
830
260
        tc->cur_frame = NULL;
831
260
        return 0;
832
260
    }
833
12.4M
}
834
835
/* Attempt to return from the current frame. Returns non-zero if we can,
836
 * and zero if there is nowhere to return to (which would signal the exit
837
 * of the interpreter). */
838
0
static void remove_after_handler(MVMThreadContext *tc, void *sr_data) {
839
0
    remove_one_frame(tc, 0);
840
0
}
841
12.4M
MVMuint64 MVM_frame_try_return(MVMThreadContext *tc) {
842
12.4M
    MVMFrame *cur_frame = tc->cur_frame;
843
12.4M
844
12.4M
    if (cur_frame->static_info->body.has_exit_handler &&
845
0
            !(cur_frame->flags & MVM_FRAME_FLAG_EXIT_HAND_RUN)) {
846
0
        /* Set us up to run exit handler, and make it so we'll really exit the
847
0
         * frame when that has been done. */
848
0
        MVMFrame     *caller = cur_frame->caller;
849
0
        MVMHLLConfig *hll    = MVM_hll_current(tc);
850
0
        MVMObject    *handler;
851
0
        MVMObject    *result;
852
0
        MVMCallsite *two_args_callsite;
853
0
854
0
        if (!caller)
855
0
            MVM_exception_throw_adhoc(tc, "Entry point frame cannot have an exit handler");
856
0
        if (tc->cur_frame == tc->thread_entry_frame)
857
0
            MVM_exception_throw_adhoc(tc, "Thread entry point frame cannot have an exit handler");
858
0
859
0
        if (caller->return_type == MVM_RETURN_OBJ) {
860
0
            result = caller->return_value->o;
861
0
        }
862
0
        else {
863
0
            MVMROOT(tc, cur_frame, {
864
0
                switch (caller->return_type) {
865
0
                    case MVM_RETURN_INT:
866
0
                        result = MVM_repr_box_int(tc, hll->int_box_type, caller->return_value->i64);
867
0
                        break;
868
0
                    case MVM_RETURN_NUM:
869
0
                        result = MVM_repr_box_num(tc, hll->num_box_type, caller->return_value->n64);
870
0
                        break;
871
0
                    case MVM_RETURN_STR:
872
0
                        result = MVM_repr_box_str(tc, hll->str_box_type, caller->return_value->s);
873
0
                        break;
874
0
                    default:
875
0
                        result = NULL;
876
0
                }
877
0
            });
878
0
        }
879
0
880
0
        handler = MVM_frame_find_invokee(tc, hll->exit_handler, NULL);
881
0
        two_args_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TWO_OBJ);
882
0
        MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, two_args_callsite);
883
0
        cur_frame->args[0].o = cur_frame->code_ref;
884
0
        cur_frame->args[1].o = result;
885
0
        cur_frame->special_return = remove_after_handler;
886
0
        cur_frame->flags |= MVM_FRAME_FLAG_EXIT_HAND_RUN;
887
0
        STABLE(handler)->invoke(tc, handler, two_args_callsite, cur_frame->args);
888
0
        return 1;
889
0
    }
890
12.4M
    else {
891
12.4M
        /* No exit handler, so a straight return. */
892
12.4M
        return remove_one_frame(tc, 0);
893
12.4M
    }
894
12.4M
}
895
896
/* Try a return from the current frame; skip running any exit handlers. */
897
0
MVMuint64 MVM_frame_try_return_no_exit_handlers(MVMThreadContext *tc) {
898
0
    return remove_one_frame(tc, 0);
899
0
}
900
901
/* Unwinds execution state to the specified frame, placing control flow at either
902
 * an absolute or relative (to start of target frame) address and optionally
903
 * setting a returned result. */
904
typedef struct {
905
    MVMFrame  *frame;
906
    MVMuint8  *abs_addr;
907
    MVMuint32  rel_addr;
908
} MVMUnwindData;
909
0
static void mark_unwind_data(MVMThreadContext *tc, MVMFrame *frame, MVMGCWorklist *worklist) {
910
0
    MVMUnwindData *ud  = (MVMUnwindData *)frame->special_return_data;
911
0
    MVM_gc_worklist_add(tc, worklist, &(ud->frame));
912
0
}
913
0
static void continue_unwind(MVMThreadContext *tc, void *sr_data) {
914
0
    MVMUnwindData *ud  = (MVMUnwindData *)sr_data;
915
0
    MVMFrame *frame    = ud->frame;
916
0
    MVMuint8 *abs_addr = ud->abs_addr;
917
0
    MVMuint32 rel_addr = ud->rel_addr;
918
0
    MVM_free(sr_data);
919
0
    MVM_frame_unwind_to(tc, frame, abs_addr, rel_addr, NULL);
920
0
}
921
void MVM_frame_unwind_to(MVMThreadContext *tc, MVMFrame *frame, MVMuint8 *abs_addr,
922
415k
                         MVMuint32 rel_addr, MVMObject *return_value) {
923
419k
    while (tc->cur_frame != frame) {
924
3.40k
        MVMFrame *cur_frame = tc->cur_frame;
925
3.40k
        if (cur_frame->static_info->body.has_exit_handler &&
926
0
                !(cur_frame->flags & MVM_FRAME_FLAG_EXIT_HAND_RUN)) {
927
0
            /* We're unwinding a frame with an exit handler. Thus we need to
928
0
             * pause the unwind, run the exit handler, and keep enough info
929
0
             * around in order to finish up the unwind afterwards. */
930
0
            MVMHLLConfig *hll    = MVM_hll_current(tc);
931
0
            MVMFrame     *caller;
932
0
            MVMObject    *handler;
933
0
            MVMCallsite *two_args_callsite;
934
0
935
0
            /* Force the frame onto the heap, since we'll reference it from the
936
0
             * unwind data. */
937
0
            MVMROOT(tc, frame, {
938
0
            MVMROOT(tc, cur_frame, {
939
0
            MVMROOT(tc, return_value, {
940
0
                frame = MVM_frame_force_to_heap(tc, frame);
941
0
                cur_frame = tc->cur_frame;
942
0
            });
943
0
            });
944
0
            });
945
0
946
0
            caller = cur_frame->caller;
947
0
            if (!caller)
948
0
                MVM_exception_throw_adhoc(tc, "Entry point frame cannot have an exit handler");
949
0
            if (cur_frame == tc->thread_entry_frame)
950
0
                MVM_exception_throw_adhoc(tc, "Thread entry point frame cannot have an exit handler");
951
0
952
0
            handler = MVM_frame_find_invokee(tc, hll->exit_handler, NULL);
953
0
            two_args_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TWO_OBJ);
954
0
            MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, two_args_callsite);
955
0
            cur_frame->args[0].o = cur_frame->code_ref;
956
0
            cur_frame->args[1].o = NULL;
957
0
            cur_frame->special_return = continue_unwind;
958
0
            cur_frame->mark_special_return_data = mark_unwind_data;
959
0
            {
960
0
                MVMUnwindData *ud = MVM_malloc(sizeof(MVMUnwindData));
961
0
                ud->frame = frame;
962
0
                ud->abs_addr = abs_addr;
963
0
                ud->rel_addr = rel_addr;
964
0
                if (return_value)
965
0
                    MVM_exception_throw_adhoc(tc, "return_value + exit_handler case NYI");
966
0
                cur_frame->special_return_data = ud;
967
0
            }
968
0
            cur_frame->flags |= MVM_FRAME_FLAG_EXIT_HAND_RUN;
969
0
            STABLE(handler)->invoke(tc, handler, two_args_callsite, cur_frame->args);
970
0
            return;
971
0
        }
972
3.40k
        else {
973
3.40k
            /* If we're profiling, log an exit. */
974
3.40k
            if (tc->instance->profiling)
975
0
                MVM_profile_log_unwind(tc);
976
3.40k
977
3.40k
            /* No exit handler, so just remove the frame. */
978
3.40k
            if (!remove_one_frame(tc, 1))
979
0
                MVM_panic(1, "Internal error: Unwound entire stack and missed handler");
980
3.40k
        }
981
3.40k
    }
982
415k
    if (abs_addr)
983
9
        *tc->interp_cur_op = abs_addr;
984
415k
    else if (rel_addr)
985
415k
        *tc->interp_cur_op = *tc->interp_bytecode_start + rel_addr;
986
415k
    if (return_value)
987
0
        MVM_args_set_result_obj(tc, return_value, 1);
988
415k
}
989
990
/* Gets a code object for a frame, lazily deserializing it if needed. */
991
742k
MVMObject * MVM_frame_get_code_object(MVMThreadContext *tc, MVMCode *code) {
992
742k
    if (REPR(code)->ID != MVM_REPR_ID_MVMCode)
993
0
        MVM_exception_throw_adhoc(tc, "getcodeobj needs a code ref");
994
742k
995
742k
    if (!code->body.code_object) {
996
35.4k
        MVMStaticFrame *sf = code->body.sf;
997
35.4k
        if (sf->body.code_obj_sc_dep_idx > 0) {
998
35.4k
            MVMObject *resolved;
999
35.4k
            MVMSerializationContext *sc = MVM_sc_get_sc(tc, sf->body.cu,
1000
35.4k
                sf->body.code_obj_sc_dep_idx - 1);
1001
35.4k
            if (sc == NULL)
1002
0
                MVM_exception_throw_adhoc(tc,
1003
0
                    "SC not yet resolved; lookup failed");
1004
35.4k
1005
35.4k
            MVMROOT(tc, code, {
1006
35.4k
                resolved = MVM_sc_get_object(tc, sc, sf->body.code_obj_sc_idx);
1007
35.4k
            });
1008
35.4k
1009
35.4k
            MVM_ASSIGN_REF(tc, &(code->common.header), code->body.code_object,
1010
35.4k
                resolved);
1011
35.4k
        }
1012
35.4k
    }
1013
742k
    return code->body.code_object;
1014
742k
}
1015
1016
/* Given the specified code object, sets its outer to the current scope. */
1017
191k
void MVM_frame_capturelex(MVMThreadContext *tc, MVMObject *code) {
1018
191k
    MVMCode *code_obj = (MVMCode *)code;
1019
191k
    MVMFrame *captured;
1020
191k
    if (REPR(code)->ID != MVM_REPR_ID_MVMCode)
1021
0
        MVM_exception_throw_adhoc(tc,
1022
0
            "Can only perform capturelex on object with representation MVMCode");
1023
191k
    MVMROOT(tc, code, {
1024
191k
        captured = MVM_frame_force_to_heap(tc, tc->cur_frame);
1025
191k
    });
1026
191k
    MVM_ASSIGN_REF(tc, &(code->header), code_obj->body.outer, captured);
1027
191k
}
1028
1029
/* This is used for situations in Perl 6 like:
1030
 * supply {
1031
 *     my $x = something();
1032
 *     whenever $supply {
1033
 *         QUIT { $x.foo() }
1034
 *     }
1035
 * }
1036
 * Here, the QUIT may be called without an invocation of the whenever ever
1037
 * having taken place. At the point we closure-clone the whenever block, we
1038
 * will capture_inner the QUIT phaser. This creates a fake outer for the
1039
 * QUIT, but makes *its* outer point to the nearest instance of the relevant
1040
 * static frame on the call stack, so that the QUIT will disocver the correct
1041
 * $x.
1042
 */
1043
0
void MVM_frame_capture_inner(MVMThreadContext *tc, MVMObject *code) {
1044
0
    MVMCode *code_obj = (MVMCode *)code;
1045
0
    MVMFrame *outer;
1046
0
    MVMROOT(tc, code, {
1047
0
        MVMStaticFrame *sf_outer = code_obj->body.sf->body.outer;
1048
0
        MVMROOT(tc, sf_outer, {
1049
0
            outer = create_context_only(tc, sf_outer, (MVMObject *)sf_outer->body.static_code, 1);
1050
0
        });
1051
0
        MVMROOT(tc, outer, {
1052
0
            MVMFrame *outer_outer = autoclose(tc, sf_outer->body.outer);
1053
0
            MVM_ASSIGN_REF(tc, &(outer->header), outer->outer, outer_outer);
1054
0
        });
1055
0
    });
1056
0
    MVM_ASSIGN_REF(tc, &(code->header), code_obj->body.outer, outer);
1057
0
}
1058
1059
/* Given the specified code object, copies it and returns a copy which
1060
 * captures a closure over the current scope. */
1061
352k
MVMObject * MVM_frame_takeclosure(MVMThreadContext *tc, MVMObject *code) {
1062
352k
    MVMCode *closure;
1063
352k
    MVMFrame *captured;
1064
352k
1065
352k
    if (REPR(code)->ID != MVM_REPR_ID_MVMCode)
1066
0
        MVM_exception_throw_adhoc(tc,
1067
0
            "Can only perform takeclosure on object with representation MVMCode");
1068
352k
1069
352k
    MVMROOT(tc, code, {
1070
352k
        closure = (MVMCode *)REPR(code)->allocate(tc, STABLE(code));
1071
352k
        MVMROOT(tc, closure, {
1072
352k
            captured = MVM_frame_force_to_heap(tc, tc->cur_frame);
1073
352k
        });
1074
352k
    });
1075
352k
1076
352k
    MVM_ASSIGN_REF(tc, &(closure->common.header), closure->body.sf, ((MVMCode *)code)->body.sf);
1077
352k
    MVM_ASSIGN_REF(tc, &(closure->common.header), closure->body.name, ((MVMCode *)code)->body.name);
1078
352k
    MVM_ASSIGN_REF(tc, &(closure->common.header), closure->body.outer, captured);
1079
352k
1080
352k
    MVM_ASSIGN_REF(tc, &(closure->common.header), closure->body.code_object,
1081
352k
        ((MVMCode *)code)->body.code_object);
1082
352k
1083
352k
    return (MVMObject *)closure;
1084
352k
}
1085
1086
/* Vivifies a lexical in a frame. */
1087
5.88k
MVMObject * MVM_frame_vivify_lexical(MVMThreadContext *tc, MVMFrame *f, MVMuint16 idx) {
1088
5.88k
    MVMuint8       *flags;
1089
5.88k
    MVMint16        flag;
1090
5.88k
    MVMRegister    *static_env;
1091
5.88k
    MVMuint16       effective_idx = 0;
1092
5.88k
    MVMStaticFrame *effective_sf;
1093
5.88k
    if (idx < f->static_info->body.num_lexicals) {
1094
5.88k
        flags         = f->static_info->body.static_env_flags;
1095
5.88k
        static_env    = f->static_info->body.static_env;
1096
5.88k
        effective_idx = idx;
1097
5.88k
        effective_sf  = f->static_info;
1098
5.88k
    }
1099
0
    else if (f->spesh_cand) {
1100
0
        MVMint32 i;
1101
0
        flags = NULL;
1102
0
        for (i = 0; i < f->spesh_cand->num_inlines; i++) {
1103
0
            MVMStaticFrame *isf = f->spesh_cand->inlines[i].code->body.sf;
1104
0
            effective_idx = idx - f->spesh_cand->inlines[i].lexicals_start;
1105
0
            if (effective_idx < isf->body.num_lexicals) {
1106
0
                flags        = isf->body.static_env_flags;
1107
0
                static_env   = isf->body.static_env;
1108
0
                effective_sf = isf;
1109
0
                break;
1110
0
            }
1111
0
        }
1112
0
    }
1113
0
    else {
1114
0
        flags = NULL;
1115
0
    }
1116
5.88k
    flag  = flags ? flags[effective_idx] : -1;
1117
5.88k
    if (flag != -1 && static_env[effective_idx].o == NULL) {
1118
5.88k
        MVMint32 scid, objid;
1119
5.88k
        if (MVM_bytecode_find_static_lexical_scref(tc, effective_sf->body.cu,
1120
5.75k
                effective_sf, effective_idx, &scid, &objid)) {
1121
5.75k
            MVMSerializationContext *sc = MVM_sc_get_sc(tc, effective_sf->body.cu, scid);
1122
5.75k
            MVMObject *resolved;
1123
5.75k
            if (sc == NULL)
1124
0
                MVM_exception_throw_adhoc(tc,
1125
0
                    "SC not yet resolved; lookup failed");
1126
5.75k
            MVMROOT(tc, f, {
1127
5.75k
                resolved = MVM_sc_get_object(tc, sc, objid);
1128
5.75k
            });
1129
5.75k
            MVM_ASSIGN_REF(tc, &(f->static_info->common.header),
1130
5.75k
                f->static_info->body.static_env[effective_idx].o,
1131
5.75k
                resolved);
1132
5.75k
        }
1133
5.88k
    }
1134
5.88k
    if (flag == 0) {
1135
5.88k
        MVMObject *viv = static_env[effective_idx].o;
1136
5.88k
        if (!viv)
1137
130
            viv = tc->instance->VMNull;
1138
5.88k
        MVM_ASSIGN_REF(tc, &(f->header), f->env[idx].o, viv);
1139
5.88k
        return viv;
1140
5.88k
    }
1141
4
    else if (flag == 1) {
1142
4
        MVMObject *viv;
1143
4
        MVMROOT(tc, f, {
1144
4
            viv = MVM_repr_clone(tc, static_env[effective_idx].o);
1145
4
            MVM_ASSIGN_REF(tc, &(f->header), f->env[idx].o, viv);
1146
4
        });
1147
4
        return viv;
1148
4
    }
1149
0
    else {
1150
0
        return tc->instance->VMNull;
1151
0
    }
1152
5.88k
}
1153
1154
/* Looks up the address of the lexical with the specified name and the
1155
 * specified type. Non-existing object lexicals produce NULL, expected
1156
 * (for better or worse) by various things. Otherwise, an error is thrown
1157
 * if it does not exist. Incorrect type always throws. */
1158
3.32M
MVMRegister * MVM_frame_find_lexical_by_name(MVMThreadContext *tc, MVMString *name, MVMuint16 type) {
1159
3.32M
    MVMFrame *cur_frame = tc->cur_frame;
1160
6.73M
    while (cur_frame != NULL) {
1161
6.73M
        MVMLexicalRegistry *lexical_names = cur_frame->static_info->body.lexical_names;
1162
6.73M
        if (lexical_names) {
1163
3.52M
            /* Indexes were formerly stored off-by-one to avoid semi-predicate issue. */
1164
3.52M
            MVMLexicalRegistry *entry;
1165
3.52M
            MVM_HASH_GET(tc, lexical_names, name, entry)
1166
3.52M
            if (entry) {
1167
3.32M
                if (cur_frame->static_info->body.lexical_types[entry->value] == type) {
1168
3.32M
                    MVMRegister *result = &cur_frame->env[entry->value];
1169
3.32M
                    if (type == MVM_reg_obj && !result->o)
1170
131
                        MVM_frame_vivify_lexical(tc, cur_frame, entry->value);
1171
3.32M
                    return result;
1172
3.32M
                }
1173
0
                else {
1174
0
                    char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1175
0
                    char *waste[] = { c_name, NULL };
1176
0
                    MVM_exception_throw_adhoc_free(tc, waste,
1177
0
                        "Lexical with name '%s' has wrong type",
1178
0
                            c_name);
1179
0
                }
1180
3.32M
            }
1181
3.52M
        }
1182
3.41M
        cur_frame = cur_frame->outer;
1183
3.41M
    }
1184
0
    if (type != MVM_reg_obj) {
1185
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1186
0
        char *waste[] = { c_name, NULL };
1187
0
        MVM_exception_throw_adhoc_free(tc, waste, "No lexical found with name '%s'",
1188
0
            c_name);
1189
0
    }
1190
0
    return NULL;
1191
3.32M
}
1192
1193
/* Binds the specified value to the given lexical, finding it along the static
1194
 * chain. */
1195
0
MVM_PUBLIC void MVM_frame_bind_lexical_by_name(MVMThreadContext *tc, MVMString *name, MVMuint16 type, MVMRegister *value) {
1196
0
    MVMFrame *cur_frame = tc->cur_frame;
1197
0
    while (cur_frame != NULL) {
1198
0
        MVMLexicalRegistry *lexical_names = cur_frame->static_info->body.lexical_names;
1199
0
        if (lexical_names) {
1200
0
            MVMLexicalRegistry *entry;
1201
0
            MVM_HASH_GET(tc, lexical_names, name, entry)
1202
0
            if (entry) {
1203
0
                if (cur_frame->static_info->body.lexical_types[entry->value] == type) {
1204
0
                    if (type == MVM_reg_obj || type == MVM_reg_str) {
1205
0
                        MVM_ASSIGN_REF(tc, &(cur_frame->header),
1206
0
                            cur_frame->env[entry->value].o, value->o);
1207
0
                    }
1208
0
                    else {
1209
0
                        cur_frame->env[entry->value] = *value;
1210
0
                    }
1211
0
                    return;
1212
0
                }
1213
0
                else {
1214
0
                    char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1215
0
                    char *waste[] = { c_name, NULL };
1216
0
                    MVM_exception_throw_adhoc_free(tc, waste,
1217
0
                        "Lexical with name '%s' has wrong type",
1218
0
                            c_name);
1219
0
                }
1220
0
            }
1221
0
        }
1222
0
        cur_frame = cur_frame->outer;
1223
0
    }
1224
0
    {
1225
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1226
0
        char *waste[] = { c_name, NULL };
1227
0
        MVM_exception_throw_adhoc_free(tc, waste, "No lexical found with name '%s'",
1228
0
            c_name);
1229
0
    }
1230
0
}
1231
1232
/* Finds a lexical in the outer frame, throwing if it's not there. */
1233
4
MVMObject * MVM_frame_find_lexical_by_name_outer(MVMThreadContext *tc, MVMString *name) {
1234
4
    MVMRegister *r = MVM_frame_find_lexical_by_name_rel(tc, name, tc->cur_frame->outer);
1235
4
    if (r)
1236
4
        return r->o;
1237
0
    else {
1238
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1239
0
        char *waste[] = { c_name, NULL };
1240
0
        MVM_exception_throw_adhoc_free(tc, waste, "No lexical found with name '%s'",
1241
0
            c_name);
1242
0
    }
1243
4
}
1244
1245
/* Looks up the address of the lexical with the specified name, starting with
1246
 * the specified frame. Only works if it's an object lexical.  */
1247
6
MVMRegister * MVM_frame_find_lexical_by_name_rel(MVMThreadContext *tc, MVMString *name, MVMFrame *cur_frame) {
1248
11
    while (cur_frame != NULL) {
1249
10
        MVMLexicalRegistry *lexical_names = cur_frame->static_info->body.lexical_names;
1250
10
        if (lexical_names) {
1251
10
            /* Indexes were formerly stored off-by-one to avoid semi-predicate issue. */
1252
10
            MVMLexicalRegistry *entry;
1253
10
            MVM_HASH_GET(tc, lexical_names, name, entry)
1254
10
            if (entry) {
1255
5
                if (cur_frame->static_info->body.lexical_types[entry->value] == MVM_reg_obj) {
1256
5
                    MVMRegister *result = &cur_frame->env[entry->value];
1257
5
                    if (!result->o)
1258
0
                        MVM_frame_vivify_lexical(tc, cur_frame, entry->value);
1259
5
                    return result;
1260
5
                }
1261
0
                else {
1262
0
                    char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1263
0
                    char *waste[] = { c_name, NULL };
1264
0
                    MVM_exception_throw_adhoc_free(tc, waste,
1265
0
                        "Lexical with name '%s' has wrong type",
1266
0
                            c_name);
1267
0
                }
1268
5
            }
1269
10
        }
1270
5
        cur_frame = cur_frame->outer;
1271
5
    }
1272
1
    return NULL;
1273
6
}
1274
1275
/* Looks up the address of the lexical with the specified name, starting with
1276
 * the specified frame. It checks all outer frames of the caller frame chain.  */
1277
10
MVMRegister * MVM_frame_find_lexical_by_name_rel_caller(MVMThreadContext *tc, MVMString *name, MVMFrame *cur_caller_frame) {
1278
37
    while (cur_caller_frame != NULL) {
1279
35
        MVMFrame *cur_frame = cur_caller_frame;
1280
124
        while (cur_frame != NULL) {
1281
97
            MVMLexicalRegistry *lexical_names = cur_frame->static_info->body.lexical_names;
1282
97
            if (lexical_names) {
1283
84
                /* Indexes were formerly stored off-by-one to avoid semi-predicate issue. */
1284
84
                MVMLexicalRegistry *entry;
1285
84
                MVM_HASH_GET(tc, lexical_names, name, entry)
1286
84
                if (entry) {
1287
8
                    if (cur_frame->static_info->body.lexical_types[entry->value] == MVM_reg_obj) {
1288
8
                        MVMRegister *result = &cur_frame->env[entry->value];
1289
8
                        if (!result->o)
1290
0
                            MVM_frame_vivify_lexical(tc, cur_frame, entry->value);
1291
8
                        return result;
1292
8
                    }
1293
0
                    else {
1294
0
                        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1295
0
                        char *waste[] = { c_name, NULL };
1296
0
                        MVM_exception_throw_adhoc_free(tc, waste,
1297
0
                            "Lexical with name '%s' has wrong type",
1298
0
                                c_name);
1299
0
                    }
1300
8
                }
1301
84
            }
1302
89
            cur_frame = cur_frame->outer;
1303
89
        }
1304
27
        cur_caller_frame = cur_caller_frame->caller;
1305
27
    }
1306
2
    return NULL;
1307
10
}
1308
1309
/* Looks up the address of the lexical with the specified name and the
1310
 * specified type. Returns null if it does not exist. */
1311
237k
static void try_cache_dynlex(MVMThreadContext *tc, MVMFrame *from, MVMFrame *to, MVMString *name, MVMRegister *reg, MVMuint16 type, MVMuint32 fcost, MVMuint32 icost) {
1312
237k
#if MVM_DYNLEX_CACHE_ENABLED
1313
237k
    MVMint32 next = 0;
1314
237k
    MVMint32 frames = 0;
1315
237k
    MVMuint32 desperation = 0;
1316
237k
1317
237k
    if (fcost+icost > 20)
1318
39.5k
        desperation = 1;
1319
237k
1320
955k
    while (from && from != to) {
1321
854k
        frames++;
1322
854k
        if (frames >= next) {
1323
527k
            if (!from->dynlex_cache_name || (desperation && frames > 1)) {
1324
390k
                MVM_ASSIGN_REF(tc, &(from->header), from->dynlex_cache_name, name);
1325
390k
                from->dynlex_cache_reg  = reg;
1326
390k
                from->dynlex_cache_type = type;
1327
390k
                if (desperation && next == 3) {
1328
34.8k
                    next = fcost / 2;
1329
34.8k
                }
1330
355k
                else {
1331
355k
                    if (next)
1332
136k
                        return;
1333
218k
                    next = 3;
1334
218k
                }
1335
390k
            }
1336
527k
        }
1337
717k
        from = from->caller;
1338
717k
    }
1339
237k
#endif
1340
237k
}
1341
690k
MVMRegister * MVM_frame_find_contextual_by_name(MVMThreadContext *tc, MVMString *name, MVMuint16 *type, MVMFrame *cur_frame, MVMint32 vivify, MVMFrame **found_frame) {
1342
690k
    FILE *dlog = tc->instance->dynvar_log_fh;
1343
690k
    MVMuint32 fcost = 0;  /* frames traversed */
1344
690k
    MVMuint32 icost = 0;  /* inlines traversed */
1345
690k
    MVMuint32 ecost = 0;  /* frames traversed with empty cache */
1346
690k
    MVMuint32 xcost = 0;  /* frames traversed with wrong name */
1347
690k
    char *c_name;
1348
690k
    MVMuint64 start_time;
1349
690k
    MVMuint64 last_time;
1350
690k
1351
690k
    MVMFrame *initial_frame = cur_frame;
1352
690k
    if (!name)
1353
0
        MVM_exception_throw_adhoc(tc, "Contextual name cannot be null");
1354
690k
    if (dlog) {
1355
0
        c_name = MVM_string_utf8_encode_C_string(tc, name);
1356
0
        start_time = uv_hrtime();
1357
0
        last_time = tc->instance->dynvar_log_lasttime;
1358
0
    }
1359
690k
1360
3.38M
    while (cur_frame != NULL) {
1361
3.35M
        MVMLexicalRegistry *lexical_names;
1362
3.35M
        MVMSpeshCandidate  *cand     = cur_frame->spesh_cand;
1363
3.35M
        /* See if we are inside an inline. Note that this isn't actually
1364
3.35M
         * correct for a leaf frame, but those aren't inlined and don't
1365
3.35M
         * use getdynlex for their own lexicals since the compiler already
1366
3.35M
         * knows where to find them */
1367
3.35M
        if (cand && cand->num_inlines) {
1368
521k
            if (cand->jitcode && cur_frame->effective_bytecode == cand->jitcode->bytecode) {
1369
375k
                void      **labels = cand->jitcode->labels;
1370
375k
                void *return_label = cur_frame->jit_entry_label;
1371
375k
                MVMJitInline *inls = cand->jitcode->inlines;
1372
375k
                MVMint32 i;
1373
375k
                if (return_label == NULL)
1374
0
                    MVM_oops(tc, "Return label is NULL!\n");
1375
1.40M
                for (i = 0; i < cand->jitcode->num_inlines; i++) {
1376
1.03M
                    icost++;
1377
1.03M
                    if (return_label >= labels[inls[i].start_label] && return_label <= labels[inls[i].end_label]) {
1378
88.5k
                        MVMStaticFrame *isf = cand->inlines[i].code->body.sf;
1379
88.5k
                        if ((lexical_names = isf->body.lexical_names)) {
1380
262
                            MVMLexicalRegistry *entry;
1381
262
                            MVM_HASH_GET(tc, lexical_names, name, entry);
1382
262
                            if (entry) {
1383
0
                                MVMuint16    lexidx = cand->inlines[i].lexicals_start + entry->value;
1384
0
                                MVMRegister *result = &cur_frame->env[lexidx];
1385
0
                                *type = cand->lexical_types[lexidx];
1386
0
                                if (vivify && *type == MVM_reg_obj && !result->o) {
1387
0
                                    MVMROOT(tc, cur_frame, {
1388
0
                                    MVMROOT(tc, initial_frame, {
1389
0
                                    MVMROOT(tc, name, {
1390
0
                                        MVM_frame_vivify_lexical(tc, cur_frame, lexidx);
1391
0
                                    });
1392
0
                                    });
1393
0
                                    });
1394
0
                                }
1395
0
                                if (fcost+icost > 1)
1396
0
                                  try_cache_dynlex(tc, initial_frame, cur_frame, name, result, *type, fcost, icost);
1397
0
                                if (dlog) {
1398
0
                                    fprintf(dlog, "I %s %d %d %d %d %"PRIu64" %"PRIu64" %"PRIu64"\n", c_name, fcost, icost, ecost, xcost, last_time, start_time, uv_hrtime());
1399
0
                                    fflush(dlog);
1400
0
                                    MVM_free(c_name);
1401
0
                                    tc->instance->dynvar_log_lasttime = uv_hrtime();
1402
0
                                }
1403
0
                                *found_frame = cur_frame;
1404
0
                                return result;
1405
0
                            }
1406
262
                        }
1407
88.5k
                    }
1408
1.03M
                }
1409
145k
            } else {
1410
145k
                MVMint32 ret_offset = cur_frame->return_address - cur_frame->effective_bytecode;
1411
145k
                MVMint32 i;
1412
578k
                for (i = 0; i < cand->num_inlines; i++) {
1413
433k
                    icost++;
1414
433k
                    if (ret_offset >= cand->inlines[i].start && ret_offset < cand->inlines[i].end) {
1415
9.60k
                        MVMStaticFrame *isf = cand->inlines[i].code->body.sf;
1416
9.60k
                        if ((lexical_names = isf->body.lexical_names)) {
1417
0
                            MVMLexicalRegistry *entry;
1418
0
                            MVM_HASH_GET(tc, lexical_names, name, entry);
1419
0
                            if (entry) {
1420
0
                                MVMuint16    lexidx = cand->inlines[i].lexicals_start + entry->value;
1421
0
                                MVMRegister *result = &cur_frame->env[lexidx];
1422
0
                                *type = cand->lexical_types[lexidx];
1423
0
                                if (vivify && *type == MVM_reg_obj && !result->o) {
1424
0
                                    MVMROOT(tc, cur_frame, {
1425
0
                                    MVMROOT(tc, initial_frame, {
1426
0
                                    MVMROOT(tc, name, {
1427
0
                                        MVM_frame_vivify_lexical(tc, cur_frame, lexidx);
1428
0
                                    });
1429
0
                                    });
1430
0
                                    });
1431
0
                                }
1432
0
                                if (fcost+icost > 1)
1433
0
                                  try_cache_dynlex(tc, initial_frame, cur_frame, name, result, *type, fcost, icost);
1434
0
                                if (dlog) {
1435
0
                                    fprintf(dlog, "I %s %d %d %d %d %"PRIu64" %"PRIu64" %"PRIu64"\n", c_name, fcost, icost, ecost, xcost, last_time, start_time, uv_hrtime());
1436
0
                                    fflush(dlog);
1437
0
                                    MVM_free(c_name);
1438
0
                                    tc->instance->dynvar_log_lasttime = uv_hrtime();
1439
0
                                }
1440
0
                                *found_frame = cur_frame;
1441
0
                                return result;
1442
0
                            }
1443
0
                        }
1444
9.60k
                    }
1445
433k
                }
1446
145k
            }
1447
521k
        }
1448
3.35M
1449
3.35M
        /* See if we've got it cached at this level. */
1450
3.35M
        if (cur_frame->dynlex_cache_name) {
1451
1.29M
            if (MVM_string_equal(tc, name, cur_frame->dynlex_cache_name)) {
1452
478k
                MVMRegister *result = cur_frame->dynlex_cache_reg;
1453
478k
                *type = cur_frame->dynlex_cache_type;
1454
478k
                if (fcost+icost > 5)
1455
94.9k
                    try_cache_dynlex(tc, initial_frame, cur_frame, name, result, *type, fcost, icost);
1456
478k
                if (dlog) {
1457
0
                    fprintf(dlog, "C %s %d %d %d %d %"PRIu64" %"PRIu64" %"PRIu64"\n", c_name, fcost, icost, ecost, xcost, last_time, start_time, uv_hrtime());
1458
0
                    fflush(dlog);
1459
0
                    MVM_free(c_name);
1460
0
                    tc->instance->dynvar_log_lasttime = uv_hrtime();
1461
0
                }
1462
478k
                *found_frame = cur_frame;
1463
478k
                return result;
1464
478k
            }
1465
1.29M
            else
1466
815k
                xcost++;
1467
1.29M
        }
1468
3.35M
        else
1469
2.06M
            ecost++;
1470
3.35M
1471
3.35M
        /* Now look in the frame itself. */
1472
2.87M
        if ((lexical_names = cur_frame->static_info->body.lexical_names)) {
1473
1.50M
            MVMLexicalRegistry *entry;
1474
1.50M
            MVM_HASH_GET(tc, lexical_names, name, entry)
1475
1.50M
            if (entry) {
1476
184k
                MVMRegister *result = &cur_frame->env[entry->value];
1477
184k
                *type = cur_frame->static_info->body.lexical_types[entry->value];
1478
184k
                if (vivify && *type == MVM_reg_obj && !result->o) {
1479
0
                    MVMROOT(tc, cur_frame, {
1480
0
                    MVMROOT(tc, initial_frame, {
1481
0
                    MVMROOT(tc, name, {
1482
0
                        MVM_frame_vivify_lexical(tc, cur_frame, entry->value);
1483
0
                    });
1484
0
                    });
1485
0
                    });
1486
0
                }
1487
184k
                if (dlog) {
1488
0
                    fprintf(dlog, "F %s %d %d %d %d %"PRIu64" %"PRIu64" %"PRIu64"\n", c_name, fcost, icost, ecost, xcost, last_time, start_time, uv_hrtime());
1489
0
                    fflush(dlog);
1490
0
                    MVM_free(c_name);
1491
0
                    tc->instance->dynvar_log_lasttime = uv_hrtime();
1492
0
                }
1493
184k
                if (fcost+icost > 1)
1494
142k
                    try_cache_dynlex(tc, initial_frame, cur_frame, name, result, *type, fcost, icost);
1495
184k
                *found_frame = cur_frame;
1496
184k
                return result;
1497
184k
            }
1498
1.50M
        }
1499
2.69M
        fcost++;
1500
2.69M
        cur_frame = cur_frame->caller;
1501
2.69M
    }
1502
27.5k
    if (dlog) {
1503
0
        fprintf(dlog, "N %s %d %d %d %d %"PRIu64" %"PRIu64" %"PRIu64"\n", c_name, fcost, icost, ecost, xcost, last_time, start_time, uv_hrtime());
1504
0
        fflush(dlog);
1505
0
        MVM_free(c_name);
1506
0
        tc->instance->dynvar_log_lasttime = uv_hrtime();
1507
0
    }
1508
27.5k
    *found_frame = NULL;
1509
27.5k
    return NULL;
1510
690k
}
1511
1512
681k
MVMObject * MVM_frame_getdynlex(MVMThreadContext *tc, MVMString *name, MVMFrame *cur_frame) {
1513
681k
    MVMuint16 type;
1514
681k
    MVMFrame *found_frame;
1515
681k
    MVMRegister *lex_reg = MVM_frame_find_contextual_by_name(tc, name, &type, cur_frame, 1, &found_frame);
1516
681k
    MVMObject *result = NULL, *result_type = NULL;
1517
681k
    if (lex_reg) {
1518
654k
        switch (type) {
1519
0
            case MVM_reg_int64:
1520
0
                result_type = (*tc->interp_cu)->body.hll_config->int_box_type;
1521
0
                if (!result_type)
1522
0
                    MVM_exception_throw_adhoc(tc, "missing int box type");
1523
0
                result = REPR(result_type)->allocate(tc, STABLE(result_type));
1524
0
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&result);
1525
0
                if (REPR(result)->initialize)
1526
0
                    REPR(result)->initialize(tc, STABLE(result), result, OBJECT_BODY(result));
1527
0
                REPR(result)->box_funcs.set_int(tc, STABLE(result), result,
1528
0
                    OBJECT_BODY(result), lex_reg->i64);
1529
0
                MVM_gc_root_temp_pop(tc);
1530
0
                break;
1531
0
            case MVM_reg_num64:
1532
0
                result_type = (*tc->interp_cu)->body.hll_config->num_box_type;
1533
0
                if (!result_type)
1534
0
                    MVM_exception_throw_adhoc(tc, "missing num box type");
1535
0
                result = REPR(result_type)->allocate(tc, STABLE(result_type));
1536
0
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&result);
1537
0
                if (REPR(result)->initialize)
1538
0
                    REPR(result)->initialize(tc, STABLE(result), result, OBJECT_BODY(result));
1539
0
                REPR(result)->box_funcs.set_num(tc, STABLE(result), result,
1540
0
                    OBJECT_BODY(result), lex_reg->n64);
1541
0
                MVM_gc_root_temp_pop(tc);
1542
0
                break;
1543
0
            case MVM_reg_str:
1544
0
                result_type = (*tc->interp_cu)->body.hll_config->str_box_type;
1545
0
                if (!result_type)
1546
0
                    MVM_exception_throw_adhoc(tc, "missing str box type");
1547
0
                result = REPR(result_type)->allocate(tc, STABLE(result_type));
1548
0
                MVM_gc_root_temp_push(tc, (MVMCollectable **)&result);
1549
0
                if (REPR(result)->initialize)
1550
0
                    REPR(result)->initialize(tc, STABLE(result), result, OBJECT_BODY(result));
1551
0
                REPR(result)->box_funcs.set_str(tc, STABLE(result), result,
1552
0
                    OBJECT_BODY(result), lex_reg->s);
1553
0
                MVM_gc_root_temp_pop(tc);
1554
0
                break;
1555
654k
            case MVM_reg_obj:
1556
654k
                result = lex_reg->o;
1557
654k
                break;
1558
0
            default:
1559
0
                MVM_exception_throw_adhoc(tc, "invalid register type in getdynlex: %d", type);
1560
654k
        }
1561
654k
    }
1562
681k
    return result;
1563
681k
}
1564
1565
9.12k
void MVM_frame_binddynlex(MVMThreadContext *tc, MVMString *name, MVMObject *value, MVMFrame *cur_frame) {
1566
9.12k
    MVMuint16 type;
1567
9.12k
    MVMFrame *found_frame;
1568
9.12k
    MVMRegister *lex_reg = MVM_frame_find_contextual_by_name(tc, name, &type, cur_frame, 0, &found_frame);
1569
9.12k
    if (!lex_reg) {
1570
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1571
0
        char *waste[] = { c_name, NULL };
1572
0
        MVM_exception_throw_adhoc_free(tc, waste, "No contextual found with name '%s'",
1573
0
            c_name);
1574
0
    }
1575
9.12k
    switch (type) {
1576
0
        case MVM_reg_int64:
1577
0
            lex_reg->i64 = REPR(value)->box_funcs.get_int(tc,
1578
0
                STABLE(value), value, OBJECT_BODY(value));
1579
0
            break;
1580
0
        case MVM_reg_num64:
1581
0
            lex_reg->n64 = REPR(value)->box_funcs.get_num(tc,
1582
0
                STABLE(value), value, OBJECT_BODY(value));
1583
0
            break;
1584
0
        case MVM_reg_str:
1585
0
            MVM_ASSIGN_REF(tc, &(found_frame->header), lex_reg->s,
1586
0
                REPR(value)->box_funcs.get_str(tc, STABLE(value), value, OBJECT_BODY(value)));
1587
0
            break;
1588
9.12k
        case MVM_reg_obj:
1589
9.12k
            MVM_ASSIGN_REF(tc, &(found_frame->header), lex_reg->o, value);
1590
9.12k
            break;
1591
0
        default:
1592
0
            MVM_exception_throw_adhoc(tc, "invalid register type in binddynlex");
1593
9.12k
    }
1594
9.12k
}
1595
1596
/* Returns the storage unit for the lexical in the specified frame. Does not
1597
 * try to vivify anything - gets exactly what is there. */
1598
4.58k
MVMRegister * MVM_frame_lexical(MVMThreadContext *tc, MVMFrame *f, MVMString *name) {
1599
4.58k
    MVMLexicalRegistry *lexical_names = f->static_info->body.lexical_names;
1600
4.58k
    if (lexical_names) {
1601
4.58k
        MVMLexicalRegistry *entry;
1602
4.58k
        MVM_HASH_GET(tc, lexical_names, name, entry)
1603
4.58k
        if (entry)
1604
4.58k
            return &f->env[entry->value];
1605
4.58k
    }
1606
4.58k
1607
0
    {
1608
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1609
0
        char *waste[] = { c_name, NULL };
1610
0
        MVM_exception_throw_adhoc_free(tc, waste, "Frame has no lexical with name '%s'",
1611
0
            c_name);
1612
0
    }
1613
0
}
1614
1615
/* Returns the storage unit for the lexical in the specified frame. */
1616
0
MVMRegister * MVM_frame_try_get_lexical(MVMThreadContext *tc, MVMFrame *f, MVMString *name, MVMuint16 type) {
1617
0
    MVMLexicalRegistry *lexical_names = f->static_info->body.lexical_names;
1618
0
    if (lexical_names) {
1619
0
        MVMLexicalRegistry *entry;
1620
0
        MVM_HASH_GET(tc, lexical_names, name, entry)
1621
0
        if (entry && f->static_info->body.lexical_types[entry->value] == type) {
1622
0
            MVMRegister *result = &f->env[entry->value];
1623
0
            if (type == MVM_reg_obj && !result->o)
1624
0
                MVM_frame_vivify_lexical(tc, f, entry->value);
1625
0
            return result;
1626
0
        }
1627
0
    }
1628
0
    return NULL;
1629
0
}
1630
1631
/* Returns the primitive type specification for a lexical. */
1632
10.3k
MVMuint16 MVM_frame_lexical_primspec(MVMThreadContext *tc, MVMFrame *f, MVMString *name) {
1633
10.3k
    MVMLexicalRegistry *lexical_names = f->static_info->body.lexical_names;
1634
10.3k
    if (lexical_names) {
1635
10.3k
        MVMLexicalRegistry *entry;
1636
10.3k
        MVM_HASH_GET(tc, lexical_names, name, entry)
1637
10.3k
        if (entry) {
1638
10.3k
            switch (f->static_info->body.lexical_types[entry->value]) {
1639
0
                case MVM_reg_int64:
1640
0
                    return MVM_STORAGE_SPEC_BP_INT;
1641
0
                case MVM_reg_num64:
1642
0
                    return MVM_STORAGE_SPEC_BP_NUM;
1643
0
                case MVM_reg_str:
1644
0
                    return MVM_STORAGE_SPEC_BP_STR;
1645
10.3k
                case MVM_reg_obj:
1646
10.3k
                    return MVM_STORAGE_SPEC_BP_NONE;
1647
0
                default:
1648
0
                {
1649
0
                    char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1650
0
                    char *waste[] = { c_name, NULL };
1651
0
                    MVM_exception_throw_adhoc_free(tc, waste,
1652
0
                        "Unhandled lexical type in lexprimspec for '%s'",
1653
0
                        c_name);
1654
0
                }
1655
10.3k
            }
1656
10.3k
        }
1657
10.3k
    }
1658
0
    {
1659
0
        char *c_name = MVM_string_utf8_encode_C_string(tc, name);
1660
0
        char *waste[] = { c_name, NULL };
1661
0
        MVM_exception_throw_adhoc_free(tc, waste, "Frame has no lexical with name '%s'",
1662
0
            c_name);
1663
0
    }
1664
0
}
1665
1666
8.11M
static MVMObject * find_invokee_internal(MVMThreadContext *tc, MVMObject *code, MVMCallsite **tweak_cs, MVMInvocationSpec *is) {
1667
8.11M
    if (!MVM_is_null(tc, is->class_handle)) {
1668
8.11M
        MVMRegister dest;
1669
8.11M
        if (!IS_CONCRETE(code))
1670
0
            MVM_exception_throw_adhoc(tc, "Can not invoke a code type object");
1671
8.11M
        REPR(code)->attr_funcs.get_attribute(tc,
1672
8.11M
            STABLE(code), code, OBJECT_BODY(code),
1673
8.11M
            is->class_handle, is->attr_name,
1674
8.11M
            is->hint, &dest, MVM_reg_obj);
1675
8.11M
        code = dest.o;
1676
8.11M
    }
1677
3
    else {
1678
3
        /* Need to tweak the callsite and args to include the code object
1679
3
         * being invoked. */
1680
3
        if (tweak_cs) {
1681
3
            MVMCallsite *orig = *tweak_cs;
1682
3
            if (orig->with_invocant) {
1683
0
                *tweak_cs = orig->with_invocant;
1684
0
            }
1685
3
            else {
1686
3
                MVMCallsite *new   = MVM_calloc(1, sizeof(MVMCallsite));
1687
3
                MVMint32     fsize = orig->flag_count;
1688
3
                new->flag_count    = fsize + 1;
1689
3
                new->arg_flags     = MVM_malloc(new->flag_count * sizeof(MVMCallsiteEntry));
1690
3
                new->arg_flags[0]  = MVM_CALLSITE_ARG_OBJ;
1691
3
                memcpy(new->arg_flags + 1, orig->arg_flags, fsize);
1692
3
                new->arg_count      = orig->arg_count + 1;
1693
3
                new->num_pos        = orig->num_pos + 1;
1694
3
                new->has_flattening = orig->has_flattening;
1695
3
                new->is_interned    = 0;
1696
3
                new->with_invocant  = NULL;
1697
3
                *tweak_cs = orig->with_invocant = new;
1698
3
            }
1699
3
            memmove(tc->cur_frame->args + 1, tc->cur_frame->args,
1700
3
                orig->arg_count * sizeof(MVMRegister));
1701
3
            tc->cur_frame->args[0].o = code;
1702
3
            tc->cur_frame->cur_args_callsite = *tweak_cs; /* Keep in sync. */
1703
3
        }
1704
0
        else {
1705
0
            MVM_exception_throw_adhoc(tc,
1706
0
                "Cannot invoke object with invocation handler in this context");
1707
0
        }
1708
3
        code = is->invocation_handler;
1709
3
    }
1710
8.11M
    return code;
1711
8.11M
}
1712
1713
347k
MVMObject * MVM_frame_find_invokee(MVMThreadContext *tc, MVMObject *code, MVMCallsite **tweak_cs) {
1714
347k
    if (MVM_is_null(tc, code))
1715
0
        MVM_exception_throw_adhoc(tc, "Cannot invoke null object");
1716
347k
    if (STABLE(code)->invoke == MVM_6model_invoke_default) {
1717
346k
        MVMInvocationSpec *is = STABLE(code)->invocation_spec;
1718
346k
        if (!is) {
1719
0
            MVM_exception_throw_adhoc(tc, "Cannot invoke this object (REPR: %s; %s)",
1720
0
                REPR(code)->name, STABLE(code)->debug_name);
1721
0
        }
1722
346k
        code = find_invokee_internal(tc, code, tweak_cs, is);
1723
346k
    }
1724
347k
    return code;
1725
347k
}
1726
1727
MVM_USED_BY_JIT
1728
10.8M
MVMObject * MVM_frame_find_invokee_multi_ok(MVMThreadContext *tc, MVMObject *code, MVMCallsite **tweak_cs, MVMRegister *args) {
1729
10.8M
    if (!code)
1730
0
        MVM_exception_throw_adhoc(tc, "Cannot invoke null object");
1731
10.8M
    if (STABLE(code)->invoke == MVM_6model_invoke_default) {
1732
7.90M
        MVMInvocationSpec *is = STABLE(code)->invocation_spec;
1733
7.90M
        if (!is) {
1734
0
            MVM_exception_throw_adhoc(tc, "Cannot invoke this object (REPR: %s; %s)", REPR(code)->name, STABLE(code)->debug_name);
1735
0
        }
1736
7.90M
        if (!MVM_is_null(tc, is->md_class_handle)) {
1737
7.26M
            /* We might be able to dig straight into the multi cache and not
1738
7.26M
             * have to invoke the proto. */
1739
7.26M
            MVMRegister dest;
1740
7.26M
            if (!IS_CONCRETE(code))
1741
0
                MVM_exception_throw_adhoc(tc, "Can not invoke a code type object");
1742
7.26M
            REPR(code)->attr_funcs.get_attribute(tc,
1743
7.26M
                STABLE(code), code, OBJECT_BODY(code),
1744
7.26M
                is->md_class_handle, is->md_valid_attr_name,
1745
7.26M
                is->md_valid_hint, &dest, MVM_reg_int64);
1746
7.26M
            if (dest.i64) {
1747
134k
                REPR(code)->attr_funcs.get_attribute(tc,
1748
134k
                    STABLE(code), code, OBJECT_BODY(code),
1749
134k
                    is->md_class_handle, is->md_cache_attr_name,
1750
134k
                    is->md_cache_hint, &dest, MVM_reg_obj);
1751
134k
                if (!MVM_is_null(tc, dest.o)) {
1752
134k
                    MVMObject *result = MVM_multi_cache_find_callsite_args(tc,
1753
134k
                        dest.o, *tweak_cs, args);
1754
134k
                    if (result)
1755
130k
                        return MVM_frame_find_invokee(tc, result, tweak_cs);
1756
134k
                }
1757
134k
            }
1758
7.26M
        }
1759
7.76M
        code = find_invokee_internal(tc, code, tweak_cs, is);
1760
7.76M
    }
1761
10.6M
    return code;
1762
10.8M
}
1763
1764
/* Creates a MVMContent wrapper object around an MVMFrame. */
1765
2.61k
MVMObject * MVM_frame_context_wrapper(MVMThreadContext *tc, MVMFrame *f) {
1766
2.61k
    MVMObject *ctx;
1767
2.61k
    f = MVM_frame_force_to_heap(tc, f);
1768
2.61k
    MVMROOT(tc, f, {
1769
2.61k
        ctx = MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTContext);
1770
2.61k
        MVM_ASSIGN_REF(tc, &(ctx->header), ((MVMContext *)ctx)->body.context, f);
1771
2.61k
    });
1772
2.61k
    return ctx;
1773
2.61k
}