-
Notifications
You must be signed in to change notification settings - Fork 138
/
extend.c
258 lines (194 loc) · 8.1 KB
/
extend.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
Copyright (C) 2001-2011, Parrot Foundation.
=head1 NAME
src/extend.c - Parrot extension interface
=head1 DESCRIPTION
These are utility functions which extension code may use, but which are
typically not used by Parrot internally. These functions are for EXTENDING
use only, not for EMBEDDING. Embedding should be handed through the embedding
API with c files in directory src/embed/.
Extending situations are things like NCI function libraries, dyn-pmc and
dyn-op libraries which are loaded into Parrot and called from Parrot (as
opposed to embedding, where an external program calls into Parrot). These
functions assume the existance of an interpreter, memory management through
GC and stackwalking, and the presence of an exception-handling infrastructure.
=head2 Functions
=over 4
=cut
*/
/* DO NOT CALL THESE FUNCTIONS WITHOUT LIBPARROT, OR FROM OUTSIDE LIBPARROT!!
These functions presume that GC is available and is properly configured
(setting the stacktop for stack walking, etc) and that there is an active
exception-handling infrastructure. Calling these functions when there are
no exception handlers available, including a default top-level handler, or
when the GC is not properly initialized can lead to big problems. Be sure
to understand the difference between an embedding and an extending
situation. Using the wrong kind of function in the wrong situation, or
combining some functions from the Embedding API with functions from the
Extending API is a recipe for disaster. We (Parrot developers) will not be
held responsible if you insist on making these kinds of mistakes.
If there are utility functions that *YOU* as a user of parrot need from
either the extending or the embedding API, please request them or attempt
to write them yourself. Blindly mixing things from the wrong API, or
calling a function in the wrong context will cause you problems.
You have been warned.
Notice that the "Extending API" is a loosely-defined concept which is
currently understood to mean the sum of public APIs for various subsystems.
This definition may change in the future, but this is what we mean by the
phrase right now. The functions in this file do not belong to any
particular subsystem, and are always part of the extending API. Functions
named "Parrot_xxx_..." where "xxx" is a 2- or 3-letter subsystem
abbreviation and which are marked with "PARROT_EXPORT" can generally be
considered to be part of the public API. Subsystems which are properly
arranged will typically have a folder src/xxx/, and an "api.c" file
therein for holding API functions from that subsystem. Many of the bigger
systems are arranged in this way (and the rest of the systems will be
eventually). If so, that is the canonical source of information regarding
API functions for that subsystem.
Other documentation sources, such as the PDDs or other files in the
docs/ directory may include other information about the extending API.
*/
#include "parrot/parrot.h"
#include "parrot/extend.h"
#include "parrot/events.h"
#include "pmc/pmc_sub.h"
#include "pmc/pmc_callcontext.h"
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
static void restore_context(PARROT_INTERP,
ARGIN(Parrot_Context * const initialctx))
__attribute__nonnull__(1)
__attribute__nonnull__(2);
#define ASSERT_ARGS_restore_context __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(initialctx))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/* HEADERIZER HFILE: include/parrot/extend.h */
/*
=item C<Parrot_Int Parrot_PMC_typenum(PARROT_INTERP, const char *_class)>
Returns the internal identifier that represents the named class.
DEPRECATED. Use Parrot_pmc_get_type_str instead.
=cut
*/
PARROT_EXPORT
Parrot_Int
Parrot_PMC_typenum(PARROT_INTERP, ARGIN_NULLOK(const char *_class))
{
ASSERT_ARGS(Parrot_PMC_typenum)
Parrot_Int retval = Parrot_pmc_get_type_str(interp, Parrot_str_new(interp, _class, 0));
return retval;
}
/*
=item C<void Parrot_ext_call(PARROT_INTERP, Parrot_PMC sub_pmc, const char
*signature, ...)>
Call a Parrot subroutine or method with the given function signature. The
function signature holds one type character for each argument or return, these
are:
I ... Parrot_Int
N ... Parrot_Float
S ... Parrot_String
P ... Parrot_PMC
Returns come after the arguments, separated by an arrow, so "PN->S" takes a PMC
and a float as arguments and returns a string.
Pass the variables for the arguments and returns in the same order as the
signature, with returns as reference to the variable (so it can be modified).
Parrot_ext_call(interp, sub, "P->S", pmc_arg, &string_result);
To call a method, pass the object for the method as the first argument, and
mark it in the signature as "Pi" ("i" stands for "invocant").
Parrot_ext_call(interp, sub, "PiP->S", object_arg, pmc_arg, &string_result);
=cut
*/
PARROT_EXPORT
void
Parrot_ext_call(PARROT_INTERP, ARGIN(Parrot_PMC sub_pmc),
ARGIN(const char *signature), ...)
{
ASSERT_ARGS(Parrot_ext_call)
va_list args;
PMC *call_obj;
const char *arg_sig, *ret_sig;
PMC * old_call_obj = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
Parrot_pcc_split_signature_string(signature, &arg_sig, &ret_sig);
va_start(args, signature);
call_obj = Parrot_pcc_build_call_from_varargs(interp, PMCNULL,
arg_sig, &args);
Parrot_pcc_invoke_from_sig_object(interp, sub_pmc, call_obj);
call_obj = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp));
Parrot_pcc_fill_params_from_varargs(interp, call_obj, ret_sig, &args,
PARROT_ERRORS_RESULT_COUNT_FLAG);
va_end(args);
Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_call_obj);
}
/*
=item C<static void restore_context(PARROT_INTERP, Parrot_Context * const
initialctx)>
Helper function to restore the caller context in Parrot_ext_try.
=cut
*/
static void
restore_context(PARROT_INTERP, ARGIN(Parrot_Context * const initialctx))
{
ASSERT_ARGS(restore_context)
Parrot_Context *curctx = CONTEXT(interp);
if (curctx != initialctx) {
Parrot_warn((interp), PARROT_WARNINGS_NONE_FLAG,
"popping context in Parrot_ext_try");
do {
Parrot_pop_context(interp);
curctx = CONTEXT(interp);
if (curctx == NULL)
PANIC(interp, "cannot restore context");
} while (curctx != initialctx);
}
}
/*
=item C<void Parrot_ext_try(PARROT_INTERP, void (*cfunction(Parrot_Interp, void
*)), void (*chandler(Parrot_Interp, PMC *, void *)), void *data)>
Executes the cfunction argument wrapped in a exception handler.
If the function throws, the provided handler function is invoked
=cut
*/
PARROT_EXPORT
void
Parrot_ext_try(PARROT_INTERP,
ARGIN_NULLOK(void (*cfunction)(Parrot_Interp, ARGIN_NULLOK(void *))),
ARGIN_NULLOK(void (*chandler)(Parrot_Interp, ARGIN_NULLOK(PMC *), ARGIN_NULLOK(void *))),
ARGIN_NULLOK(void *data))
{
ASSERT_ARGS(Parrot_ext_try)
if (cfunction) {
Parrot_runloop jmp;
Parrot_Context * const initialctx = CONTEXT(interp);
switch (setjmp(jmp.resume)) {
case 0: /* try */
Parrot_ex_add_c_handler(interp, &jmp);
(*cfunction)(interp, data);
restore_context(interp, initialctx);
Parrot_cx_delete_handler_local(interp);
break;
default: /* catch */
{
PMC *exception = jmp.exception;
restore_context(interp, initialctx);
Parrot_cx_delete_handler_local(interp);
if (chandler)
(*chandler)(interp, exception, data);
}
}
}
}
/*
=back
=head1 SEE ALSO
See F<include/parrot/extend.h> and F<docs/pdds/pdd11_extending.pod>.
=head1 HISTORY
Initial version by Dan Sugalski.
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/