Re: custom model rows-reordered marshal
- From: Torsten Schoenfeld <kaffeetisch gmx de>
- To: gtk-perl-list gnome org
- Subject: Re: custom model rows-reordered marshal
- Date: Sun, 24 Aug 2008 19:12:40 +0200
Kevin Ryde wrote:
There might be another similar bit in gtk_tree_model_get too.
OK, I just sat down and I think I figured it out. If you are *really*
interested, I attach two files: perl-stack-fiddling lists the expansions of the
relevant macros[1], and perl-stack-fiddling-tree-model-get-all is a "trace" of
what happens to the relevant stacks[2] at each point in the execution of
$model->get($iter).
It all boils down to this: when Perl code is invoked, for example by
gtk2perl_tree_model_get_value, the arguments for the Perl code are put on the
stack *after the element pointed to by the global stack pointer*. That is,
everything after the global stack pointer is the scratch area used by the
calling code to marshal arguments in and out of Perl code. So when you put
stuff on the stack in some XSUB, and there's a chance that some code is going to
invoke Perl code before you return from the XSUB, make sure you update the
global stack pointer to point to the element you just put on the stack.
In practical terms: after every XPUSHs or similar, use PUTBACK if it's possible
that some Perl code is invoked before you return from the XSUB.
I hope I can remember all this because I don't want to have to think through it
again.
The case where you give explicit column numbers seems ok. I suppose the
sp global is already past where the local XPUSHs is writing. But do
both cases need an SPAGAIN in case the stack has been extended deep
within the get_value and/or get_n_columns?
In practice, Gtk2::TreeModel::get with explicit column numbers is safe since
there are always more input arguments than return values, and so the stuff we
put on the stack can't end up being overwritten. But a PUTBACK can't hurt
either, I think. The get_n_columns() call is harmless since we haven't put
anything on the stack yet that might be overwritten. So, I think the attached
patch should do it.
Or for that matter the iter_n_children in the marshal too?
I don't see how iter_n_children is affected by this -- can you elaborate?
Does all of the above make sense?
--
Bye,
-Torsten
[1] Created with Porting/expand-macro.pl from bleadperl.
[2] Actually, I think the markstack stuff isn't relevant after all. So maybe
just ignore that.
dSP
SV **sp = (my_perl->Istack_sp)
dXSARGS
SV **sp = (my_perl->Istack_sp);
I32 ax = (*(my_perl->Imarkstack_ptr)--);
SV **mark = (my_perl->Istack_base) + ax++;
I32 items = (I32) (sp - mark)
PUSHMARK(A0)
(void) ({
if (++(my_perl->Imarkstack_ptr) == (my_perl->Imarkstack_max))
Perl_markstack_grow (my_perl);
*(my_perl->Imarkstack_ptr) = (I32) ((A0) - (my_perl->Istack_base));
})
ST(A0)
(my_perl->Istack_base)[ax + (A0)]
PUSHs(A0)
(*++sp = (A0))
XPUSHs(A0)
(void) ({
(void) ({
if ((my_perl->Istack_max) - sp < (int) (1)) {
sp = Perl_stack_grow (my_perl, sp, sp, (int) (1));
}
});
(*++sp = (A0));
})
POPs
(*sp--)
PUTBACK
(my_perl->Istack_sp) = sp
SPAGAIN
sp = (my_perl->Istack_sp)
my @a = $m->get($i)
XS(XS_Gtk2__TreeModel_get)
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^sp
^PL_stack_sp
dXSARGS -> PL_markstack_ptr--
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^sp
^PL_stack_sp
PPCODE -> sp -= items
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^sp
^PL_stack_sp
gtk_tree_model_get_n_columns (tree_model)
gtk2perl_tree_model_get_n_columns
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^sp
^PL_stack_sp
PUSHMARK (SP)
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^y
^sp
^PL_stack_sp
PUSHs (m)
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | m | ...
^x
^y
^sp
^PL_stack_sp
PUTBACK
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | m | ...
^x
^y
^sp
^PL_stack_sp
call_method("GET_N_COLUMNS") -> GET_N_COLUMNS(m) -> returns n
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | n | ...
^x
^y
^sp
^PL_stack_sp
SPAGAIN
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | n | ...
^x
^y
^sp
^PL_stack_sp
POPi
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | | ...
^x
^y
^sp
^PL_stack_sp
PUTBACK
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | | ...
^x
^y
^sp
^PL_stack_sp
back in XS(XS_Gtk2__TreeModel_get)
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^y
^sp
^PL_stack_sp
gtk_tree_model_get_value (tree_model, iter, 0, &gvalue)
gtk2perl_tree_model_get_value (tree_model, iter, 0, &gvalue)
markstack: ... | y | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^y
^sp
^PL_stack_sp
PUSHMARK (SP)
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^z
^sp
^PL_stack_sp
PUSHs (m), PUSHs (i), PUSHs (0)
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | m | i | 0 | ...
^x
^z
^sp
^PL_stack_sp
PUTBACK
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | m | i | 0 | ...
^x
^z
^sp
^PL_stack_sp
call_method("GET_VALUE") -> GET_VALUE(m, i, 0) -> returns v
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | v | | | ...
^x
^z
^sp
^PL_stack_sp
SPAGAIN
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | v | | | ...
^x
^z
^sp
^PL_stack_sp
POPs
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | | | | ...
^x
^z
^sp
^PL_stack_sp
PUTBACK
markstack: ... | z | x | ...
^PL_markstack_ptr
stack: ... | m | i | | | | ...
^x
^z
^sp
^PL_stack_sp
back in XS(XS_Gtk2__TreeModel_get)
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | m | i | ...
^x
^sp
^PL_stack_sp
XPUSHs(v)
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | v | i | ...
^x
^sp
^PL_stack_sp
in the next iteration, after the call to gtk_tree_model_get_value returned:
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | v | i | ...
^x
^sp
^PL_stack_sp
XPUSHs(v)
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | v | v | ...
^x
^sp
^PL_stack_sp
in the next iteration, after the call to gtk_tree_model_get_value returned:
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | v | v | ...
^x
^sp
^PL_stack_sp
XPUSHs(v)
markstack: ... | x | ...
^PL_markstack_ptr
stack: ... | v | v | v | ...
^x
^sp
^PL_stack_sp
When we now call into gtk_tree_model_get_value, the shit hits the fan. The
marshaling code overwrite everything beyond PL_stack_sp and so nukes everything
after and including the third value we pushed on the stack.
Index: xs/GtkTreeModel.xs
===================================================================
RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/xs/GtkTreeModel.xs,v
retrieving revision 1.57
diff -u -d -p -r1.57 GtkTreeModel.xs
--- xs/GtkTreeModel.xs 18 Aug 2008 20:28:44 -0000 1.57
+++ xs/GtkTreeModel.xs 24 Aug 2008 17:10:46 -0000
@@ -1132,26 +1132,29 @@ gtk_tree_model_get (tree_model, iter, ..
int i;
PPCODE:
PERL_UNUSED_VAR (ix);
- /* if column id's were passed, just return those columns */
- if( items > 2 )
- {
+ if (items > 2) {
+ /* if column id's were passed, just return those columns */
for (i = 2 ; i < items ; i++) {
GValue gvalue = {0, };
gtk_tree_model_get_value (tree_model, iter,
SvIV (ST (i)), &gvalue);
XPUSHs (sv_2mortal (gperl_sv_from_value (&gvalue)));
+ // Update the global stack pointer so that other xsubs
+ // don't overwrite what we put on the stack.
+ PUTBACK;
g_value_unset (&gvalue);
}
- }
- else
- {
+ } else {
/* otherwise return all of the columns */
- for( i = 0; i < gtk_tree_model_get_n_columns(tree_model); i++ )
- {
+ int n_columns = gtk_tree_model_get_n_columns (tree_model);
+ for (i = 0; i < n_columns; i++) {
GValue gvalue = {0, };
gtk_tree_model_get_value (tree_model, iter,
i, &gvalue);
XPUSHs (sv_2mortal (gperl_sv_from_value (&gvalue)));
+ // Update the global stack pointer so that other xsubs
+ // don't overwrite what we put on the stack.
+ PUTBACK;
g_value_unset (&gvalue);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]