Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/core/nativecall.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#ifndef _WIN32
3
#include <dlfcn.h>
4
#endif
5
#include <platform/threads.h>
6
#include <platform/time.h>
7
8
/* Grabs a NativeCall body. */
9
6
MVMNativeCallBody * MVM_nativecall_get_nc_body(MVMThreadContext *tc, MVMObject *obj) {
10
6
    if (REPR(obj)->ID == MVM_REPR_ID_MVMNativeCall)
11
6
        return (MVMNativeCallBody *)OBJECT_BODY(obj);
12
6
    else
13
0
        return (MVMNativeCallBody *)REPR(obj)->box_funcs.get_boxed_ref(tc,
14
0
            STABLE(obj), obj, OBJECT_BODY(obj), MVM_REPR_ID_MVMNativeCall);
15
6
}
16
17
/* Gets the flag for whether to free a string after a call or not. */
18
2
static MVMint16 get_str_free_flag(MVMThreadContext *tc, MVMObject *info) {
19
2
    MVMString *flag = tc->instance->str_consts.free_str;
20
2
    if (MVM_repr_exists_key(tc, info, flag))
21
2
        if (!MVM_repr_get_int(tc, MVM_repr_at_key_o(tc, info, flag)))
22
0
            return MVM_NATIVECALL_ARG_NO_FREE_STR;
23
2
    return MVM_NATIVECALL_ARG_FREE_STR;
24
2
}
25
26
/* Gets the flag for whether an arg is rw or not. */
27
2
static MVMint16 get_rw_flag(MVMThreadContext *tc, MVMObject *info) {
28
2
    MVMString *flag = tc->instance->str_consts.rw;
29
2
    if (MVM_repr_exists_key(tc, info, flag)) {
30
0
        if (MVM_repr_get_int(tc, MVM_repr_at_key_o(tc, info, flag)))
31
0
            return MVM_NATIVECALL_ARG_RW;
32
0
    }
33
2
    return MVM_NATIVECALL_ARG_NO_RW;
34
2
}
35
36
/* Gets the flag for whether an arg is rw or not. */
37
0
static MVMint16 get_refresh_flag(MVMThreadContext *tc, MVMObject *info) {
38
0
    MVMString *typeobj_str = tc->instance->str_consts.typeobj;
39
0
    if (MVM_repr_exists_key(tc, info, typeobj_str)) {
40
0
        MVMObject *typeobj = MVM_repr_at_key_o(tc, info, typeobj_str);
41
0
42
0
        if (REPR(typeobj)->ID == MVM_REPR_ID_MVMCArray) {
43
0
            MVMCArrayREPRData  *repr_data = (MVMCArrayREPRData *)STABLE(typeobj)->REPR_data;
44
0
45
0
            /* No need to refresh numbers. They're stored directly in the array. */
46
0
            if (repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_NUMERIC)
47
0
                return MVM_NATIVECALL_ARG_NO_REFRESH;
48
0
49
0
            return MVM_NATIVECALL_ARG_REFRESH;
50
0
        }
51
0
    }
52
0
53
0
    /* We don't know, so fail safe by assuming we have to refresh */
54
0
    return MVM_NATIVECALL_ARG_REFRESH;
55
0
}
56
57
/* Takes a hash describing a type hands back an argument type code. */
58
6
MVMint16 MVM_nativecall_get_arg_type(MVMThreadContext *tc, MVMObject *info, MVMint16 is_return) {
59
6
    MVMString *typename = MVM_repr_get_str(tc, MVM_repr_at_key_o(tc, info,
60
6
        tc->instance->str_consts.type));
61
6
    char *ctypename = MVM_string_utf8_encode_C_string(tc, typename);
62
6
    MVMint16 result;
63
6
    if (strcmp(ctypename, "void") == 0) {
64
2
        if (!is_return) {
65
0
            MVM_free(ctypename);
66
0
            MVM_exception_throw_adhoc(tc,
67
0
                "Cannot use 'void' type except for on native call return values");
68
0
        }
69
2
        result = MVM_NATIVECALL_ARG_VOID;
70
2
    }
71
4
    else if (strcmp(ctypename, "char") == 0)
72
0
        result = MVM_NATIVECALL_ARG_CHAR | get_rw_flag(tc, info);
73
4
    else if (strcmp(ctypename, "short") == 0)
74
0
        result = MVM_NATIVECALL_ARG_SHORT | get_rw_flag(tc, info);
75
4
    else if (strcmp(ctypename, "int") == 0)
76
0
        result = MVM_NATIVECALL_ARG_INT | get_rw_flag(tc, info);
77
4
    else if (strcmp(ctypename, "long") == 0)
78
0
        result = MVM_NATIVECALL_ARG_LONG | get_rw_flag(tc, info);
79
4
    else if (strcmp(ctypename, "longlong") == 0)
80
0
        result = MVM_NATIVECALL_ARG_LONGLONG | get_rw_flag(tc, info);
81
4
    else if (strcmp(ctypename, "uchar") == 0)
82
0
        result = MVM_NATIVECALL_ARG_UCHAR | get_rw_flag(tc, info);
83
4
    else if (strcmp(ctypename, "ushort") == 0)
84
0
        result = MVM_NATIVECALL_ARG_USHORT | get_rw_flag(tc, info);
85
4
    else if (strcmp(ctypename, "uint") == 0)
86
0
        result = MVM_NATIVECALL_ARG_UINT | get_rw_flag(tc, info);
87
4
    else if (strcmp(ctypename, "ulong") == 0)
88
0
        result = MVM_NATIVECALL_ARG_ULONG | get_rw_flag(tc, info);
89
4
    else if (strcmp(ctypename, "ulonglong") == 0)
90
0
        result = MVM_NATIVECALL_ARG_ULONGLONG | get_rw_flag(tc, info);
91
4
    else if (strcmp(ctypename, "float") == 0)
92
0
        result = MVM_NATIVECALL_ARG_FLOAT | get_rw_flag(tc, info);
93
4
    else if (strcmp(ctypename, "double") == 0)
94
0
        result = MVM_NATIVECALL_ARG_DOUBLE | get_rw_flag(tc, info);
95
4
    else if (strcmp(ctypename, "asciistr") == 0)
96
0
        result = MVM_NATIVECALL_ARG_ASCIISTR | get_str_free_flag(tc, info);
97
4
    else if (strcmp(ctypename, "utf8str") == 0)
98
2
        result = MVM_NATIVECALL_ARG_UTF8STR | get_str_free_flag(tc, info);
99
2
    else if (strcmp(ctypename, "utf16str") == 0)
100
0
        result = MVM_NATIVECALL_ARG_UTF16STR | get_str_free_flag(tc, info);
101
2
    else if (strcmp(ctypename, "cstruct") == 0)
102
0
        result = MVM_NATIVECALL_ARG_CSTRUCT;
103
2
    else if (strcmp(ctypename, "cppstruct") == 0)
104
0
        result = MVM_NATIVECALL_ARG_CPPSTRUCT;
105
2
    else if (strcmp(ctypename, "cpointer") == 0)
106
2
        result = MVM_NATIVECALL_ARG_CPOINTER | get_rw_flag(tc, info);
107
0
    else if (strcmp(ctypename, "carray") == 0)
108
0
        result = MVM_NATIVECALL_ARG_CARRAY | get_refresh_flag(tc, info);
109
0
    else if (strcmp(ctypename, "cunion") == 0)
110
0
        result = MVM_NATIVECALL_ARG_CUNION;
111
0
    else if (strcmp(ctypename, "vmarray") == 0)
112
0
        result = MVM_NATIVECALL_ARG_VMARRAY;
113
0
    else if (strcmp(ctypename, "callback") == 0)
114
0
        result = MVM_NATIVECALL_ARG_CALLBACK;
115
0
    else {
116
0
        char *waste[] = { ctypename, NULL };
117
0
        MVM_exception_throw_adhoc_free(tc, waste, "Unknown type '%s' used for native call", ctypename);
118
0
    }
119
6
    MVM_free(ctypename);
120
6
    return result;
121
6
}
122
123
0
MVMObject * MVM_nativecall_make_int(MVMThreadContext *tc, MVMObject *type, MVMint64 value) {
124
0
    return type ? MVM_repr_box_int(tc, type, value) : NULL;
125
0
}
126
127
0
MVMObject * MVM_nativecall_make_uint(MVMThreadContext *tc, MVMObject *type, MVMuint64 value) {
128
0
    return type ? MVM_repr_box_int(tc, type, (MVMint64)value) : NULL;
129
0
}
130
131
0
MVMObject * MVM_nativecall_make_num(MVMThreadContext *tc, MVMObject *type, MVMnum64 value) {
132
0
    return type ? MVM_repr_box_num(tc, type, value) : NULL;
133
0
}
134
135
0
MVMObject * MVM_nativecall_make_str(MVMThreadContext *tc, MVMObject *type, MVMint16 ret_type, char *cstring) {
136
0
    MVMObject *result = type;
137
0
    if (cstring && type) {
138
0
        MVMString *value;
139
0
140
0
        MVM_gc_root_temp_push(tc, (MVMCollectable **)&type);
141
0
142
0
        switch (ret_type & MVM_NATIVECALL_ARG_TYPE_MASK) {
143
0
            case MVM_NATIVECALL_ARG_ASCIISTR:
144
0
                value = MVM_string_ascii_decode(tc, tc->instance->VMString, cstring, strlen(cstring));
145
0
                break;
146
0
            case MVM_NATIVECALL_ARG_UTF8STR:
147
0
                value = MVM_string_utf8_decode(tc, tc->instance->VMString, cstring, strlen(cstring));
148
0
                break;
149
0
            case MVM_NATIVECALL_ARG_UTF16STR:
150
0
                value = MVM_string_utf16_decode(tc, tc->instance->VMString, cstring, strlen(cstring));
151
0
                break;
152
0
            default:
153
0
                MVM_exception_throw_adhoc(tc, "Internal error: unhandled encoding");
154
0
        }
155
0
156
0
        MVM_gc_root_temp_pop(tc);
157
0
        result = MVM_repr_box_str(tc, type, value);
158
0
        if (ret_type & MVM_NATIVECALL_ARG_FREE_STR)
159
0
            MVM_free(cstring);
160
0
    }
161
0
162
0
    return result;
163
0
}
164
165
/* Constructs a boxed result using a CStruct REPR type. */
166
0
MVMObject * MVM_nativecall_make_cstruct(MVMThreadContext *tc, MVMObject *type, void *cstruct) {
167
0
    MVMObject *result = type;
168
0
    if (cstruct && type) {
169
0
        MVMCStructREPRData *repr_data = (MVMCStructREPRData *)STABLE(type)->REPR_data;
170
0
        if (REPR(type)->ID != MVM_REPR_ID_MVMCStruct)
171
0
            MVM_exception_throw_adhoc(tc,
172
0
                "Native call expected return type with CStruct representation, but got a %s (%s)", REPR(type)->name, MVM_6model_get_debug_name(tc, type));
173
0
        result = REPR(type)->allocate(tc, STABLE(type));
174
0
        ((MVMCStruct *)result)->body.cstruct = cstruct;
175
0
        if (repr_data->num_child_objs)
176
0
            ((MVMCStruct *)result)->body.child_objs = MVM_calloc(repr_data->num_child_objs, sizeof(MVMObject *));
177
0
    }
178
0
    return result;
179
0
}
180
181
/* Constructs a boxed result using a CUnion REPR type. */
182
0
MVMObject * MVM_nativecall_make_cunion(MVMThreadContext *tc, MVMObject *type, void *cunion) {
183
0
    MVMObject *result = type;
184
0
    if (cunion && type) {
185
0
        MVMCUnionREPRData *repr_data = (MVMCUnionREPRData *)STABLE(type)->REPR_data;
186
0
        if (REPR(type)->ID != MVM_REPR_ID_MVMCUnion)
187
0
            MVM_exception_throw_adhoc(tc,
188
0
                "Native call expected return type with CUnion representation, but got a %s (%s)", REPR(type)->name, MVM_6model_get_debug_name(tc, type));
189
0
        result = REPR(type)->allocate(tc, STABLE(type));
190
0
        ((MVMCUnion *)result)->body.cunion = cunion;
191
0
        if (repr_data->num_child_objs)
192
0
            ((MVMCUnion *)result)->body.child_objs = MVM_calloc(repr_data->num_child_objs, sizeof(MVMObject *));
193
0
    }
194
0
    return result;
195
0
}
196
197
0
MVMObject * MVM_nativecall_make_cppstruct(MVMThreadContext *tc, MVMObject *type, void *cppstruct) {
198
0
    MVMObject *result = type;
199
0
    if (cppstruct && type) {
200
0
        MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)STABLE(type)->REPR_data;
201
0
        if (REPR(type)->ID != MVM_REPR_ID_MVMCPPStruct)
202
0
            MVM_exception_throw_adhoc(tc,
203
0
                "Native call expected return type with CPPStruct representation, but got a %s (%s)", REPR(type)->name, MVM_6model_get_debug_name(tc, type));
204
0
        result = REPR(type)->allocate(tc, STABLE(type));
205
0
        ((MVMCPPStruct *)result)->body.cppstruct = cppstruct;
206
0
        if (repr_data->num_child_objs)
207
0
            ((MVMCPPStruct *)result)->body.child_objs = MVM_calloc(repr_data->num_child_objs, sizeof(MVMObject *));
208
0
    }
209
0
    return result;
210
0
}
211
212
/* Constructs a boxed result using a CPointer REPR type. */
213
1
MVMObject * MVM_nativecall_make_cpointer(MVMThreadContext *tc, MVMObject *type, void *ptr) {
214
1
    MVMObject *result = type;
215
1
    if (ptr && type) {
216
1
        if (REPR(type)->ID != MVM_REPR_ID_MVMCPointer)
217
0
            MVM_exception_throw_adhoc(tc,
218
0
                "Native call expected return type with CPointer representation, but got a %s (%s)", REPR(type)->name, MVM_6model_get_debug_name(tc, type));
219
1
        result = REPR(type)->allocate(tc, STABLE(type));
220
1
        ((MVMCPointer *)result)->body.ptr = ptr;
221
1
    }
222
1
    return result;
223
1
}
224
225
/* Constructs a boxed result using a CArray REPR type. */
226
0
MVMObject * MVM_nativecall_make_carray(MVMThreadContext *tc, MVMObject *type, void *carray) {
227
0
    MVMObject *result = type;
228
0
    if (carray && type) {
229
0
        if (REPR(type)->ID != MVM_REPR_ID_MVMCArray)
230
0
            MVM_exception_throw_adhoc(tc,
231
0
                "Native call expected return type with CArray representation, but got a %s (%s)", REPR(type)->name, MVM_6model_get_debug_name(tc, type));
232
0
        result = REPR(type)->allocate(tc, STABLE(type));
233
0
        ((MVMCArray *)result)->body.storage = carray;
234
0
    }
235
0
    return result;
236
0
}
237
238
0
signed char MVM_nativecall_unmarshal_char(MVMThreadContext *tc, MVMObject *value) {
239
0
    return (signed char)MVM_repr_get_int(tc, value);
240
0
}
241
242
0
signed short MVM_nativecall_unmarshal_short(MVMThreadContext *tc, MVMObject *value) {
243
0
    return (signed short)MVM_repr_get_int(tc, value);
244
0
}
245
246
0
signed int MVM_nativecall_unmarshal_int(MVMThreadContext *tc, MVMObject *value) {
247
0
    return (signed int)MVM_repr_get_int(tc, value);
248
0
}
249
250
0
signed long MVM_nativecall_unmarshal_long(MVMThreadContext *tc, MVMObject *value) {
251
0
    return (signed long)MVM_repr_get_int(tc, value);
252
0
}
253
254
0
signed long long MVM_nativecall_unmarshal_longlong(MVMThreadContext *tc, MVMObject *value) {
255
0
    return (signed long long)MVM_repr_get_int(tc, value);
256
0
}
257
258
0
unsigned char MVM_nativecall_unmarshal_uchar(MVMThreadContext *tc, MVMObject *value) {
259
0
    return (unsigned char)MVM_repr_get_int(tc, value);
260
0
}
261
262
0
unsigned short MVM_nativecall_unmarshal_ushort(MVMThreadContext *tc, MVMObject *value) {
263
0
    return (unsigned short)MVM_repr_get_int(tc, value);
264
0
}
265
266
0
unsigned int MVM_nativecall_unmarshal_uint(MVMThreadContext *tc, MVMObject *value) {
267
0
    return (unsigned int)MVM_repr_get_int(tc, value);
268
0
}
269
270
0
unsigned long MVM_nativecall_unmarshal_ulong(MVMThreadContext *tc, MVMObject *value) {
271
0
    return (unsigned long)MVM_repr_get_int(tc, value);
272
0
}
273
274
0
unsigned long long MVM_nativecall_unmarshal_ulonglong(MVMThreadContext *tc, MVMObject *value) {
275
0
    return (unsigned long long)MVM_repr_get_int(tc, value);
276
0
}
277
278
0
float MVM_nativecall_unmarshal_float(MVMThreadContext *tc, MVMObject *value) {
279
0
    return (float)MVM_repr_get_num(tc, value);
280
0
}
281
282
0
double MVM_nativecall_unmarshal_double(MVMThreadContext *tc, MVMObject *value) {
283
0
    return (double)MVM_repr_get_num(tc, value);
284
0
}
285
286
2
char * MVM_nativecall_unmarshal_string(MVMThreadContext *tc, MVMObject *value, MVMint16 type, MVMint16 *free) {
287
2
    if (IS_CONCRETE(value)) {
288
2
        MVMString *value_str = MVM_repr_get_str(tc, value);
289
2
290
2
        /* Encode string. */
291
2
        char *str;
292
2
        switch (type & MVM_NATIVECALL_ARG_TYPE_MASK) {
293
0
            case MVM_NATIVECALL_ARG_ASCIISTR:
294
0
                str = MVM_string_ascii_encode_any(tc, value_str);
295
0
                break;
296
0
            case MVM_NATIVECALL_ARG_UTF16STR:
297
0
                str = MVM_string_utf16_encode(tc, value_str, 0);
298
0
                break;
299
2
            default:
300
2
                str = MVM_string_utf8_encode_C_string(tc, value_str);
301
2
        }
302
2
303
2
        /* Set whether to free it or not. */
304
2
        if (free) {
305
2
            if (REPR(value)->ID == MVM_REPR_ID_MVMCStr)
306
0
                *free = 0; /* Manually managed. */
307
2
            else if (free && type & MVM_NATIVECALL_ARG_FREE_STR_MASK)
308
2
                *free = 1;
309
2
            else
310
0
                *free = 0;
311
2
        }
312
2
313
2
        return str;
314
2
    }
315
0
    else {
316
0
        return NULL;
317
0
    }
318
2
}
319
320
0
void * MVM_nativecall_unmarshal_cstruct(MVMThreadContext *tc, MVMObject *value) {
321
0
    if (!IS_CONCRETE(value))
322
0
        return NULL;
323
0
    else if (REPR(value)->ID == MVM_REPR_ID_MVMCStruct)
324
0
        return ((MVMCStruct *)value)->body.cstruct;
325
0
    else
326
0
        MVM_exception_throw_adhoc(tc,
327
0
            "Native call expected return type with CStruct representation, but got a %s (%s)", REPR(value)->name, MVM_6model_get_debug_name(tc, value));
328
0
}
329
330
0
void * MVM_nativecall_unmarshal_cppstruct(MVMThreadContext *tc, MVMObject *value) {
331
0
    if (!IS_CONCRETE(value))
332
0
        return NULL;
333
0
    else if (REPR(value)->ID == MVM_REPR_ID_MVMCPPStruct)
334
0
        return ((MVMCPPStruct *)value)->body.cppstruct;
335
0
    else
336
0
        MVM_exception_throw_adhoc(tc,
337
0
            "Native call expected return type with CPPStruct representation, but got a %s (%s)", REPR(value)->name, MVM_6model_get_debug_name(tc, value));
338
0
}
339
340
4
void * MVM_nativecall_unmarshal_cpointer(MVMThreadContext *tc, MVMObject *value) {
341
4
    if (!IS_CONCRETE(value))
342
3
        return NULL;
343
1
    else if (REPR(value)->ID == MVM_REPR_ID_MVMCPointer)
344
1
        return ((MVMCPointer *)value)->body.ptr;
345
1
    else
346
0
        MVM_exception_throw_adhoc(tc,
347
0
            "Native call expected return type with CPointer representation, but got a %s (%s)", REPR(value)->name, MVM_6model_get_debug_name(tc, value));
348
4
}
349
350
0
void * MVM_nativecall_unmarshal_carray(MVMThreadContext *tc, MVMObject *value) {
351
0
    if (!IS_CONCRETE(value))
352
0
        return NULL;
353
0
    else if (REPR(value)->ID == MVM_REPR_ID_MVMCArray)
354
0
        return ((MVMCArray *)value)->body.storage;
355
0
    else
356
0
        MVM_exception_throw_adhoc(tc,
357
0
            "Native call expected return type with CArray representation, but got a %s (%s)", REPR(value)->name, MVM_6model_get_debug_name(tc, value));
358
0
}
359
360
0
void * MVM_nativecall_unmarshal_vmarray(MVMThreadContext *tc, MVMObject *value) {
361
0
    if (!IS_CONCRETE(value))
362
0
        return NULL;
363
0
    else if (REPR(value)->ID == MVM_REPR_ID_VMArray) {
364
0
        MVMArrayBody *body          = &((MVMArray *)value)->body;
365
0
        MVMArrayREPRData *repr_data = (MVMArrayREPRData *)STABLE(value)->REPR_data;
366
0
        size_t start_pos            = body->start * repr_data->elem_size;
367
0
        return ((char *)body->slots.any) + start_pos;
368
0
    }
369
0
    else
370
0
        MVM_exception_throw_adhoc(tc,
371
0
            "Native call expected object with Array representation, but got a %s (%s)", REPR(value)->name, MVM_6model_get_debug_name(tc, value));
372
0
}
373
374
0
void * MVM_nativecall_unmarshal_cunion(MVMThreadContext *tc, MVMObject *value) {
375
0
    if (!IS_CONCRETE(value))
376
0
        return NULL;
377
0
    else if (REPR(value)->ID == MVM_REPR_ID_MVMCUnion)
378
0
        return ((MVMCUnion *)value)->body.cunion;
379
0
    else
380
0
        MVM_exception_throw_adhoc(tc,
381
0
            "Native call expected return type with CUnion representation, but got a %s (%s)", REPR(value)->name, MVM_6model_get_debug_name(tc, value));
382
0
}
383
384
#ifdef _WIN32
385
static const char *dlerror(void)
386
{
387
    static char buf[32];
388
    DWORD dw = GetLastError();
389
    if (dw == 0)
390
        return NULL;
391
    snprintf(buf, 32, "error 0x%"PRIx32"", (MVMuint32)dw);
392
    return buf;
393
}
394
#endif
395
396
14
void init_c_call_node(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMJitNode *node, void *func_ptr, MVMint16 num_args, MVMJitCallArg *args) {
397
14
    node->type = MVM_JIT_NODE_CALL_C;
398
14
    node->u.call.func_ptr = func_ptr;
399
14
    if (0 < num_args) {
400
11
        node->u.call.args = MVM_spesh_alloc(tc, sg, num_args * sizeof(MVMJitCallArg));
401
11
        memcpy(node->u.call.args, args, num_args * sizeof(MVMJitCallArg));
402
11
    }
403
3
    else {
404
3
        node->u.call.args = NULL;
405
3
    }
406
14
    node->u.call.num_args = num_args;
407
14
    node->u.call.has_vargs = 0;
408
14
    node->u.call.rv_mode = MVM_JIT_RV_VOID;
409
14
    node->u.call.rv_idx  = -1;
410
14
}
411
412
5
void save_rv_to_stack(MVMThreadContext *tc, MVMJitNode *node, MVMint32 storage_pos) {
413
5
    node->u.call.rv_mode = MVM_JIT_RV_TO_STACK;
414
5
    node->u.call.rv_idx = storage_pos;
415
5
}
416
417
1
void init_box_call_node(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMJitNode *box_rv_node, void *func_ptr, MVMint16 restype, MVMint16 dst) {
418
1
    MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
419
1
                             { MVM_JIT_REG_DYNIDX, { 2 } },
420
1
                             { MVM_JIT_STACK_VALUE, { 0 } }};
421
1
    init_c_call_node(tc, sg, box_rv_node, func_ptr, 3, args);
422
1
    box_rv_node->next = NULL;
423
1
    if (dst == -1) {
424
1
        box_rv_node->u.call.rv_mode = MVM_JIT_RV_DYNIDX;
425
1
        box_rv_node->u.call.rv_idx = 0;
426
1
    }
427
0
    else {
428
0
        box_rv_node->u.call.args[1].type = MVM_JIT_REG_VAL;
429
0
        box_rv_node->u.call.args[1].v.reg = restype;
430
0
431
0
        box_rv_node->u.call.rv_mode = MVM_JIT_RV_PTR;
432
0
        box_rv_node->u.call.rv_idx = dst;
433
0
    }
434
1
}
435
436
MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(
437
    MVMThreadContext   *tc,
438
    MVMSpeshGraph      *sg,
439
    MVMNativeCallBody  *body,
440
    MVMint16            restype,
441
    MVMint16            dst,
442
    MVMSpeshIns       **arg_ins
443
3
) {
444
3
    MVMJitGraph *jg = MVM_spesh_alloc(tc, sg, sizeof(MVMJitGraph)); /* will actually calloc */
445
3
    MVMJitNode *block_gc_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
446
3
    MVMJitNode *unblock_gc_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
447
3
    MVMJitNode *call_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
448
3
    MVMJitNode *box_rv_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
449
3
    MVMJitCode *jitcode = NULL;
450
3
    MVMJitCallArg block_gc_args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } } };
451
3
452
3
    jg->sg = sg;
453
3
    jg->first_node = block_gc_node;
454
3
    init_c_call_node(tc, sg, block_gc_node,   &MVM_gc_mark_thread_blocked, 1, block_gc_args);
455
3
    block_gc_node->next = call_node;
456
3
    init_c_call_node(tc, sg, call_node, body->entry_point, 0, NULL); /* we handle args manually */
457
3
    save_rv_to_stack(tc, call_node, 0);
458
3
459
3
    init_c_call_node(tc, sg, unblock_gc_node, &MVM_gc_mark_thread_unblocked, 1, block_gc_args);
460
3
461
3
    call_node->next = unblock_gc_node;
462
3
    call_node->u.call.num_args = body->num_args;
463
3
    jg->last_node = unblock_gc_node->next = box_rv_node;
464
3
465
3
    if (0 < body->num_args) {
466
3
        MVMuint16 i = 0, str_arg_count = 0;
467
3
        call_node->u.call.args = MVM_spesh_alloc(tc, sg, body->num_args * sizeof(MVMJitCallArg));
468
6
        for (i = 0; i < body->num_args; i++) {
469
3
            if ((body->arg_types[i] & MVM_NATIVECALL_ARG_TYPE_MASK) == MVM_NATIVECALL_ARG_UTF8STR) {
470
2
                MVMJitNode *unbox_str_node;
471
2
                MVMJitNode *free_str_node;
472
2
473
2
                if (7 < ++str_arg_count) /* only got 7 empty slots in the stack scratch space */
474
0
                    goto fail;
475
2
476
2
                unbox_str_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
477
2
                {
478
2
                    MVMJitCallArg unbox_str_args[] = {
479
2
                        { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
480
2
                        {
481
2
                            dst == -1 ? MVM_JIT_ARG_I64 : MVM_JIT_PARAM_I64 ,
482
2
                            { dst == -1 ? i : arg_ins[i]->operands[1].reg.orig }
483
2
                        }
484
2
                    };
485
2
                    init_c_call_node(tc, sg, unbox_str_node, &MVM_string_utf8_maybe_encode_C_string, 2, unbox_str_args);
486
2
                    save_rv_to_stack(tc, unbox_str_node, str_arg_count);
487
2
                }
488
2
                unbox_str_node->next = jg->first_node;
489
2
                jg->first_node = unbox_str_node;
490
2
491
2
                call_node->u.call.args[i].type = MVM_JIT_STACK_VALUE;
492
2
                call_node->u.call.args[i].v.lit_i64 = str_arg_count;
493
2
494
2
                if ((body->arg_types[i] & MVM_NATIVECALL_ARG_FREE_STR_MASK) != 0) {
495
2
                    MVMJitCallArg free_str_args[] = {
496
2
                        { MVM_JIT_STACK_VALUE , { str_arg_count } }
497
2
                    };
498
2
                    free_str_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
499
2
                    init_c_call_node(tc, sg, free_str_node, &MVM_free, 1, free_str_args);
500
2
                    free_str_node->next = unblock_gc_node->next;
501
2
                    unblock_gc_node->next = free_str_node;
502
2
                }
503
2
            }
504
3
        }
505
6
        for (i = 0; i < body->num_args; i++) {
506
3
            MVMJitArgType arg_type;
507
3
            int is_rw = ((body->arg_types[i] & MVM_NATIVECALL_ARG_RW_MASK) == MVM_NATIVECALL_ARG_RW);
508
3
509
3
            switch (body->arg_types[i] & MVM_NATIVECALL_ARG_TYPE_MASK) {
510
0
                case MVM_NATIVECALL_ARG_CHAR:
511
0
                case MVM_NATIVECALL_ARG_UCHAR:
512
0
                case MVM_NATIVECALL_ARG_SHORT:
513
0
                case MVM_NATIVECALL_ARG_USHORT:
514
0
                case MVM_NATIVECALL_ARG_INT:
515
0
                case MVM_NATIVECALL_ARG_UINT:
516
0
                case MVM_NATIVECALL_ARG_LONG:
517
0
                case MVM_NATIVECALL_ARG_ULONG:
518
0
                case MVM_NATIVECALL_ARG_LONGLONG:
519
0
                case MVM_NATIVECALL_ARG_ULONGLONG:
520
0
                    arg_type = dst == -1
521
0
                        ? is_rw ? MVM_JIT_ARG_I64_RW : MVM_JIT_ARG_I64
522
0
                        : is_rw ? MVM_JIT_PARAM_I64_RW : MVM_JIT_PARAM_I64;
523
0
                    break;
524
1
                case MVM_NATIVECALL_ARG_CPOINTER:
525
1
                    if (is_rw) goto fail;
526
1
                    arg_type = dst == -1 ? MVM_JIT_ARG_PTR : MVM_JIT_PARAM_PTR;
527
1
                    break;
528
0
                case MVM_NATIVECALL_ARG_CARRAY:
529
0
                    if (body->arg_types[i] & MVM_NATIVECALL_ARG_REFRESH_MASK) goto fail;
530
0
                    if (is_rw) goto fail;
531
0
                    arg_type = dst == -1 ? MVM_JIT_ARG_PTR : MVM_JIT_PARAM_PTR;
532
0
                    break;
533
0
                case MVM_NATIVECALL_ARG_VMARRAY:
534
0
                    if (is_rw) goto fail;
535
0
                    arg_type = dst == -1 ? MVM_JIT_ARG_VMARRAY : MVM_JIT_PARAM_VMARRAY;
536
0
                    break;
537
2
                case MVM_NATIVECALL_ARG_UTF8STR:
538
2
                    if (is_rw) goto fail;
539
2
                    continue; /* already handled */
540
0
                default:
541
0
                    goto fail;
542
3
            }
543
1
            call_node->u.call.args[i].type = arg_type;
544
1
            call_node->u.call.args[i].v.lit_i64 = dst == -1 ? i : arg_ins[i]->operands[1].reg.orig;
545
1
        }
546
3
    }
547
3
548
3
    if (body->ret_type == MVM_NATIVECALL_ARG_CHAR
549
3
        || body->ret_type == MVM_NATIVECALL_ARG_UCHAR
550
3
        || body->ret_type == MVM_NATIVECALL_ARG_SHORT
551
3
        || body->ret_type == MVM_NATIVECALL_ARG_USHORT
552
3
        || body->ret_type == MVM_NATIVECALL_ARG_INT
553
3
        || body->ret_type == MVM_NATIVECALL_ARG_UINT
554
3
        || body->ret_type == MVM_NATIVECALL_ARG_LONG
555
3
        || body->ret_type == MVM_NATIVECALL_ARG_ULONG
556
3
        || body->ret_type == MVM_NATIVECALL_ARG_LONGLONG
557
3
        || body->ret_type == MVM_NATIVECALL_ARG_ULONGLONG
558
0
    ) {
559
0
        init_box_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_int, restype, dst);
560
0
    }
561
3
    else if (body->ret_type == MVM_NATIVECALL_ARG_CPOINTER) {
562
1
        init_box_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_cpointer, restype, dst);
563
1
    }
564
2
    else if (body->ret_type == MVM_NATIVECALL_ARG_UTF8STR) {
565
0
        MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
566
0
                                 { MVM_JIT_REG_DYNIDX, { 2 } },
567
0
                                 { MVM_JIT_LITERAL, { MVM_NATIVECALL_ARG_UTF8STR } },
568
0
                                 { MVM_JIT_STACK_VALUE, { 0 } }};
569
0
        init_c_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_str, 4, args);
570
0
        box_rv_node->next = NULL;
571
0
        if (dst == -1) {
572
0
            box_rv_node->u.call.rv_mode = MVM_JIT_RV_DYNIDX;
573
0
            box_rv_node->u.call.rv_idx = 0;
574
0
        }
575
0
        else {
576
0
            box_rv_node->u.call.args[1].type = MVM_JIT_REG_VAL;
577
0
            box_rv_node->u.call.args[1].v.reg = restype;
578
0
579
0
            box_rv_node->u.call.rv_mode = MVM_JIT_RV_PTR;
580
0
            box_rv_node->u.call.rv_idx = dst;
581
0
        }
582
0
    }
583
2
    else if (body->ret_type == MVM_NATIVECALL_ARG_VOID) {
584
2
        call_node->next = unblock_gc_node;
585
2
        unblock_gc_node->next = NULL;
586
2
        jg->last_node = unblock_gc_node;
587
2
    }
588
0
    else {
589
0
        goto fail;
590
0
    }
591
3
592
3
    return jg;
593
0
fail:
594
0
    return NULL;
595
3
}
596
597
3
MVMJitCode *create_caller_code(MVMThreadContext *tc, MVMNativeCallBody *body) {
598
3
    MVMSpeshGraph *sg = MVM_calloc(1, sizeof(MVMSpeshGraph));
599
3
    MVMJitGraph *jg = MVM_nativecall_jit_graph_for_caller_code(tc, sg, body, -1, -1, NULL);
600
3
    MVMJitCode *jitcode;
601
3
    if (jg != NULL) {
602
3
        MVMJitNode *entry_label = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
603
3
        entry_label->next = jg->first_node;
604
3
        jg->first_node = entry_label;
605
3
        jg->num_labels = 1;
606
3
        jg->no_trampoline = 1;
607
3
608
3
        entry_label->type = MVM_JIT_NODE_LABEL;
609
3
        entry_label->u.label.name = 0;
610
3
        jitcode = MVM_jit_compile_graph(tc, jg);
611
3
    }
612
0
    else {
613
0
        jitcode = NULL;
614
0
    }
615
3
    MVM_spesh_graph_destroy(tc, sg);
616
3
    return jitcode;
617
3
}
618
619
/* Builds up a native call site out of the supplied arguments. */
620
MVMint8 MVM_nativecall_build(MVMThreadContext *tc, MVMObject *site, MVMString *lib,
621
3
        MVMString *sym, MVMString *conv, MVMObject *arg_info, MVMObject *ret_info) {
622
3
    char *lib_name = MVM_string_utf8_c8_encode_C_string(tc, lib);
623
3
    char *sym_name = MVM_string_utf8_c8_encode_C_string(tc, sym);
624
3
    MVMint8  keep_sym_name = 0;
625
3
    MVMint16 i;
626
3
627
3
    unsigned int interval_id = MVM_telemetry_interval_start(tc, "building native call");
628
3
629
3
    MVMObject *entry_point_o = (MVMObject *)MVM_repr_at_key_o(tc, ret_info,
630
3
        tc->instance->str_consts.entry_point);
631
3
632
3
    /* Initialize the object; grab native call part of its body. */
633
3
    MVMNativeCallBody *body = MVM_nativecall_get_nc_body(tc, site);
634
3
635
3
    /* Try to load the library. */
636
3
    body->lib_name = lib_name;
637
3
    body->lib_handle = MVM_nativecall_load_lib(lib_name[0] ? lib_name : NULL);
638
3
639
3
    if (!body->lib_handle) {
640
0
        char *waste[] = { lib_name, NULL };
641
0
        MVM_free(sym_name);
642
0
        MVM_telemetry_interval_stop(tc, interval_id, "error building native call");
643
0
        MVM_exception_throw_adhoc_free(tc, waste, "Cannot locate native library '%s': %s", lib_name, dlerror());
644
0
    }
645
3
646
3
    /* Try to locate the symbol. */
647
3
    if (entry_point_o) {
648
3
        body->entry_point = MVM_nativecall_unmarshal_cpointer(tc, entry_point_o);
649
3
        body->sym_name    = sym_name;
650
3
        keep_sym_name     = 1;
651
3
    }
652
3
653
3
    if (!body->entry_point) {
654
3
        body->entry_point = MVM_nativecall_find_sym(body->lib_handle, sym_name);
655
3
        if (!body->entry_point) {
656
0
            char *waste[] = { sym_name, lib_name, NULL };
657
0
            MVM_telemetry_interval_stop(tc, interval_id, "error building native call");
658
0
            MVM_exception_throw_adhoc_free(tc, waste, "Cannot locate symbol '%s' in native library '%s'",
659
0
                sym_name, lib_name);
660
0
        }
661
3
        body->sym_name = sym_name;
662
3
        keep_sym_name     = 1;
663
3
    }
664
3
665
3
    MVM_telemetry_interval_annotate_dynamic((uintptr_t)body->entry_point, interval_id, body->sym_name);
666
3
667
3
    if (keep_sym_name == 0) {
668
0
        MVM_free(sym_name);
669
0
    }
670
3
671
3
    /* Set calling convention, if any. */
672
3
    body->convention = MVM_nativecall_get_calling_convention(tc, conv);
673
3
674
3
    /* Transform each of the args info structures into a flag. */
675
3
    body->num_args  = MVM_repr_elems(tc, arg_info);
676
3
    body->arg_types = MVM_malloc(sizeof(MVMint16) * (body->num_args ? body->num_args : 1));
677
3
    body->arg_info  = MVM_malloc(sizeof(MVMObject *) * (body->num_args ? body->num_args : 1));
678
3
#ifdef HAVE_LIBFFI
679
    body->ffi_arg_types = MVM_malloc(sizeof(ffi_type *) * (body->num_args ? body->num_args : 1));
680
#endif
681
6
    for (i = 0; i < body->num_args; i++) {
682
3
        MVMObject *info = MVM_repr_at_pos_o(tc, arg_info, i);
683
3
        body->arg_types[i] = MVM_nativecall_get_arg_type(tc, info, 0);
684
3
#ifdef HAVE_LIBFFI
685
        body->ffi_arg_types[i] = MVM_nativecall_get_ffi_type(tc, body->arg_types[i]);
686
#endif
687
3
        if(body->arg_types[i] == MVM_NATIVECALL_ARG_CALLBACK) {
688
0
            MVM_ASSIGN_REF(tc, &(site->header), body->arg_info[i],
689
0
                MVM_repr_at_key_o(tc, info, tc->instance->str_consts.callback_args));
690
0
        }
691
3
        else {
692
3
            body->arg_info[i]  = NULL;
693
3
        }
694
3
    }
695
3
696
3
    /* Transform return argument type info a flag. */
697
3
    body->ret_type     = MVM_nativecall_get_arg_type(tc, ret_info, 1);
698
3
#ifdef HAVE_LIBFFI
699
    body->ffi_ret_type = MVM_nativecall_get_ffi_type(tc, body->ret_type);
700
#endif
701
3
    if (tc->instance->jit_enabled) {
702
3
        body->jitcode = create_caller_code(tc, body);
703
3
    }
704
3
    else
705
0
        body->jitcode = NULL;
706
3
707
3
    MVM_telemetry_interval_stop(tc, interval_id, "nativecall built");
708
3
709
3
    return body->jitcode != NULL;
710
3
}
711
712
0
static MVMObject * nativecall_cast(MVMThreadContext *tc, MVMObject *target_spec, MVMObject *target_type, void *cpointer_body) {
713
0
    MVMObject *result = NULL;
714
0
715
0
    MVMROOT2(tc, target_spec, target_type, {
716
0
        switch (REPR(target_type)->ID) {
717
0
            case MVM_REPR_ID_P6opaque: {
718
0
                const MVMStorageSpec *ss = REPR(target_spec)->get_storage_spec(tc, STABLE(target_spec));
719
0
                if(ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT) {
720
0
                    MVMint64 value = 0;
721
0
                    if (ss->is_unsigned)
722
0
                        switch(ss->bits) {
723
0
                            case 8:
724
0
                                value = *(MVMuint8 *)cpointer_body;
725
0
                                break;
726
0
                            case 16:
727
0
                                value = *(MVMuint16 *)cpointer_body;
728
0
                                break;
729
0
                            case 32:
730
0
                                value = *(MVMuint32 *)cpointer_body;
731
0
                                break;
732
0
                            case 64:
733
0
                            default:
734
0
                                value = *(MVMuint64 *)cpointer_body;
735
0
                        }
736
0
                    else
737
0
                        switch(ss->bits) {
738
0
                            case 8:
739
0
                                value = *(MVMint8 *)cpointer_body;
740
0
                                break;
741
0
                            case 16:
742
0
                                value = *(MVMint16 *)cpointer_body;
743
0
                                break;
744
0
                            case 32:
745
0
                                value = *(MVMint32 *)cpointer_body;
746
0
                                break;
747
0
                            case 64:
748
0
                            default:
749
0
                                value = *(MVMint64 *)cpointer_body;
750
0
                        }
751
0
752
0
                    result = MVM_nativecall_make_int(tc, target_type, value);
753
0
                }
754
0
                else if(ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM) {
755
0
                    MVMnum64 value;
756
0
757
0
                    switch(ss->bits) {
758
0
                        case 32:
759
0
                            value = *(MVMnum32 *)cpointer_body;
760
0
                            break;
761
0
                        case 64:
762
0
                        default:
763
0
                            value = *(MVMnum64 *)cpointer_body;
764
0
                    }
765
0
766
0
                    result = MVM_nativecall_make_num(tc, target_type, value);
767
0
                }
768
0
                else if(ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) {
769
0
                    result = MVM_nativecall_make_str(tc, target_type, MVM_NATIVECALL_ARG_UTF8STR,
770
0
                    (char *)cpointer_body);
771
0
                }
772
0
                else
773
0
                    MVM_exception_throw_adhoc(tc, "Internal error: unhandled target type");
774
0
775
0
                break;
776
0
            }
777
0
            case MVM_REPR_ID_P6int: {
778
0
                const MVMStorageSpec *ss = REPR(target_spec)->get_storage_spec(tc, STABLE(target_spec));
779
0
                MVMint64 value;
780
0
                if (ss->is_unsigned)
781
0
                    switch(ss->bits) {
782
0
                        case 8:
783
0
                            value = *(MVMuint8 *)cpointer_body;
784
0
                            break;
785
0
                        case 16:
786
0
                            value = *(MVMuint16 *)cpointer_body;
787
0
                            break;
788
0
                        case 32:
789
0
                            value = *(MVMuint32 *)cpointer_body;
790
0
                            break;
791
0
                        case 64:
792
0
                        default:
793
0
                            value = *(MVMuint64 *)cpointer_body;
794
0
                    }
795
0
                else
796
0
                    switch(ss->bits) {
797
0
                        case 8:
798
0
                            value = *(MVMint8 *)cpointer_body;
799
0
                            break;
800
0
                        case 16:
801
0
                            value = *(MVMint16 *)cpointer_body;
802
0
                            break;
803
0
                        case 32:
804
0
                            value = *(MVMint32 *)cpointer_body;
805
0
                            break;
806
0
                        case 64:
807
0
                        default:
808
0
                            value = *(MVMint64 *)cpointer_body;
809
0
                    }
810
0
                result = MVM_nativecall_make_int(tc, target_type, value);
811
0
                break;
812
0
            }
813
0
            case MVM_REPR_ID_P6num: {
814
0
                const MVMStorageSpec *ss = REPR(target_spec)->get_storage_spec(tc, STABLE(target_spec));
815
0
                MVMnum64 value;
816
0
817
0
                switch(ss->bits) {
818
0
                    case 32:
819
0
                        value = *(MVMnum32 *)cpointer_body;
820
0
                        break;
821
0
                    case 64:
822
0
                    default:
823
0
                        value = *(MVMnum64 *)cpointer_body;
824
0
                }
825
0
826
0
                result = MVM_nativecall_make_num(tc, target_type, value);
827
0
                break;
828
0
            }
829
0
            case MVM_REPR_ID_MVMCStr:
830
0
            case MVM_REPR_ID_P6str:
831
0
                result = MVM_nativecall_make_str(tc, target_type, MVM_NATIVECALL_ARG_UTF8STR,
832
0
                    (char *)cpointer_body);
833
0
                break;
834
0
            case MVM_REPR_ID_MVMCStruct:
835
0
                result = MVM_nativecall_make_cstruct(tc, target_type, (void *)cpointer_body);
836
0
                break;
837
0
            case MVM_REPR_ID_MVMCPPStruct:
838
0
                result = MVM_nativecall_make_cppstruct(tc, target_type, (void *)cpointer_body);
839
0
                break;
840
0
            case MVM_REPR_ID_MVMCUnion:
841
0
                result = MVM_nativecall_make_cunion(tc, target_type, (void *)cpointer_body);
842
0
                break;
843
0
            case MVM_REPR_ID_MVMCPointer:
844
0
                result = MVM_nativecall_make_cpointer(tc, target_type, (void *)cpointer_body);
845
0
                break;
846
0
            case MVM_REPR_ID_MVMCArray: {
847
0
                result = MVM_nativecall_make_carray(tc, target_type, (void *)cpointer_body);
848
0
                break;
849
0
            }
850
0
            default:
851
0
                MVM_exception_throw_adhoc(tc, "Internal error: unhandled target type");
852
0
        }
853
0
    });
854
0
855
0
    return result;
856
0
}
857
858
0
MVMObject * MVM_nativecall_global(MVMThreadContext *tc, MVMString *lib, MVMString *sym, MVMObject *target_spec, MVMObject *target_type) {
859
0
    char *lib_name = MVM_string_utf8_c8_encode_C_string(tc, lib);
860
0
    char *sym_name = MVM_string_utf8_c8_encode_C_string(tc, sym);
861
0
    DLLib *lib_handle;
862
0
    void *entry_point;
863
0
    MVMObject *ret = NULL;
864
0
865
0
    /* Try to load the library. */
866
0
    lib_handle = MVM_nativecall_load_lib(lib_name[0] ? lib_name : NULL);
867
0
    if (!lib_handle) {
868
0
        char *waste[] = { lib_name, NULL };
869
0
        MVM_free(sym_name);
870
0
        MVM_exception_throw_adhoc_free(tc, waste, "Cannot locate native library '%s': %s", lib_name, dlerror());
871
0
    }
872
0
873
0
    /* Try to locate the symbol. */
874
0
    entry_point = MVM_nativecall_find_sym(lib_handle, sym_name);
875
0
    if (!entry_point) {
876
0
        char *waste[] = { sym_name, lib_name, NULL };
877
0
        MVM_exception_throw_adhoc_free(tc, waste, "Cannot locate symbol '%s' in native library '%s'",
878
0
            sym_name, lib_name);
879
0
    }
880
0
    MVM_free(sym_name);
881
0
    MVM_free(lib_name);
882
0
883
0
    if (REPR(target_type)->ID == MVM_REPR_ID_MVMCStr
884
0
    ||  REPR(target_type)->ID == MVM_REPR_ID_P6str
885
0
    || (REPR(target_type)->ID == MVM_REPR_ID_P6opaque
886
0
        && REPR(target_spec)->get_storage_spec(tc, STABLE(target_spec))->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR)) {
887
0
        entry_point = *(void **)entry_point;
888
0
    }
889
0
890
0
    ret = nativecall_cast(tc, target_spec, target_type, entry_point);
891
0
    MVM_nativecall_free_lib(lib_handle);
892
0
    return ret;
893
0
}
894
895
0
MVMObject * MVM_nativecall_cast(MVMThreadContext *tc, MVMObject *target_spec, MVMObject *target_type, MVMObject *source) {
896
0
    void *data_body;
897
0
898
0
    if (!source)
899
0
        return target_type;
900
0
901
0
    if (REPR(source)->ID == MVM_REPR_ID_MVMCStruct)
902
0
        data_body = MVM_nativecall_unmarshal_cstruct(tc, source);
903
0
    else if (REPR(source)->ID == MVM_REPR_ID_MVMCPPStruct)
904
0
        data_body = MVM_nativecall_unmarshal_cppstruct(tc, source);
905
0
    else if (REPR(source)->ID == MVM_REPR_ID_MVMCUnion)
906
0
        data_body = MVM_nativecall_unmarshal_cunion(tc, source);
907
0
    else if (REPR(source)->ID == MVM_REPR_ID_MVMCPointer)
908
0
        data_body = MVM_nativecall_unmarshal_cpointer(tc, source);
909
0
    else if (REPR(source)->ID == MVM_REPR_ID_MVMCArray)
910
0
        data_body = MVM_nativecall_unmarshal_carray(tc, source);
911
0
    else if (REPR(source)->ID == MVM_REPR_ID_VMArray)
912
0
        data_body = MVM_nativecall_unmarshal_vmarray(tc, source);
913
0
    else
914
0
        MVM_exception_throw_adhoc(tc,
915
0
            "Native call expected return type with CPointer, CStruct, CArray, or VMArray representation, but got a %s (%s)", REPR(source)->name, MVM_6model_get_debug_name(tc, source));
916
0
    return nativecall_cast(tc, target_spec, target_type, data_body);
917
0
}
918
919
0
MVMint64 MVM_nativecall_sizeof(MVMThreadContext *tc, MVMObject *obj) {
920
0
    if (REPR(obj)->ID == MVM_REPR_ID_MVMCStruct)
921
0
        return ((MVMCStructREPRData *)STABLE(obj)->REPR_data)->struct_size;
922
0
    else if (REPR(obj)->ID == MVM_REPR_ID_MVMCPPStruct)
923
0
        return ((MVMCPPStructREPRData *)STABLE(obj)->REPR_data)->struct_size;
924
0
    else if (REPR(obj)->ID == MVM_REPR_ID_MVMCUnion)
925
0
        return ((MVMCUnionREPRData *)STABLE(obj)->REPR_data)->struct_size;
926
0
    else if (REPR(obj)->ID == MVM_REPR_ID_P6int)
927
0
        return ((MVMP6intREPRData *)STABLE(obj)->REPR_data)->bits / 8;
928
0
    else if (REPR(obj)->ID == MVM_REPR_ID_P6num)
929
0
        return ((MVMP6numREPRData *)STABLE(obj)->REPR_data)->bits / 8;
930
0
    else if (REPR(obj)->ID == MVM_REPR_ID_MVMCPointer
931
0
          || REPR(obj)->ID == MVM_REPR_ID_MVMCArray
932
0
          || REPR(obj)->ID == MVM_REPR_ID_MVMCStr
933
0
          || REPR(obj)->ID == MVM_REPR_ID_P6str)
934
0
        return sizeof(void *);
935
0
    else
936
0
        MVM_exception_throw_adhoc(tc,
937
0
            "NativeCall op sizeof expected type with CPointer, CStruct, CArray, P6int or P6num representation, but got a %s (%s)",
938
0
            REPR(obj)->name, MVM_6model_get_debug_name(tc, obj));
939
0
}
940
941
/* Write-barriers a dyncall object so that delayed changes to the C-side of
942
 * objects are propagated to the HLL side. All CArray and CStruct arguments to
943
 * C functions are write-barriered automatically, so this should be necessary
944
 * only in the rarest of cases. */
