2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/sub.c - Subroutines
11 Subroutines, continuations, co-routines and other fun stuff...
21 #include "parrot/parrot.h"
22 #include "parrot/oplib/ops.h"
24 #include "pmc/pmc_sub.h"
25 #include "pmc/pmc_continuation.h"
27 /* HEADERIZER HFILE: include/parrot/sub.h */
32 =item C<void mark_context_start(void)>
34 Indicate that a new round of context marking is about to take place.
40 static int context_gc_mark
= 0;
43 mark_context_start(void)
45 ASSERT_ARGS(mark_context_start
)
46 if (++context_gc_mark
== 0) context_gc_mark
= 1;
52 =item C<PMC * new_ret_continuation_pmc(PARROT_INTERP, opcode_t *address)>
54 Returns a new C<RetContinuation> PMC, and sets address field to C<address>
62 PARROT_CANNOT_RETURN_NULL
64 new_ret_continuation_pmc(PARROT_INTERP
, ARGIN_NULLOK(opcode_t
*address
))
66 ASSERT_ARGS(new_ret_continuation_pmc
)
67 PMC
* const continuation
= pmc_new(interp
, enum_class_RetContinuation
);
68 VTABLE_set_pointer(interp
, continuation
, address
);
74 =item C<void invalidate_retc_context(PARROT_INTERP, PMC *cont)>
76 Make true Continuations from all RetContinuations up the call chain.
83 invalidate_retc_context(PARROT_INTERP
, ARGMOD(PMC
*cont
))
85 ASSERT_ARGS(invalidate_retc_context
)
87 PMC
*ctx
= PARROT_CONTINUATION(cont
)->from_ctx
;
88 cont
= Parrot_pcc_get_continuation(interp
, ctx
);
92 * We stop if we encounter a true continuation, because
93 * if one were created, everything up the chain would have been
94 * invalidated earlier.
96 if (!cont
|| cont
->vtable
!= interp
->vtables
[enum_class_RetContinuation
])
98 cont
->vtable
= interp
->vtables
[enum_class_Continuation
];
99 ctx
= Parrot_pcc_get_caller_ctx(interp
, ctx
);
100 cont
= Parrot_pcc_get_continuation(interp
, ctx
);
106 =item C<STRING* Parrot_full_sub_name(PARROT_INTERP, PMC* sub_pmc)>
108 Return namespace, name, and location of subroutine.
115 PARROT_CAN_RETURN_NULL
116 PARROT_WARN_UNUSED_RESULT
118 Parrot_full_sub_name(PARROT_INTERP
, ARGIN_NULLOK(PMC
* sub_pmc
))
120 ASSERT_ARGS(Parrot_full_sub_name
)
121 if (sub_pmc
&& VTABLE_defined(interp
, sub_pmc
)) {
122 Parrot_Sub_attributes
*sub
;
124 PMC_get_sub(interp
, sub_pmc
, sub
);
126 if (PMC_IS_NULL(sub
->namespace_stash
)) {
131 STRING
* const semicolon
= CONST_STRING(interp
, ";");
135 * When running with -t4, the invoke done in
136 * Parrot_ns_get_name stomps on settings in interp; we
137 * have to save these and restore them to avoid affecting
138 * the running program.
140 PMC
* const saved_ccont
= interp
->current_cont
;
141 opcode_t
* const current_args
= interp
->current_args
;
142 opcode_t
* const current_params
= interp
->current_params
;
143 opcode_t
* const current_returns
= interp
->current_returns
;
144 PMC
* const args_signature
= interp
->args_signature
;
145 PMC
* const params_signature
= interp
->params_signature
;
146 PMC
* const returns_signature
= interp
->returns_signature
;
148 Parrot_block_GC_mark(interp
);
150 ns_array
= Parrot_ns_get_name(interp
, sub
->namespace_stash
);
152 /* Restore stuff that might have got overwritten */
153 interp
->current_cont
= saved_ccont
;
154 interp
->current_args
= current_args
;
155 interp
->current_params
= current_params
;
156 interp
->current_returns
= current_returns
;
157 interp
->args_signature
= args_signature
;
158 interp
->params_signature
= params_signature
;
159 interp
->returns_signature
= returns_signature
;
162 VTABLE_push_string(interp
, ns_array
, sub
->name
);
164 res
= Parrot_str_join(interp
, semicolon
, ns_array
);
165 Parrot_unblock_GC_mark(interp
);
174 =item C<int Parrot_Context_get_info(PARROT_INTERP, PMC *ctx, Parrot_Context_info
177 Takes pointers to a context and its information table.
178 Populates the table and returns 0 or 1. XXX needs explanation
179 Used by Parrot_Context_infostr.
187 Parrot_Context_get_info(PARROT_INTERP
, ARGIN(PMC
*ctx
),
188 ARGOUT(Parrot_Context_info
*info
))
190 ASSERT_ARGS(Parrot_Context_get_info
)
192 Parrot_Sub_attributes
*sub
;
194 /* set file/line/pc defaults */
195 info
->file
= CONST_STRING(interp
, "(unknown file)");
199 info
->subname
= NULL
;
200 info
->fullname
= NULL
;
202 subpmc
= Parrot_pcc_get_sub(interp
, ctx
);
204 /* is the current sub of the specified context valid? */
205 if (PMC_IS_NULL(subpmc
)) {
206 info
->subname
= Parrot_str_new(interp
, "???", 3);
207 info
->nsname
= info
->subname
;
208 info
->fullname
= Parrot_str_new(interp
, "??? :: ???", 10);
213 /* fetch Parrot_sub of the current sub in the given context */
214 if (!VTABLE_isa(interp
, subpmc
, CONST_STRING(interp
, "Sub")))
217 PMC_get_sub(interp
, subpmc
, sub
);
218 /* set the sub name */
219 info
->subname
= sub
->name
;
221 /* set the namespace name and fullname of the sub */
222 if (PMC_IS_NULL(sub
->namespace_name
)) {
223 info
->nsname
= CONST_STRING(interp
, "");
224 info
->fullname
= info
->subname
;
227 info
->nsname
= VTABLE_get_string(interp
, sub
->namespace_name
);
228 info
->fullname
= Parrot_full_sub_name(interp
, subpmc
);
231 /* return here if there is no current pc */
232 if (Parrot_pcc_get_pc(interp
, ctx
) == NULL
)
235 /* calculate the current pc */
236 info
->pc
= Parrot_pcc_get_pc(interp
, ctx
) - sub
->seg
->base
.data
;
238 /* determine the current source file/line */
239 if (Parrot_pcc_get_pc(interp
, ctx
)) {
240 const size_t offs
= info
->pc
;
242 opcode_t
*pc
= sub
->seg
->base
.data
;
243 PackFile_Debug
* const debug
= sub
->seg
->debugs
;
247 for (i
= n
= 0; n
< sub
->seg
->base
.size
; i
++) {
248 op_info_t
* const op_info
= &interp
->op_info_table
[*pc
];
249 opcode_t var_args
= 0;
251 if (i
>= debug
->base
.size
)
254 /* set source line and file */
255 info
->line
= debug
->base
.data
[i
];
256 info
->file
= Parrot_debug_pc_to_filename(interp
, debug
, i
);
259 ADD_OP_VAR_PART(interp
, sub
->seg
, pc
, var_args
);
260 n
+= op_info
->op_count
+ var_args
;
261 pc
+= op_info
->op_count
+ var_args
;
269 =item C<STRING* Parrot_Context_infostr(PARROT_INTERP, PMC *ctx)>
271 Formats context information for display. Takes a context pointer and
272 returns a pointer to the text. Used in debug.c and warnings.c
279 PARROT_CAN_RETURN_NULL
280 PARROT_WARN_UNUSED_RESULT
282 Parrot_Context_infostr(PARROT_INTERP
, ARGIN(PMC
*ctx
))
284 ASSERT_ARGS(Parrot_Context_infostr
)
285 Parrot_Context_info info
;
287 const char * const msg
= (CURRENT_CONTEXT(interp
) == ctx
)
291 Parrot_block_GC_mark(interp
);
292 if (Parrot_Context_get_info(interp
, ctx
, &info
)) {
294 res
= Parrot_sprintf_c(interp
,
295 "%s '%Ss' pc %d (%Ss:%d)", msg
,
296 info
.fullname
, info
.pc
, info
.file
, info
.line
);
299 Parrot_unblock_GC_mark(interp
);
305 =item C<PMC* Parrot_find_pad(PARROT_INTERP, STRING *lex_name, PMC *ctx)>
307 Locate the LexPad containing the given name. Return NULL on failure.
313 PARROT_CAN_RETURN_NULL
314 PARROT_WARN_UNUSED_RESULT
316 Parrot_find_pad(PARROT_INTERP
, ARGIN(STRING
*lex_name
), ARGIN(PMC
*ctx
))
318 ASSERT_ARGS(Parrot_find_pad
)
320 PMC
* const lex_pad
= Parrot_pcc_get_lex_pad(interp
, ctx
);
321 PMC
* outer
= Parrot_pcc_get_outer_ctx(interp
, ctx
);
326 if (!PMC_IS_NULL(lex_pad
))
327 if (VTABLE_exists_keyed_str(interp
, lex_pad
, lex_name
))
337 =item C<PMC* Parrot_find_dynamic_pad(PARROT_INTERP, STRING *lex_name, PMC *ctx)>
339 Locate the LexPad containing the given C<lex_name> in C<ctx> and
340 its caller pads. Return PMCNULL on failure.
346 PARROT_CAN_RETURN_NULL
347 PARROT_WARN_UNUSED_RESULT
349 Parrot_find_dynamic_pad(PARROT_INTERP
, ARGIN(STRING
*lex_name
), ARGIN(PMC
*ctx
))
351 ASSERT_ARGS(Parrot_find_dynamic_pad
)
353 PMC
* const lex_pad
= Parrot_pcc_get_lex_pad(interp
, ctx
);
354 PMC
* caller
= Parrot_pcc_get_caller_ctx(interp
, ctx
);
359 if (!PMC_IS_NULL(lex_pad
))
360 if (VTABLE_exists_keyed_str(interp
, lex_pad
, lex_name
))
370 =item C<void Parrot_capture_lex(PARROT_INTERP, PMC *sub_pmc)>
372 Capture the current lexical environment of a sub.
379 Parrot_capture_lex(PARROT_INTERP
, ARGMOD(PMC
*sub_pmc
))
381 ASSERT_ARGS(Parrot_capture_lex
)
382 PMC
* const ctx
= CURRENT_CONTEXT(interp
);
383 Parrot_Sub_attributes
*current_sub
;
384 Parrot_Sub_attributes
*sub
;
386 PMC_get_sub(interp
, Parrot_pcc_get_sub(interp
, ctx
), current_sub
);
388 /* MultiSub gets special treatment */
389 if (VTABLE_isa(interp
, sub_pmc
, CONST_STRING(interp
, "MultiSub"))) {
391 PMC
* const iter
= VTABLE_get_iter(interp
, sub_pmc
);
393 while (VTABLE_get_bool(interp
, iter
)) {
395 PMC
* const child_pmc
= VTABLE_shift_pmc(interp
, iter
);
396 Parrot_Sub_attributes
*child_sub
, *child_outer_sub
;
398 PMC_get_sub(interp
, child_pmc
, child_sub
);
400 if (!PMC_IS_NULL(child_sub
->outer_sub
)) {
401 PMC_get_sub(interp
, child_sub
->outer_sub
, child_outer_sub
);
402 if (Parrot_str_equal(interp
, current_sub
->subid
,
403 child_outer_sub
->subid
)) {
404 child_sub
->outer_ctx
= ctx
;
411 /* the sub_pmc has to have an outer_sub that is the caller */
412 PMC_get_sub(interp
, sub_pmc
, sub
);
413 if (PMC_IS_NULL(sub
->outer_sub
))
417 /* verify that the current sub is sub_pmc's :outer */
418 PMC_get_sub(interp
, sub
->outer_sub
, outer_sub
);
419 if (Parrot_str_not_equal(interp
, current_sub
->subid
,
421 Parrot_ex_throw_from_c_args(interp
, NULL
,
422 EXCEPTION_INVALID_OPERATION
, "'%Ss' isn't the :outer of '%Ss'",
423 current_sub
->name
, sub
->name
);
428 /* set the sub's outer context to the current context */
429 sub
->outer_ctx
= ctx
;
435 =item C<PMC* parrot_new_closure(PARROT_INTERP, PMC *sub_pmc)>
439 Creates a new closure, saving the context information. Takes a pointer
442 Returns a pointer to the closure, (or throws exceptions if invalid).
449 PARROT_CANNOT_RETURN_NULL
450 PARROT_WARN_UNUSED_RESULT
452 parrot_new_closure(PARROT_INTERP
, ARGIN(PMC
*sub_pmc
))
454 ASSERT_ARGS(parrot_new_closure
)
455 PMC
* const clos_pmc
= VTABLE_clone(interp
, sub_pmc
);
456 Parrot_capture_lex(interp
, clos_pmc
);
463 =item C<void Parrot_continuation_check(PARROT_INTERP, const PMC *pmc)>
465 Verifies that the provided continuation is sane.
472 Parrot_continuation_check(PARROT_INTERP
, ARGIN(const PMC
*pmc
))
474 ASSERT_ARGS(Parrot_continuation_check
)
475 PMC
* const to_ctx
= PARROT_CONTINUATION(pmc
)->to_ctx
;
476 if (PMC_IS_NULL(to_ctx
))
477 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
478 "Continuation invoked after deactivation.");
483 =item C<void Parrot_continuation_rewind_environment(PARROT_INTERP, PMC *pmc)>
485 Restores the appropriate context for the continuation.
492 Parrot_continuation_rewind_environment(PARROT_INTERP
, ARGIN(PMC
*pmc
))
494 ASSERT_ARGS(Parrot_continuation_rewind_environment
)
496 PMC
* const to_ctx
= PARROT_CONTINUATION(pmc
)->to_ctx
;
498 /* debug print before context is switched */
499 if (Interp_trace_TEST(interp
, PARROT_TRACE_SUB_CALL_FLAG
)) {
500 PMC
* const sub
= Parrot_pcc_get_sub(interp
, to_ctx
);
502 Parrot_io_eprintf(interp
, "# Back in sub '%Ss', env %p\n",
503 Parrot_full_sub_name(interp
, sub
),
504 interp
->dynamic_env
);
508 CURRENT_CONTEXT(interp
) = to_ctx
;
514 =item C<void * Parrot_get_sub_pmc_from_subclass(PARROT_INTERP, PMC *subclass)>
516 Gets a Parrot_sub structure from something that isn't a Sub PMC, but rather a
524 PARROT_CANNOT_RETURN_NULL
526 Parrot_get_sub_pmc_from_subclass(PARROT_INTERP
, ARGIN(PMC
*subclass
)) {
527 ASSERT_ARGS(Parrot_get_sub_pmc_from_subclass
)
530 /* Ensure we really do have a subclass of sub. */
531 if (VTABLE_isa(interp
, subclass
, CONST_STRING(interp
, "Sub"))) {
532 /* If it's actually a PMC still, probably does the same structure
534 if (!PObj_is_object_TEST(subclass
)) {
535 return PARROT_SUB(subclass
);
538 /* Get the Sub PMC itself. */
539 key
= pmc_new(interp
, enum_class_String
);
540 VTABLE_set_string_native(interp
, key
, CONST_STRING(interp
, "Sub"));
541 sub_pmc
= VTABLE_get_attr_keyed(interp
, subclass
, key
, CONST_STRING(interp
, "proxy"));
542 if (sub_pmc
->vtable
->base_type
== enum_class_Sub
) {
543 return PARROT_SUB(sub_pmc
);
546 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
547 "Attempting to do sub operation on non-Sub.");
556 F<include/parrot/sub.h>.
560 Initial version by Melvin on 2002/06/6.
569 * c-file-style: "parrot"
571 * vim: expandtab shiftwidth=4: