Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
409 lines (258 sloc) 8.58 KB
/*
Copyright (C) 2001-2014, Parrot Foundation.
=head1 NAME
src/pmc/continuation.pmc - Continuation PMC
=head1 DESCRIPTION
A C<Continuation> has a copy of the interpreter's context at the location where
the Continuation was constructed. See the L<Glossary|docs/glossary.pod> for
more information.
=head2 Functions
=over 4
=cut
*/
#include "parrot/oplib/ops.h"
#include "pmc/pmc_sub.h"
/*
=back
=head2 Methods
=over 4
=cut
*/
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */
/*
* A Continuation (and an ExceptionHandler) has in its context a pointer
* to the register frame, which contains active objects.
* Additionally ct->current_cont has the continuation of the caller.
*/
pmclass Continuation auto_attrs provides invokable {
/* continuation destination */
ATTR PackFile_ByteCode *seg; /* bytecode segment */
ATTR opcode_t *address; /* start of bytecode, addr to continue */
ATTR PMC *to_ctx; /* pointer to dest context */
ATTR PMC *to_call_object; /* pointer to CallSignature */
/* a Continuation keeps the from_ctx alive */
ATTR PMC *from_ctx; /* sub, this cont is returning from */
ATTR INTVAL runloop_id; /* id of the creating runloop. */
ATTR INTVAL invoked; /* flag when a handler has been invoked. */
/*
=item C<void init()>
Initializes the continuation.
=cut
*/
VTABLE void init() {
PMC * const to_ctx = CURRENT_CONTEXT(INTERP);
SET_ATTR_to_ctx(INTERP, SELF, to_ctx);
SET_ATTR_to_call_object(INTERP, SELF, Parrot_pcc_get_signature(INTERP, to_ctx));
SET_ATTR_from_ctx(INTERP, SELF, CURRENT_CONTEXT(INTERP));
SET_ATTR_runloop_id(INTERP, SELF, 0);
SET_ATTR_seg(INTERP, SELF, INTERP->code);
SET_ATTR_address(INTERP, SELF, NULL);
PObj_custom_mark_SET(SELF);
}
/*
=item C<void init_pmc(PMC *continuation)>
Initializes the continuation with values from the provided continuation.
=cut
*/
/* if they pass in a PMC to initialize with */
VTABLE void init_pmc(PMC *values) {
PMC *to_ctx;
opcode_t *address;
PackFile_ByteCode *seg;
GET_ATTR_to_ctx(INTERP, values, to_ctx);
SET_ATTR_to_ctx(INTERP, SELF, to_ctx);
SET_ATTR_to_call_object(INTERP, SELF, Parrot_pcc_get_signature(INTERP, to_ctx));
SET_ATTR_from_ctx(INTERP, SELF, CURRENT_CONTEXT(INTERP));
SET_ATTR_runloop_id(INTERP, SELF, 0);
GET_ATTR_seg(INTERP, values, seg);
SET_ATTR_seg(INTERP, SELF, seg);
GET_ATTR_address(INTERP, values, address);
SET_ATTR_address(INTERP, SELF, address);
PObj_custom_mark_SET(SELF);
}
/*
=item C<void mark()>
Marks the continuation as live.
=cut
*/
VTABLE void mark() :no_wb {
Parrot_Continuation_attributes * const cont = PARROT_CONTINUATION(SELF);
/* If Continuation wasn't fully constructed yet */
if (!cont) return;
if (cont->to_ctx) Parrot_gc_mark_PMC_alive(INTERP, cont->to_ctx);
if (cont->to_call_object) Parrot_gc_mark_PMC_alive(INTERP, cont->to_call_object);
if (cont->from_ctx) Parrot_gc_mark_PMC_alive(INTERP, cont->from_ctx);
if (cont->seg && ! Interp_flags_TEST(interp, PARROT_IS_THREAD))
Parrot_gc_mark_PMC_alive(INTERP, cont->seg->base.pf->view);
}
/*
=item C<PMC * get_attr_str(STRING *attr)>
Get the value of an attribute by name
=cut
*/
VTABLE PMC * get_attr_str(STRING *attr) :no_wb {
PMC * val = PMCNULL;
INTVAL ival;
/*if (STRING_equal(INTERP, attr, CONST_STRING(INTERP, "seg")))
GET_ATTR_seg(INTERP, SELF, val);*/
if (STRING_equal(INTERP, attr, CONST_STRING(INTERP, "to_ctx")))
GET_ATTR_to_ctx(INTERP, SELF, val);
else if (STRING_equal(INTERP, attr, CONST_STRING(INTERP, "to_call_object")))
GET_ATTR_to_call_object(INTERP, SELF, val);
else if (STRING_equal(INTERP, attr, CONST_STRING(INTERP, "from_ctx")))
GET_ATTR_from_ctx(INTERP, SELF, val);
else if (STRING_equal(INTERP, attr, CONST_STRING(INTERP, "runloop_id"))) {
GET_ATTR_runloop_id(INTERP, SELF, ival);
val = Parrot_pmc_box_integer(INTERP, ival);
}
else if (STRING_equal(INTERP, attr, CONST_STRING(INTERP, "invoked"))) {
GET_ATTR_invoked(INTERP, SELF, ival);
val = Parrot_pmc_box_integer(INTERP, ival);
}
else
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ATTRIB_NOT_FOUND,
"%Ss: Attribute %Ss not found", VTABLE_name(INTERP, SELF), attr);
return val;
}
/*
=item C<PMC *clone()>
Creates and returns a clone of the continuation.
=cut
*/
VTABLE PMC *clone() :no_wb {
/* Start to prepare for subclassable continuations */
return Parrot_pmc_new_init(INTERP, SELF->vtable->base_type, SELF);
}
/*
=item C<PMC *set_pmc()>
Assigns context.
=cut
*/
VTABLE void set_pmc(PMC *src) {
STRUCT_COPY(PMC_data_typed(SELF, Parrot_Continuation_attributes *),
PMC_data_typed(src, Parrot_Continuation_attributes *));
}
/*
=item C<void set_pointer(void *value)>
Sets the pointer to the given return instruction and captures the runloop id
for any returned values.
=cut
*/
VTABLE void set_pointer(void *value) {
SET_ATTR_address(INTERP, SELF, (opcode_t *)value);
SET_ATTR_runloop_id(INTERP, SELF, INTERP->current_runloop_id);
}
/*
=item C<void *get_pointer()>
Returns the pointer to the return instruction.
=cut
*/
VTABLE void *get_pointer() :no_wb {
opcode_t *address;
GET_ATTR_address(INTERP, SELF, address);
return address;
}
/*
=item C<INTVAL defined()>
=item C<INTVAL get_bool()>
Returns whether the subroutine is defined.
=cut
*/
VTABLE INTVAL defined() :no_wb {
opcode_t *address;
GET_ATTR_address(INTERP, SELF, address);
return address != NULL;
}
VTABLE INTVAL get_bool() :no_wb {
opcode_t *address;
GET_ATTR_address(INTERP, SELF, address);
return address != NULL;
}
/*
=item C<opcode_t *invoke(void *next)>
Restores the context of the interpreter and returns the branch
destination to continue execution.
=cut
*/
VTABLE opcode_t *invoke(void *next) :no_wb {
UNUSED(next)
PMC * const from_obj = Parrot_pcc_get_signature(INTERP, CURRENT_CONTEXT(INTERP));
opcode_t *pc;
PackFile_ByteCode *seg;
GET_ATTR_seg(INTERP, SELF, seg);
GET_ATTR_address(INTERP, SELF, pc);
SET_ATTR_invoked(INTERP, SELF, 1);
Parrot_sub_continuation_check(INTERP, SELF);
Parrot_sub_continuation_rewind_environment(INTERP, SELF);
if (!PMC_IS_NULL(from_obj))
Parrot_pcc_set_signature(INTERP, CURRENT_CONTEXT(INTERP), from_obj);
/* switch segment */
if (INTERP->code != seg)
Parrot_pf_switch_to_cs(INTERP, seg, 1);
return pc;
}
/*
=item C<STRING *get_string()>
Experimental: returns caller info as a STRING.
=cut
*/
VTABLE STRING *get_string() :no_wb {
PMC *to_ctx;
GET_ATTR_to_ctx(INTERP, SELF, to_ctx);
return Parrot_sub_Context_infostr(INTERP, to_ctx, 0);
}
/*
=item C<INTVAL rid()>
Experimental: return the runloop_id value.
=cut
*/
METHOD rid() {
INTVAL runloop_id;
GET_ATTR_runloop_id(INTERP, SELF, runloop_id);
RETURN(INTVAL runloop_id);
}
/*
=item C<PMC *caller()>
Experimental: return callers PMC or PMCNULL if none.
=cut
*/
METHOD caller() {
PMC *to_ctx, *caller;
GET_ATTR_to_ctx(INTERP, SELF, to_ctx);
caller = Parrot_pcc_get_sub(INTERP, to_ctx);
if (!caller)
caller = PMCNULL;
else {
Parrot_Sub_attributes *sub;
PMC_get_sub(INTERP, caller, sub);
if (!sub->seg)
caller = PMCNULL;
}
RETURN(PMC *caller);
}
/*
=item C<PMC *continuation()>
Experimental: fetches the return continuation PMC of this Continuation or PMCNULL if none.
=cut
*/
METHOD continuation() {
PMC *to_ctx, *cont;
GET_ATTR_to_ctx(INTERP, SELF, to_ctx);
cont = Parrot_pcc_get_continuation(INTERP, to_ctx);
if (cont)
RETURN(PMC *cont);
RETURN(PMC *PMCNULL);
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/