symtable: Substantial performance improvement in processing

This further improves performance of the symbol table processing.  The next
step will be to address how symbols are handled on a more intimate level,
since it's a huge mess atm.  But I'll save that for later, after the
low-hanging fruit has been resolved.

* src/current/include/preproc/symtable.xsl (preproc:sym-discover): Use
    `for-each-group' in place of `preceding-sibling'.  Aggressive use of
    maps for geneating the `dedup' sequence, which is a mess.
  (preproc:symtable-process-symbols): Additional maps to avoid
    preceding-sibling and following-sibling selectors (O(n²)=>O(n)).
master
Mike Gerwitz 2019-02-20 01:35:52 -05:00
parent 16749a9a45
commit 5714bfb96b
1 changed files with 52 additions and 19 deletions

View File

@ -248,12 +248,12 @@
</variable>
<!-- remove duplicates (if any) -->
<sequence select="
$extresults/preproc:sym[
not( @name=preceding-sibling::preproc:sym/@name )
]
, $extresults//preproc:error
" />
<for-each-group select="$extresults/preproc:sym"
group-by="@name">
<sequence select="current-group()[ 1 ]" />
</for-each-group>
<sequence select="$extresults//preproc:error" />
<!-- process symbols (except imported externs) -->
<variable name="newresult" as="element( preproc:syms )">
@ -264,6 +264,24 @@
</call-template>
</variable>
<!-- contains duplicates -->
<variable name="new-seq-map" as="map( xs:string, element( preproc:sym )+ )"
select="map:merge(
for $sym in $newresult/preproc:sym
return map{ string( $sym/@name ) : $sym },
map{ 'duplicates' : 'combine' } )" />
<variable name="new-typed-map" as="map( xs:string, element( preproc:sym ) )"
select="map:merge(
for $sym in $newresult/preproc:sym[ @type ]
return map{ string( $sym/@name ) : $sym } )" />
<variable name="nonlocals-map" as="map( xs:string, element( preproc:sym ) )"
select="map:merge(
for $sym in $newresult/preproc:sym[ not( @local = 'true' ) ]
return map{ string( $sym/@name ) : $sym } )" />
<!-- TODO: revisit this logic -->
<variable name="dedup" as="element( preproc:sym )*"
select="$newresult/preproc:sym[
not(
@ -271,29 +289,27 @@
@pollute='true'
and not( @type )
and (
@name=preceding-sibling::preproc:sym/@name
or @name=$newresult/preproc:sym[ @type ]/@name
(
( count( $new-seq-map( @name ) ) gt 1 )
and @name=preceding-sibling::preproc:sym/@name
)
or exists( $new-typed-map( @name ) )
)
)
or (
@local = 'true'
and @name = following-sibling::preproc:sym[
not( @local = 'true' )
]/@name
and exists( $nonlocals-map( @name ) )
)
)
]" />
<apply-templates mode="preproc:symtable-complete"
select="$dedup">
<with-param name="syms" select="$dedup" />
</apply-templates>
</preproc:symtable>
<message>
<text>[preproc/symtable] done.</text>
</message>
<message select="'[preproc/symtable] done.'" />
<!-- copy all of the original elements after the symbol table; we're not
outputting them as we go, so we need to make sure that we don't get
@ -434,6 +450,7 @@
</function>
<!-- TODO: revisit this mess -->
<template name="preproc:symtable-process-symbols">
<param name="extresults" as="element( preproc:syms )" />
<param name="new" as="element( preproc:syms )" />
@ -457,6 +474,18 @@
for $sym in $extresults/preproc:sym
return map{ string( $sym/@name ) : $sym } )" />
<!-- contains duplicates -->
<variable name="new-seq-map" as="map( xs:string, element( preproc:sym )+ )"
select="map:merge(
for $sym in $new/preproc:sym
return map{ string( $sym/@name ) : $sym },
map{ 'duplicates' : 'combine' } )" />
<variable name="new-overrides-map" as="map( xs:string, element( preproc:sym ) )"
select="map:merge(
for $sym in $new/preproc:sym[ @override = 'true' ]
return map{ string( $sym/@name ) : $sym } )" />
<preproc:syms>
<sequence select="$cursym" />
@ -467,7 +496,13 @@
<variable name="dupall" as="element( preproc:sym )*"
select="$cursym-map( $name ),
$extresults-map( $name ),
preceding-sibling::preproc:sym[ @name = $name ]" />
if ( count( $new-seq-map( $name ) ) gt 1 ) then
preceding-sibling::preproc:sym[ @name = $name ]
else
()" />
<variable name="override" as="element( preproc:sym )?"
select="$new-overrides-map( @name )" />
<choose>
<when test="@pollute='true' and not( @type )">
@ -475,9 +510,7 @@
<sequence select="." />
</when>
<!-- note that dupall uses preceding-sibling, which will catch
duplicates in that case even if @override is not set -->
<when test="following-sibling::preproc:sym[ @name=$name and @override='true' ]">
<when test="exists( $override ) and not( $override is . )">
<!-- overridden; we're obsolete :( -->
</when>