Re: Issue 2376: Automatic footnotes on \null markups causes unexpected results (issue 5755058)

2012-03-07 Thread David Kastrup
"m...@apollinemike.com"  writes:

> On Mar 7, 2012, at 8:48 AM, d...@gnu.org wrote:
>
>> Given the level and amount of code you write, it might be worth
>> investing the time rereading the garbage collection chapter of the Guile
>> manual.
>> 
>
> You're right that I know nothing about guile's garbage
> collection...it'd help to know this.

In a nutshell: if an SCM object is not referenced, the garbage collector
is free to throw it and its contents away.

As a reference counts:

a) getting marked using scm_gc_mark during garbage collection (mark
phase) because another referenced object does this.  All Scheme data
structures do that to their members (with the exception of "weak" parts
of a hash table).  Our own "Scheme" objects need to do this to their
contents via their own mark subroutines (like derived_mark).

b) getting permanently "protected".  Many of our own data structures
when created with new start out in protected state (since they don't
have an SCM referencing them yet, hard to avoid) and convert into SCM
via a call to unprotect () once they are properly initialized so that
calling their mark routine does not cause uninitialized garbage to be
marked.

c) having an SCM type variable in the stack referencing it.  This is a
somewhat shaky operation since the compiler may optimize variables away
when they are no longer needed.  If that is a concern, you can use
scm_remember_upto_here_1 and its cousins to keep the SCM variables
alive.

Strictly speaking, code like

  Stencil *s = unsmob_stencil (Text_interface::interpret_markup (layout, pro
  if (!s)
{
  programming_error ("Your numbering function needs to return a stencil.
  footnote_number_markups.push_back (SCM_EOL);
  footnote_number_stencils.push_back (Stencil (Box (Interval (0, 0), Int
}
  else
{
  footnote_number_markups.push_back (markup);
  footnote_number_stencils.push_back (*s);
}
  counter++;

is already borderline.  From the time of unsmob_stencil, the returned
markup is no longer protected as an SCM object.  If
footnote_number_markups.push_back were to cause Scheme garbage
collection to trigger, *s would likely already be trashed.

If we get a multithreaded garbage collector at one point of time, you
first need to assign the result of interpret_markup to an SCM variable
and put an scm_remember_upto_here_1 on this variable after the last use
of the unsmobbed stencil pointer.  Of course, if the unsmobbed object is
part of a larger protected data structure, you need not worry all that
much.  Much of the Grob * in our code base is rather laissez-faire about
protection because the grobs are usually registered somewhere else.  For
example, Grob_info does not bother protecting its contents at all if I
remember correctly because it assumes that they will live longer than
the Grob_info because of unrelated reasons.

> I'll investigate.  It'd also be good to do a little write-up for the
> CG w/ garbage collection dos and don'ts in the LilyPond base
> (i.e. what mark_smob, derived_mark, unsmob_thingee, smobbed_copy,
> self_scm & co. all mean).

A smobbed_copy is a Scheme object with the same contents as the original
but not using it (and thus also not protecting it from collection).  A
self_scm is a Scheme object referencing the original.  unsmob gives a
pointer to the unwrapped object.  mark_smob is called during the mark
phase of a referenced object and should in turn mark all SCM objects
that it references.

-- 
David Kastrup

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Issue 2376: Automatic footnotes on \null markups causes unexpected results (issue 5755058)

2012-03-07 Thread m...@apollinemike.com
On Mar 7, 2012, at 8:48 AM, d...@gnu.org wrote:

> Given the level and amount of code you write, it might be worth
> investing the time rereading the garbage collection chapter of the Guile
> manual.
> 

You're right that I know nothing about guile's garbage collection...it'd help 
to know this.  I'll investigate.  It'd also be good to do a little write-up for 
the CG w/ garbage collection dos and don'ts in the LilyPond base (i.e. what 
mark_smob, derived_mark, unsmob_thingee, smobbed_copy, self_scm & co. all mean).

Cheers,
MS
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Issue 2376: Automatic footnotes on \null markups causes unexpected results (issue 5755058)

2012-03-07 Thread dak


http://codereview.appspot.com/5755058/diff/1/lily/page-layout-problem.cc
File lily/page-layout-problem.cc (right):

http://codereview.appspot.com/5755058/diff/1/lily/page-layout-problem.cc#newcode343
lily/page-layout-problem.cc:343: return footnote_separator;
Uh, Mike?

You call a Scheme function for calculating a stencil, then unsmob the
stencil and return a pointer to the unsmobbbed entity.  The SCM
expression is not kept around in any manner.  How on Earth is the Scheme
garbage collector supposed to guess that the Stencil for which you have
retained a pointer but no referring SCM is not supposed to be collected
right away?

That's not just buggy code, it is also a function call interface that
can't be made to work.  You can't return pointers to unsmobbed entities
for which no SCM reference is retained anywhere.

Given the level and amount of code you write, it might be worth
investing the time rereading the garbage collection chapter of the Guile
manual.

I'll be preparing a fix for this one as well.

http://codereview.appspot.com/5755058/

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Issue 2376: Automatic footnotes on \null markups causes unexpected results (issue 5755058)

2012-03-06 Thread dak

Reviewers: MikeSol,


http://codereview.appspot.com/5755058/diff/1/lily/page-breaking.cc
File lily/page-breaking.cc (right):

http://codereview.appspot.com/5755058/diff/1/lily/page-breaking.cc#newcode584
lily/page-breaking.cc:584: }
On 2012/03/07 07:30:42, MikeSol wrote:

Just a C++ question - do these lines implicitly call the copy

constructor to

create footnote_stencil so that footnote_stencil is a copy of foot?

I'm not

familiar with this syntax for copying, so I just wanted to be sure

that this is

what these lines were doing.


The first line calls the assignment operator.  The second line just
resets the foot pointer to point at footnote_stencil.

It would likely be cleaner to just pass a pointer to footnote_stencil
(which is constructed as a null Stencil as far as I can see) in either
case.  Since the special case "foot == 0" would then be ruled out in
advance (do you need the error message?  Can add_footnotes_to_footer
deal with a null stencil?) one could in a more C++-like manner pass foot
in by reference instead of by pointer.

I did not want to meddle with the logic of the code: I just made sure
that it copied what was needed.  If you say that add_footnotes_to_footer
can deal with getting a null stencil for starters, that's what I would
prefer using.  Incidentally, the length of the axes of a null stencil
should turn out to be 0, so this would remove a few special cases as
well.

Description:
Issue 2376: Automatic footnotes on \null markups causes unexpected
results

The page layout routines passed around pointers to stencils rather
indiscriminately and worked on them rather than on stencil copies.

Sort of copy-on-write without the copy.  This tries working on actual
copies where appropriate.

Please review this at http://codereview.appspot.com/5755058/

Affected files:
  M lily/page-breaking.cc
  M lily/page-layout-problem.cc


Index: lily/page-breaking.cc
diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc
index  
61a4e82f91d3098baf29e77b800a622749902522..0eee8e90a45f346a84caffeac89925da05390857  
100644

--- a/lily/page-breaking.cc
+++ b/lily/page-breaking.cc
@@ -574,14 +574,21 @@ Page_breaking::draw_page (SCM systems, SCM  
configuration, int page_num, bool las

   p->set_property ("lines", paper_systems);
   p->set_property ("configuration", configuration);

+  Stencil footnote_stencil;
+
   Stencil *foot = unsmob_stencil (p->get_property ("foot-stencil"));
+  if (foot)
+{
+  footnote_stencil = *foot;
+  foot = &footnote_stencil;
+}

   SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems);

   Page_layout_problem::add_footnotes_to_footer (footnotes, foot, book_);

   if (foot)
-p->set_property ("foot-stencil", foot->smobbed_copy ());
+p->set_property ("foot-stencil", footnote_stencil.smobbed_copy ());
   scm_apply_1 (page_stencil, page, SCM_EOL);

   return page;
Index: lily/page-layout-problem.cc
diff --git a/lily/page-layout-problem.cc b/lily/page-layout-problem.cc
index  
6320827c767a74b07078d328eb7041d7649f6179..82be7f204fe11223d15050ccebbf01c2d28a2dc9  
100644

--- a/lily/page-layout-problem.cc
+++ b/lily/page-layout-problem.cc
@@ -162,7 +162,7 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines,  
int counter, Paper_book

 by passing its results downstream.
   */
   vector footnote_number_markups; // Holds the numbering markups.
-  vector footnote_number_stencils; // Holds translated versions  
of the stencilized numbering markups.
+  vector footnote_number_stencils; // Holds translated versions  
of the stencilized numbering markups.

   for (vsize i = 0; i < fn_count; i++)
 {
   if (fn_grobs[i])
@@ -176,36 +176,39 @@ Page_layout_problem::add_footnotes_to_lines (SCM  
lines, int counter, Paper_book

   if (!s)
 {
   programming_error ("Your numbering function needs to return a  
stencil.");

-  markup = SCM_EOL;
-  s = new Stencil (Box (Interval (0, 0), Interval (0, 0)),  
SCM_EOL);

+ footnote_number_markups.push_back (SCM_EOL);
+  footnote_number_stencils.push_back (Stencil (Box (Interval (0,  
0), Interval (0, 0)), SCM_EOL));

 }
-  footnote_number_markups.push_back (markup);
-  footnote_number_stencils.push_back (s);
+  else
+   {
+ footnote_number_markups.push_back (markup);
+ footnote_number_stencils.push_back (*s);
+   }
   counter++;
 }

   // find the maximum X_AXIS length
   Real max_length = -infinity_f;
   for (vsize i = 0; i < fn_count; i++)
-max_length = max (max_length, footnote_number_stencils[i]->extent  
(X_AXIS).length ());
+max_length = max (max_length, footnote_number_stencils[i].extent  
(X_AXIS).length ());


   /*
 translate each stencil such that it attains the correct maximum length  
and bundle the

 footnotes into a scheme object.
   */
-  SCM *tail = &numbers;
-  SCM *in_text_tail = &in_text_numbers;

   for (vsize i = 0; i < fn_count; i++)
 {
-  *in_text_t

Issue 2376: Automatic footnotes on \null markups causes unexpected results (issue 5755058)

2012-03-06 Thread mtsolo


http://codereview.appspot.com/5755058/diff/1/lily/page-breaking.cc
File lily/page-breaking.cc (right):

http://codereview.appspot.com/5755058/diff/1/lily/page-breaking.cc#newcode584
lily/page-breaking.cc:584: }
Just a C++ question - do these lines implicitly call the copy
constructor to create footnote_stencil so that footnote_stencil is a
copy of foot?  I'm not familiar with this syntax for copying, so I just
wanted to be sure that this is what these lines were doing.

http://codereview.appspot.com/5755058/

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel