This is a first part of two patch suite which is a remake of
Heavy::Exporter.  Following Gurusamy Sarathy's suggestion, it is
Exporter::Heavy now.  (This patch updates Exporter, second one will
provide additional tweaks to other files.)

These patches lower heap consumption of

      use DynaLoader;

from appr. 160K to appr. 100K (it is 295K with 5.004_04!) used memory
on Solaris.  This is *without* any change to DynaLoader, the changes
are general-purpose savings.

(The amount of free memory also drops a little bit, but this not that
important, since the caller of DynaLoader will probably use this
memory.)

Perl builds itself, all tests pass (they would not with the older version).

Enjoy,
Ilya

P.S. This adds a new file, so if accepted, repository should be updated.

--- ./lib/Exporter.pm.orig	Tue Jan 27 14:13:30 1998
+++ ./lib/Exporter.pm	Fri Jul 10 20:28:40 1998
@@ -2,227 +2,54 @@ package Exporter;
 
 require 5.001;
 
-#
-# We go to a lot of trouble not to 'require Carp' at file scope,
-#  because Carp requires Exporter, and something has to give.
-#
-
 $ExportLevel = 0;
-$Verbose = 0 unless $Verbose;
-
-sub export {
-
-    # First make import warnings look like they're coming from the "use".
-    local $SIG{__WARN__} = sub {
-	my $text = shift;
-	if ($text =~ s/ at \S*Exporter.pm line \d+.*\n//) {
-	    require Carp;
-	    local $Carp::CarpLevel = 1;	# ignore package calling us too.
-	    Carp::carp($text);
-	}
-	else {
-	    warn $text;
-	}
-    };
-    local $SIG{__DIE__} = sub {
-	require Carp;
-	local $Carp::CarpLevel = 1;	# ignore package calling us too.
-	Carp::croak("$_[0]Illegal null symbol in \@${1}::EXPORT")
-	    if $_[0] =~ /^Unable to create sub named "(.*?)::"/;
-    };
-
-    my($pkg, $callpkg, @imports) = @_;
-    my($type, $sym, $oops);
-    *exports = *{"${pkg}::EXPORT"};
-
-    if (@imports) {
-	if (!%exports) {
-	    grep(s/^&//, @exports);
-	    @exports{@exports} = (1) x @exports;
-	    my $ok = \@{"${pkg}::EXPORT_OK"};
-	    if (@$ok) {
-		grep(s/^&//, @$ok);
-		@exports{@$ok} = (1) x @$ok;
-	    }
-	}
-
-	if ($imports[0] =~ m#^[/!:]#){
-	    my $tagsref = \%{"${pkg}::EXPORT_TAGS"};
-	    my $tagdata;
-	    my %imports;
-	    my($remove, $spec, @names, @allexports);
-	    # negated first item implies starting with default set:
-	    unshift @imports, ':DEFAULT' if $imports[0] =~ m/^!/;
-	    foreach $spec (@imports){
-		$remove = $spec =~ s/^!//;
-
-		if ($spec =~ s/^://){
-		    if ($spec eq 'DEFAULT'){
-			@names = @exports;
-		    }
-		    elsif ($tagdata = $tagsref->{$spec}) {
-			@names = @$tagdata;
-		    }
-		    else {
-			warn qq["$spec" is not defined in %${pkg}::EXPORT_TAGS];
-			++$oops;
-			next;
-		    }
-		}
-		elsif ($spec =~ m:^/(.*)/$:){
-		    my $patn = $1;
-		    @allexports = keys %exports unless @allexports; # only do keys once
-		    @names = grep(/$patn/, @allexports); # not anchored by default
-		}
-		else {
-		    @names = ($spec); # is a normal symbol name
-		}
-
-		warn "Import ".($remove ? "del":"add").": @names "
-		    if $Verbose;
-
-		if ($remove) {
-		   foreach $sym (@names) { delete $imports{$sym} } 
-		}
-		else {
-		    @imports{@names} = (1) x @names;
-		}
-	    }
-	    @imports = keys %imports;
-	}
-
-	foreach $sym (@imports) {
-	    if (!$exports{$sym}) {
-		if ($sym =~ m/^\d/) {
-		    $pkg->require_version($sym);
-		    # If the version number was the only thing specified
-		    # then we should act as if nothing was specified:
-		    if (@imports == 1) {
-			@imports = @exports;
-			last;
-		    }
-		    # We need a way to emulate 'use Foo ()' but still
-		    # allow an easy version check: "use Foo 1.23, ''";
-		    if (@imports == 2 and !$imports[1]) {
-			@imports = ();
-			last;
-		    }
-		} elsif ($sym !~ s/^&// || !$exports{$sym}) {
-                    require Carp;
-		    Carp::carp(qq["$sym" is not exported by the $pkg module]);
-		    $oops++;
-		}
-	    }
-	}
-	if ($oops) {
-	    require Carp;
-	    Carp::croak("Can't continue after import errors");
-	}
-    }
-    else {
-	@imports = @exports;
-    }
-
-    *fail = *{"${pkg}::EXPORT_FAIL"};
-    if (@fail) {
-	if (!%fail) {
-	    # Build cache of symbols. Optimise the lookup by adding
-	    # barewords twice... both with and without a leading &.
-	    # (Technique could be applied to %exports cache at cost of memory)
-	    my @expanded = map { /^\w/ ? ($_, '&'.$_) : $_ } @fail;
-	    warn "${pkg}::EXPORT_FAIL cached: @expanded" if $Verbose;
-	    @fail{@expanded} = (1) x @expanded;
-	}
-	my @failed;
-	foreach $sym (@imports) { push(@failed, $sym) if $fail{$sym} }
-	if (@failed) {
-	    @failed = $pkg->export_fail(@failed);
-	    foreach $sym (@failed) {
-                require Carp;
-		Carp::carp(qq["$sym" is not implemented by the $pkg module ],
-			"on this architecture");
-	    }
-	    if (@failed) {
-		require Carp;
-		Carp::croak("Can't continue after import errors");
-	    }
-	}
-    }
+$Verbose ||= 0;
 
-    warn "Importing into $callpkg from $pkg: ",
-		join(", ",sort @imports) if $Verbose;
-
-    foreach $sym (@imports) {
-	# shortcut for the common case of no type character
-	(*{"${callpkg}::$sym"} = \&{"${pkg}::$sym"}, next)
-	    unless $sym =~ s/^(\W)//;
-	$type = $1;
-	*{"${callpkg}::$sym"} =
-	    $type eq '&' ? \&{"${pkg}::$sym"} :
-	    $type eq '$' ? \${"${pkg}::$sym"} :
-	    $type eq '@' ? \@{"${pkg}::$sym"} :
-	    $type eq '%' ? \%{"${pkg}::$sym"} :
-	    $type eq '*' ?  *{"${pkg}::$sym"} :
-	    do { require Carp; Carp::croak("Can't export symbol: $type$sym") };
-    }
+sub export_to_level {
+  require Exporter::Heavy;
+  goto &heavy_export_to_level;
 }
 
-sub export_to_level
-{
-      my $pkg = shift;
-      my ($level, $junk) = (shift, shift);  # need to get rid of first arg
-                                            # we know it already.
-      my $callpkg = caller($level);
-      $pkg->export($callpkg, @_);
+sub export {
+  require Exporter::Heavy;
+  goto &heavy_export;
 }
 
-sub import {
-    my $pkg = shift;
-    my $callpkg = caller($ExportLevel);
-    export $pkg, $callpkg, @_;
+sub export_tags {
+  require Exporter::Heavy;
+  _push_tags((caller)[0], "EXPORT",    \@_);
 }
 
-
-
-# Utility functions
-
-sub _push_tags {
-    my($pkg, $var, $syms) = @_;
-    my $nontag;
-    *export_tags = \%{"${pkg}::EXPORT_TAGS"};
-    push(@{"${pkg}::$var"},
-	map { $export_tags{$_} ? @{$export_tags{$_}} : scalar(++$nontag,$_) }
-		(@$syms) ? @$syms : keys %export_tags);
-    if ($nontag and $^W) {
-	# This may change to a die one day
-	require Carp;
-	Carp::carp("Some names are not tags");
-    }
+sub export_ok_tags {
+  require Exporter::Heavy;
+  _push_tags((caller)[0], "EXPORT_OK", \@_);
 }
 
-sub export_tags    { _push_tags((caller)[0], "EXPORT",    \@_) }
-sub export_ok_tags { _push_tags((caller)[0], "EXPORT_OK", \@_) }
-
-
-# Default methods
-
-sub export_fail {
-    my $self = shift;
-    @_;
-}
-
-sub require_version {
-    my($self, $wanted) = @_;
-    my $pkg = ref $self || $self;
-    my $version = ${"${pkg}::VERSION"};
-    if (!$version or $version < $wanted) {
-	$version ||= "(undef)";
-	my $file = $INC{"$pkg.pm"};
-	$file &&= " ($file)";
-	require Carp;
-	Carp::croak("$pkg $wanted required--this is only version $version$file")
-    }
-    $version;
+sub import {
+  my $pkg = shift;
+  my $callpkg = caller($ExportLevel);
+  *exports = *{"$pkg\::EXPORT"};
+  # We *need* to treat @{"$pkg\::EXPORT_FAIL"} since Carp uses it :-(
+  return export $pkg, $callpkg, @_
+    if $Verbose or $Debug or @{"$pkg\::EXPORT_FAIL"} > 1;
+  my $args = @_ or @_ = @exports;
+  
+  if ($args and not %exports) {
+    foreach my $sym (@exports, @{"$pkg\::EXPORT_OK"}) {
+      $sym =~ s/^&//;
+      $exports{$sym} = 1;
+    }
+  }
+  if ($Verbose or $Debug 
+      or grep {/\W/ or $args and not exists $exports{$_}
+	       or (@{"$pkg\::EXPORT_OK"} 
+		   and $_ eq ${"$pkg\::EXPORT_OK"}[0])} @_) {
+    return export $pkg, $callpkg, ($args ? @_ : ());
+  }
+  foreach $sym (@_) {
+    # shortcut for the common case of no type character
+    *{"$callpkg\::$sym"} = \&{"$pkg\::$sym"};
+  }
 }
 
 1;
--- ./MANIFEST.orig	Thu Jul  9 02:43:34 1998
+++ ./MANIFEST	Fri Jul 10 17:52:40 1998
@@ -453,6 +453,7 @@ lib/Devel/SelfStubber.pm Generate stubs 
 lib/DirHandle.pm	like FileHandle only for directories
 lib/English.pm		Readable aliases for short variables
 lib/Env.pm		Map environment into ordinary variables
+lib/Exporter/Heavy.pm	Complicated routines for Exporter
 lib/Exporter.pm		Exporter base class
 lib/ExtUtils/Command.pm	Utilities for Make on non-UNIX platforms
 lib/ExtUtils/Embed.pm	Utilities for embedding Perl in C programs
--- ./lib/Exporter/Heavy.pm.orig	Fri Jul 10 21:03:56 1998
+++ ./lib/Exporter/Heavy.pm	Fri Jul 10 17:45:12 1998
@@ -0,0 +1,212 @@
+package Exporter;
+
+#
+# We go to a lot of trouble not to 'require Carp' at file scope,
+#  because Carp requires Exporter, and something has to give.
+#
+
+sub heavy_export {
+
+    # First make import warnings look like they're coming from the "use".
+    local $SIG{__WARN__} = sub {
+	my $text = shift;
+	if ($text =~ s/ at \S*Exporter.pm line \d+.*\n//) {
+	    require Carp;
+	    local $Carp::CarpLevel = 1;	# ignore package calling us too.
+	    Carp::carp($text);
+	}
+	else {
+	    warn $text;
+	}
+    };
+    local $SIG{__DIE__} = sub {
+	require Carp;
+	local $Carp::CarpLevel = 1;	# ignore package calling us too.
+	Carp::croak("$_[0]Illegal null symbol in \@${1}::EXPORT")
+	    if $_[0] =~ /^Unable to create sub named "(.*?)::"/;
+    };
+
+    my($pkg, $callpkg, @imports) = @_;
+    my($type, $sym, $oops);
+    *exports = *{"${pkg}::EXPORT"};
+
+    if (@imports) {
+	if (!%exports) {
+	    grep(s/^&//, @exports);
+	    @exports{@exports} = (1) x @exports;
+	    my $ok = \@{"${pkg}::EXPORT_OK"};
+	    if (@$ok) {
+		grep(s/^&//, @$ok);
+		@exports{@$ok} = (1) x @$ok;
+	    }
+	}
+
+	if ($imports[0] =~ m#^[/!:]#){
+	    my $tagsref = \%{"${pkg}::EXPORT_TAGS"};
+	    my $tagdata;
+	    my %imports;
+	    my($remove, $spec, @names, @allexports);
+	    # negated first item implies starting with default set:
+	    unshift @imports, ':DEFAULT' if $imports[0] =~ m/^!/;
+	    foreach $spec (@imports){
+		$remove = $spec =~ s/^!//;
+
+		if ($spec =~ s/^://){
+		    if ($spec eq 'DEFAULT'){
+			@names = @exports;
+		    }
+		    elsif ($tagdata = $tagsref->{$spec}) {
+			@names = @$tagdata;
+		    }
+		    else {
+			warn qq["$spec" is not defined in %${pkg}::EXPORT_TAGS];
+			++$oops;
+			next;
+		    }
+		}
+		elsif ($spec =~ m:^/(.*)/$:){
+		    my $patn = $1;
+		    @allexports = keys %exports unless @allexports; # only do keys once
+		    @names = grep(/$patn/, @allexports); # not anchored by default
+		}
+		else {
+		    @names = ($spec); # is a normal symbol name
+		}
+
+		warn "Import ".($remove ? "del":"add").": @names "
+		    if $Verbose;
+
+		if ($remove) {
+		   foreach $sym (@names) { delete $imports{$sym} } 
+		}
+		else {
+		    @imports{@names} = (1) x @names;
+		}
+	    }
+	    @imports = keys %imports;
+	}
+
+	foreach $sym (@imports) {
+	    if (!$exports{$sym}) {
+		if ($sym =~ m/^\d/) {
+		    $pkg->require_version($sym);
+		    # If the version number was the only thing specified
+		    # then we should act as if nothing was specified:
+		    if (@imports == 1) {
+			@imports = @exports;
+			last;
+		    }
+		    # We need a way to emulate 'use Foo ()' but still
+		    # allow an easy version check: "use Foo 1.23, ''";
+		    if (@imports == 2 and !$imports[1]) {
+			@imports = ();
+			last;
+		    }
+		} elsif ($sym !~ s/^&// || !$exports{$sym}) {
+                    require Carp;
+		    Carp::carp(qq["$sym" is not exported by the $pkg module]);
+		    $oops++;
+		}
+	    }
+	}
+	if ($oops) {
+	    require Carp;
+	    Carp::croak("Can't continue after import errors");
+	}
+    }
+    else {
+	@imports = @exports;
+    }
+
+    *fail = *{"${pkg}::EXPORT_FAIL"};
+    if (@fail) {
+	if (!%fail) {
+	    # Build cache of symbols. Optimise the lookup by adding
+	    # barewords twice... both with and without a leading &.
+	    # (Technique could be applied to %exports cache at cost of memory)
+	    my @expanded = map { /^\w/ ? ($_, '&'.$_) : $_ } @fail;
+	    warn "${pkg}::EXPORT_FAIL cached: @expanded" if $Verbose;
+	    @fail{@expanded} = (1) x @expanded;
+	}
+	my @failed;
+	foreach $sym (@imports) { push(@failed, $sym) if $fail{$sym} }
+	if (@failed) {
+	    @failed = $pkg->export_fail(@failed);
+	    foreach $sym (@failed) {
+                require Carp;
+		Carp::carp(qq["$sym" is not implemented by the $pkg module ],
+			"on this architecture");
+	    }
+	    if (@failed) {
+		require Carp;
+		Carp::croak("Can't continue after import errors");
+	    }
+	}
+    }
+
+    warn "Importing into $callpkg from $pkg: ",
+		join(", ",sort @imports) if $Verbose;
+
+    foreach $sym (@imports) {
+	# shortcut for the common case of no type character
+	(*{"${callpkg}::$sym"} = \&{"${pkg}::$sym"}, next)
+	    unless $sym =~ s/^(\W)//;
+	$type = $1;
+	*{"${callpkg}::$sym"} =
+	    $type eq '&' ? \&{"${pkg}::$sym"} :
+	    $type eq '$' ? \${"${pkg}::$sym"} :
+	    $type eq '@' ? \@{"${pkg}::$sym"} :
+	    $type eq '%' ? \%{"${pkg}::$sym"} :
+	    $type eq '*' ?  *{"${pkg}::$sym"} :
+	    do { require Carp; Carp::croak("Can't export symbol: $type$sym") };
+    }
+}
+
+sub heavy_export_to_level
+{
+      my $pkg = shift;
+      my ($level, $junk) = (shift, shift);  # need to get rid of first arg
+                                            # we know it already.
+      my $callpkg = caller($level);
+      $pkg->export($callpkg, @_);
+}
+
+# Utility functions
+
+sub _push_tags {
+    my($pkg, $var, $syms) = @_;
+    my $nontag;
+    *export_tags = \%{"${pkg}::EXPORT_TAGS"};
+    push(@{"${pkg}::$var"},
+	map { $export_tags{$_} ? @{$export_tags{$_}} : scalar(++$nontag,$_) }
+		(@$syms) ? @$syms : keys %export_tags);
+    if ($nontag and $^W) {
+	# This may change to a die one day
+	require Carp;
+	Carp::carp("Some names are not tags");
+    }
+}
+
+# Default methods
+
+sub export_fail {
+    my $self = shift;
+    @_;
+}
+
+sub require_version {
+    my($self, $wanted) = @_;
+    my $pkg = ref $self || $self;
+    my $version = ${"${pkg}::VERSION"};
+    if (!$version or $version < $wanted) {
+	$version ||= "(undef)";
+	my $file = $INC{"$pkg.pm"};
+	$file &&= " ($file)";
+	require Carp;
+	Carp::croak("$pkg $wanted required--this is only version $version$file")
+    }
+    $version;
+}
+
+1;
+
