This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Tweak Peek.t
[perl5.git] / ext / Devel-Peek / t / Peek.t
index 1debcb5..c601b6e 100644 (file)
@@ -6,6 +6,11 @@ BEGIN {
         print "1..0 # Skip: Devel::Peek was not built\n";
         exit 0;
     }
+    {
+    package t;
+       my $core = !!$ENV{PERL_CORE};
+       require($core ? '../../t/test.pl' : './t/test.pl');
+    }
 }
 
 use Test::More;
@@ -31,11 +36,24 @@ sub do_test {
     my $todo = $_[3];
     my $repeat_todo = $_[4];
     my $pattern = $_[2];
+    my $do_eval = $_[5];
     if (open(OUT,">peek$$")) {
        open(STDERR, ">&OUT") or die "Can't dup OUT: $!";
-       Dump($_[1]);
-        print STDERR "*****\n";
-        Dump($_[1]); # second dump to compare with the first to make sure nothing changed.
+        if ($do_eval) {
+            my $sub = eval "sub { Dump $_[1] }";
+            $sub->();
+            print STDERR "*****\n";
+            # second dump to compare with the first to make sure nothing
+            # changed.
+            $sub->();
+        }
+        else {
+            Dump($_[1]);
+            print STDERR "*****\n";
+            # second dump to compare with the first to make sure nothing
+            # changed.
+            Dump($_[1]);
+        }
        open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!";
        close(OUT);
        if (open(IN, "peek$$")) {
@@ -73,7 +91,10 @@ sub do_test {
            $pattern =~ s/\$RV/
                ($] < 5.011) ? 'RV' : 'IV';
            /mge;
-
+           $pattern =~ s/^\h+COW_REFCNT = .*\n//mg
+               if $Config{ccflags} =~
+                       /-DPERL_(?:OLD_COPY_ON_WRITE|NO_COW)/
+                           || $] < 5.019003;
            print $pattern, "\n" if $DEBUG;
            my ($dump, $dump2) = split m/\*\*\*\*\*\n/, scalar <IN>;
            print $dump, "\n"    if $DEBUG;
@@ -108,20 +129,23 @@ do_test('assignment of immediate constant (string)',
        $a = "foo",
 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 1
-  FLAGS = \\(POK,pPOK\\)
+  FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
   PV = $ADDR "foo"\\\0
   CUR = 3
-  LEN = \\d+'
-       );
+  LEN = \\d+
+  COW_REFCNT = 1
+');
 
 do_test('immediate constant (string)',
         "bar",
 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 1
-  FLAGS = \\(.*POK,READONLY,pPOK\\)
+  FLAGS = \\(.*POK,READONLY,(?:IsCOW,)?pPOK\\)
   PV = $ADDR "bar"\\\0
   CUR = 3
-  LEN = \\d+');
+  LEN = \\d+
+  COW_REFCNT = 0
+');
 
 do_test('assignment of immediate constant (integer)',
         $b = 123,
@@ -153,13 +177,17 @@ my $type = do_test('result of addition',
         $c + $d,
 'SV = ([NI])V\\($ADDR\\) at $ADDR
   REFCNT = 1
-  FLAGS = \\(PADTMP,\1OK,p\1OK\\)
+  FLAGS = \\(PADTMP,\1OK,p\1OK\\)              # $] < 5.019003
+  FLAGS = \\(\1OK,p\1OK\\)                     # $] >=5.019003
   \1V = 456');
 
 ($d = "789") += 0.1;
 
 do_test('floating point value',
        $d,
+       $] < 5.019003
+        || $Config{ccflags} =~ /-DPERL_(?:NO_COW|OLD_COPY_ON_WRITE)/
+       ?
 'SV = PVNV\\($ADDR\\) at $ADDR
   REFCNT = 1
   FLAGS = \\(NOK,pNOK\\)
@@ -167,7 +195,14 @@ do_test('floating point value',
   NV = 789\\.(?:1(?:000+\d+)?|0999+\d+)
   PV = $ADDR "789"\\\0
   CUR = 3
-  LEN = \\d+');
+  LEN = \\d+'
+       :
+'SV = PVNV\\($ADDR\\) at $ADDR
+  REFCNT = 1
+  FLAGS = \\(NOK,pNOK\\)
+  IV = \d+
+  NV = 789\\.(?:1(?:000+\d+)?|0999+\d+)
+  PV = 0');
 
 do_test('integer constant',
         0xabcd,
@@ -179,8 +214,8 @@ do_test('integer constant',
 do_test('undef',
         undef,
 'SV = NULL\\(0x0\\) at $ADDR
-  REFCNT = 1
-  FLAGS = \\(\\)');
+  REFCNT = \d+
+  FLAGS = \\(READONLY\\)');
 
 do_test('reference to scalar',
         \$a,
@@ -190,10 +225,12 @@ do_test('reference to scalar',
   RV = $ADDR
   SV = PV\\($ADDR\\) at $ADDR
     REFCNT = 2
-    FLAGS = \\(POK,pPOK\\)
+    FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
     PV = $ADDR "foo"\\\0
     CUR = 3
-    LEN = \\d+');
+    LEN = \\d+
+    COW_REFCNT = 1
+');
 
 my $c_pattern;
 if ($type eq 'N') {
@@ -316,6 +353,8 @@ do_test('reference to named subroutine without prototype',
        \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$todo"
        \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$repeat_todo"
        \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$pattern"
+       \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$do_eval"
+      \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$sub"
       \\d+\\. $ADDR<\\d+> FAKE "\\$DEBUG"                      # $] < 5.009
       \\d+\\. $ADDR<\\d+> FAKE "\\$DEBUG" flags=0x0 index=0    # $] >= 5.009
       \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$dump"
@@ -323,6 +362,7 @@ do_test('reference to named subroutine without prototype',
     OUTSIDE = $ADDR \\(MAIN\\)');
 
 if ($] >= 5.011) {
+# note the conditionals on ENGINE and INTFLAGS were introduced in 5.19.9
 do_test('reference to regexp',
         qr(tic),
 'SV = $RV\\($ADDR\\) at $ADDR
@@ -339,8 +379,10 @@ do_test('reference to regexp',
     STASH = $ADDR\\t"Regexp"'
 . ($] < 5.013 ? '' :
 '
+    COMPFLAGS = 0x0 \(\)
     EXTFLAGS = 0x680000 \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
-    INTFLAGS = 0x0
+(?:    ENGINE = $ADDR \(STANDARD\)
+)?    INTFLAGS = 0x0(?: \(\))?
     NPARENS = 0
     LASTPAREN = 0
     LASTCLOSEPAREN = 0
@@ -352,8 +394,37 @@ do_test('reference to regexp',
     SUBOFFSET = 0
     SUBCOFFSET = 0
     SUBBEG = 0x0
-    ENGINE = $ADDR
-    MOTHER_RE = $ADDR
+(?:    ENGINE = $ADDR
+)?    MOTHER_RE = $ADDR'
+. ($] < 5.019003 ? '' : '
+    SV = REGEXP\($ADDR\) at $ADDR
+      REFCNT = 2
+      FLAGS = \(\)
+      PV = $ADDR "\(\?\^:tic\)"
+      CUR = 8
+      COMPFLAGS = 0x0 \(\)
+      EXTFLAGS = 0x680000 \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
+(?:      ENGINE = $ADDR \(STANDARD\)
+)?      INTFLAGS = 0x0(?: \(\))?
+      NPARENS = 0
+      LASTPAREN = 0
+      LASTCLOSEPAREN = 0
+      MINLEN = 3
+      MINLENRET = 3
+      GOFS = 0
+      PRE_PREFIX = 4
+      SUBLEN = 0
+      SUBOFFSET = 0
+      SUBCOFFSET = 0
+      SUBBEG = 0x0
+(?:    ENGINE = $ADDR
+)?      MOTHER_RE = 0x0
+      PAREN_NAMES = 0x0
+      SUBSTRS = $ADDR
+      PPRIVATE = $ADDR
+      OFFS = $ADDR
+      QR_ANONCV = 0x0(?:
+      SAVED_COPY = 0x0)?') . '
     PAREN_NAMES = 0x0
     SUBSTRS = $ADDR
     PPRIVATE = $ADDR
@@ -441,19 +512,25 @@ do_test('string with Unicode',
        chr(256).chr(0).chr(512),
 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 1
-  FLAGS = \\((?:$PADTMP,)?POK,READONLY,pPOK,UTF8\\)
+  FLAGS = \\((?:$PADTMP,)?POK,READONLY,pPOK,UTF8\\)    # $] < 5.019003
+  FLAGS = \\((?:$PADTMP,)?POK,(?:IsCOW,)?pPOK,UTF8\\)  # $] >=5.019003
   PV = $ADDR "\\\214\\\101\\\0\\\235\\\101"\\\0 \[UTF8 "\\\x\{100\}\\\x\{0\}\\\x\{200\}"\]
   CUR = 5
-  LEN = \\d+');
+  LEN = \\d+
+  COW_REFCNT = 1                                       # $] < 5.019007
+');
 } else {
 do_test('string with Unicode',
        chr(256).chr(0).chr(512),
 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 1
-  FLAGS = \\((?:$PADTMP,)?POK,READONLY,pPOK,UTF8\\)
+  FLAGS = \\((?:$PADTMP,)?POK,READONLY,pPOK,UTF8\\)    # $] < 5.019003
+  FLAGS = \\((?:$PADTMP,)?POK,(?:IsCOW,)?pPOK,UTF8\\)  # $] >=5.019003
   PV = $ADDR "\\\304\\\200\\\0\\\310\\\200"\\\0 \[UTF8 "\\\x\{100\}\\\x\{0\}\\\x\{200\}"\]
   CUR = 5
-  LEN = \\d+');
+  LEN = \\d+
+  COW_REFCNT = 1                                       # $] < 5.019007
+');
 }
 
 if (ord('A') == 193) {
@@ -476,10 +553,12 @@ do_test('reference to hash containing Unicode',
     Elt "\\\214\\\101" \[UTF8 "\\\x\{100\}"\] HASH = $ADDR
     SV = PV\\($ADDR\\) at $ADDR
       REFCNT = 1
-      FLAGS = \\(POK,pPOK,UTF8\\)
+      FLAGS = \\(POK,(?:IsCOW,)?pPOK,UTF8\\)
       PV = $ADDR "\\\235\\\101"\\\0 \[UTF8 "\\\x\{200\}"\]
       CUR = 2
-      LEN = \\d+',
+      LEN = \\d+
+      COW_REFCNT = 1                           # $] < 5.019007
+',      '',
        $] > 5.009
        ? $] >= 5.015
            ?  0
@@ -505,10 +584,12 @@ do_test('reference to hash containing Unicode',
     Elt "\\\304\\\200" \[UTF8 "\\\x\{100\}"\] HASH = $ADDR
     SV = PV\\($ADDR\\) at $ADDR
       REFCNT = 1
-      FLAGS = \\(POK,pPOK,UTF8\\)
+      FLAGS = \\(POK,(?:IsCOW,)?pPOK,UTF8\\)
       PV = $ADDR "\\\310\\\200"\\\0 \[UTF8 "\\\x\{200\}"\]
       CUR = 2
-      LEN = \\d+', '',
+      LEN = \\d+
+      COW_REFCNT = 1                           # $] < 5.019007
+',      '',
        $] > 5.009
        ? $] >= 5.015
            ?  0
@@ -527,13 +608,16 @@ do_test('scalar with pos magic',
   NV = 0
   PV = $ADDR ""\\\0
   CUR = 0
-  LEN = \d+(?:
-  COW_REFCNT = 1)?
+  LEN = \d+
+  COW_REFCNT = [12]
   MAGIC = $ADDR
     MG_VIRTUAL = &PL_vtbl_mglob
     MG_TYPE = PERL_MAGIC_regex_global\\(g\\)
-    MG_FLAGS = 0x01
-      MINMATCH');
+    MG_FLAGS = 0x01                                    # $] < 5.019003
+    MG_FLAGS = 0x41                                    # $] >=5.019003
+      MINMATCH
+      BYTES                                            # $] >=5.019003
+');
 
 #
 # TAINTEDDIR is not set on: OS2, AMIGAOS, WIN32, MSDOS
@@ -545,6 +629,8 @@ do_test('scalar with pos magic',
 # ENV hashes is also not always null terminated.
 #
 if (${^TAINT}) {
+  # Save and restore PATH, since fresh_perl ends up using that in Windows.
+  my $path = $ENV{PATH};
   do_test('tainted value in %ENV',
           $ENV{PATH}=@ARGV,  # scalar(@ARGV) is a handy known tainted value
 'SV = PVMG\\($ADDR\\) at $ADDR
@@ -564,7 +650,7 @@ if (${^TAINT}) {
     MG_PTR = $ADDR (?:"(?i:PATH)"|=> HEf_SVKEY
     SV = PV(?:IV)?\\($ADDR\\) at $ADDR
       REFCNT = \d+
-      FLAGS = \\(TEMP,POK,(?:FAKE,READONLY,)?pPOK\\)
+      FLAGS = \\((?:TEMP,)?POK,(?:FAKE,READONLY,)?pPOK\\)
 (?:      IV = 0
 )?      PV = $ADDR "(?i:PATH)"(?:\\\0)?
       CUR = \d+
@@ -572,6 +658,7 @@ if (${^TAINT}) {
   MAGIC = $ADDR
     MG_VIRTUAL = &PL_vtbl_taint
     MG_TYPE = PERL_MAGIC_taint\\(t\\)');
+    $ENV{PATH} = $path;
 }
 
 do_test('blessed reference',
@@ -611,16 +698,18 @@ do_test('constant subroutine',
     IV = 0                                     # $] < 5.009
     NV = 0                                     # $] < 5.009
     PROTOTYPE = ""
-    COMP_STASH = 0x0
+    COMP_STASH = 0x0                           # $] < 5.021004
+    COMP_STASH = $ADDR "main"                  # $] >=5.021004
     ROOT = 0x0                                 # $] < 5.009
     XSUB = $ADDR
     XSUBANY = $ADDR \\(CONST SV\\)
     SV = PV\\($ADDR\\) at $ADDR
       REFCNT = 1
-      FLAGS = \\(.*POK,READONLY,pPOK\\)
+      FLAGS = \\(.*POK,READONLY,(?:IsCOW,)?pPOK\\)
       PV = $ADDR "Perl rules"\\\0
       CUR = 10
       LEN = \\d+
+      COW_REFCNT = 0
     GVGV::GV = $ADDR\\t"main" :: "const"
     FILE = ".*\\b(?i:peek\\.t)"
     DEPTH = 0(?:
@@ -733,9 +822,10 @@ do_test('ENAME on a stash',
     FLAGS = \\(OOK,SHAREKEYS\\)
     IV = 1                                     # $] < 5.009
     NV = $FLOAT                                        # $] < 5.009
+    AUX_FLAGS = 0                               # $] > 5.019008
     ARRAY = $ADDR
     KEYS = 0
-    FILL = 0
+    FILL = 0 \(cached = 0\)
     MAX = 7
     RITER = -1
     EITER = 0x0
@@ -757,9 +847,10 @@ do_test('ENAMEs on a stash',
     FLAGS = \\(OOK,SHAREKEYS\\)
     IV = 1                                     # $] < 5.009
     NV = $FLOAT                                        # $] < 5.009
+    AUX_FLAGS = 0                               # $] > 5.019008
     ARRAY = $ADDR
     KEYS = 0
-    FILL = 0
+    FILL = 0 \(cached = 0\)
     MAX = 7
     RITER = -1
     EITER = 0x0
@@ -783,9 +874,10 @@ do_test('ENAMEs on a stash with no NAME',
     FLAGS = \\(OOK,OVERLOAD,SHAREKEYS\\)       # $] >=5.017
     IV = 1                                     # $] < 5.009
     NV = $FLOAT                                        # $] < 5.009
+    AUX_FLAGS = 0                               # $] > 5.019008
     ARRAY = $ADDR
     KEYS = 0
-    FILL = 0
+    FILL = 0 \(cached = 0\)
     MAX = 7
     RITER = -1
     EITER = 0x0
@@ -794,12 +886,209 @@ do_test('ENAMEs on a stash with no NAME',
     ENAME = "RWOM", "KLANK"                    # $] > 5.012
 ');
 
+my %small = ("Perl", "Rules", "Beer", "Foamy");
+my $b = %small;
+do_test('small hash',
+        \%small,
+'SV = $RV\\($ADDR\\) at $ADDR
+  REFCNT = 1
+  FLAGS = \\(ROK\\)
+  RV = $ADDR
+  SV = PVHV\\($ADDR\\) at $ADDR
+    REFCNT = 2
+    FLAGS = \\(PADMY,SHAREKEYS\\)
+    IV = 1                                     # $] < 5.009
+    NV = $FLOAT                                        # $] < 5.009
+    ARRAY = $ADDR  \\(0:[67],.*\\)
+    hash quality = [0-9.]+%
+    KEYS = 2
+    FILL = [12]
+    MAX = 7
+(?:    Elt "(?:Perl|Beer)" HASH = $ADDR
+    SV = PV\\($ADDR\\) at $ADDR
+      REFCNT = 1
+      FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
+      PV = $ADDR "(?:Rules|Foamy)"\\\0
+      CUR = \d+
+      LEN = \d+
+      COW_REFCNT = 1
+){2}');
+
+$b = keys %small;
+
+do_test('small hash after keys',
+        \%small,
+'SV = $RV\\($ADDR\\) at $ADDR
+  REFCNT = 1
+  FLAGS = \\(ROK\\)
+  RV = $ADDR
+  SV = PVHV\\($ADDR\\) at $ADDR
+    REFCNT = 2
+    FLAGS = \\(PADMY,OOK,SHAREKEYS\\)
+    IV = 1                                     # $] < 5.009
+    NV = $FLOAT                                        # $] < 5.009
+    AUX_FLAGS = 0                               # $] > 5.019008
+    ARRAY = $ADDR  \\(0:[67],.*\\)
+    hash quality = [0-9.]+%
+    KEYS = 2
+    FILL = [12] \\(cached = 0\\)
+    MAX = 7
+    RITER = -1
+    EITER = 0x0
+    RAND = $ADDR
+(?:    Elt "(?:Perl|Beer)" HASH = $ADDR
+    SV = PV\\($ADDR\\) at $ADDR
+      REFCNT = 1
+      FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
+      PV = $ADDR "(?:Rules|Foamy)"\\\0
+      CUR = \d+
+      LEN = \d+
+      COW_REFCNT = 1
+){2}');
+
+$b = %small;
+
+do_test('small hash after keys and scalar',
+        \%small,
+'SV = $RV\\($ADDR\\) at $ADDR
+  REFCNT = 1
+  FLAGS = \\(ROK\\)
+  RV = $ADDR
+  SV = PVHV\\($ADDR\\) at $ADDR
+    REFCNT = 2
+    FLAGS = \\(PADMY,OOK,SHAREKEYS\\)
+    IV = 1                                     # $] < 5.009
+    NV = $FLOAT                                        # $] < 5.009
+    AUX_FLAGS = 0                               # $] > 5.019008
+    ARRAY = $ADDR  \\(0:[67],.*\\)
+    hash quality = [0-9.]+%
+    KEYS = 2
+    FILL = ([12]) \\(cached = \1\\)
+    MAX = 7
+    RITER = -1
+    EITER = 0x0
+    RAND = $ADDR
+(?:    Elt "(?:Perl|Beer)" HASH = $ADDR
+    SV = PV\\($ADDR\\) at $ADDR
+      REFCNT = 1
+      FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
+      PV = $ADDR "(?:Rules|Foamy)"\\\0
+      CUR = \d+
+      LEN = \d+
+      COW_REFCNT = 1
+){2}');
+
+# This should immediately start with the FILL cached correctly.
+my %large = (0..1999);
+$b = %large;
+do_test('large hash',
+        \%large,
+'SV = $RV\\($ADDR\\) at $ADDR
+  REFCNT = 1
+  FLAGS = \\(ROK\\)
+  RV = $ADDR
+  SV = PVHV\\($ADDR\\) at $ADDR
+    REFCNT = 2
+    FLAGS = \\(PADMY,OOK,SHAREKEYS\\)
+    IV = 1                                     # $] < 5.009
+    NV = $FLOAT                                        # $] < 5.009
+    AUX_FLAGS = 0                               # $] > 5.019008
+    ARRAY = $ADDR  \\(0:\d+,.*\\)
+    hash quality = \d+\\.\d+%
+    KEYS = 1000
+    FILL = (\d+) \\(cached = \1\\)
+    MAX = 1023
+    RITER = -1
+    EITER = 0x0
+    RAND = $ADDR
+    Elt .*
+');
+
+# Dump with arrays, hashes, and operator return values
+@array = 1..3;
+do_test('Dump @array', '@array', <<'ARRAY', '', '', 1);
+SV = PVAV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(\)
+  ARRAY = $ADDR
+  FILL = 2
+  MAX = 3
+  ARYLEN = 0x0
+  FLAGS = \(REAL\)
+  Elt No. 0
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 1
+  Elt No. 1
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 2
+  Elt No. 2
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 3
+ARRAY
+
+do_test('Dump @array,1', '@array,1', <<'ARRAY', '', '', 1);
+SV = PVAV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(\)
+  ARRAY = $ADDR
+  FILL = 2
+  MAX = 3
+  ARYLEN = 0x0
+  FLAGS = \(REAL\)
+  Elt No. 0
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 1
+ARRAY
+
+%hash = 1..2;
+do_test('Dump %hash', '%hash', <<'HASH', '', '', 1);
+SV = PVHV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(SHAREKEYS\)
+  ARRAY = $ADDR  \(0:7, 1:1\)
+  hash quality = 100.0%
+  KEYS = 1
+  FILL = 1
+  MAX = 7
+  Elt "1" HASH = $ADDR
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 2
+HASH
+
+$_ = "hello";
+do_test('rvalue substr', 'substr $_, 1, 2', <<'SUBSTR', '', '', 1);
+SV = PV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(PADTMP,POK,pPOK\)
+  PV = $ADDR "el"\\0
+  CUR = 2
+  LEN = \d+
+SUBSTR
+
+# Dump with no arguments
+eval 'Dump';
+like $@, qr/^Not enough arguments for Devel::Peek::Dump/, 'Dump;';
+eval 'Dump()';
+like $@, qr/^Not enough arguments for Devel::Peek::Dump/, 'Dump()';
+
 SKIP: {
-    skip "Not built with usemymalloc", 1
+    skip "Not built with usemymalloc", 2
       unless $Config{usemymalloc} eq 'y';
     my $x = __PACKAGE__;
     ok eval { fill_mstats($x); 1 }, 'fill_mstats on COW scalar'
      or diag $@;
+    my $y;
+    ok eval { fill_mstats($y); 1 }, 'fill_mstats on undef scalar';
 }
 
 # This is more a test of fbm_compile/pp_study (non) interaction than dumping
@@ -818,10 +1107,11 @@ unless ($Config{useithreads}) {
     do_test('regular string constant', perl,
 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 5
-  FLAGS = \\(PADMY,POK,READONLY,pPOK\\)
+  FLAGS = \\(PADMY,POK,READONLY,(?:IsCOW,)?pPOK\\)
   PV = $ADDR "rules"\\\0
   CUR = 5
   LEN = \d+
+  COW_REFCNT = 0
 ');
 
     eval 'index "", perl';
@@ -833,17 +1123,18 @@ unless ($Config{useithreads}) {
     do_test('string constant now an FBM', perl,
 'SV = PVMG\\($ADDR\\) at $ADDR
   REFCNT = 5
-  FLAGS = \\(PADMY,SMG,POK,READONLY,pPOK,VALID,EVALED\\)
+  FLAGS = \\(PADMY,SMG,POK,READONLY,(?:IsCOW,)?pPOK,VALID,EVALED\\)
   PV = $ADDR "rules"\\\0
   CUR = 5
   LEN = \d+
+  COW_REFCNT = 0
   MAGIC = $ADDR
     MG_VIRTUAL = &PL_vtbl_regexp
     MG_TYPE = PERL_MAGIC_bm\\(B\\)
     MG_LEN = 256
     MG_PTR = $ADDR "(?:\\\\\d){256}"
-  RARE = \d+
-  PREVIOUS = 1
+  RARE = \d+                                   # $] < 5.019002
+  PREVIOUS = 1                                 # $] < 5.019002
   USEFUL = 100
 ');
 
@@ -852,52 +1143,56 @@ unless ($Config{useithreads}) {
     do_test('string constant still an FBM', perl,
 'SV = PVMG\\($ADDR\\) at $ADDR
   REFCNT = 5
-  FLAGS = \\(PADMY,SMG,POK,READONLY,pPOK,VALID,EVALED\\)
+  FLAGS = \\(PADMY,SMG,POK,READONLY,(?:IsCOW,)?pPOK,VALID,EVALED\\)
   PV = $ADDR "rules"\\\0
   CUR = 5
   LEN = \d+
+  COW_REFCNT = 0
   MAGIC = $ADDR
     MG_VIRTUAL = &PL_vtbl_regexp
     MG_TYPE = PERL_MAGIC_bm\\(B\\)
     MG_LEN = 256
     MG_PTR = $ADDR "(?:\\\\\d){256}"
-  RARE = \d+
-  PREVIOUS = 1
+  RARE = \d+                                   # $] < 5.019002
+  PREVIOUS = 1                                 # $] < 5.019002
   USEFUL = 100
 ');
 
     do_test('regular string constant', beer,
 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 6
-  FLAGS = \\(PADMY,POK,READONLY,pPOK\\)
+  FLAGS = \\(PADMY,POK,READONLY,(?:IsCOW,)?pPOK\\)
   PV = $ADDR "foamy"\\\0
   CUR = 5
   LEN = \d+
+  COW_REFCNT = 0
 ');
 
     is(study beer, 1, "Our studies were successful");
 
     do_test('string constant quite unaffected', beer, 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 6
-  FLAGS = \\(PADMY,POK,READONLY,pPOK\\)
+  FLAGS = \\(PADMY,POK,READONLY,(?:IsCOW,)?pPOK\\)
   PV = $ADDR "foamy"\\\0
   CUR = 5
   LEN = \d+
+  COW_REFCNT = 0
 ');
 
     my $want = 'SV = PVMG\\($ADDR\\) at $ADDR
   REFCNT = 6
-  FLAGS = \\(PADMY,SMG,POK,READONLY,pPOK,VALID,EVALED\\)
+  FLAGS = \\(PADMY,SMG,POK,READONLY,(?:IsCOW,)?pPOK,VALID,EVALED\\)
   PV = $ADDR "foamy"\\\0
   CUR = 5
   LEN = \d+
+  COW_REFCNT = 0
   MAGIC = $ADDR
     MG_VIRTUAL = &PL_vtbl_regexp
     MG_TYPE = PERL_MAGIC_bm\\(B\\)
     MG_LEN = 256
     MG_PTR = $ADDR "(?:\\\\\d){256}"
-  RARE = \d+
-  PREVIOUS = \d+
+  RARE = \d+                                   # $] < 5.019002
+  PREVIOUS = \d+                               # $] < 5.019002
   USEFUL = 100
 ';
 
@@ -913,10 +1208,11 @@ unless ($Config{useithreads}) {
 
     do_test('second string also unaffected', $pie, 'SV = PV\\($ADDR\\) at $ADDR
   REFCNT = 1
-  FLAGS = \\(PADMY,POK,pPOK\\)
+  FLAGS = \\(PADMY,POK,(?:IsCOW,)?pPOK\\)
   PV = $ADDR "good"\\\0
   CUR = 4
   LEN = \d+
+  COW_REFCNT = 1
 ');
 }
 
@@ -930,7 +1226,7 @@ unless ($Config{useithreads}) {
     pass "no crash with DeadCode";
     close OUT;
 }
-
+# note the conditionals on ENGINE and INTFLAGS were introduced in 5.19.9
 do_test('UTF-8 in a regular expression',
         qr/\x{100}/,
 'SV = IV\($ADDR\) at $ADDR
@@ -943,8 +1239,10 @@ do_test('UTF-8 in a regular expression',
     PV = $ADDR "\(\?\^u:\\\\\\\\x\{100\}\)" \[UTF8 "\(\?\^u:\\\\\\\\x\{100\}\)"\]
     CUR = 13
     STASH = $ADDR      "Regexp"
+    COMPFLAGS = 0x0 \(\)
     EXTFLAGS = 0x680040 \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
-    INTFLAGS = 0x0
+(?:    ENGINE = $ADDR \(STANDARD\)
+)?    INTFLAGS = 0x0(?: \(\))?
     NPARENS = 0
     LASTPAREN = 0
     LASTCLOSEPAREN = 0
@@ -956,8 +1254,37 @@ do_test('UTF-8 in a regular expression',
     SUBOFFSET = 0
     SUBCOFFSET = 0
     SUBBEG = 0x0
-    ENGINE = $ADDR
-    MOTHER_RE = $ADDR
+(?:    ENGINE = $ADDR
+)?    MOTHER_RE = $ADDR'
+. ($] < 5.019003 ? '' : '
+    SV = REGEXP\($ADDR\) at $ADDR
+      REFCNT = 2
+      FLAGS = \(UTF8\)
+      PV = $ADDR "\(\?\^u:\\\\\\\\x\{100\}\)" \[UTF8 "\(\?\^u:\\\\\\\\x\{100\}\)"\]
+      CUR = 13
+      COMPFLAGS = 0x0 \(\)
+      EXTFLAGS = 0x680040 \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
+(?:      ENGINE = $ADDR \(STANDARD\)
+)?      INTFLAGS = 0x0(?: \(\))?
+      NPARENS = 0
+      LASTPAREN = 0
+      LASTCLOSEPAREN = 0
+      MINLEN = 1
+      MINLENRET = 1
+      GOFS = 0
+      PRE_PREFIX = 5
+      SUBLEN = 0
+      SUBOFFSET = 0
+      SUBCOFFSET = 0
+      SUBBEG = 0x0
+(?:    ENGINE = $ADDR
+)?      MOTHER_RE = 0x0
+      PAREN_NAMES = 0x0
+      SUBSTRS = $ADDR
+      PPRIVATE = $ADDR
+      OFFS = $ADDR
+      QR_ANONCV = 0x0(?:
+      SAVED_COPY = 0x0)?') . '
     PAREN_NAMES = 0x0
     SUBSTRS = $ADDR
     PPRIVATE = $ADDR
@@ -966,4 +1293,287 @@ do_test('UTF-8 in a regular expression',
     SAVED_COPY = 0x0)?
 ');
 
+{ # perl #117793: Extend SvREFCNT* to work on any perl variable type
+  my %hash;
+  my $base_count = Devel::Peek::SvREFCNT(%hash);
+  my $ref = \%hash;
+  is(Devel::Peek::SvREFCNT(%hash), $base_count + 1, "SvREFCNT on non-scalar");
+  ok(!eval { &Devel::Peek::SvREFCNT(1) }, "requires prototype");
+}
+{
+# utf8 tests
+use utf8;
+
+sub _dump {
+   open(OUT,">peek$$") or die $!;
+   open(STDERR, ">&OUT") or die "Can't dup OUT: $!";
+   Dump($_[0]);
+   open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!";
+   close(OUT);
+   open(IN, "peek$$") or die $!;
+   my $dump = do { local $/; <IN> };
+   close(IN);
+   1 while unlink "peek$$";
+   return $dump;
+}
+
+sub _get_coderef {
+   my $x = $_[0];
+   utf8::upgrade($x);
+   eval "sub $x {}; 1" or die $@;
+   return *{$x}{CODE};
+}
+
+like(
+   _dump(_get_coderef("\x{df}::\xdf")),
+   qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\xdf" :: "\xdf"/,
+   "GVGV's are correctly escaped for latin1 :: latin1",
+);
+
+like(
+   _dump(_get_coderef("\x{30cd}::\x{30cd}")),
+   qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\x{30cd}" :: "\x{30cd}"/,
+   "GVGV's are correctly escaped for UTF8 :: UTF8",
+);
+
+like(
+   _dump(_get_coderef("\x{df}::\x{30cd}")),
+   qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\xdf" :: "\x{30cd}"/,
+   "GVGV's are correctly escaped for latin1 :: UTF8",
+);
+
+like(
+   _dump(_get_coderef("\x{30cd}::\x{df}")),
+   qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\x{30cd}" :: "\xdf"/,
+   "GVGV's are correctly escaped for UTF8 :: latin1",
+);
+
+like(
+   _dump(_get_coderef("\x{30cb}::\x{df}::\x{30cd}")),
+   qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\x{30cb}::\x{df}" :: "\x{30cd}"/,
+   "GVGV's are correctly escaped for UTF8 :: latin 1 :: UTF8",
+);
+
+my $dump = _dump(*{"\x{30cb}::\x{df}::\x{30dc}"});
+
+like(
+   $dump,
+   qr/NAME = \Q"\x{30dc}"/,
+   "NAME is correctly escaped for UTF8 globs",
+);
+
+like(
+   $dump,
+   qr/GvSTASH = 0x[[:xdigit:]]+\s+\Q"\x{30cb}::\x{df}"/,
+   "GvSTASH is correctly escaped for UTF8 globs"
+);
+
+like(
+   $dump,
+   qr/EGV = 0x[[:xdigit:]]+\s+\Q"\x{30dc}"/,
+   "EGV is correctly escaped for UTF8 globs"
+);
+
+$dump = _dump(*{"\x{df}::\x{30cc}"});
+
+like(
+   $dump,
+   qr/NAME = \Q"\x{30cc}"/,
+   "NAME is correctly escaped for UTF8 globs with latin1 stashes",
+);
+
+like(
+   $dump,
+   qr/GvSTASH = 0x[[:xdigit:]]+\s+\Q"\xdf"/,
+   "GvSTASH is correctly escaped for UTF8 globs with latin1 stashes"
+);
+
+like(
+   $dump,
+   qr/EGV = 0x[[:xdigit:]]+\s+\Q"\x{30cc}"/,
+   "EGV is correctly escaped for UTF8 globs with latin1 stashes"
+);
+
+like(
+   _dump(bless {}, "\0::\1::\x{30cd}"),
+   qr/STASH = 0x[[:xdigit:]]+\s+\Q"\0::\x{01}::\x{30cd}"/,
+   "STASH for blessed hashrefs is correct"
+);
+
+BEGIN { $::{doof} = "\0\1\x{30cd}" }
+like(
+   _dump(\&doof),
+   qr/PROTOTYPE = \Q"\0\x{01}\x{30cd}"/,
+   "PROTOTYPE is escaped correctly"
+);
+
+{
+    my $coderef = eval <<"EOP";
+    use feature 'lexical_subs';
+    no warnings 'experimental::lexical_subs';
+    my sub bar (\$\x{30cd}) {1}; \\&bar
+EOP
+    like(
+       _dump($coderef),
+       qr/PROTOTYPE = "\$\Q\x{30cd}"/,
+       "PROTOTYPE works on lexical subs"
+    )
+}
+
+sub get_outside {
+   eval "sub $_[0] { my \$x; \$x++; return sub { eval q{\$x} } } $_[0]()";
+}
+sub basic { my $x; return eval q{sub { eval q{$x} }} }
+like(
+    _dump(basic()),
+    qr/OUTSIDE = 0x[[:xdigit:]]+\s+\Q(basic)/,
+    'OUTSIDE works'
+);
+
+like(
+    _dump(get_outside("\x{30ce}")),
+    qr/OUTSIDE = 0x[[:xdigit:]]+\s+\Q(\x{30ce})/,
+    'OUTSIDE + UTF8 works'
+);
+
+# TODO AUTOLOAD = stashname, which requires using a XS autoload
+# and calling Dump() on the cv
+
+
+
+sub test_utf8_stashes {
+   my ($stash_name, $test) = @_;
+
+   $dump = _dump(\%{"${stash_name}::"});
+
+   my $format = utf8::is_utf8($stash_name) ? '\x{%2x}' : '\x%2x';
+   $escaped_stash_name = join "", map {
+         $_ eq ':' ? $_ : sprintf $format, ord $_
+   } split //, $stash_name;
+
+   like(
+      $dump,
+      qr/\QNAME = "$escaped_stash_name"/,
+      "NAME is correct escaped for $test"
+   );
+
+   like(
+      $dump,
+      qr/\QENAME = "$escaped_stash_name"/,
+      "ENAME is correct escaped for $test"
+   );
+}
+
+for my $test (
+  [ "\x{30cd}", "UTF8 stashes" ],
+   [ "\x{df}", "latin 1 stashes" ],
+   [ "\x{df}::\x{30cd}", "latin1 + UTF8 stashes" ],
+   [ "\x{30cd}::\x{df}", "UTF8 + latin1 stashes" ],
+) {
+   test_utf8_stashes(@$test);
+}
+
+}
+
+my $runperl_args = { switches => ['-Ilib'] };
+sub test_DumpProg {
+    my ($prog, $expected, $name, $test) = @_;
+    $test ||= 'like';
+
+    my $u = 'use Devel::Peek "DumpProg"; DumpProg();';
+
+    # Interface between Test::Builder & test.pl
+    my $builder = Test::More->builder();
+    t::curr_test($builder->current_test() + 1);
+
+    utf8::encode($prog);
+    
+    if ( $test eq 'is' ) {
+        t::fresh_perl_is($prog . $u, $expected, $runperl_args, $name)
+    }
+    else {
+        t::fresh_perl_like($prog . $u, $expected, $runperl_args, $name)
+    }
+
+    $builder->current_test(t::curr_test() - 1);
+}
+
+my $threads = $Config{'useithreads'};
+
+for my $test (
+[
+    "package test;",
+    qr/PACKAGE = "test"/,
+    "DumpProg() + package declaration"
+],
+[
+    "use utf8; package \x{30cd};",
+    qr/PACKAGE = "\\x\Q{30cd}"/,
+    "DumpProg() + UTF8 package declaration"
+],
+[
+    "use utf8; sub \x{30cc}::\x{30cd} {1}; \x{30cc}::\x{30cd};",
+    ($threads ? qr/PADIX = \d+/ : qr/GV = \Q\x{30cc}::\x{30cd}\E/)
+],
+[
+    "use utf8; \x{30cc}: { last \x{30cc} }",
+    qr/LABEL = \Q"\x{30cc}"/
+],
+)
+{
+   test_DumpProg(@$test);
+}
+
+my $e = <<'EODUMP';
+dumpindent is 4 at - line 1.
+{
+1   TYPE = leave  ===> NULL
+    TARG = 1
+    FLAGS = (VOID,KIDS,PARENS,SLABBED,LASTSIB)
+    PRIVATE = (REFC)
+    REFCNT = 1
+    {
+2       TYPE = enter  ===> 3
+        FLAGS = (UNKNOWN,SLABBED)
+    }
+    {
+3       TYPE = nextstate  ===> 4
+        FLAGS = (VOID,SLABBED)
+        LINE = 1
+        PACKAGE = "t"
+    }
+    {
+5       TYPE = entersub  ===> 1
+        TARG = 1
+        FLAGS = (VOID,KIDS,STACKED,SLABBED,LASTSIB)
+        PRIVATE = (TARG)
+        {
+6           TYPE = null  ===> (5)
+              (was list)
+            FLAGS = (UNKNOWN,KIDS,SLABBED,LASTSIB)
+            {
+4               TYPE = pushmark  ===> 7
+                FLAGS = (SCALAR,SLABBED)
+            }
+            {
+8               TYPE = null  ===> (6)
+                  (was rv2cv)
+                FLAGS = (SCALAR,KIDS,SLABBED,LASTSIB)
+                PRIVATE = (0x1)
+                {
+7                   TYPE = gv  ===> 5
+                    FLAGS = (SCALAR,SLABBED,LASTSIB)
+                    GV_OR_PADIX
+                }
+            }
+        }
+    }
+}
+EODUMP
+
+$e =~ s/GV_OR_PADIX/$threads ? "PADIX = 2" : "GV = t::DumpProg"/e;
+$e =~ s/.*PRIVATE = \(0x1\).*\n// if $] < 5.021004;
+
+test_DumpProg("package t;", $e, "DumpProg() has no 'Attempt to free X prematurely' warning", "is" );
+
 done_testing();