- return undef unless defined($src);
- return $src->as_debug_info if blessed($src) && $src->can('as_debug_info');
- return [ map { _clone_for_dump($_) } @{ $src } ] if reftype($src) eq 'ARRAY';
- return { map { ($_ => _clone_for_dump($src->{$_})) } keys %{ $src } } if reftype($src) eq 'HASH';
- return "$src";
+ return undef if !defined($src);
+ return $src if !ref($src);
+
+ $dumped ||= {};
+ my $addr = refaddr($src);
+
+ return $dumped->{$addr} if $dumped->{$addr // ''};
+
+
+ if (blessed($src) && $src->can('as_debug_info')) {
+ $dumped->{$addr} = $src->as_debug_info;
+
+ } elsif (ref($src) eq 'ARRAY') {
+ $dumped->{$addr} = [];
+
+ foreach my $entry (@{ $src }) {
+ my $exists = !!$dumped->{refaddr($entry) // ''};
+ push @{ $dumped->{$addr} }, clone_for_dump($entry, $dumped);
+
+ weaken($dumped->{$addr}->[-1]) if $exists;
+
+ }
+
+ } elsif (ref($src) =~ m{^(?:HASH|Form|SL::.+)$}) {
+ $dumped->{$addr} = {};
+
+ foreach my $key (keys %{ $src }) {
+ my $exists = !!$dumped->{refaddr($src->{$key}) // ''};
+ $dumped->{$addr}->{$key} = clone_for_dump($src->{$key}, $dumped);
+
+ weaken($dumped->{$addr}->{$key}) if $exists;
+ }
+ }
+
+ return $dumped->{$addr} // "$src";