| #!/usr/bin/tcl | 
 | # | 
 | # This script makes modifications to the vdbe.c source file which reduce | 
 | # the amount of stack space required by the sqlite3VdbeExec() routine. | 
 | # | 
 | # The modifications performed by this script are optional.  The vdbe.c | 
 | # source file will compile correctly with and without the modifications | 
 | # performed by this script.  And all routines within vdbe.c will compute | 
 | # the same result.  The modifications made by this script merely help | 
 | # the C compiler to generate code for sqlite3VdbeExec() that uses less | 
 | # stack space. | 
 | # | 
 | # Script usage: | 
 | # | 
 | #          mv vdbe.c vdbe.c.template | 
 | #          tclsh vdbe-compress.tcl $CFLAGS <vdbe.c.template >vdbe.c | 
 | # | 
 | # Modifications made: | 
 | # | 
 | # All modifications are within the sqlite3VdbeExec() function.  The | 
 | # modifications seek to reduce the amount of stack space allocated by | 
 | # this routine by moving local variable declarations out of individual | 
 | # opcode implementations and into a single large union.  The union contains | 
 | # a separate structure for each opcode and that structure contains the | 
 | # local variables used by that opcode.  In this way, the total amount | 
 | # of stack space required by sqlite3VdbeExec() is reduced from the | 
 | # sum of all local variables to the maximum of the local variable space | 
 | # required for any single opcode. | 
 | # | 
 | # In order to be recognized by this script, local variables must appear | 
 | # on the first line after the open curly-brace that begins a new opcode | 
 | # implementation.  Local variables must not have initializers, though they | 
 | # may be commented. | 
 | # | 
 | # The union definition is inserted in place of a special marker comment | 
 | # in the preamble to the sqlite3VdbeExec() implementation. | 
 | # | 
 | ############################################################################# | 
 | # | 
 | set beforeUnion {}   ;# C code before union | 
 | set unionDef {}      ;# C code of the union | 
 | set afterUnion {}    ;# C code after the union | 
 | set sCtr 0           ;# Context counter | 
 |  | 
 | # If the SQLITE_SMALL_STACK compile-time option is missing, then | 
 | # this transformation becomes a no-op. | 
 | # | 
 | if {![regexp {SQLITE_SMALL_STACK} $argv]} { | 
 |   while {![eof stdin]} { | 
 |     puts [gets stdin] | 
 |   } | 
 |   exit | 
 | } | 
 |  | 
 | # Read program text up to the spot where the union should be | 
 | # inserted. | 
 | # | 
 | while {![eof stdin]} { | 
 |   set line [gets stdin] | 
 |   if {[regexp {INSERT STACK UNION HERE} $line]} break | 
 |   append beforeUnion $line\n | 
 | } | 
 |  | 
 | # Process the remaining text.  Build up the union definition as we go. | 
 | # | 
 | set vlist {} | 
 | set seenDecl 0 | 
 | set namechars {abcdefghijklmnopqrstuvwxyz} | 
 | set nnc [string length $namechars] | 
 | while {![eof stdin]} { | 
 |   set line [gets stdin] | 
 |   if {[regexp "^case (OP_\\w+): \173" $line all operator]} { | 
 |     append afterUnion $line\n | 
 |     set vlist {} | 
 |     while {![eof stdin]} { | 
 |       set line [gets stdin] | 
 |       if {[regexp {^ +(const )?\w+ \**(\w+)(\[.*\])?;} $line \ | 
 |            all constKeyword vname notused1]} { | 
 |         if {!$seenDecl} { | 
 |           set sname {} | 
 |           append sname [string index $namechars [expr {$sCtr/$nnc}]] | 
 |           append sname [string index $namechars [expr {$sCtr%$nnc}]] | 
 |           incr sCtr | 
 |           append unionDef "    struct ${operator}_stack_vars \173\n" | 
 |           append afterUnion \ | 
 |              "#if 0  /* local variables moved into u.$sname */\n" | 
 |           set seenDecl 1 | 
 |         } | 
 |         append unionDef "    $line\n" | 
 |         append afterUnion $line\n | 
 |         lappend vlist $vname | 
 |       } elseif {[regexp {^#(if|endif)} $line] && [llength $vlist]>0} { | 
 |         append unionDef "$line\n" | 
 |         append afterUnion $line\n | 
 |       } else { | 
 |         break | 
 |       } | 
 |     } | 
 |     if {$seenDecl} { | 
 |       append unionDef   "    \175 $sname;\n" | 
 |       append afterUnion "#endif /* local variables moved into u.$sname */\n" | 
 |     } | 
 |     set seenDecl 0 | 
 |   } | 
 |   if {[regexp "^\175" $line]} { | 
 |     append afterUnion $line\n | 
 |     set vlist {} | 
 |   } elseif {[llength $vlist]>0} { | 
 |     append line " " | 
 |     foreach v $vlist { | 
 |       regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line | 
 |       regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line | 
 |  | 
 |       # The expressions above fail to catch instance of variable "abc" in | 
 |       # expressions like (32>abc). The following expression makes those | 
 |       # substitutions. | 
 |       regsub -all "(\[^-\])>${v}(\\W)" $line "\\1>u.$sname.$v\\2" line | 
 |     } | 
 |     append afterUnion [string trimright $line]\n | 
 |   } elseif {$line=="" && [eof stdin]} { | 
 |     # no-op | 
 |   } else { | 
 |     append afterUnion $line\n | 
 |   } | 
 | } | 
 |  | 
 | # Output the resulting text. | 
 | # | 
 | puts -nonewline $beforeUnion | 
 | puts "  /********************************************************************" | 
 | puts "  ** Automatically generated code" | 
 | puts "  **" | 
 | puts "  ** The following union is automatically generated by the" | 
 | puts "  ** vdbe-compress.tcl script.  The purpose of this union is to" | 
 | puts "  ** reduce the amount of stack space required by this function." | 
 | puts "  ** See comments in the vdbe-compress.tcl script for details." | 
 | puts "  */" | 
 | puts "  union vdbeExecUnion \173" | 
 | puts -nonewline $unionDef | 
 | puts "  \175 u;" | 
 | puts "  /* End automatically generated code" | 
 | puts "  ********************************************************************/" | 
 | puts -nonewline $afterUnion |