In perl.git, the branch smoke-me/vtbl has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/cf395be7e975b8f37c27c237eba305b1596dad2e?hp=452cca5ccbee507639e1f443a4b39eb052a1015b>

- Log -----------------------------------------------------------------
commit cf395be7e975b8f37c27c237eba305b1596dad2e
Author: Nicholas Clark <n...@ccl4.org>
Date:   Sun May 15 14:45:53 2011 +0100

    In PL_magic_data flag whether magic can be added to a readonly value.
    
    Use this to simplify the logic in Perl_sv_magic().
    
    This introduces a small change of behaviour for error cases involving 
unknown
    magic types. Previously, if Perl_sv_magic() was passed a magic type unknown 
to
    it, it would
    
    1: Croak "Modification of a read-only value attempted" if read only
    2: Return without error if the SV happened to already have this magic
    3: otherwise croak "Don't know how to handle magic of type \\%o"
    
    Now it will always croak "Don't know how to handle magic of type \\%o", even
    on read only values, or SVs which already have the unknown magic type.

M       mg_raw.h
M       perl.h
M       regen/mg_vtable.pl
M       sv.c

commit 63efdc9965894e92d60b0b1c0aeffa3687e09412
Author: Nicholas Clark <n...@ccl4.org>
Date:   Sun May 15 13:54:19 2011 +0100

    Store a flag for container/value magic in PL_magic_data.
    
    Use this to replace S_is_container_magic() in mg.c with a direct lookup.

M       mg.c
M       mg_raw.h
M       perl.h
M       regen/mg_vtable.pl
M       sv.c

commit da86261127c75edda993a3e1a32c377b8e5ac34a
Author: Nicholas Clark <n...@ccl4.org>
Date:   Sun May 15 13:21:09 2011 +0100

    Create a lookup table for magic vtables from magic type, PL_magic_data.
    
    Use it to eliminate the large switch statement in Perl_sv_magic().
    
    As the table needs to be keyed on magic type, which is expressed as C 
character
    constants, the order depends on the compiler's character set. Frustratingly,
    EBCDIC variants don't agree on the code points for '~' and ']', which we use
    here. Instead of having (at least) 4 tables, get the local runtime to sort 
the
    table for us. Hence the regen script writes out the (unsorted) mg_raw.h, 
which
    generate_uudmap sorts to generate mg_data.h

M       MANIFEST
M       Makefile.SH
M       Makefile.micro
M       generate_uudmap.c
M       globvar.sym
A       mg_raw.h
M       perl.h
M       regen/mg_vtable.pl
M       sv.c
M       t/porting/regen.t
M       vms/descrip_mms.template
M       win32/Makefile
M       win32/makefile.mk

commit da7ac0b3bde1534777493a7852e7bffe8d8c39a3
Author: Nicholas Clark <n...@ccl4.org>
Date:   Sun May 15 12:02:28 2011 +0100

    Refactor generate_uudmap.c to use a helper function to output init blocks.
    
    In future, this will allow it to generate other output formats without
    duplicating code.

M       generate_uudmap.c
-----------------------------------------------------------------------

Summary of changes:
 MANIFEST                 |    1 +
 Makefile.SH              |   10 ++-
 Makefile.micro           |    8 +-
 generate_uudmap.c        |   90 ++++++++++++++++++++++++-----
 globvar.sym              |    1 +
 mg.c                     |   41 +-------------
 mg_raw.h                 |   90 ++++++++++++++++++++++++++++++
 perl.h                   |   17 ++++++
 regen/mg_vtable.pl       |  139 ++++++++++++++++++++++++++++++++++++++++++----
 sv.c                     |  137 ++++++---------------------------------------
 t/porting/regen.t        |    2 +-
 vms/descrip_mms.template |   10 ++-
 win32/Makefile           |   11 ++-
 win32/makefile.mk        |   11 ++-
 14 files changed, 361 insertions(+), 207 deletions(-)
 create mode 100644 mg_raw.h

diff --git a/MANIFEST b/MANIFEST
index b7add30..e056cef 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -4118,6 +4118,7 @@ metaconfig.SH                     Control file for the 
metaconfig process
 META.yml                       Distribution meta-data in YAML
 mg.c                           Magic code
 mg.h                           Magic header
+mg_raw.h                       Generated magic data used by generate_uudmap.c
 mg_vtable.h                    Generated magic vtable data
 minimod.pl                     Writes lib/ExtUtils/Miniperl.pm
 miniperlmain.c                 Basic perl w/o dynamic loading or extensions
diff --git a/Makefile.SH b/Makefile.SH
index 33f8505..a374300 100755
--- a/Makefile.SH
+++ b/Makefile.SH
@@ -619,12 +619,14 @@ done
 
 $spitshell >>$Makefile <<'!NO!SUBS!'
 
-globals$(OBJ_EXT): uudmap.h bitcount.h
+globals$(OBJ_EXT): uudmap.h bitcount.h mg_data.h
 
-uudmap.h: bitcount.h
+uudmap.h mg_data.h: bitcount.h
 
 bitcount.h: generate_uudmap$(HOST_EXE_EXT)
-       $(RUN) ./generate_uudmap$(HOST_EXE_EXT) uudmap.h bitcount.h
+       $(RUN) ./generate_uudmap$(HOST_EXE_EXT) uudmap.h bitcount.h mg_data.h
+
+generate_uudmap$(OBJ_EXT): mg_raw.h
 
 generate_uudmap$(HOST_EXE_EXT): generate_uudmap$(OBJ_EXT)
        $(CC) -o generate_uudmap$(EXE_EXT) $(LDFLAGS) generate_uudmap$(OBJ_EXT) 
$(libs)
@@ -1213,7 +1215,7 @@ veryclean:        _verycleaner _mopup _clobber
 
 # Do not 'make _mopup' directly.
 _mopup:
-       rm -f *$(OBJ_EXT) *$(LIB_EXT) all perlmain.c opmini.c perlmini.c 
uudmap.h generate_uudmap$(EXE_EXT) bitcount.h
+       rm -f *$(OBJ_EXT) *$(LIB_EXT) all perlmain.c opmini.c perlmini.c 
uudmap.h generate_uudmap$(EXE_EXT) bitcount.h mg_data.h
        -rmdir .depending
        -@test -f extra.pods && rm -f `cat extra.pods`
        -@test -f vms/README_vms.pod && rm -f vms/README_vms.pod
diff --git a/Makefile.micro b/Makefile.micro
index b5a7123..45cf26e 100644
--- a/Makefile.micro
+++ b/Makefile.micro
@@ -36,7 +36,7 @@ H = av.h uconfig.h cop.h cv.h embed.h embedvar.h form.h gv.h 
handy.h \
 HE = $(H) EXTERN.h
 
 clean:
-       -rm -f $(O) microperl generate_uudmap$(_X) uudmap.h bitcount.h
+       -rm -f $(O) microperl generate_uudmap$(_X) uudmap.h bitcount.h mg_data.h
 
 distclean:     clean
 
@@ -78,7 +78,7 @@ udoop$(_O):   $(HE) doop.c
 udump$(_O):    $(HE) dump.c regcomp.h regnodes.h
        $(CC) $(CCFLAGS) -o $@ $(CFLAGS) dump.c
 
-uglobals$(_O): $(H) globals.c INTERN.h perlapi.h uudmap.h bitcount.h
+uglobals$(_O): $(H) globals.c INTERN.h perlapi.h uudmap.h bitcount.h mg_data.h
        $(CC) $(CCFLAGS) -o $@ $(CFLAGS) globals.c
 
 ugv$(_O):      $(HE) gv.c
@@ -177,8 +177,8 @@ uutil$(_O): $(HE) util.c
 uperlapi$(_O): $(HE) perlapi.c perlapi.h
        $(CC) $(CCFLAGS) -o $@ $(CFLAGS) perlapi.c
 
-uudmap.h bitcount.h: generate_uudmap$(_X)
-       $(RUN) ./generate_uudmap$(_X) uudmap.h bitcount.h
+uudmap.h bitcount.h mg_data.h: generate_uudmap$(_X)
+       $(RUN) ./generate_uudmap$(_X) uudmap.h bitcount.h mg_data.h
 
 generate_uudmap$(_O): generate_uudmap.c
        $(CC) $(CCFLAGS) -o $@ $(CFLAGS) generate_uudmap.c
diff --git a/generate_uudmap.c b/generate_uudmap.c
index 2c3e24a..7fdc7c3 100644
--- a/generate_uudmap.c
+++ b/generate_uudmap.c
@@ -12,17 +12,47 @@
    "hello world" won't port easily to it.  */
 #include <errno.h>
 
