2 Copyright (C) 2001-2010, 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"
26 #include "parrot/oplib/core_ops.h"
28 /* HEADERIZER HFILE: include/parrot/sub.h */
33 =item C<void mark_context_start(void)>
35 Indicate that a new round of context marking is about to take place.
41 static int context_gc_mark
= 0;
44 mark_context_start(void)
46 ASSERT_ARGS(mark_context_start
)
47 if (++context_gc_mark
== 0) context_gc_mark
= 1;
53 =item C<STRING* Parrot_full_sub_name(PARROT_INTERP, PMC* sub_pmc)>
55 Return namespace, name, and location of subroutine.
62 PARROT_CAN_RETURN_NULL
63 PARROT_WARN_UNUSED_RESULT
65 Parrot_full_sub_name(PARROT_INTERP
, ARGIN_NULLOK(PMC
* sub_pmc
))
67 ASSERT_ARGS(Parrot_full_sub_name
)
68 if (sub_pmc
&& VTABLE_defined(interp
, sub_pmc
)) {
69 Parrot_Sub_attributes
*sub
;
71 PMC_get_sub(interp
, sub_pmc
, sub
);
73 if (PMC_IS_NULL(sub
->namespace_stash
)) {
78 STRING
* const semicolon
= CONST_STRING(interp
, ";");
82 * When running with -t4, the invoke done in
83 * Parrot_ns_get_name stomps on settings in interp; we
84 * have to save these and restore them to avoid affecting
85 * the running program.
87 PMC
* const saved_ccont
= interp
->current_cont
;
89 Parrot_block_GC_mark(interp
);
91 ns_array
= Parrot_ns_get_name(interp
, sub
->namespace_stash
);
93 /* Restore stuff that might have got overwritten */
94 interp
->current_cont
= saved_ccont
;
97 VTABLE_push_string(interp
, ns_array
, sub
->name
);
99 res
= Parrot_str_join(interp
, semicolon
, ns_array
);
100 Parrot_unblock_GC_mark(interp
);
109 =item C<int Parrot_Context_get_info(PARROT_INTERP, PMC *ctx, Parrot_Context_info
112 Takes pointers to a context and its information table.
113 Populates the table and returns 0 or 1. XXX needs explanation
114 Used by Parrot_Context_infostr.
122 Parrot_Context_get_info(PARROT_INTERP
, ARGIN(PMC
*ctx
),
123 ARGOUT(Parrot_Context_info
*info
))
125 ASSERT_ARGS(Parrot_Context_get_info
)
127 Parrot_Sub_attributes
*sub
;
130 /* set file/line/pc defaults */
131 info
->file
= CONST_STRING(interp
, "(unknown file)");
135 info
->subname
= NULL
;
136 info
->fullname
= NULL
;
138 subpmc
= Parrot_pcc_get_sub(interp
, ctx
);
140 /* is the current sub of the specified context valid? */
141 if (PMC_IS_NULL(subpmc
)) {
142 info
->subname
= Parrot_str_new(interp
, "???", 3);
143 info
->nsname
= info
->subname
;
144 info
->fullname
= Parrot_str_new(interp
, "??? :: ???", 10);
149 /* fetch Parrot_sub of the current sub in the given context */
150 if (!VTABLE_isa(interp
, subpmc
, CONST_STRING(interp
, "Sub")))
153 PMC_get_sub(interp
, subpmc
, sub
);
154 /* set the sub name */
155 info
->subname
= sub
->name
;
157 /* set the namespace name and fullname of the sub */
158 if (PMC_IS_NULL(sub
->namespace_name
)) {
159 info
->nsname
= CONST_STRING(interp
, "");
160 info
->fullname
= info
->subname
;
163 info
->nsname
= VTABLE_get_string(interp
, sub
->namespace_name
);
164 info
->fullname
= Parrot_full_sub_name(interp
, subpmc
);
167 pc
= Parrot_pcc_get_pc(interp
, ctx
);
169 /* return here if there is no current pc */
173 /* calculate the current pc */
174 info
->pc
= pc
- sub
->seg
->base
.data
;
176 /* determine the current source file/line */
178 const size_t offs
= info
->pc
;
180 opcode_t
*pc
= sub
->seg
->base
.data
;
181 PackFile_Debug
* const debug
= sub
->seg
->debugs
;
185 for (i
= n
= 0; n
< sub
->seg
->base
.size
; ++i
) {
186 op_info_t
* const op_info
= sub
->seg
->op_info_table
[*pc
];
187 opcode_t var_args
= 0;
189 if (i
>= debug
->base
.size
)
192 /* set source line and file */
193 info
->line
= debug
->base
.data
[i
];
194 info
->file
= Parrot_debug_pc_to_filename(interp
, debug
, i
);
197 ADD_OP_VAR_PART(interp
, sub
->seg
, pc
, var_args
);
198 n
+= op_info
->op_count
+ var_args
;
199 pc
+= op_info
->op_count
+ var_args
;
209 =item C<INTVAL Parrot_Sub_get_line_from_pc(PARROT_INTERP, PMC *subpmc, opcode_t
212 Given a PMC sub and the current opcode, returns the corresponding PIR line
220 Parrot_Sub_get_line_from_pc(PARROT_INTERP
, ARGIN_NULLOK(PMC
*subpmc
), ARGIN_NULLOK(opcode_t
*pc
))
222 ASSERT_ARGS(Parrot_Sub_get_line_from_pc
)
223 Parrot_Sub_attributes
*sub
;
224 opcode_t
*base_pc
, *debug_ops
;
225 size_t i
, op
, current_annotation
, debug_size
;
230 PMC_get_sub(interp
, subpmc
, sub
);
232 debug_ops
= sub
->seg
->debugs
->base
.data
;
233 debug_size
= sub
->seg
->debugs
->base
.size
;
234 base_pc
= sub
->seg
->base
.data
;
235 current_annotation
= pc
- base_pc
;
237 for (i
= op
= 0; op
< debug_size
; ++i
) {
238 op_info_t
* const op_info
= interp
->code
->op_info_table
[*base_pc
];
239 opcode_t var_args
= 0;
244 if (op
>= current_annotation
)
247 ADD_OP_VAR_PART(interp
, sub
->seg
, base_pc
, var_args
);
248 op
+= op_info
->op_count
+ var_args
;
249 base_pc
+= op_info
->op_count
+ var_args
;
258 =item C<STRING * Parrot_Sub_get_filename_from_pc(PARROT_INTERP, PMC *subpmc,
261 Given a PMC sub and the current opcode, returns the corresponding PIR file
268 PARROT_CANNOT_RETURN_NULL
270 Parrot_Sub_get_filename_from_pc(PARROT_INTERP
, ARGIN_NULLOK(PMC
*subpmc
),
271 ARGIN_NULLOK(opcode_t
*pc
))
273 ASSERT_ARGS(Parrot_Sub_get_filename_from_pc
)
274 Parrot_Sub_attributes
*sub
;
275 PackFile_Debug
*debug
;
279 return CONST_STRING(interp
, "unknown file");
281 PMC_get_sub(interp
, subpmc
, sub
);
283 debug
= sub
->seg
->debugs
;
284 position
= pc
- sub
->seg
->base
.data
;
286 return Parrot_debug_pc_to_filename(interp
, debug
, position
);
291 =item C<STRING* Parrot_Context_infostr(PARROT_INTERP, PMC *ctx)>
293 Formats context information for display. Takes a context pointer and
294 returns a pointer to the text. Used in debug.c and warnings.c
301 PARROT_CAN_RETURN_NULL
302 PARROT_WARN_UNUSED_RESULT
304 Parrot_Context_infostr(PARROT_INTERP
, ARGIN(PMC
*ctx
))
306 ASSERT_ARGS(Parrot_Context_infostr
)
307 Parrot_Context_info info
;
309 const char * const msg
= (CURRENT_CONTEXT(interp
) == ctx
)
313 Parrot_block_GC_mark(interp
);
314 if (Parrot_Context_get_info(interp
, ctx
, &info
)) {
316 res
= Parrot_sprintf_c(interp
,
317 "%s '%Ss' pc %d (%Ss:%d)", msg
,
318 info
.fullname
, info
.pc
, info
.file
, info
.line
);
321 Parrot_unblock_GC_mark(interp
);
327 =item C<PMC* Parrot_find_pad(PARROT_INTERP, STRING *lex_name, PMC *ctx)>
329 Locate the LexPad containing the given name. Return NULL on failure.
335 PARROT_CAN_RETURN_NULL
336 PARROT_WARN_UNUSED_RESULT
338 Parrot_find_pad(PARROT_INTERP
, ARGIN(STRING
*lex_name
), ARGIN(PMC
*ctx
))
340 ASSERT_ARGS(Parrot_find_pad
)
342 PMC
* const lex_pad
= Parrot_pcc_get_lex_pad(interp
, ctx
);
343 PMC
* outer
= Parrot_pcc_get_outer_ctx(interp
, ctx
);
345 if (PMC_IS_NULL(outer
))
348 if (!PMC_IS_NULL(lex_pad
))
349 if (VTABLE_exists_keyed_str(interp
, lex_pad
, lex_name
))
359 =item C<PMC* Parrot_find_dynamic_pad(PARROT_INTERP, STRING *lex_name, PMC *ctx)>
361 Locate the LexPad containing the given C<lex_name> in C<ctx> and
362 its caller pads. Return PMCNULL on failure.
368 PARROT_CAN_RETURN_NULL
369 PARROT_WARN_UNUSED_RESULT
371 Parrot_find_dynamic_pad(PARROT_INTERP
, ARGIN(STRING
*lex_name
), ARGIN(PMC
*ctx
))
373 ASSERT_ARGS(Parrot_find_dynamic_pad
)
375 PMC
* const lex_pad
= Parrot_pcc_get_lex_pad(interp
, ctx
);
376 PMC
* caller
= Parrot_pcc_get_caller_ctx(interp
, ctx
);
378 if (PMC_IS_NULL(caller
))
381 if (!PMC_IS_NULL(lex_pad
))
382 if (VTABLE_exists_keyed_str(interp
, lex_pad
, lex_name
))
392 =item C<void Parrot_capture_lex(PARROT_INTERP, PMC *sub_pmc)>
394 Capture the current lexical environment of a sub.
402 Parrot_capture_lex(PARROT_INTERP
, ARGMOD(PMC
*sub_pmc
))
404 ASSERT_ARGS(Parrot_capture_lex
)
405 PMC
* const ctx
= CURRENT_CONTEXT(interp
);
406 Parrot_Sub_attributes
*current_sub
;
407 Parrot_Sub_attributes
*sub
;
409 PMC_get_sub(interp
, Parrot_pcc_get_sub(interp
, ctx
), current_sub
);
411 /* MultiSub gets special treatment */
412 if (VTABLE_isa(interp
, sub_pmc
, CONST_STRING(interp
, "MultiSub"))) {
414 PMC
* const iter
= VTABLE_get_iter(interp
, sub_pmc
);
416 while (VTABLE_get_bool(interp
, iter
)) {
418 PMC
* const child_pmc
= VTABLE_shift_pmc(interp
, iter
);
419 Parrot_Sub_attributes
*child_sub
, *child_outer_sub
;
421 PMC_get_sub(interp
, child_pmc
, child_sub
);
423 if (!PMC_IS_NULL(child_sub
->outer_sub
)) {
424 PMC_get_sub(interp
, child_sub
->outer_sub
, child_outer_sub
);
425 if (Parrot_str_equal(interp
, current_sub
->subid
,
426 child_outer_sub
->subid
)) {
427 child_sub
->outer_ctx
= ctx
;
434 /* the sub_pmc has to have an outer_sub that is the caller */
435 PMC_get_sub(interp
, sub_pmc
, sub
);
436 if (PMC_IS_NULL(sub
->outer_sub
))
439 /* set the sub's outer context to the current context */
440 sub
->outer_ctx
= ctx
;
446 =item C<PMC* parrot_new_closure(PARROT_INTERP, PMC *sub_pmc)>
450 Creates a new closure, saving the context information. Takes a pointer
453 Returns a pointer to the closure, (or throws exceptions if invalid).
460 PARROT_CANNOT_RETURN_NULL
461 PARROT_WARN_UNUSED_RESULT
463 parrot_new_closure(PARROT_INTERP
, ARGIN(PMC
*sub_pmc
))
465 ASSERT_ARGS(parrot_new_closure
)
466 PMC
* const clos_pmc
= VTABLE_clone(interp
, sub_pmc
);
467 Parrot_capture_lex(interp
, clos_pmc
);
474 =item C<void Parrot_continuation_check(PARROT_INTERP, const PMC *pmc)>
476 Verifies that the provided continuation is sane.
483 Parrot_continuation_check(PARROT_INTERP
, ARGIN(const PMC
*pmc
))
485 ASSERT_ARGS(Parrot_continuation_check
)
486 PMC
* const to_ctx
= PARROT_CONTINUATION(pmc
)->to_ctx
;
487 if (PMC_IS_NULL(to_ctx
))
488 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
489 "Continuation invoked after deactivation.");
494 =item C<void Parrot_continuation_rewind_environment(PARROT_INTERP, PMC *pmc)>
496 Restores the appropriate context for the continuation.
503 Parrot_continuation_rewind_environment(PARROT_INTERP
, ARGIN(PMC
*pmc
))
505 ASSERT_ARGS(Parrot_continuation_rewind_environment
)
507 PMC
* const to_ctx
= PARROT_CONTINUATION(pmc
)->to_ctx
;
508 PMC
* const sig
= Parrot_pcc_get_signature(interp
, CURRENT_CONTEXT(interp
));
510 /* debug print before context is switched */
511 if (Interp_trace_TEST(interp
, PARROT_TRACE_SUB_CALL_FLAG
)) {
512 PMC
* const sub
= Parrot_pcc_get_sub(interp
, to_ctx
);
514 Parrot_io_eprintf(interp
, "# Back in sub '%Ss', env %p\n",
515 Parrot_full_sub_name(interp
, sub
),
516 interp
->dynamic_env
);
520 CURRENT_CONTEXT(interp
) = to_ctx
;
521 Parrot_pcc_set_signature(interp
, to_ctx
, sig
);
527 =item C<void * Parrot_get_sub_pmc_from_subclass(PARROT_INTERP, PMC *subclass)>
529 Gets a Parrot_sub structure from something that isn't a Sub PMC, but rather a
537 PARROT_CANNOT_RETURN_NULL
539 Parrot_get_sub_pmc_from_subclass(PARROT_INTERP
, ARGIN(PMC
*subclass
)) {
540 ASSERT_ARGS(Parrot_get_sub_pmc_from_subclass
)
542 /* Ensure we really do have a subclass of sub. */
543 if (VTABLE_isa(interp
, subclass
, CONST_STRING(interp
, "Sub"))) {
546 /* If it's actually a PMC still, probably does the same structure
548 if (!PObj_is_object_TEST(subclass
)) {
549 return PARROT_SUB(subclass
);
552 /* Get the Sub PMC itself. */
553 key
= Parrot_pmc_new(interp
, enum_class_String
);
554 VTABLE_set_string_native(interp
, key
, CONST_STRING(interp
, "Sub"));
555 sub_pmc
= VTABLE_get_attr_keyed(interp
, subclass
, key
, CONST_STRING(interp
, "proxy"));
556 if (sub_pmc
->vtable
->base_type
== enum_class_Sub
) {
557 return PARROT_SUB(sub_pmc
);
560 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
561 "Attempting to do sub operation on non-Sub.");
570 F<include/parrot/sub.h>.
579 * c-file-style: "parrot"
581 * vim: expandtab shiftwidth=4: