Hi, The mechanism described below is now implemented in the CVS HEAD. Hope it's robust enough. There's now a new xsltRegisterLocalRVT(), which substitutes the now deprecated xsltRegisterTmpRVT(); the lifetime of the registered fragment will be restricted to the instruction where the fragment was created. Changed all code in LibXSLT and LibEXSLT to use xsltRegisterLocalRVT().
Regards, Kasimier > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] > On Behalf Of Buchcik, Kasimier > Hi, > > > -----Original Message----- > > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] > > On Behalf Of Daniel Veillard > > > On Mon, Jul 10, 2006 at 05:43:18PM +0200, Buchcik, Kasimier wrote: > > > > I think we could easily change this further to cleanup > > tree fragments, > > > > which were created in/underneath an instruction, > directly after an > > > > instruction exits - if this is what you mean. Taking > xsl:for-each > > > > > > [...] > > > > > > While implementing the cleanup of temporary tree > fragments directly > > > when an instruction exits, I noticed that we'll get problems if > > > trying to do the same for extension elements. With the current > > > implementation of EXSLT's functions, this won't work: > > > > > > <func:function name="foo:foo"> > > > <func:result>result</func:result> > > > </func:function> > > > > > > When <func:result> exits, we still need to preserve the > > tree fragment, > > > until <func:function> exits. With xsltRegisterTmpRVT(), there's no > > > way to define the scope of the tree fragment; e.g. one cannot bind > > > it to the <func:function> (e.g. with a unique stamp for a specific > > > instruction/extension element). Since this cannot be undone > > > (xsltRegisterTmpRVT() is probably also used in other extension > > > elements), > > > I'll leave out extension elements from this optimization. > > Maybe we can > > > optimize this also for EXSLT's functions; we'll need an other > > > registration > > > function for this. > > > > Now that you raise it, I remember being really annoyed by > > func:function > > precisely because the RVT outlived the scope of the current > > template, I > > don't remember how I did actually :-) > > > > Daniel > > I realized today that the rabbit whole goes deeper than I thought. > This means that you actually did not do it :-) > > First: Mark, you are right, the local tree fragments are not > freed until xsl:template leaves. I'm so used to look at my changed > code that I overlooked that in the old code, the fragments are > only freed on the exit of xsltApplyOneTemplate() if @templ is *not* > NULL; and this is only the case when we leave an xsl:template. > > The EXSLT function: > > The main issue here is that func:function is a function, thus > *returns* a value. This makes any attempts to predict the lifetime > of tree fragments fail. > Example: > <func:function name="my:boo"> > <xsl:variable name="var-1"> > <var-1/> > </xsl:variable> > <xsl:variable name="var-2"> > <var-2/> > </xsl:variable> > <func:result select="common:node-set($var-1)/* | > common:node-set($var-2)/*"/> > </func:function> > > Now what happens here? > The nodes of the tree fragments of both local variables are > selected and returned. The current mechanism will > free the tree fragments of the variables before the result is > returned; and consequently free the selected nodes to be returned. > This is a scenario where a non-reference counting machinery > is bound to keep alive _all_ items created inside a function, > since it does not know what is actually returned and still > referenced. > > What can we do here? > One could inspect the result generated by func:result: if it's a > node set, then iterate over all nodes and gather all docs of those > nodes which are tree fragments, then register those docs somewhere, > then let the variable-freeing process skip those docs. Not very nice > if the node set is large; but, on the other hand, adding > reference-counting to the XPath machinery for this scenario, is even > worse. > > The result would need to be kept alive until the calling > function exits. > Example: > <xsl:apply-templates select="common:node-set(my:boo())/*"/> > When xsl:apply-templates is finished, the result can be freed. > > A fragment manager could work in the following way: > - Are we inside a function? > > If yes, then: > > - Was the result was already evaluated? And can > the evaluated result reference local fragments? > > Yes if we used the "select" attribute on func:result. > If the result was built using a sequence > constructor then there won't be references. > > If yes, then: > > - When locally registered fragments > (e.g the value of a variable) are about to be freed, > they need to be checked against the fragments in > use by the result. > > Gather a set of all local result free fragments of all > nodes in the result. Do not add global fragments > (values of global vars/params, results of the > document() function, etc.). > If a locally registered fragment is part of the > result, then don't free it. > > When the calling process exits, all remaining "function result" > fragments are freed. > > Since we would probably break too much user-code, we should leave > the xsltRegisterTmpRVT() mechanism as-is, mark it as obsolete, > and don't use it internally. > > Regards, > > Kasimier > _______________________________________________ > xslt mailing list, project page http://xmlsoft.org/XSLT/ > [email protected] > http://mail.gnome.org/mailman/listinfo/xslt > > _______________________________________________ xslt mailing list, project page http://xmlsoft.org/XSLT/ [email protected] http://mail.gnome.org/mailman/listinfo/xslt