-void output_block_to_file(const char *progname, const char *filename,
-                         const char *block, size_t count) {
-  FILE *const out = fopen(filename, "w");
-
-  if (!out) {
-    fprintf(stderr, "%s: Could not open '%s': %s\n", progname, filename,
-           strerror(errno));
-    exit(1);
+struct mg_data_raw_t {
+    unsigned char type;
+    const char *value;
+    const char *comment;
+};
+
+static struct mg_data_raw_t mg_data_raw[] = {
+#include "mg_raw.h"
+    {0, 0, 0}
+};
+
+struct mg_data_t {
+    const char *value;
+    const char *comment;
+};
+
+static struct mg_data_t mg_data[256];
+
+static void
+format_mg_data(FILE *out, const void *thing, size_t count) {
+  const struct mg_data_t *p = (const struct mg_data_t *)thing;
+
+  while (1) {
+      if (p->value) {
+         fprintf(out, "    %s\n    %s", p->comment, p->value);
+      } else {
+         fputs("    0", out);
+      }
+      ++p;
+      if (!--count)
+         break;
+      fputs(",\n", out);
   }
+  fputc('\n', out);
+}
+
+static void
+format_char_block(FILE *out, const void *thing, size_t count) {
+  const char *block = (const char *)thing;
 
-  fputs("{\n    ", out);
+  fputs("    ", out);
   while (count--) {
     fprintf(out, "%d", *block);
     block++;
@@ -33,7 +63,24 @@ void output_block_to_file(const char *progname, const char 
*filename,
       }
     }
   }
-  fputs("\n}\n", out);
+  fputc('\n', out);
+}
+
+static void
+output_to_file(const char *progname, const char *filename,
+              void (format_function)(FILE *out, const void *thing, size_t 
count),
+              const void *thing, size_t count) {
+  FILE *const out = fopen(filename, "w");
+
+  if (!out) {
+    fprintf(stderr, "%s: Could not open '%s': %s\n", progname, filename,
+           strerror(errno));
+    exit(1);
+  }
+
+  fputs("{\n", out);
+  format_function(out, thing, count);
+  fputs("}\n", out);
 
   if (fclose(out)) {
     fprintf(stderr, "%s: Could not close '%s': %s\n", progname, filename,
@@ -55,9 +102,11 @@ static char PL_bitcount[256];
 int main(int argc, char **argv) {
   size_t i;
   int bits;
+  struct mg_data_raw_t *p = mg_data_raw;
 
-  if (argc < 3 || argv[1][0] == '\0' || argv[2][0] == '\0') {
-    fprintf(stderr, "Usage: %s uudemap.h bitcount.h\n", argv[0]);
+  if (argc < 4 || argv[1][0] == '\0' || argv[2][0] == '\0'
+      || argv[3][0] == '\0') {
+    fprintf(stderr, "Usage: %s uudemap.h bitcount.h mg_data.h\n", argv[0]);
     return 1;
   }
 
@@ -69,7 +118,8 @@ int main(int argc, char **argv) {
    */
   PL_uudmap[(U8)' '] = 0;
 
-  output_block_to_file(argv[0], argv[1], PL_uudmap, sizeof(PL_uudmap));
+  output_to_file(argv[0], argv[1], &format_char_block,
+                (const void *)PL_uudmap, sizeof(PL_uudmap));
 
   for (bits = 1; bits < 256; bits++) {
     if (bits & 1)      PL_bitcount[bits]++;
@@ -82,9 +132,17 @@ int main(int argc, char **argv) {
     if (bits & 128)    PL_bitcount[bits]++;
   }
 
-  output_block_to_file(argv[0], argv[2], PL_bitcount, sizeof(PL_bitcount));
+  output_to_file(argv[0], argv[2], &format_char_block,
+                (const void *)PL_bitcount, sizeof(PL_bitcount));
+
+  while (p->value) {
+      mg_data[p->type].value = p->value;
+      mg_data[p->type].comment = p->comment;
+      ++p;
+  }
+      
+  output_to_file(argv[0], argv[3], &format_mg_data,
+                (const void *)mg_data, sizeof(mg_data)/sizeof(mg_data[0]));
 
   return 0;
 }
-
-  
diff --git a/globvar.sym b/globvar.sym
index c6355c9..a12c322 100644
--- a/globvar.sym
+++ b/globvar.sym
@@ -12,6 +12,7 @@ fold_latin1
 fold_locale
 freq
 keyword_plugin
+magic_data
 magic_vtables
 magic_vtable_names
 memory_wrap
diff --git a/mg.c b/mg.c
index 04daa32..3af646f 100644
--- a/mg.c
+++ b/mg.c
@@ -164,42 +164,6 @@ Perl_mg_magical(pTHX_ SV *sv)
     }
 }
 
-
-/* is this container magic (%ENV, $1 etc), or value magic (pos, taint etc)? */
-
-STATIC bool
-S_is_container_magic(const MAGIC *mg)
-{
-    assert(mg);
-    switch (mg->mg_type) {
-    case PERL_MAGIC_bm:
-    case PERL_MAGIC_fm:
-    case PERL_MAGIC_regex_global:
-    case PERL_MAGIC_nkeys:
-#ifdef USE_LOCALE_COLLATE
-    case PERL_MAGIC_collxfrm:
-#endif
-    case PERL_MAGIC_qr:
-    case PERL_MAGIC_taint:
-    case PERL_MAGIC_vec:
-    case PERL_MAGIC_vstring:
-    case PERL_MAGIC_utf8:
-    case PERL_MAGIC_substr:
-    case PERL_MAGIC_defelem:
-    case PERL_MAGIC_arylen:
-    case PERL_MAGIC_pos:
-    case PERL_MAGIC_backref:
-    case PERL_MAGIC_arylen_p:
-    case PERL_MAGIC_rhash:
-    case PERL_MAGIC_symtab:
-    case PERL_MAGIC_tied: /* treat as value, so 'local @tied' isn't tied */
-    case PERL_MAGIC_checkcall:
-       return 0;
-    default:
-       return 1;
-    }
-}
-
 /*
 =for apidoc mg_get
 
@@ -296,7 +260,8 @@ Perl_mg_set(pTHX_ SV *sv)
            mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */
            (SSPTR(mgs_ix, MGS*))->mgs_magical = 0;
        }
-       if (PL_localizing == 2 && (!S_is_container_magic(mg) || sv == DEFSV))
+       if (PL_localizing == 2
+           && (PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type) || sv == DEFSV))
            continue;
        if (vtbl && vtbl->svt_set)
            vtbl->svt_set(aTHX_ sv, mg);
@@ -526,7 +491,7 @@ Perl_mg_localize(pTHX_ SV *sv, SV *nsv, bool setmagic)
 
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
        const MGVTBL* const vtbl = mg->mg_virtual;
-       if (!S_is_container_magic(mg))
+       if (PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type))
            continue;
                
        if ((mg->mg_flags & MGf_LOCAL) && vtbl->svt_local)
diff --git a/mg_raw.h b/mg_raw.h
new file mode 100644
index 0000000..7ed04ee
--- /dev/null
+++ b/mg_raw.h
@@ -0,0 +1,90 @@
+/* -*- buffer-read-only: t -*-
+ *
+ *    mg_raw.h
+ * !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
+ * This file is built by regen/mg_vtable.pl.
+ * Any changes made here will be lost!
+ */
+
+    { '\0', "want_vtbl_sv | PERL_MAGIC_READONLY_ACCEPTABLE",
+      "/* sv '\\0' Special scalar variable */" },
+    { 'A', "want_vtbl_amagic",
+      "/* overload 'A' %OVERLOAD hash */" },
+    { 'a', "want_vtbl_amagicelem",
+      "/* overload_elem 'a' %OVERLOAD hash element */" },
+    { 'c', "want_vtbl_ovrld",
+      "/* overload_table 'c' Holds overload table (AMT) on stash */" },
+    { 'B', "want_vtbl_regexp | PERL_MAGIC_READONLY_ACCEPTABLE | 
PERL_MAGIC_VALUE_MAGIC",
+      "/* bm 'B' Boyer-Moore (fast string search) */" },
+    { 'D', "want_vtbl_regdata",
+      "/* regdata 'D' Regex match position data (@+ and @- vars) */" },
+    { 'd', "want_vtbl_regdatum",
+      "/* regdatum 'd' Regex match position data element */" },
+    { 'E', "want_vtbl_env",
+      "/* env 'E' %ENV hash */" },
+    { 'e', "want_vtbl_envelem",
+      "/* envelem 'e' %ENV hash element */" },
+    { 'f', "want_vtbl_regdata | PERL_MAGIC_READONLY_ACCEPTABLE | 
PERL_MAGIC_VALUE_MAGIC",
+      "/* fm 'f' Formline ('compiled' format) */" },
+    { 'g', "want_vtbl_mglob | PERL_MAGIC_READONLY_ACCEPTABLE | 
PERL_MAGIC_VALUE_MAGIC",
+      "/* regex_global 'g' m//g target / study()ed string */" },
+    { 'H', "want_vtbl_hints",
+      "/* hints 'H' %^H hash */" },
+    { 'h', "want_vtbl_hintselem",
+      "/* hintselem 'h' %^H hash element */" },
+    { 'I', "want_vtbl_isa",
+      "/* isa 'I' @ISA array */" },
+    { 'i', "want_vtbl_isaelem",
+      "/* isaelem 'i' @ISA array element */" },
+    { 'k', "want_vtbl_nkeys | PERL_MAGIC_VALUE_MAGIC",
+      "/* nkeys 'k' scalar(keys()) lvalue */" },
+    { 'L', "want_vtbl_dbline",
+      "/* dbfile 'L' Debugger %_<filename */" },
+    { 'l', "magic_vtable_max",
+      "/* dbline 'l' Debugger %_<filename element */" },
+    { 'o', "want_vtbl_collxfrm | PERL_MAGIC_VALUE_MAGIC",
+      "/* collxfrm 'o' Locale transformation */" },
+    { 'P', "want_vtbl_pack | PERL_MAGIC_VALUE_MAGIC",
+      "/* tied 'P' Tied array or hash */" },
+    { 'p', "want_vtbl_packelem",
+      "/* tiedelem 'p' Tied array or hash element */" },
+    { 'q', "want_vtbl_packelem",
+      "/* tiedscalar 'q' Tied scalar or handle */" },
+    { 'r', "want_vtbl_regexp | PERL_MAGIC_VALUE_MAGIC",
+      "/* qr 'r' precompiled qr// regex */" },
+    { 'S', "magic_vtable_max",
+      "/* sig 'S' %SIG hash */" },
+    { 's', "want_vtbl_sigelem",
+      "/* sigelem 's' %SIG hash element */" },
+    { 't', "want_vtbl_taint | PERL_MAGIC_VALUE_MAGIC",
+      "/* taint 't' Taintedness */" },
+    { 'U', "want_vtbl_uvar",
+      "/* uvar 'U' Available for use by extensions */" },
+    { 'v', "want_vtbl_vec | PERL_MAGIC_VALUE_MAGIC",
+      "/* vec 'v' vec() lvalue */" },
+    { 'V', "magic_vtable_max | PERL_MAGIC_VALUE_MAGIC",
+      "/* vstring 'V' SV was vstring literal */" },
+    { 'w', "want_vtbl_utf8 | PERL_MAGIC_VALUE_MAGIC",
+      "/* utf8 'w' Cached UTF-8 information */" },
+    { 'x', "want_vtbl_substr | PERL_MAGIC_VALUE_MAGIC",
+      "/* substr 'x' substr() lvalue */" },
+    { 'y', "want_vtbl_defelem | PERL_MAGIC_VALUE_MAGIC",
+      "/* defelem 'y' Shadow \"foreach\" iterator variable / smart parameter 
vivification */" },
+    { '#', "want_vtbl_arylen | PERL_MAGIC_VALUE_MAGIC",
+      "/* arylen '#' Array length ($#ary) */" },
+    { '.', "want_vtbl_pos | PERL_MAGIC_VALUE_MAGIC",
+      "/* pos '.' pos() lvalue */" },
+    { '<', "want_vtbl_backref | PERL_MAGIC_READONLY_ACCEPTABLE | 
PERL_MAGIC_VALUE_MAGIC",
+      "/* backref '<' for weak ref data */" },
+    { ':', "magic_vtable_max | PERL_MAGIC_VALUE_MAGIC",
+      "/* symtab ':' extra data for symbol tables */" },
+    { '%', "magic_vtable_max | PERL_MAGIC_VALUE_MAGIC",
+      "/* rhash '%' extra data for restricted hashes */" },
+    { '@', "magic_vtable_max | PERL_MAGIC_VALUE_MAGIC",
+      "/* arylen_p '@' to move arylen out of XPVAV */" },
+    { '~', "magic_vtable_max",
+      "/* ext '~' Available for use by extensions */" },
+    { ']', "magic_vtable_max | PERL_MAGIC_VALUE_MAGIC",
+      "/* checkcall ']' inlining/mutation of call to this CV */" },
+
+/* ex: set ro: */
diff --git a/perl.h b/perl.h
index 9c00120..9405788 100644
--- a/perl.h
+++ b/perl.h
@@ -5071,7 +5071,24 @@ START_EXTERN_C
 #  define EXT_MGVTBL EXT MGVTBL
 #endif
 
+#define PERL_MAGIC_READONLY_ACCEPTABLE 0x40
+#define PERL_MAGIC_VALUE_MAGIC 0x80
+#define PERL_MAGIC_VTABLE_MASK 0x3F
+#define PERL_MAGIC_TYPE_READONLY_ACCEPTABLE(t) \
+    (PL_magic_data[(U8)(t)] & PERL_MAGIC_READONLY_ACCEPTABLE)
+#define PERL_MAGIC_TYPE_IS_VALUE_MAGIC(t) \
+    (PL_magic_data[(U8)(t)] & PERL_MAGIC_VALUE_MAGIC)
+
 #include "mg_vtable.h"
+
+#ifdef DOINIT
+EXTCONST U8 PL_magic_data[256] =
+#include "mg_data.h"
+;
+#else
+EXTCONST U8 PL_magic_data[256];
+#endif
+
 #include "overload.h"
 
 END_EXTERN_C
diff --git a/regen/mg_vtable.pl b/regen/mg_vtable.pl
index f527a3e..8b587ff 100644
--- a/regen/mg_vtable.pl
+++ b/regen/mg_vtable.pl
@@ -18,6 +18,92 @@ BEGIN {
     require 'regen/regen_lib.pl';
 }
 
+my @mg =
+    (
+     sv => { char => '\0', vtable => 'sv', readonly_acceptable => 1,
+            desc => 'Special scalar variable' },
+     overload => { char => 'A', vtable => 'amagic', desc => '%OVERLOAD hash' },
+     overload_elem => { char => 'a', vtable => 'amagicelem',
+                       desc => '%OVERLOAD hash element' },
+     overload_table => { char => 'c', vtable => 'ovrld',
+                        desc => 'Holds overload table (AMT) on stash' },
+     bm => { char => 'B', vtable => 'regexp', value_magic => 1,
+            readonly_acceptable => 1,
+            desc => 'Boyer-Moore (fast string search)' },
+     regdata => { char => 'D', vtable => 'regdata',
+                 desc => 'Regex match position data (@+ and @- vars)' },
+     regdatum => { char => 'd', vtable => 'regdatum',
+                  desc => 'Regex match position data element' },
+     env => { char => 'E', vtable => 'env', desc => '%ENV hash' },
+     envelem => { char => 'e', vtable => 'envelem',
+                 desc => '%ENV hash element' },
+     fm => { char => 'f', vtable => 'regdata', value_magic => 1,
+            readonly_acceptable => 1, desc => "Formline ('compiled' format)" },
+     regex_global => { char => 'g', vtable => 'mglob', value_magic => 1,
+                      readonly_acceptable => 1,
+                      desc => 'm//g target / study()ed string' },
+     hints => { char => 'H', vtable => 'hints', desc => '%^H hash' },
+     hintselem => { char => 'h', vtable => 'hintselem',
+                   desc => '%^H hash element' },
+     isa => { char => 'I', vtable => 'isa', desc => '@ISA array' },
+     isaelem => { char => 'i', vtable => 'isaelem',
+                 desc => '@ISA array element' },
+     nkeys => { char => 'k', vtable => 'nkeys', value_magic => 1,
+               desc => 'scalar(keys()) lvalue' },
+     dbfile => { char => 'L', vtable => 'dbline',
+                desc => 'Debugger %_<filename' },
+     dbline => { char => 'l', desc => 'Debugger %_<filename element' },
+     shared => { char => 'N', desc => 'Shared between threads',
+                unknown_to_sv_magic => 1 },
+     shared_scalar => { char => 'n', desc => 'Shared between threads',
+                       unknown_to_sv_magic => 1 },
+     collxfrm => { char => 'o', vtable => 'collxfrm', value_magic => 1,
+                  desc => 'Locale transformation' },
+     tied => { char => 'P', vtable => 'pack',
+              value_magic => 1, # treat as value, so 'local @tied' isn't tied
+              desc => 'Tied array or hash' },
+     tiedelem => { char => 'p', vtable => 'packelem',
+                  desc => 'Tied array or hash element' },
+     tiedscalar => { char => 'q', vtable => 'packelem',
+                    desc => 'Tied scalar or handle' },
+     qr => { char => 'r', vtable => 'regexp', value_magic => 1, 
+            desc => 'precompiled qr// regex' },
+     sig => { char => 'S', desc => '%SIG hash' },
+     sigelem => { char => 's', vtable => 'sigelem',
+                 desc => '%SIG hash element' },
+     taint => { char => 't', vtable => 'taint', value_magic => 1,
+               desc => 'Taintedness' },
+     uvar => { char => 'U', vtable => 'uvar',
+              desc => 'Available for use by extensions' },
+     uvar_elem => { char => 'u', desc => 'Reserved for use by extensions',
+                   unknown_to_sv_magic => 1 },
+     vec => { char => 'v', vtable => 'vec', value_magic => 1,
+             desc => 'vec() lvalue' },
+     vstring => { char => 'V', value_magic => 1,
+                 desc => 'SV was vstring literal' },
+     utf8 => { char => 'w', vtable => 'utf8', value_magic => 1,
+              desc => 'Cached UTF-8 information' },
+     substr => { char => 'x', vtable => 'substr',  value_magic => 1,
+                desc => 'substr() lvalue' },
+     defelem => { char => 'y', vtable => 'defelem', value_magic => 1,
+                 desc => 'Shadow "foreach" iterator variable / smart parameter 
vivification' },
+     arylen => { char => '#', vtable => 'arylen', value_magic => 1,
+                desc => 'Array length ($#ary)' },
+     pos => { char => '.', vtable => 'pos', value_magic => 1,
+             desc => 'pos() lvalue' },
+     backref => { char => '<', vtable => 'backref', value_magic => 1,
+                 readonly_acceptable => 1, desc => 'for weak ref data' },
+     symtab => { char => ':', value_magic => 1,
+                desc => 'extra data for symbol tables' },
+     rhash => { char => '%', value_magic => 1,
+               desc => 'extra data for restricted hashes' },
+     arylen_p => { char => '@', value_magic => 1,
+                  desc => 'to move arylen out of XPVAV' },
+     ext => { char => '~', desc => 'Available for use by extensions' },
+     checkcall => { char => ']', value_magic => 1,
+                   desc => 'inlining/mutation of call to this CV'},
+);
+
 # These have a subtly different "namespace" from the magic types.
 my @sig =
     (
@@ -55,16 +141,42 @@ my @sig =
      'hints' => {clear => 'clearhints'},
 );
 
-my $h = open_new('mg_vtable.h', '>',
-                { by => 'regen/mg_vtable.pl', file => 'mg_vtable.h',
-                  style => '*' });
+my ($vt, $raw) = map {
+    open_new($_, '>',
+            { by => 'regen/mg_vtable.pl', file => $_, style => '*' });
+} 'mg_vtable.h', 'mg_raw.h';
+
+# Of course, it would be *much* easier if we could output this table directly
+# here and now. However, for our sins, we try to support EBCDIC, which wouldn't
+# be *so* bad, except that there are (at least) 3 EBCDIC charset variants, and
+# they don't agree on the code point for '~'. Which we use. Great.
+# So we have to get the local build runtime to sort our table in character 
order
+# (And of course, just to be helpful, in POSIX BC '~' is \xFF, so we can't even
+# simplify the C code by assuming that the last element of the array is
+# predictable)
+
+{
+    while (my ($name, $data) = splice @mg, 0, 2) {
+       my $i = ord eval qq{"$data->{char}"};
+       unless ($data->{unknown_to_sv_magic}) {
+           my $value = $data->{vtable}
+               ? "want_vtbl_$data->{vtable}" : 'magic_vtable_max';
+           $value .= ' | PERL_MAGIC_READONLY_ACCEPTABLE'
+               if $data->{readonly_acceptable};
+           $value .= ' | PERL_MAGIC_VALUE_MAGIC' if $data->{value_magic};
+           my $comment = "/* $name '$data->{char}' $data->{desc} */";
+           $comment =~ s/([\\"])/\\$1/g;
+           print $raw qq{    { '$data->{char}', "$value",\n      "$comment" 
},\n};
+       }
+    }
+}
 
 {
     my @names = grep {!ref $_} @sig;
     my $want = join ",\n    ", (map {"want_vtbl_$_"} @names), 
'magic_vtable_max';
     my $names = join qq{",\n    "}, @names;
 
-    print $h <<"EOH";
+    print $vt <<"EOH";
 enum {         /* pass one of these to get_vtbl */
     $want
 };
@@ -80,7 +192,7 @@ EXTCONST char *PL_magic_vtable_names[magic_vtable_max];
 EOH
 }
 
-print $h <<'EOH';
+print $vt <<'EOH';
 /* These all need to be 0, not NULL, as NULL can be (void*)0, which is a
  * pointer to data, whereas we're assigning pointers to functions, which are
  * not the same beast. ANSI doesn't allow the assignment from one to the other.
@@ -117,9 +229,9 @@ while (my ($name, $data) = splice @sig, 0, 2) {
     # Because we can't have a , after the last {...}
     my $comma = @sig ? ',' : '';
 
-    print $h "$data->{cond}\n" if $data->{cond};
-    print $h "  { $funcs }$comma\n";
-    print $h <<"EOH" if $data->{cond};
+    print $vt "$data->{cond}\n" if $data->{cond};
+    print $vt "  { $funcs }$comma\n";
+    print $vt <<"EOH" if $data->{cond};
 #else
   { 0, 0, 0, 0, 0, 0, 0, 0 }$comma
 #endif
@@ -130,7 +242,7 @@ EOH
     }
 }
 
-print $h <<'EOH';
+print $vt <<'EOH';
 };
 #else
 EXT_MGVTBL PL_magic_vtables[magic_vtable_max];
@@ -138,9 +250,12 @@ EXT_MGVTBL PL_magic_vtables[magic_vtable_max];
 
 EOH
 
-print $h (sort @aliases), "\n";
+print $vt (sort @aliases), "\n";
 
-print $h "#define PL_vtbl_$_ PL_magic_vtables[want_vtbl_$_]\n"
+print $vt "#define PL_vtbl_$_ PL_magic_vtables[want_vtbl_$_]\n"
     foreach sort @vtable_names;
 
-read_only_bottom_close_and_rename($h);
+# 63, not 64, As we rely on the last possible value to mean "NULL vtable"
+die "Too many vtable names" if @vtable_names > 63;
+
+read_only_bottom_close_and_rename($_) foreach $vt, $raw;
diff --git a/sv.c b/sv.c
index 957dc80..fd5c262 100644
--- a/sv.c
+++ b/sv.c
@@ -5243,9 +5243,25 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const 
obj, const int how,
     dVAR;
     const MGVTBL *vtable;
     MAGIC* mg;
+    unsigned int flags;
+    unsigned int vtable_index;
 
     PERL_ARGS_ASSERT_SV_MAGIC;
 
+    if (how < 0 || how > C_ARRAY_LENGTH(PL_magic_data)
+       || ((flags = PL_magic_data[how]),
+           (vtable_index = flags & PERL_MAGIC_VTABLE_MASK)
+           > magic_vtable_max))
+       Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
+
+    /* PERL_MAGIC_ext is reserved for use by extensions not perl internals.
+       Useful for attaching extension internal data to perl vars.
+       Note that multiple extensions may clash if magical scalars
+       etc holding private data from one are passed to another. */
+
+    vtable = (vtable_index == magic_vtable_max)
+       ? NULL : PL_magic_vtables + vtable_index;
+
 #ifdef PERL_OLD_COPY_ON_WRITE
     if (SvIsCOW(sv))
         sv_force_normal_flags(sv, 0);
@@ -5257,11 +5273,7 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const 
obj, const int how,
            !(SvFAKE(sv) && SvTYPE(sv) < SVt_PVMG)
 
            && IN_PERL_RUNTIME
-           && how != PERL_MAGIC_regex_global
-           && how != PERL_MAGIC_bm
-           && how != PERL_MAGIC_fm
-           && how != PERL_MAGIC_sv
-           && how != PERL_MAGIC_backref
+           && !PERL_MAGIC_TYPE_READONLY_ACCEPTABLE(how)
           )
        {
            Perl_croak_no_modify(aTHX);
@@ -5283,121 +5295,6 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const 
obj, const int how,
        }
     }
 
-    switch (how) {
-    case PERL_MAGIC_sv:
-       vtable = &PL_vtbl_sv;
-       break;
-    case PERL_MAGIC_overload:
-        vtable = &PL_vtbl_amagic;
-        break;
-    case PERL_MAGIC_overload_elem:
-        vtable = &PL_vtbl_amagicelem;
-        break;
-    case PERL_MAGIC_overload_table:
-        vtable = &PL_vtbl_ovrld;
-        break;
-    case PERL_MAGIC_regdata:
-       vtable = &PL_vtbl_regdata;
-       break;
-    case PERL_MAGIC_regdatum:
-       vtable = &PL_vtbl_regdatum;
-       break;
-    case PERL_MAGIC_env:
-       vtable = &PL_vtbl_env;
-       break;
-    case PERL_MAGIC_envelem:
-       vtable = &PL_vtbl_envelem;
-       break;
-    case PERL_MAGIC_regex_global:
-       vtable = &PL_vtbl_mglob;
-       break;
-    case PERL_MAGIC_isa:
-       vtable = &PL_vtbl_isa;
-       break;
-    case PERL_MAGIC_isaelem:
-       vtable = &PL_vtbl_isaelem;
-       break;
-    case PERL_MAGIC_nkeys:
-       vtable = &PL_vtbl_nkeys;
-       break;
-    case PERL_MAGIC_dbline:
-       vtable = &PL_vtbl_dbline;
-       break;
-#ifdef USE_LOCALE_COLLATE
-    case PERL_MAGIC_collxfrm:
-        vtable = &PL_vtbl_collxfrm;
-        break;
-#endif /* USE_LOCALE_COLLATE */
-    case PERL_MAGIC_tied:
-       vtable = &PL_vtbl_pack;
-       break;
-    case PERL_MAGIC_tiedelem:
-    case PERL_MAGIC_tiedscalar:
-       vtable = &PL_vtbl_packelem;
-       break;
-    case PERL_MAGIC_fm:
-    case PERL_MAGIC_bm:
-    case PERL_MAGIC_qr:
-       vtable = &PL_vtbl_regexp;
-       break;
-#ifndef PERL_MICRO
-    case PERL_MAGIC_sigelem:
-       vtable = &PL_vtbl_sigelem;
-       break;
-#endif
-    case PERL_MAGIC_taint:
-       vtable = &PL_vtbl_taint;
-       break;
-    case PERL_MAGIC_uvar:
-       vtable = &PL_vtbl_uvar;
-       break;
-    case PERL_MAGIC_vec:
-       vtable = &PL_vtbl_vec;
-       break;
-    case PERL_MAGIC_dbfile:
-    case PERL_MAGIC_sig:
-    case PERL_MAGIC_arylen_p:
-    case PERL_MAGIC_rhash:
-    case PERL_MAGIC_symtab:
-    case PERL_MAGIC_vstring:
-    case PERL_MAGIC_checkcall:
-       vtable = NULL;
-       break;
-    case PERL_MAGIC_utf8:
-       vtable = &PL_vtbl_utf8;
-       break;
-    case PERL_MAGIC_substr:
-       vtable = &PL_vtbl_substr;
-       break;
-    case PERL_MAGIC_defelem:
-       vtable = &PL_vtbl_defelem;
-       break;
-    case PERL_MAGIC_arylen:
-       vtable = &PL_vtbl_arylen;
-       break;
-    case PERL_MAGIC_pos:
-       vtable = &PL_vtbl_pos;
-       break;
-    case PERL_MAGIC_backref:
-       vtable = &PL_vtbl_backref;
-       break;
-    case PERL_MAGIC_hintselem:
-       vtable = &PL_vtbl_hintselem;
-       break;
-    case PERL_MAGIC_hints:
-       vtable = &PL_vtbl_hints;
-       break;
-    case PERL_MAGIC_ext:
-       /* Reserved for use by extensions not perl internals.           */
-       /* Useful for attaching extension internal data to perl vars.   */
-       /* Note that multiple extensions may clash if magical scalars   */
-       /* etc holding private data from one are passed to another.     */
-       vtable = NULL;
-       break;
-    default:
-       Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
-    }
-
     /* Rest of work is done else where */
     mg = sv_magicext(sv,obj,how,vtable,name,namlen);
 
diff --git a/t/porting/regen.t b/t/porting/regen.t
index 0e052dd..b644d70 100644
--- a/t/porting/regen.t
+++ b/t/porting/regen.t
@@ -27,7 +27,7 @@ if ( $^O eq "VMS" ) {
   skip_all( "- regen.pl needs porting." );
 }
 
-my $in_regen_pl = 18; # I can't see a clean way to calculate this 
automatically.
+my $in_regen_pl = 19; # I can't see a clean way to calculate this 
automatically.
 my @files = qw(perly.act perly.h perly.tab keywords.c keywords.h uconfig.h);
 my @progs = qw(Porting/makemeta regen/regcharclass.pl 
regen/mk_PL_charclass.pl);
 
diff --git a/vms/descrip_mms.template b/vms/descrip_mms.template
index a3a48b1..5145cde 100644
--- a/vms/descrip_mms.template
+++ b/vms/descrip_mms.template
@@ -508,16 +508,16 @@ perlmini.c : perl.c
 perlmini$(O) : perlmini.c
        $(CC) $(CORECFLAGS) $(MMS$SOURCE)
 
-bitcount.h : uudmap.h 
+bitcount.h mg_data.h : uudmap.h 
        @ $(NOOP)
 
 uudmap.h : generate_uudmap$(E)
-       MCR SYS$DISK:[]generate_uudmap$(E) uudmap.h bitcount.h
+       MCR SYS$DISK:[]generate_uudmap$(E) uudmap.h bitcount.h mg_data.h
 
 generate_uudmap$(E) : generate_uudmap$(O) $(CRTL)
        Link $(LINKFLAGS)/NoDebug/Trace/NoMap/NoFull/NoCross/Exe=$(MMS$TARGET) 
generate_uudmap$(O) $(CRTLOPTS)
 
-generate_uudmap$(O) : generate_uudmap.c
+generate_uudmap$(O) : generate_uudmap.c mg_raw.h
         $(CC) $(CORECFLAGS) $(MMS$SOURCE)
 
 # The following files are built in one go by gen_shrfls.pl:
@@ -1752,7 +1752,7 @@ doop$(O) : doop.c $(h)
        $(CC) $(CORECFLAGS) $(MMS$SOURCE)
 dump$(O) : dump.c $(h)
        $(CC) $(CORECFLAGS) $(MMS$SOURCE)
-globals$(O) : globals.c uudmap.h bitcount.h $(h)
+globals$(O) : globals.c uudmap.h bitcount.h mg_data.h $(h)
         $(CC) $(CORECFLAGS) $(MMS$SOURCE)
 gv$(O) : gv.c $(h)
        $(CC) $(CORECFLAGS) $(MMS$SOURCE)
@@ -1887,6 +1887,7 @@ tidy : cleanlis
        - If F$Search("perlmain.c;-1")   .nes."" Then Purge/NoConfirm/Log 
perlmain.c
        - If F$Search("uudmap.h;-1")   .nes."" Then Purge/NoConfirm/Log uudmap.h
        - If F$Search("bitcount.h;-1")   .nes."" Then Purge/NoConfirm/Log 
bitcount.h
+       - If F$Search("mg_data.h;-1")   .nes."" Then Purge/NoConfirm/Log 
mg_data.h
        - If F$Search("Perlshr_Gbl*.Mar;-1")   .nes."" Then Purge/NoConfirm/Log 
Perlshr_Gbl*.Mar
        - If F$Search("[.ext.Opcode...];-1").nes."" Then Purge/NoConfirm/Log 
[.ext.Opcode]
        - If F$Search("[.vms.ext...]*.C;-1").nes."" Then Purge/NoConfirm/Log 
[.vms.ext...]*.C
@@ -1920,6 +1921,7 @@ clean : tidy cleantest
        - If F$Search("perlmini.c")   .nes."" Then Delete/NoConfirm/Log 
perlmini.c;*
        - If F$Search("uudmap.h")   .nes."" Then Delete/NoConfirm/Log uudmap.h;*
        - If F$Search("bitcount.h")   .nes."" Then Delete/NoConfirm/Log 
bitcount.h;*
+       - If F$Search("mg_data.h")   .nes."" Then Delete/NoConfirm/Log 
md_data.h;*
        - If F$Search("Perlshr_Gbl*.Mar")   .nes."" Then Delete/NoConfirm/Log 
Perlshr_Gbl*.Mar;*
        - If F$Search("*.TS").nes."" Then Delete/NoConfirm/Log *.TS;*
        - If F$Search("[.vms.ext...]*.C").nes."" Then Delete/NoConfirm/Log 
[.vms.ext...]*.C;*
diff --git a/win32/Makefile b/win32/Makefile
index 2a35c31..6ca3f94 100644
--- a/win32/Makefile
+++ b/win32/Makefile
@@ -726,6 +726,7 @@ CORE_H              = $(CORE_NOCFG_H) .\config.h 
..\git_version.h
 
 UUDMAP_H       = ..\uudmap.h
 BITCOUNT_H     = ..\bitcount.h
+MG_DATA_H      = ..\mg_data.h
 
 MICROCORE_OBJ  = $(MICROCORE_SRC:.c=.obj)
 CORE_OBJ       = $(MICROCORE_OBJ) $(EXTRACORE_SRC:.c=.obj)
@@ -947,12 +948,14 @@ $(X2P) : $(MINIPERL) $(X2P_OBJ) Extensions
 <<
        $(EMBED_EXE_MANI)
 
-$(MINIDIR)\globals$(o) : $(UUDMAP_H) $(BITCOUNT_H)
+$(MINIDIR)\globals$(o) : $(UUDMAP_H) $(BITCOUNT_H) $(MG_DATA_H)
 
-$(UUDMAP_H) : $(BITCOUNT_H)
+$(UUDMAP_H) $(MG_DATA_H) : $(BITCOUNT_H)
 
 $(BITCOUNT_H) : $(GENUUDMAP)
-       $(GENUUDMAP) $(UUDMAP_H) $(BITCOUNT_H)
+       $(GENUUDMAP) $(UUDMAP_H) $(BITCOUNT_H) $(MG_DATA_H)
+
+$(GENUUDMAP_OBJ) : mg_raw.h
 
 $(GENUUDMAP) : $(GENUUDMAP_OBJ)
        $(LINK32) -subsystem:console -out:$@ @<<
@@ -1279,7 +1282,7 @@ _clean :
        -@$(DEL) $(PERLSTATICLIB)
        -@$(DEL) $(PERLDLL)
        -@$(DEL) $(CORE_OBJ)
-       -@$(DEL) $(GENUUDMAP) $(GENUUDMAP_OBJ) $(UUDMAP_H) $(BITCOUNT_H)
+       -@$(DEL) $(GENUUDMAP) $(GENUUDMAP_OBJ) $(UUDMAP_H) $(BITCOUNT_H) 
$(MG_DATA_H)
        -if exist $(MINIDIR) rmdir /s /q $(MINIDIR)
        -if exist $(UNIDATADIR1) rmdir /s /q $(UNIDATADIR1)
        -if exist $(UNIDATADIR2) rmdir /s /q $(UNIDATADIR2)
diff --git a/win32/makefile.mk b/win32/makefile.mk
index a6e1593..26869aa 100644
--- a/win32/makefile.mk
+++ b/win32/makefile.mk
@@ -937,6 +937,7 @@ CORE_H              = $(CORE_NOCFG_H) .\config.h 
..\git_version.h
 
 UUDMAP_H       = ..\uudmap.h
 BITCOUNT_H     = ..\bitcount.h
+MG_DATA_H      = ..\mg_data.h
 
 MICROCORE_OBJ  = $(MICROCORE_SRC:db:+$(o))
 CORE_OBJ       = $(MICROCORE_OBJ) $(EXTRACORE_SRC:db:+$(o))
@@ -1308,12 +1309,14 @@ $(X2P) : $(MINIPERL) $(X2P_OBJ) Extensions
        $(EMBED_EXE_MANI)
 .ENDIF
 
-$(MINIDIR)\globals$(o) : $(UUDMAP_H) $(BITCOUNT_H)
+$(MINIDIR)\globals$(o) : $(UUDMAP_H) $(BITCOUNT_H) $(MG_DATA_H)
 
-$(UUDMAP_H) : $(BITCOUNT_H)
+$(UUDMAP_H) $(MG_DATA_H) : $(BITCOUNT_H)
 
 $(BITCOUNT_H) : $(GENUUDMAP)
-       $(GENUUDMAP) $(UUDMAP_H) $(BITCOUNT_H)
+       $(GENUUDMAP) $(UUDMAP_H) $(BITCOUNT_H) $(MG_DATA_H)
+
+$(GENUUDMAP_OBJ) : mg_raw.h
 
 $(GENUUDMAP) : $(GENUUDMAP_OBJ)
 .IF "$(CCTYPE)" == "BORLAND"
@@ -1676,7 +1679,7 @@ _clean :
        -@erase $(PERLSTATICLIB)
        -@erase $(PERLDLL)
        -@erase $(CORE_OBJ)
-       -@erase $(GENUUDMAP) $(GENUUDMAP_OBJ) $(UUDMAP_H) $(BITCOUNT_H)
+       -@erase $(GENUUDMAP) $(GENUUDMAP_OBJ) $(UUDMAP_H) $(BITCOUNT_H) 
$(MG_DATA_H)
        -if exist $(MINIDIR) rmdir /s /q $(MINIDIR)
        -if exist $(UNIDATADIR1) rmdir /s /q $(UNIDATADIR1)
        -if exist $(UNIDATADIR2) rmdir /s /q $(UNIDATADIR2)

--
Perl5 Master Repository

Reply via email to