Viewing File: /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/x86_64-linux/B/C/OverLoad/B/UNOP_AUX.pm
package B::UNOP_AUX;
use B::C::Std;
use B qw/svref_2object/;
use B::C::Debug qw/debug/;
use B::C::File qw/unopauxsect init free meta_unopaux_item/;
use B::C::Helpers qw/is_constant/;
use B::C::Save qw/savecowpv/;
sub _clear_stack() {
#'B::C::Save'->can('stack_flat')->();
return join '', ( 1 .. 42 ); # large enough to do stuff & clear
}
# hardcoded would require a check to detect this is going to the correct position
sub OP_AUX_IX { 15 }
sub do_save ( $op, @ ) {
_clear_stack(); # avoid a weird B (or B::C) issue when calling aux_list_thr
unopauxsect()->comment_for_op("first, aux");
my ( $ix, $sym ) = unopauxsect()->reserve( $op, "OP*" );
unopauxsect()->debug( $op->name, $op );
my $first = $op->first->save;
# cast to avoid warning
if ( $first eq '(void*)Nullsv' ) {
$first = '(OP*) 0';
}
unopauxsect()->supdate(
$ix, "%s, %s, %s", $op->save_baseop, $first,
'AUX-TO-BE-FILLED'
);
my @aux_list;
if ( $op->name eq 'argelem' ) {
# argelem has no aux_list, it's stealing the pointer to save one integer
# from pp.c for PP(pp_argelem)
# IV ix = PTR2IV(cUNOP_AUXo->op_aux);
my $op_aux = $op->aux_ptr2iv // 0;
unopauxsect()->update_field( $ix, OP_AUX_IX(), ' (UNOP_AUX_item *) ' . $op_aux );
return $sym;
}
elsif ( $op->name eq 'argcheck' ) {
@aux_list = $op->aux_list_thr;
#print STDERR join( ' ', '# ARGCHECK', @aux_list, "\n" );
}
elsif ( $op->name eq 'multideref' ) {
@aux_list = $op->aux_list_thr;
}
elsif ( $op->name eq 'multiconcat' ) {
my $list = aux_list_for_multiconcat($op);
@aux_list = @$list;
}
else { # ithread
# Usage: B::UNOP_AUX::aux_list(o, cv)
die "ithreads";
@aux_list = $op->aux_list; # GH#283, GH#341
}
#### Saving the regular AUX LIST
my $auxlen = scalar @aux_list;
my @to_be_filled = map { 0 } 1 .. $auxlen; #
my $list_size = $auxlen + 1;
my $unopaux_item_sect = meta_unopaux_item($list_size);
$unopaux_item_sect->comment(q{length prefix, UNOP_AUX_item * $auxlen });
my $uaux_item_ix = $unopaux_item_sect->add( join( ', ', qq[{.uv=$auxlen}], @to_be_filled ) );
my $symname = sprintf(
'meta_unopaux_item%d_list[%d]', $list_size,
$uaux_item_ix
);
my $op_aux = sprintf( '&%s.aaab', $symname );
unopauxsect()->update_field( $ix, OP_AUX_IX(), $op_aux );
# This cannot be a section, as the number of elements is variable
my $i = 1; # maybe rename to field_ix
my $struct_field = q{aaaa};
my $action = 0;
foreach my $item (@aux_list) {
my $field;
$struct_field++;
my $symat = "${symname}.$struct_field";
unless ( ref $item ) {
# symbolize MDEREF action
#my $cmt = $op->get_action_name($item);
$action = $item;
if ( $item =~ qr{^-?[0-9]+$} && $item < 0 ) { # -1 should be the only negative known value at this point
$field = sprintf( '{.iv=%d}', $item );
}
elsif ( $item =~ qr{COWPV} ) {
$field = sprintf( '{.pv= (char*) %s}', $item );
}
else {
#debug( hv => $op->name . " action $action $cmt" );
$field = sprintf( '{.uv=0x%x}', $item ); # \t/* %s: %u */ , $cmt, $item
}
}
else {
# const and sv already at compile-time, gv deferred to init-time.
# testcase: $a[-1] -1 as B::IV not as -1
# hmm, if const ensure that candidate CONSTs have been HEKified. (pp_multideref assertion)
# || SvTYPE(keysv) >= SVt_PVMG
# || !SvOK(keysv)
# || SvROK(keysv)
# || SvIsCOW_shared_hash(keysv));
my $constkey = ( $action & 0x30 ) == 0x10 ? 1 : 0;
my $itemsym = $item->save( "$symat" . ( $constkey ? " const" : "" ) );
if ( is_constant($itemsym) ) {
if ( ref $item eq 'B::IV' ) {
my $iv = $item->IVX;
$field = "{.iv=$iv}";
}
elsif ( ref $item eq 'B::UV' ) { # also for PAD_OFFSET
my $uv = $item->UVX;
$field = "{.uv=$uv}";
}
else { # SV
$field = "{.sv=$itemsym}";
}
}
else {
if ( $itemsym =~ qr{^PL_} ) {
$field = "{.sv=Nullsv}"; # \t/* $itemsym */
init()->add("$symat.sv = (SV*)$itemsym;");
init()->add("SvREFCNT_inc_NN((SV*)$itemsym);");
}
else {
## gv or other late inits
$field = "{.sv = (SV*) $itemsym}";
}
}
}
$unopaux_item_sect->update_field( $uaux_item_ix, $i, q[ ] . $field );
$i++;
}
free()->add(" ($sym)->op_type = OP_NULL;");
return $sym;
}
sub get_action_name ( $op, $item ) {
my $cmt = 'action';
if ( $op->name eq 'multideref' ) {
my $act = $item & 0xf; # MDEREF_ACTION_MASK
$cmt = 'AV_pop_rv2av_aelem' if $act == 1;
$cmt = 'AV_gvsv_vivify_rv2av_aelem' if $act == 2;
$cmt = 'AV_padsv_vivify_rv2av_aelem' if $act == 3;
$cmt = 'AV_vivify_rv2av_aelem' if $act == 4;
$cmt = 'AV_padav_aelem' if $act == 5;
$cmt = 'AV_gvav_aelem' if $act == 6;
$cmt = 'HV_pop_rv2hv_helem' if $act == 8;
$cmt = 'HV_gvsv_vivify_rv2hv_helem' if $act == 9;
$cmt = 'HV_padsv_vivify_rv2hv_helem' if $act == 10;
$cmt = 'HV_vivify_rv2hv_helem' if $act == 11;
$cmt = 'HV_padhv_helem' if $act == 12;
$cmt = 'HV_gvhv_helem' if $act == 13;
my $idx = $item & 0x30; # MDEREF_INDEX_MASK
$cmt .= '' if $idx == 0x0;
$cmt .= ' INDEX_const' if $idx == 0x10;
$cmt .= ' INDEX_padsv' if $idx == 0x20;
$cmt .= ' INDEX_gvsv' if $idx == 0x30;
}
elsif ( $op->name eq 'signature' ) { # cperl only for now
my $act = $item & 0xf; # SIGNATURE_ACTION_MASK
$cmt = 'reload' if $act == 0;
$cmt = 'end' if $act == 1;
$cmt = 'padintro' if $act == 2;
$cmt = 'arg' if $act == 3;
$cmt = 'arg_default_none' if $act == 4;
$cmt = 'arg_default_undef' if $act == 5;
$cmt = 'arg_default_0' if $act == 6;
$cmt = 'arg_default_1' if $act == 7;
$cmt = 'arg_default_iv' if $act == 8;
$cmt = 'arg_default_const' if $act == 9;
$cmt = 'arg_default_padsv' if $act == 10;
$cmt = 'arg_default_gvsv' if $act == 11;
$cmt = 'arg_default_op' if $act == 12;
$cmt = 'array' if $act == 13;
$cmt = 'hash' if $act == 14;
my $idx = $item & 0x3F; # SIGNATURE_MASK
$cmt .= '' if $idx == 0x0;
$cmt .= ' flag skip' if $idx == 0x10;
$cmt .= ' flag ref' if $idx == 0x20;
}
elsif ( $op->name eq 'multiconcat' ) {
$cmt .= ' multiconcat';
}
else {
die "Unknown UNOP_AUX op {$op->name}";
}
return $cmt;
}
sub MULTICONCAT_IX_NARGS { 0 } # number of arguments
sub MULTICONCAT_IX_PLAIN_PV { 1 } # non-utf8 constant string
sub MULTICONCAT_IX_PLAIN_LEN { 2 } # non-utf8 constant string length
sub MULTICONCAT_IX_UTF8_PV { 3 } # utf8 constant string
sub MULTICONCAT_IX_UTF8_LEN { 4 } # utf8 constant string length
#sub MULTICONCAT_IX_LENGTHS { 5 } # first of nargs+1 const segment lens - B::C does not need this value
sub MULTICONCAT_HEADER_SIZE { 5 } # The number of fields of a multiconcat header
=pod
with multiconcat the string:
"a=$a b=$bX"
will become
[
2, # nargs
'c= d=X', # string as a single pv
2, 3, 1 # length of segments
]
=cut
sub aux_list_for_multiconcat {
my ($op) = @_;
# note that the B API aux_list method needs a useless CV
# we are using our own custom version of aux_list for multiconcat
# (required to read content correctly when the string is utf8)
# - it returns the plain PV & the utf8 PV (the original B function only return one PV)
# - it also returns the raw contents of the aux slots (@segments part) without converting it
my ( $nargs, $pv_as_sv_plain, $pv_as_sv_utf8, @segments ) = $op->aux_list_thr(); # is this complete
# initialize the multiconcat header: all values to 0
my @header = (0) x MULTICONCAT_HEADER_SIZE();
$header[ MULTICONCAT_IX_NARGS() ] = $nargs; # ix=0
if ( defined $pv_as_sv_plain ) {
my ( $savesym, $cur, $len, $utf8 ) = savecowpv($pv_as_sv_plain);
$header[ MULTICONCAT_IX_PLAIN_PV() ] = $savesym; # ix=1
$header[ MULTICONCAT_IX_PLAIN_LEN() ] = $cur; # ix=2
}
if ( defined $pv_as_sv_utf8 ) {
my ( $savesym, $cur, $len, $utf8 ) = savecowpv($pv_as_sv_utf8);
$header[ MULTICONCAT_IX_UTF8_PV() ] = $savesym; # ix=3
$header[ MULTICONCAT_IX_UTF8_LEN() ] = $cur; # ix=4
}
return [ @header, @segments ];
}
1;
Back to Directory
File Manager