|
1 | 1 | BEGIN_OPS_PREAMBLE
|
2 | 2 |
|
3 |
| -/* Parroty includes. */ |
4 | 3 | #include "parrot/parrot.h"
|
5 | 4 | #include "parrot/extend.h"
|
6 | 5 | #include "parrot/dynext.h"
|
7 | 6 | #include "../6model/sixmodelobject.h"
|
| 7 | +#include "../6model/reprs/NativeCall.h" |
| 8 | + |
| 9 | +/* This library contains just three operations: one to initialize it, |
| 10 | + * one to look up a native function and build a handle to it, and |
| 11 | + * another to actually make the call. |
| 12 | + * |
| 13 | + * It uses hashes to describe arguments and return types. The following |
| 14 | + * keys are allowable. |
| 15 | + * |
| 16 | + * XXX |
| 17 | + */ |
| 18 | + |
| 19 | +/* The ID of the NativeCall REPR. */ |
| 20 | +static INTVAL nc_repr_id = 0; |
| 21 | + |
| 22 | +/* Grabs a NativeCall body. */ |
| 23 | +static NativeCallBody * get_nc_body(PARROT_INTERP, PMC *obj) { |
| 24 | + struct SixModel_REPROps *r = REPR(obj); |
| 25 | + if (r->ID == nc_repr_id) |
| 26 | + return &((NativeCallInstance *)PMC_data(obj))->body; |
| 27 | + else |
| 28 | + return (NativeCallBody *)r->get_boxed_ref(interp, STABLE(obj), |
| 29 | + OBJECT_BODY(obj), nc_repr_id); |
| 30 | +} |
8 | 31 |
|
9 | 32 | END_OPS_PREAMBLE
|
10 | 33 |
|
11 |
| -inline op nqp_XXX() :base_core { |
| 34 | +/* Initialize the navtie call library. */ |
| 35 | +inline op nqp_native_call_setup() :base_core { |
| 36 | + /* Register the NativeCall representation. */ |
| 37 | + if (!nc_repr_id) |
| 38 | + nc_repr_id = REGISTER_DYNAMIC_REPR(interp, |
| 39 | + Parrot_str_new_constant(interp, "NativeCall"), |
| 40 | + NativeCall_initialize); |
| 41 | +} |
| 42 | + |
| 43 | + |
| 44 | +/* Build a native call object. |
| 45 | + * |
| 46 | + * $2 is the type of object to build. It should be of a type that is |
| 47 | + * based on or boxes the NativeCall REPR. |
| 48 | + * $3 is the name of the library to load the function from. |
| 49 | + * $4 is the name of the function to load. |
| 50 | + * $5 is a string name specifying the calling convention to use. |
| 51 | + * $6 is an nqp::list(...) of nqp::hash(...), one hash per argument. |
| 52 | + The entries in the hash describe the type of argument being passed. |
| 53 | + * $7 is an nqp::hash(...) that describes the expected return type |
| 54 | + * |
| 55 | + * Provided all is well, $1 will end up containing an object of type $2 |
| 56 | + * that has been initialized with all the relevant call information and |
| 57 | + * can be used with the nqp_native_call op. There's no need to manually |
| 58 | + * release the handle; when it is no longer referenced, it will be |
| 59 | + * automatically garbage collected. |
| 60 | + */ |
| 61 | +inline op nqp_native_call_build(out PMC, in PMC, in STR, in STR, in STR, in PMC, in PMC) :base_core { |
| 62 | + PMC *result_type = $2; |
| 63 | + PMC *result = REPR($2)->allocate(interp, STABLE($2)); |
| 64 | + char *lib_name = Parrot_str_to_cstring(interp, $3); |
| 65 | + char *sym_name = Parrot_str_to_cstring(interp, $4); |
| 66 | + char *convention = Parrot_str_to_cstring(interp, $5); |
| 67 | + PMC *arg_info = $6; |
| 68 | + PMC *ret_info = $7; |
| 69 | + int i; |
| 70 | + |
| 71 | + /* Initialize the object; grab native call part of its body. */ |
| 72 | + NativeCallBody *body = get_nc_body(interp, result); |
| 73 | + REPR(result)->initialize(interp, STABLE(result), OBJECT_BODY(result)); |
| 74 | + |
| 75 | + /* Try to load the library. */ |
| 76 | + body->lib_name = lib_name; |
| 77 | + body->lib_handle = dlLoadLibrary(lib_name); |
| 78 | + if (!body->lib_handle) { |
| 79 | + Parrot_str_free_cstring(sym_name); |
| 80 | + Parrot_str_free_cstring(convention); |
| 81 | + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, |
| 82 | + "Cannot locate native library '%Ss'", $3); |
| 83 | + } |
| 84 | + |
| 85 | + /* Try to locate the symbol. */ |
| 86 | + body->entry_point = dlFindSymbol(body->lib_handle, sym_name); |
| 87 | + Parrot_str_free_cstring(sym_name); |
| 88 | + if (!body->entry_point) { |
| 89 | + Parrot_str_free_cstring(convention); |
| 90 | + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION, |
| 91 | + "Cannot locate symbol '%Ss' in native library '%Ss'", $4, $3); |
| 92 | + } |
| 93 | + |
| 94 | + /* Set calling convention, if any. */ |
| 95 | + Parrot_str_free_cstring(convention); |
| 96 | + |
| 97 | + /* Transform each of the args info structures into a flag. */ |
| 98 | + |
| 99 | + |
| 100 | + /* Transform return argument type info a flag. */ |
| 101 | + |
| 102 | + |
| 103 | + $1 = result; |
| 104 | +} |
| 105 | + |
| 106 | +/* Makes a native call. |
| 107 | + * |
| 108 | + * $2 is the type of result to build. It can be a null if the return value |
| 109 | + * is void or can simply be discarded. If the return value is a native |
| 110 | + * type, then this type should be capable of boxing it. |
| 111 | + * $3 is an object representing the call, obtained from nqp_native_call_build. |
| 112 | + * $4 is an nqp::list(...), which contains the arguments to pass; note this |
| 113 | + * means they are in boxed form |
| 114 | + * |
| 115 | + * $1 will be populated with an instance of $2 that contains the result |
| 116 | + * of the call. If $2 was null PMC, then $1 also will be. If the call |
| 117 | + * was to return a struct, array or some other pointer type and the |
| 118 | + * result comes back as NULL, then $1 will simply be $2 (which is |
| 119 | + * presumably a type object). |
| 120 | + */ |
| 121 | +inline op nqp_native_call(out PMC, in PMC, in PMC, in PMC) :base_core { |
| 122 | + PMC *result; |
| 123 | + INTVAL args, i; |
| 124 | + |
| 125 | + /* Get native call body, so we can locate the call info. */ |
| 126 | + NativeCallBody *body = get_nc_body(interp, $3); |
| 127 | + |
| 128 | + /* Create and set up call VM. */ |
| 129 | + DCCallVM *vm = dcNewCallVM(body->num_args * sizeof(void *)); |
| 130 | + |
| 131 | + /* Process arguments. */ |
| 132 | + /* XXX */ |
| 133 | + |
| 134 | + /* Call and process return values. */ |
| 135 | + /* XXX */ |
| 136 | + dcCallVoid(vm, body->entry_point); |
| 137 | + |
| 138 | + /* Finally, free call VM. */ |
| 139 | + dcFree(vm); |
12 | 140 | }
|
0 commit comments