945
3
void MVM_nativecall_refresh(MVMThreadContext *tc, MVMObject *cthingy) {
946
3
    if (!IS_CONCRETE(cthingy))
947
0
        return;
948
3
    if (REPR(cthingy)->ID == MVM_REPR_ID_MVMCArray) {
949
0
        MVMCArrayBody      *body      = (MVMCArrayBody *)OBJECT_BODY(cthingy);
950
0
        MVMCArrayREPRData  *repr_data = (MVMCArrayREPRData *)STABLE(cthingy)->REPR_data;
951
0
        void              **storage   = (void **) body->storage;
952
0
        MVMint64            i;
953
0
954
0
        /* No need to check for numbers. They're stored directly in the array. */
955
0
        if (repr_data->elem_kind == MVM_CARRAY_ELEM_KIND_NUMERIC)
956
0
            return;
957
0
958
0
        for (i = 0; i < body->elems; i++) {
959
0
            void *cptr;   /* The pointer in the C storage. */
960
0
            void *objptr; /* The pointer in the object representing the C object. */
961
0
962
0
            /* Ignore elements where we haven't generated an object. */
963
0
            if (!body->child_objs[i])
964
0
                continue;
965
0
966
0
            cptr = storage[i];
967
0
            if (IS_CONCRETE(body->child_objs[i])) {
968
0
                switch (repr_data->elem_kind) {
969
0
                    case MVM_CARRAY_ELEM_KIND_CARRAY:
970
0
                        objptr = ((MVMCArrayBody *)OBJECT_BODY(body->child_objs[i]))->storage;
971
0
                        break;
972
0
                    case MVM_CARRAY_ELEM_KIND_CPOINTER:
973
0
                        objptr = ((MVMCPointerBody *)OBJECT_BODY(body->child_objs[i]))->ptr;
974
0
                        break;
975
0
                    case MVM_CARRAY_ELEM_KIND_CSTRUCT:
976
0
                        objptr = ((MVMCStructBody *)OBJECT_BODY(body->child_objs[i]))->cstruct;
977
0
                        break;
978
0
                    case MVM_CARRAY_ELEM_KIND_CPPSTRUCT:
979
0
                        objptr = ((MVMCPPStructBody *)OBJECT_BODY(body->child_objs[i]))->cppstruct;
980
0
                        break;
981
0
                    case MVM_CARRAY_ELEM_KIND_CUNION:
982
0
                        objptr = ((MVMCUnionBody *)OBJECT_BODY(body->child_objs[i]))->cunion;
983
0
                        break;
984
0
                    case MVM_CARRAY_ELEM_KIND_STRING:
985
0
                        objptr = NULL; /* TODO */
986
0
                        break;
987
0
                    default:
988
0
                        MVM_exception_throw_adhoc(tc,
989
0
                            "Fatal error: bad elem_kind (%d) in CArray write barrier",
990
0
                            repr_data->elem_kind);
991
0
                }
992
0
            }
993
0
            else {
994
0
                objptr = NULL;
995
0
            }
996
0
997
0
            if (objptr != cptr)
998
0
                body->child_objs[i] = NULL;
999
0
            else
1000
0
                MVM_nativecall_refresh(tc, body->child_objs[i]);
1001
0
        }
1002
0
    }
1003
3
    else if (REPR(cthingy)->ID == MVM_REPR_ID_MVMCStruct) {
1004
0
        MVMCStructBody     *body      = (MVMCStructBody *)OBJECT_BODY(cthingy);
1005
0
        MVMCStructREPRData *repr_data = (MVMCStructREPRData *)STABLE(cthingy)->REPR_data;
1006
0
        char               *storage   = (char *) body->cstruct;
1007
0
        MVMint64            i;
1008
0
1009
0
        for (i = 0; i < repr_data->num_attributes; i++) {
1010
0
            MVMint32 kind = repr_data->attribute_locations[i] & MVM_CSTRUCT_ATTR_MASK;
1011
0
            MVMint32 slot = repr_data->attribute_locations[i] >> MVM_CSTRUCT_ATTR_SHIFT;
1012
0
            void *cptr = NULL;   /* The pointer in the C storage. */
1013
0
            void *objptr = NULL; /* The pointer in the object representing the C object. */
1014
0
1015
0
            if (kind == MVM_CSTRUCT_ATTR_IN_STRUCT || !body->child_objs[slot])
1016
0
                continue;
1017
0
1018
0
            cptr = (void*)((uintptr_t)storage + (uintptr_t)repr_data->struct_offsets[i]);
1019
0
            if (IS_CONCRETE(body->child_objs[slot])) {
1020
0
                switch (kind) {
1021
0
                    case MVM_CSTRUCT_ATTR_CARRAY:
1022
0
                        objptr = ((MVMCArrayBody *)OBJECT_BODY(body->child_objs[slot]))->storage;
1023
0
                        break;
1024
0
                    case MVM_CSTRUCT_ATTR_CPTR:
1025
0
                        objptr = ((MVMCPointerBody *)OBJECT_BODY(body->child_objs[slot]))->ptr;
1026
0
                        break;
1027
0
                    case MVM_CSTRUCT_ATTR_CSTRUCT:
1028
0
                        objptr = (MVMCStructBody *)OBJECT_BODY(body->child_objs[slot]);
1029
0
                        break;
1030
0
                    case MVM_CSTRUCT_ATTR_CPPSTRUCT:
1031
0
                        objptr = (MVMCPPStructBody *)OBJECT_BODY(body->child_objs[slot]);
1032
0
                        break;
1033
0
                    case MVM_CSTRUCT_ATTR_CUNION:
1034
0
                        objptr = (MVMCUnionBody *)OBJECT_BODY(body->child_objs[slot]);
1035
0
                        break;
1036
0
                    case MVM_CSTRUCT_ATTR_STRING:
1037
0
                        objptr = NULL;
1038
0
                        break;
1039
0
                    default:
1040
0
                        MVM_exception_throw_adhoc(tc,
1041
0
                            "Fatal error: bad kind (%d) in CStruct write barrier",
1042
0
                            kind);
1043
0
                }
1044
0
            }
1045
0
            else {
1046
0
                objptr = NULL;
1047
0
            }
1048
0
1049
0
            if (objptr != cptr)
1050
0
                body->child_objs[slot] = NULL;
1051
0
            else
1052
0
                MVM_nativecall_refresh(tc, body->child_objs[slot]);
1053
0
        }
1054
0
    }
1055
3
    else if (REPR(cthingy)->ID == MVM_REPR_ID_MVMCPPStruct) {
1056
0
        MVMCPPStructBody     *body      = (MVMCPPStructBody *)OBJECT_BODY(cthingy);
1057
0
        MVMCPPStructREPRData *repr_data = (MVMCPPStructREPRData *)STABLE(cthingy)->REPR_data;
1058
0
        char                 *storage   = (char *) body->cppstruct;
1059
0
        MVMint64              i;
1060
0
1061
0
        for (i = 0; i < repr_data->num_attributes; i++) {
1062
0
            MVMint32 kind = repr_data->attribute_locations[i] & MVM_CPPSTRUCT_ATTR_MASK;
1063
0
            MVMint32 slot = repr_data->attribute_locations[i] >> MVM_CPPSTRUCT_ATTR_SHIFT;
1064
0
            void *cptr = NULL;   /* The pointer in the C storage. */
1065
0
            void *objptr = NULL; /* The pointer in the object representing the C object. */
1066
0
1067
0
            if (kind == MVM_CPPSTRUCT_ATTR_IN_STRUCT || !body->child_objs[slot])
1068
0
                continue;
1069
0
1070
0
            cptr = (void*)((uintptr_t)storage + (uintptr_t)repr_data->struct_offsets[i]);
1071
0
            if (IS_CONCRETE(body->child_objs[slot])) {
1072
0
                switch (kind) {
1073
0
                    case MVM_CPPSTRUCT_ATTR_CARRAY:
1074
0
                        objptr = ((MVMCArrayBody *)OBJECT_BODY(body->child_objs[slot]))->storage;
1075
0
                        break;
1076
0
                    case MVM_CPPSTRUCT_ATTR_CPTR:
1077
0
                        objptr = ((MVMCPointerBody *)OBJECT_BODY(body->child_objs[slot]))->ptr;
1078
0
                        break;
1079
0
                    case MVM_CPPSTRUCT_ATTR_CSTRUCT:
1080
0
                        objptr = (MVMCStructBody *)OBJECT_BODY(body->child_objs[slot]);
1081
0
                        break;
1082
0
                    case MVM_CPPSTRUCT_ATTR_CPPSTRUCT:
1083
0
                        objptr = (MVMCPPStructBody *)OBJECT_BODY(body->child_objs[slot]);
1084
0
                        break;
1085
0
                    case MVM_CPPSTRUCT_ATTR_CUNION:
1086
0
                        objptr = (MVMCUnionBody *)OBJECT_BODY(body->child_objs[slot]);
1087
0
                        break;
1088
0
                    case MVM_CPPSTRUCT_ATTR_STRING:
1089
0
                        objptr = NULL;
1090
0
                        break;
1091
0
                    default:
1092
0
                        MVM_exception_throw_adhoc(tc,
1093
0
                            "Fatal error: bad kind (%d) in CPPStruct write barrier",
1094
0
                            kind);
1095
0
                }
1096
0
            }
1097
0
            else {
1098
0
                objptr = NULL;
1099
0
            }
1100
0
1101
0
            if (objptr != cptr)
1102
0
                body->child_objs[slot] = NULL;
1103
0
            else
1104
0
                MVM_nativecall_refresh(tc, body->child_objs[slot]);
1105
0
        }
1106
0
    }
1107
3
}
1108
1109
/* Locate the thread that a callback should be run on. */
1110
0
MVMThreadContext * MVM_nativecall_find_thread_context(MVMInstance *instance) {
1111
0
    MVMint64 wanted_thread_id = MVM_platform_thread_id();
1112
0
    MVMThreadContext *tc = NULL;
1113
0
    while (1) {
1114
0
        uv_mutex_lock(&(instance->mutex_threads));
1115
0
        if (instance->in_gc) {
1116
0
            /* VM is in GC; free lock since the GC will acquire it again to
1117
0
             * clear the in_gc flag, and sleep a bit until it's safe to read
1118
0
             * the threads list. */
1119
0
            uv_mutex_unlock(&(instance->mutex_threads));
1120
0
            MVM_platform_sleep(0.0001);
1121
0
        }
1122
0
        else {
1123
0
            /* Not in GC. If a GC starts while we are reading this, then we
1124
0
             * are holding mutex_threads, and the GC will block on it before
1125
0
             * it gets to a stage where it can move things. */
1126
0
            MVMThread *thread = instance->threads;
1127
0
            while (thread) {
1128
0
                if (thread->body.native_thread_id == wanted_thread_id) {
1129
0
                    tc = thread->body.tc;
1130
0
                    if (tc)
1131
0
                        break;
1132
0
                }
1133
0
                thread = thread->body.next;
1134
0
            }
1135
0
            if (!tc)
1136
0
                MVM_panic(1, "native callback ran on thread (%"PRId64") unknown to MoarVM",
1137
0
                    wanted_thread_id);
1138
0
            uv_mutex_unlock(&(instance->mutex_threads));
1139
0
            break;
1140
0
        }
1141
0
    }
1142
0
    return tc;
1143
0
}
1144
1145
0
void MVM_nativecall_invoke_jit(MVMThreadContext *tc, MVMObject *site) {
1146
0
    MVMNativeCallBody *body = MVM_nativecall_get_nc_body(tc, site);
1147
0
    MVMJitCode * const jitcode = body->jitcode;
1148
0
1149
0
    jitcode->func_ptr(tc, *tc->interp_cu, jitcode->labels[0]);
1150
0
}