📄 c.pm
字号:
sub B::PVMG::save {
my ($sv) = @_;
my $sym = objsym($sv);
return $sym if defined $sym;
my $pv = $sv->PV;
my $len = length($pv);
my ($pvsym, $pvmax) = savepv($pv);
$xpvmgsect->add(sprintf("%s, %u, %u, %d, %s, 0, 0",
$pvsym, $len, $pvmax, $sv->IVX, $sv->NVX));
$svsect->add(sprintf("&xpvmg_list[%d], %lu, 0x%x",
$xpvmgsect->index, $sv->REFCNT + 1, $sv->FLAGS));
if (!$pv_copy_on_grow) {
$init->add(sprintf("xpvmg_list[%d].xpv_pv = savepvn(%s, %u);",
$xpvmgsect->index, cstring($pv), $len));
}
$sym = savesym($sv, sprintf("&sv_list[%d]", $svsect->index));
$sv->save_magic;
return $sym;
}
sub B::PVMG::save_magic {
my ($sv) = @_;
#warn sprintf("saving magic for %s (0x%x)\n", class($sv), $$sv); # debug
my $stash = $sv->SvSTASH;
if ($$stash) {
warn sprintf("xmg_stash = %s (0x%x)\n", $stash->NAME, $$stash)
if $debug_mg;
# XXX Hope stash is already going to be saved.
$init->add(sprintf("SvSTASH(s\\_%x) = s\\_%x;", $$sv, $$stash));
}
my @mgchain = $sv->MAGIC;
my ($mg, $type, $obj, $ptr);
foreach $mg (@mgchain) {
$type = $mg->TYPE;
$obj = $mg->OBJ;
$ptr = $mg->PTR;
my $len = defined($ptr) ? length($ptr) : 0;
if ($debug_mg) {
warn sprintf("magic %s (0x%x), obj %s (0x%x), type %s, ptr %s\n",
class($sv), $$sv, class($obj), $$obj,
cchar($type), cstring($ptr));
}
$init->add(sprintf("sv_magic((SV*)s\\_%x, (SV*)s\\_%x, %s, %s, %d);",
$$sv, $$obj, cchar($type),cstring($ptr),$len));
}
}
sub B::RV::save {
my ($sv) = @_;
my $sym = objsym($sv);
return $sym if defined $sym;
$xrvsect->add($sv->RV->save);
$svsect->add(sprintf("&xrv_list[%d], %lu, 0x%x",
$xrvsect->index, $sv->REFCNT + 1, $sv->FLAGS));
return savesym($sv, sprintf("&sv_list[%d]", $svsect->index));
}
sub try_autoload {
my ($cvstashname, $cvname) = @_;
warn sprintf("No definition for sub %s::%s\n", $cvstashname, $cvname);
# Handle AutoLoader classes explicitly. Any more general AUTOLOAD
# use should be handled by the class itself.
no strict 'refs';
my $isa = \@{"$cvstashname\::ISA"};
if (grep($_ eq "AutoLoader", @$isa)) {
warn "Forcing immediate load of sub derived from AutoLoader\n";
# Tweaked version of AutoLoader::AUTOLOAD
my $dir = $cvstashname;
$dir =~ s(::)(/)g;
eval { require "auto/$dir/$cvname.al" };
if ($@) {
warn qq(failed require "auto/$dir/$cvname.al": $@\n);
return 0;
} else {
return 1;
}
}
}
sub B::CV::save {
my ($cv) = @_;
my $sym = objsym($cv);
if (defined($sym)) {
# warn sprintf("CV 0x%x already saved as $sym\n", $$cv); # debug
return $sym;
}
# Reserve a place in svsect and xpvcvsect and record indices
my $sv_ix = $svsect->index + 1;
$svsect->add("svix$sv_ix");
my $xpvcv_ix = $xpvcvsect->index + 1;
$xpvcvsect->add("xpvcvix$xpvcv_ix");
# Save symbol now so that GvCV() doesn't recurse back to us via CvGV()
$sym = savesym($cv, "&sv_list[$sv_ix]");
warn sprintf("saving CV 0x%x as $sym\n", $$cv) if $debug_cv;
my $gv = $cv->GV;
my $cvstashname = $gv->STASH->NAME;
my $cvname = $gv->NAME;
my $root = $cv->ROOT;
my $cvxsub = $cv->XSUB;
if (!$$root && !$cvxsub) {
if (try_autoload($cvstashname, $cvname)) {
# Recalculate root and xsub
$root = $cv->ROOT;
$cvxsub = $cv->XSUB;
if ($$root || $cvxsub) {
warn "Successful forced autoload\n";
}
}
}
my $startfield = 0;
my $padlist = $cv->PADLIST;
my $pv = $cv->PV;
my $xsub = 0;
my $xsubany = "Nullany";
if ($$root) {
warn sprintf("saving op tree for CV 0x%x, root = 0x%x\n",
$$cv, $$root) if $debug_cv;
my $ppname = "";
if ($$gv) {
my $stashname = $gv->STASH->NAME;
my $gvname = $gv->NAME;
if ($gvname ne "__ANON__") {
$ppname = (${$gv->FORM} == $$cv) ? "pp_form_" : "pp_sub_";
$ppname .= ($stashname eq "main") ?
$gvname : "$stashname\::$gvname";
$ppname =~ s/::/__/g;
}
}
if (!$ppname) {
$ppname = "pp_anonsub_$anonsub_index";
$anonsub_index++;
}
$startfield = saveoptree($ppname, $root, $cv->START, $padlist->ARRAY);
warn sprintf("done saving op tree for CV 0x%x, name %s, root 0x%x\n",
$$cv, $ppname, $$root) if $debug_cv;
if ($$padlist) {
warn sprintf("saving PADLIST 0x%x for CV 0x%x\n",
$$padlist, $$cv) if $debug_cv;
$padlist->save;
warn sprintf("done saving PADLIST 0x%x for CV 0x%x\n",
$$padlist, $$cv) if $debug_cv;
}
}
elsif ($cvxsub) {
$xsubany = sprintf("ANYINIT((void*)0x%x)", $cv->XSUBANY);
# Try to find out canonical name of XSUB function from EGV.
# XXX Doesn't work for XSUBs with PREFIX set (or anyone who
# calls newXS() manually with weird arguments).
my $egv = $gv->EGV;
my $stashname = $egv->STASH->NAME;
$stashname =~ s/::/__/g;
$xsub = sprintf("XS_%s_%s", $stashname, $egv->NAME);
$decl->add("void $xsub _((CV*));");
}
else {
warn sprintf("No definition for sub %s::%s (unable to autoload)\n",
$cvstashname, $cvname); # debug
}
$symsect->add(sprintf("xpvcvix%d\t%s, %u, 0, %d, %s, 0, Nullhv, Nullhv, %s, s\\_%x, $xsub, $xsubany, Nullgv, Nullgv, %d, s\\_%x, (CV*)s\\_%x, 0",
$xpvcv_ix, cstring($pv), length($pv), $cv->IVX,
$cv->NVX, $startfield, ${$cv->ROOT}, $cv->DEPTH,
$$padlist, ${$cv->OUTSIDE}));
if ($$gv) {
$gv->save;
$init->add(sprintf("CvGV(s\\_%x) = s\\_%x;",$$cv,$$gv));
warn sprintf("done saving GV 0x%x for CV 0x%x\n",
$$gv, $$cv) if $debug_cv;
}
my $filegv = $cv->FILEGV;
if ($$filegv) {
$filegv->save;
$init->add(sprintf("CvFILEGV(s\\_%x) = s\\_%x;", $$cv, $$filegv));
warn sprintf("done saving FILEGV 0x%x for CV 0x%x\n",
$$filegv, $$cv) if $debug_cv;
}
my $stash = $cv->STASH;
if ($$stash) {
$stash->save;
$init->add(sprintf("CvSTASH(s\\_%x) = s\\_%x;", $$cv, $$stash));
warn sprintf("done saving STASH 0x%x for CV 0x%x\n",
$$stash, $$cv) if $debug_cv;
}
$symsect->add(sprintf("svix%d\t(XPVCV*)&xpvcv_list[%u], %lu, 0x%x",
$sv_ix, $xpvcv_ix, $cv->REFCNT + 1, $cv->FLAGS));
return $sym;
}
sub B::GV::save {
my ($gv) = @_;
my $sym = objsym($gv);
if (defined($sym)) {
#warn sprintf("GV 0x%x already saved as $sym\n", $$gv); # debug
return $sym;
} else {
my $ix = $gv_index++;
$sym = savesym($gv, "gv_list[$ix]");
#warn sprintf("Saving GV 0x%x as $sym\n", $$gv); # debug
}
my $gvname = $gv->NAME;
my $name = cstring($gv->STASH->NAME . "::" . $gvname);
#warn "GV name is $name\n"; # debug
my $egv = $gv->EGV;
my $egvsym;
if ($$gv != $$egv) {
#warn(sprintf("EGV name is %s, saving it now\n",
# $egv->STASH->NAME . "::" . $egv->NAME)); # debug
$egvsym = $egv->save;
}
$init->add(qq[$sym = gv_fetchpv($name, TRUE, SVt_PV);],
sprintf("SvFLAGS($sym) = 0x%x;", $gv->FLAGS),
sprintf("GvFLAGS($sym) = 0x%x;", $gv->GvFLAGS),
sprintf("GvLINE($sym) = %u;", $gv->LINE));
# Shouldn't need to do save_magic since gv_fetchpv handles that
#$gv->save_magic;
my $refcnt = $gv->REFCNT + 1;
$init->add(sprintf("SvREFCNT($sym) += %u;", $refcnt - 1)) if $refcnt > 1;
my $gvrefcnt = $gv->GvREFCNT;
if ($gvrefcnt > 1) {
$init->add(sprintf("GvREFCNT($sym) += %u;", $gvrefcnt - 1));
}
if (defined($egvsym)) {
# Shared glob *foo = *bar
$init->add("gp_free($sym);",
"GvGP($sym) = GvGP($egvsym);");
} elsif ($gvname !~ /^([^A-Za-z]|STDIN|STDOUT|STDERR|ARGV|SIG|ENV)$/) {
# Don't save subfields of special GVs (*_, *1, *# and so on)
# warn "GV::save saving subfields\n"; # debug
my $gvsv = $gv->SV;
if ($$gvsv) {
$init->add(sprintf("GvSV($sym) = s\\_%x;", $$gvsv));
# warn "GV::save \$$name\n"; # debug
$gvsv->save;
}
my $gvav = $gv->AV;
if ($$gvav) {
$init->add(sprintf("GvAV($sym) = s\\_%x;", $$gvav));
# warn "GV::save \@$name\n"; # debug
$gvav->save;
}
my $gvhv = $gv->HV;
if ($$gvhv) {
$init->add(sprintf("GvHV($sym) = s\\_%x;", $$gvhv));
# warn "GV::save \%$name\n"; # debug
$gvhv->save;
}
my $gvcv = $gv->CV;
if ($$gvcv) {
$init->add(sprintf("GvCV($sym) = (CV*)s\\_%x;", $$gvcv));
# warn "GV::save &$name\n"; # debug
$gvcv->save;
}
my $gvfilegv = $gv->FILEGV;
if ($$gvfilegv) {
$init->add(sprintf("GvFILEGV($sym) = s\\_%x;",$$gvfilegv));
# warn "GV::save GvFILEGV(*$name)\n"; # debug
$gvfilegv->save;
}
my $gvform = $gv->FORM;
if ($$gvform) {
$init->add(sprintf("GvFORM($sym) = (CV*)s\\_%x;", $$gvform));
# warn "GV::save GvFORM(*$name)\n"; # debug
$gvform->save;
}
my $gvio = $gv->IO;
if ($$gvio) {
$init->add(sprintf("GvIOp($sym) = s\\_%x;", $$gvio));
# warn "GV::save GvIO(*$name)\n"; # debug
$gvio->save;
}
}
return $sym;
}
sub B::AV::save {
my ($av) = @_;
my $sym = objsym($av);
return $sym if defined $sym;
my $avflags = $av->AvFLAGS;
$xpvavsect->add(sprintf("0, -1, -1, 0, 0.0, 0, Nullhv, 0, 0, 0x%x",
$avflags));
$svsect->add(sprintf("&xpvav_list[%d], %lu, 0x%x",
$xpvavsect->index, $av->REFCNT + 1, $av->FLAGS));
my $sv_list_index = $svsect->index;
my $fill = $av->FILL;
$av->save_magic;
warn sprintf("saving AV 0x%x FILL=$fill AvFLAGS=0x%x", $$av, $avflags)
if $debug_av;
# XXX AVf_REAL is wrong test: need to save comppadlist but not stack
#if ($fill > -1 && ($avflags & AVf_REAL)) {
if ($fill > -1) {
my @array = $av->ARRAY;
if ($debug_av) {
my $el;
my $i = 0;
foreach $el (@array) {
warn sprintf("AV 0x%x[%d] = %s 0x%x\n",
$$av, $i++, class($el), $$el);
}
}
my @names = map($_->save, @array);
# XXX Better ways to write loop?
# Perhaps svp[0] = ...; svp[1] = ...; svp[2] = ...;
# Perhaps I32 i = 0; svp[i++] = ...; svp[i++] = ...; svp[i++] = ...;
$init->add("{",
"\tSV **svp;",
"\tAV *av = (AV*)&sv_list[$sv_list_index];",
"\tav_extend(av, $fill);",
"\tsvp = AvARRAY(av);",
map("\t*svp++ = (SV*)$_;", @names),
"\tAvFILLp(av) = $fill;",
"}");
} else {
my $max = $av->MAX;
$init->add("av_extend((AV*)&sv_list[$sv_list_index], $max);")
if $max > -1;
}
return savesym($av, "(AV*)&sv_list[$sv_list_index]");
}
sub B::HV::save {
my ($hv) = @_;
my $sym = objsym($hv);
return $sym if defined $sym;
my $name = $hv->NAME;
if ($name) {
# It's a stash
# A perl bug means HvPMROOT isn't altered when a PMOP is freed. Usually
# the only symptom is that sv_reset tries to reset the PMf_USED flag of
# a trashed op but we look at the trashed op_type and segfault.
#my $adpmroot = ${$hv->PMROOT};
my $adpmroot = 0;
$decl->add("static HV *hv$hv_index;");
# XXX Beware of weird package names containing double-quotes, \n, ...?
$init->add(qq[hv$hv_index = gv_stashpv("$name", TRUE);]);
if ($adpmroot) {
$init->add(sprintf("HvPMROOT(hv$hv_index) = (PMOP*)s\\_%x;",
$adpmroot));
}
$sym = savesym($hv, "hv$hv_index");
$hv_index++;
return $sym;
}
# It's just an ordinary HV
$xpvhvsect->add(sprintf("0, 0, %d, 0, 0.0, 0, Nullhv, %d, 0, 0, 0",
$hv->MAX, $hv->RITER));
$svsect->add(sprintf("&xpvhv_list[%d], %lu, 0x%x",
$xpvhvsect->index, $hv->REFCNT + 1, $hv->FLAGS));
my $sv_list_index = $svsect->index;
my @contents = $hv->ARRAY;
if (@contents) {
my $i;
for ($i = 1; $i < @contents; $i += 2) {
$contents[$i] = $contents[$i]->save;
}
$init->add("{", "\tHV *hv = (HV*)&sv_list[$sv_list_index];");
while (@contents) {
my ($key, $value) = splice(@contents, 0, 2);
$init->add(sprintf("\thv_store(hv, %s, %u, %s, %s);",
cstring($key),length($key),$value, hash($key)));
}
$init->add("}");
}
return savesym($hv, "(HV*)&sv_list[$sv_list_index]");
}
sub B::IO::save {
my ($io) = @_;
my $sym = objsym($io);
return $sym if defined $sym;
my $pv = $io->PV;
my $len = length($pv);
$xpviosect->add(sprintf("0, %u, %u, %d, %s, 0, 0, 0, 0, 0, %d, %d, %d, %d, %s, Nullgv, %s, Nullgv, %s, Nullgv, %d, %s, 0x%x",
$len, $len+1, $io->IVX, $io->NVX, $io->LINES,
$io->PAGE, $io->PAGE_LEN, $io->LINES_LEFT,
cstring($io->TOP_NAME), cstring($io->FMT_NAME),
cstring($io->BOTTOM_NAME), $io->SUBPROCESS,
cchar($io->IoTYPE), $io->IoFLAGS));
$svsect->add(sprintf("&xpvio_list[%d], %lu, 0x%x",
$xpviosect->index, $io->REFCNT + 1, $io->FLAGS));
$sym = savesym($io, sprintf("(IO*)&sv_list[%d]", $svsect->index));
my ($field, $fsym);
foreach $field (qw(TOP_GV FMT_GV BOTTOM_GV)) {
$fsym = $io->$field();
if ($$fsym) {
$init->add(sprintf("Io$field($sym) = (GV*)s\\_%x;", $$fsym));
$fsym->save;
}
}
$io->save_magic;
return $sym;
}
sub B::SV::save {
my $sv = shift;
# This is where we catch an honest-to-goodness Nullsv (which gets
# blessed into B::SV explicitly) and any stray erroneous SVs.
return 0 unless $$sv;
confess sprintf("cannot save that type of SV: %s (0x%x)\n",
class($sv), $$sv);
}
sub output_all {
my $init_name = shift;
my $section;
my @sections = ($opsect, $unopsect, $binopsect, $logopsect, $condopsect,
$listopsect, $pmopsect, $svopsect, $gvopsect, $pvopsect,
$cvopsect, $loopsect, $copsect, $svsect, $xpvsect,
$xpvavsect, $xpvhvsect, $xpvcvsect, $xpvivsect, $xpvnvsect,
$xpvmgsect, $xpvlvsect, $xrvsect, $xpvbmsect, $xpviosect);
$symsect->output(\*STDOUT, "#define %s\n");
print "\n";
output_declarations();
foreach $section (@sections) {
my $lines = $section->index + 1;
if ($lines) {
my $name = $section->name;
my $typename = ($name eq "xpvcv") ? "XPVCV_or_similar" : uc($name);
print "Static $typename ${name}_list[$lines];\n";
}
}
$decl->output(\*STDOUT, "%s\n");
print "\n";
foreach $section (@sections) {
my $lines = $section->index + 1;
if ($lines) {
my $name = $section->name;
my $typename = ($name eq "xpvcv") ? "XPVCV_or_similar" : uc($name);
printf "static %s %s_list[%u] = {\n", $typename, $name, $lines;
$section->output(\*STDOUT, "\t{ %s },\n");
print "};\n\n";
}
}
print <<"EOT";
static int $init_name()
{
dTHR;
EOT
$init->output(\*STDOUT, "\t%s\n");
print "\treturn 0;\n}\n";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -