目錄

名稱

B - Perl 編譯器後端

語法

use B;

說明

B 模組提供類別,讓 Perl 程式深入自己的內部。這是用於實作 Perl 編譯器「後端」的模組。使用編譯器不需要知道這個模組:請參閱 O 模組,以取得使用者可見的部分。B 模組對想要撰寫新的編譯器後端的人很有用。此文件假設讀者對 perl 的內部結構有相當的了解,包括 SV、OP,以及程式的內部符號表和語法樹等內容。

概觀

B 模組包含一組用於查詢 Perl 解譯器目前狀態的公用函式;通常這些函式會傳回 B::SV 和 B::OP 類別的物件,或其衍生類別。這些類別進而定義方法,用於查詢結果物件的內部狀態。

公用函式

B 模組匯出各種函式:有些是簡單的公用函式,有些提供 Perl 程式一個方法,用於取得內部物件的初始「控制代碼」。

傳回 B::SVB::AVB::HVB::CV 物件的函式

有關這些物件的類別階層和可在其上呼叫的方法的說明,請參閱下方、「類別概觀」「SV 相關類別」

sv_undef

傳回對應於 C 變數 sv_undef 的 SV 物件。

sv_yes

傳回對應於 C 變數 sv_yes 的 SV 物件。

sv_no

傳回對應於 C 變數 sv_no 的 SV 物件。

svref_2object(SVREF)

取得任何 Perl 值的參考,並將所參考的值轉換為適當的 B::OP 或 B::SV 衍生類別中的物件。除了 main_root 等函式外,這是取得內部 Perl 資料結構的初始「控制權」的主要方法,然後可以使用其他存取方法。

傳回的物件只會在底層 OP 和 SV 持續存在時有效。底層結構釋放後,請勿嘗試使用物件。

amagic_generation

傳回對應於 C 變數 amagic_generation 的 SV 物件。從 Perl 5.18 開始,這只是一個別名,指向 PL_na,因此其值沒有意義。

init_av

傳回表示 INIT 區塊的 AV 物件(即 B::AV 類別中)。

check_av

傳回表示 CHECK 區塊的 AV 物件(即 B::AV 類別中)。

unitcheck_av

傳回表示 UNITCHECK 區塊的 AV 物件(即 B::AV 類別中)。

begin_av

傳回表示 BEGIN 區塊的 AV 物件(即 B::AV 類別中)。

end_av

傳回表示 END 區塊的 AV 物件(即 B::AV 類別中)。

comppadlist

傳回全域 comppadlist 的 PADLIST 物件(即 B::PADLIST 類別中)。在 Perl 5.16 及更早版本中,它傳回 AV 物件(B::AV 類別)。

regex_padav

只有當 Perl 是使用 ithreads 編譯時。

main_cv

傳回對應於 Perl 程式主體部分的(偽造)CV。

檢查符號表的函式

walksymtable(SYMREF, METHOD, RECURSE, PREFIX)

從 SYMREF 開始遍歷符號表,並對拜訪的每個符號(B::GV 物件)呼叫 METHOD。當遍歷到達套件符號(例如「Foo::」)時,它會呼叫 RECURSE,傳入符號名稱,並且只有在該子常式傳回 true 時才會遞迴進入套件。

PREFIX 是您正在遍歷的 SYMREF 的名稱。

例如

# Walk CGI's symbol table calling print_subs on each symbol.
# Recurse only into CGI::Util::
walksymtable(\%CGI::, 'print_subs',
             sub { $_[0] eq 'CGI::Util::' }, 'CGI::');

print_subs() 是您已宣告的 B::GV 方法。另請參閱下方的 "B::GV 方法"

函數傳回 B::OP 物件或用於遍歷 op 樹

有關這些物件的類別階層和可呼叫它們的方法的說明,請參閱以下內容,"類別總覽""與 OP 相關的類別"

main_root

傳回 Perl 程式主體的根部 op(即 B::OP 派生類別中的物件)。

main_start

傳回 Perl 程式主體的起始 op。

walkoptree(OP, METHOD)

根據 OP 進行語法樹的樹狀遍歷,並在訪問的每個 op 上呼叫 METHOD。每個節點在它的子節點之前被訪問。如果已呼叫 walkoptree_debug(請參閱以下內容)以開啟除錯,則在呼叫 METHOD 之前,會在每個 op 上呼叫方法 walkoptree_debug

walkoptree_debug(DEBUG)

傳回 walkoptree 的目前除錯旗標。如果選擇性的 DEBUG 參數是非零,它會將除錯旗標設定為該值。請參閱上方 walkoptree 的說明,以了解除錯旗標的作用。

雜項公用程式函數

ppname(OPNUM)

傳回 op 號碼 OPNUM 的 PP 函數名稱(例如 "pp_add")。

hash(STR)

傳回字串 "0x...",代表 perl 在字串 STR 上使用的內部雜湊函數值。

cast_I32(I)

將 I 轉換為 perl 使用的內部 I32 類型。

minus_c

執行等同於 -c 命令列選項的動作。顯然,這僅在 BEGIN 區塊中才有用,否則旗標會設定得太晚。

cstring(STR)

傳回 STR 的雙引號包圍轉譯版本,可用於 C 原始碼中的字串。

perlstring(STR)

傳回 STR 的雙引號包圍轉譯版本,可用於 Perl 原始碼中的字串。

safename(STR)

此函數傳回字串,如果第一個字元是控制字元,則會修改。它會先轉換成 ^X 格式,因此 "\cG" 會變成 "^G"。這是 B::GV::SAFENAME 內部使用的,但你可以直接呼叫它。

class(OBJ)

傳回物件的類別,不包含類別名稱中第一個 "::" 之前的部分。例如,這會將 "B::UNOP" 轉換成 "UNOP"

threadsv_names

這用於提供舊版 5.005 執行緒模組的支援。它現在不執行任何動作。

匯出的公用程式變數

@optype
my $op_type = $optype[$op_type_num];

op 類型數字到其類型(例如 'COP' 或 'BINOP')的簡單對應。

@specialsv_name
my $sv_name = $specialsv_name[$sv_index];

某些 SV 類型被視為「特殊」。它們由 B::SPECIAL 表示,並由 specialsv_list 中的數字表示。此陣列將該數字對應回 SV 的名稱(例如 'Nullsv' 或 '&PL_sv_undef')。

類別概觀

Perl 內部用來儲存 SV 和 OP 資訊的 C 結構(PVIV、AV、HV、...、OP、SVOP、UNOP、...)模擬類別階層,而 B 模組透過真正的物件階層提供對它們的存取。指向其他物件(SV 類型或 OP 類型)的結構欄位由 B 模組表示為適當類別的 Perl 物件。

B 模組的大部分是存取這些結構欄位的函式。

請注意,所有存取都是唯讀的。你無法使用此模組修改內部。另外,請注意,此模組建立的 B::OP 和 B::SV 物件僅在底層物件存在時才有效;它們的建立不會增加底層物件的參考計數。嘗試存取已釋放物件的欄位會產生難以理解的結果,甚至更糟。

B::IV、B::NV、B::PV、B::PVIV、B::PVNV、B::PVMG、B::PVLV、B::AV、B::HV、B::CV、B::GV、B::FM、B::IO。這些類別以明顯的方式對應於具有類似名稱的底層 C 結構。繼承層級模擬底層 C 的「繼承」

                   B::SV
                     |
        +------------+------------+
        |            |            |
      B::PV        B::IV        B::NV
       /  \         /           /
      /    \       /           /
B::INVLIST  B::PVIV           /
                 \           /
                  \         /
                   \       /
                    B::PVNV
                       |
                       |
                    B::PVMG
                       |
   +-------+-------+---+---+-------+-------+
   |       |       |       |       |       |
 B::AV   B::GV   B::HV   B::CV   B::IO B::REGEXP
           |               |
           |               |
        B::PVLV          B::FM

存取方法對應於底層 C 巨集,用於欄位存取,通常會移除開頭的「類別指示」字首(Sv、Av、Hv 等)。僅在移除字首會導致方法名稱衝突的情況下保留開頭的字首。例如,GvREFCNT 保持原樣,因為它的縮寫會與「超類別」方法 REFCNT(對應於 C 函式 SvREFCNT)衝突。

B::SV 方法

REFCNT
FLAGS
IsBOOL

如果 SV 是布林值(真或假),則傳回 true。然後您可以使用 TRUE 檢查值是真或假。

my $something = ( 1 == 1 ) # boolean true
             || ( 1 == 0 ) # boolean false
             || 42         # IV true
             || 0;         # IV false
my $sv = B::svref_2object(\$something);

say q[Not a boolean value]
    if ! $sv->IsBOOL;

say q[This is a boolean with value: true]
    if   $sv->IsBOOL && $sv->TRUE_nomg;

say q[This is a boolean with value: false]
    if   $sv->IsBOOL && ! $sv->TRUE_nomg;
object_2svref

傳回對應於此 B::SV 物件的常規純量的參考。換句話說,此方法是 svref_2object() 子例程的反向操作。此純量及其指向的其他資料應視為唯讀:修改它們既不安全,也無法保證會產生合理的影響。

TRUE

傳回布林值,表示 Perl 是否會將 SV 評估為真或假。

警告此呼叫會執行「取得」魔法。如果您只想檢查此 SV 的性質,請使用 TRUE_nomg 輔助程式。

這是 SvTRUE($sv) 的別名。

TRUE_nomg

檢查值是否為真(不執行「取得」魔法)。傳回布林值,表示 Perl 是否會將 SV 評估為真或假。

這是 SvTRUE_nomg($sv) 的別名。

B::IV 方法

IV

傳回 IV 的值,解釋為有號整數。如果 FLAGS & SVf_IVisUV,這會產生誤導。或許您想要 int_value 方法?

IVX
UVX
int_value

此方法傳回 IV 的值作為整數。它與 IV 的不同之處在於,它傳回正確的值,無論它是以有號或無號儲存。

needs64bits
packiv

B::NV 方法

NV
NVX
COP_SEQ_RANGE_LOW
COP_SEQ_RANGE_HIGH

最後這兩個僅對 pad 名稱 SV 有效。在 Perl 5.22 之前,它們僅存在於 B::NV 類別中。在 5.22 中,它們被移至 B::PADNAME 類別。

B::RV 方法

RV

B::PV 方法

PV

此方法通常是您想要的。它使用結構中的長度和偏移資訊來建構字串:對於一般標量,它會傳回您從 Perl 看到的字串,即使它包含空字元。

RV

與 B::RV::RV 相同,但如果 PV 不是參考,它會執行 die()。

PVX

此方法較不常使用。它假設儲存在結構中的字串以空字元終止,並忽略長度資訊。

如果您需要從 padname 陣列取得詞彙變數的名稱,則這是適當的方法。詞彙變數名稱總是儲存為空字元終止符,而長度欄位 (CUR) 會因其他目的而過載,因此無法在此依賴它。

CUR

此方法傳回內部長度欄位,其中包含內部位元組數,不一定是邏輯字元的數目。

LEN

此方法傳回配置給 malloc 以儲存字串的位元組數。如果標量不「擁有」字串,則為 0。

B::PVMG 方法

MAGIC
SvSTASH

B::MAGIC 方法

MOREMAGIC
precomp

僅對 r-magic 有效,傳回產生正規表示式的字串。

PRIVATE
類型
旗標
物件

如果在 r-magic 上呼叫,將會 die()。

指標
正規表示式

僅在 r-magic 上有效,傳回儲存在 MAGIC 中的正規表示式的整數值。

B::INVLIST 方法

prev_index

傳回 invlist_search() 的快取結果 (內部使用)

is_offset

傳回布林值 (0 或 1) 以得知 invlist 是否使用偏移量。為 false 時,清單從碼點 U+0000 開始。為 true 時,清單從下列元素開始。

array_len

傳回用於定義 invlist 的陣列大小的整數。

get_invlist_array

此方法傳回代表 invlist 使用的陣列的整數清單。注意:這無法在迭代 invlist 中間使用,否則會 croak。

B::PVLV 方法

TARGOFF
TARGLEN
TYPE
TARG

B::BM 方法

USEFUL
PREVIOUS
RARE
TABLE

B::REGEXP 方法

REGEX
precomp
qr_anoncv
compflags

最後兩個在 Perl 5.22 中新增。

B::GV 方法

is_empty

如果 GV 的 GP 欄位為 NULL,此方法傳回 TRUE。

NAME
SAFENAME

此方法傳回 glob 的名稱,但如果名稱的第一個字元是控制字元,則會先將其轉換為 ^X,因此 *^G 會傳回 "^G" 而不是 "\cG"。

如果您想要列印變數的名稱,這會很有用。如果您將自己限制在編譯時存在的 glob,則結果應該是明確的,因為像 ${"^G"} = 1 的程式碼編譯為兩個運算式 - 一個常數字串和一個解除參考 (rv2gv) - 因此 glob 會在執行時建立。

如果您在執行時使用 glob,並且需要區分 *^G 和 *{"^G"},則應使用原始 NAME 方法。

STASH
SV
IO
FORM
AV
HV
EGV
CV
CVGEN
LINE
FILE
FILEGV
GvREFCNT
FLAGS
GPFLAGS

最後一個只存在於 perl 5.22.0 及更新版本中。

B::IO 方法

B::IO 物件衍生自 IO 物件,而且您將從 IO 物件本身取得更多資訊。

例如

$gvio = B::svref_2object(\*main::stdin)->IO;
$IO = $gvio->object_2svref();
$fd = $IO->fileno();
LINES
PAGE
PAGE_LEN
LINES_LEFT
TOP_NAME
TOP_GV
FMT_NAME
FMT_GV
BOTTOM_NAME
BOTTOM_GV
SUBPROCESS
IoTYPE

象徵 IO 句柄類型的字元。

-     STDIN/OUT
I     STDIN/OUT/ERR
<     read-only
>     write-only
a     append
+     read and write
s     socket
|     pipe
I     IMPLICIT
#     NUMERIC
space closed handle
\0    closed internal handle
IoFLAGS
IsSTD

取得一個引數('stdin' | 'stdout' | 'stderr'),如果物件的 IoIFP 等於作為引數傳遞的名稱,則傳回 true;亦即,如果 IoIFP($io) == PerlIO_stderr(),則 $io->IsSTD('stderr') 為 true。

B::AV 方法

FILL
MAX
ARRAY
ARRAYelt

類似於 ARRAY,但會取得一個索引作為引數,以取得只有一個元素,而不是所有元素的清單。

B::CV 方法

STASH
START
ROOT
GV
檔案
深度
PADLIST

傳回一個 B::PADLIST 物件。

外部
外部_序列
XSUB
XSUBANY

對於常數子常式,傳回子常式傳回的常數 SV。

CvFLAGS
const_sv
NAME_HEK

傳回詞彙子常式的名稱,否則為 undef

B::HV 方法

FILL
MAX
KEYS
RITER
NAME
ARRAY

B::OPB::UNOPB::UNOP_AUXB::BINOPB::LOGOPB::LISTOPB::PMOPB::SVOPB::PADOPB::PVOPB::LOOPB::COPB::METHOP

這些類別以明顯的方式對應到類似名稱的底層 C 結構。繼承階層模擬底層 C 的「繼承」

                         B::OP
                           |
           +----------+---------+--------+-------+---------+
           |          |         |        |       |         |
        B::UNOP    B::SVOP  B::PADOP  B::COP  B::PVOP  B::METHOP
           |
       +---+---+---------+
       |       |         |
   B::BINOP  B::LOGOP  B::UNOP_AUX
       |
       |
   B::LISTOP
       |
   +---+---+
   |       |
B::LOOP   B::PMOP

存取方法對應到底層 C 結構欄位名稱,並移除開頭的「類別指示」前綴 ("op_")。

B::OP 方法

這些方法取得 OP 資料結構中類似名稱欄位的值。更多資訊請參閱 op.h 的頂端。

next
sibling
parent

傳回 OP 的父項。如果沒有父項,或您的 perl 不是使用 -DPERL_OP_PARENT 建置,則傳回 NULL。

請注意,在不支援 parent 方法的較舊 perl 中,全域變數 $B::OP::does_parent 未定義,在支援此方法但未使用 -DPERL_OP_PARENT 建置的 perl 中,此變數已定義但為 false,否則為 true。

name

傳回 op 名稱作為字串 (例如「add」、「rv2av」)。

ppaddr

傳回函式名稱作為字串 (例如「PL_ppaddr[OP_ADD]」、「PL_ppaddr[OP_RV2AV]」)。

desc

這會傳回來自全域 C PL_op_desc 陣列的 op 說明(例如「加法」、「陣列解除參考」)。

targ
type
opt
flags
private
spare

B::UNOP 方法

first

B::UNOP_AUX 方法(自 5.22 起)

aux_list(cv)

這會傳回 op 的 aux 資料結構元素清單,或是在沒有 aux 的情況下傳回 null 清單。傳回的內容會根據物件類型而有所不同,但通常會是 B::IVB::GV 等物件的集合。cv 是表示包含 op 的子程式的 B::CV 物件。

string(cv)

這會傳回物件的文字表示形式(可能對剖析和除錯很有用),或是在 op 類型不支援此功能的情況下傳回空字串。cv 是表示包含 op 的子程式的 B::CV 物件。

B::BINOP 方法

last

B::LOGOP 方法

other

B::LISTOP 方法

children

B::PMOP 方法

pmreplroot
pmreplstart
pmflags
precomp
pmoffset

只有當 Perl 是使用 ithreads 編譯時。

code_list

自 perl 5.17.1 起

pmregexp

在 perl 5.22 中新增,此方法會傳回與 op 相關聯的 B::REGEXP。雖然 PMOP 在執行緒建置下實際上沒有 pmregexp 欄位,但此方法仍會傳回執行緒下的正規表示式,以方便使用。

B::SVOP 方法

sv
gv

B::PADOP 方法

padix

B::PVOP 方法

pv

B::LOOP 方法

redoop
nextop
lastop

B::COP 方法

B::COP 類別用於「nextstate」和「dbstate」操作。自 Perl 5.22 起,它也用於最初為 COP 的「null」操作。

標籤
快取
stashpv
stashoff (僅限執行緒)
檔案
cop_seq
警告
io
提示
提示_雜湊

B::METHOP 方法 (自 Perl 5.22 起)

first
meth_sv

Perl 5.18 導入了一個新的類別 B::PADLIST,由 B::CV 的 PADLIST 方法傳回。

Perl 5.22 導入了 B::PADNAMELIST 和 B::PADNAME 類別。

B::PADLIST 方法

MAX
ARRAY

一個 pad 的清單。第一個是包含名稱的 B::PADNAMELIST。其餘目前是 B::AV 物件,但這可能會在未來的版本中改變。

ARRAYelt

類似於 ARRAY,但會取得一個索引作為引數,以取得只有一個元素,而不是所有元素的清單。

NAMES

這個在 5.22 中導入的方法傳回 B::PADNAMELIST。它等於帶有 0 參數的 ARRAYelt

REFCNT
id

這個在 5.22 中導入的方法傳回同一個 padlist 的複製所共用的 ID。

outid

這個方法也在 5.22 中新增,傳回外部 padlist 的 ID。

B::PADNAMELIST 方法

MAX
ARRAY
ARRAYelt

這兩個方法會傳回 pad 名稱,使用 B::SPECIAL 物件作為 null 指標,否則使用 B::PADNAME 物件。

REFCNT

B::PADNAME 方法

PV
PVX
LEN
REFCNT
GEN
FLAGS

為了向後相容,如果 PADNAMEt_OUTER 旗標已設定,FLAGS 方法也會新增 SVf_FAKE 旗標。

TYPE

代表已鍵入詞彙的儲存空間的 B::HV 物件。

SvSTASH

TYPE 的向後相容別名。

OURSTASH

代表「our」變數的儲存空間的 B::HV 物件。

PROTOCV

「my」子例程的原型 CV。

COP_SEQ_RANGE_LOW
COP_SEQ_RANGE_HIGH

代表詞彙可見範圍的序列號碼。如果 PADNAMEt_OUTER 已設定,則沒有意義。

PARENT_PAD_INDEX

只有在 PADNAMEt_OUTER 已設定時才有意義。

PARENT_FAKELEX_FLAGS

只有在 PADNAMEt_OUTER 已設定時才有意義。

IsUndef

傳回布林值,檢查 padname 是否為 PL_padname_undef。

$B::overlay

雖然 optree 是唯讀的,但有一個覆寫功能,讓你可以覆寫 B::*OP 方法為特定 op 傳回的各種值。$B::overlay 應該設定為參考一個兩層深的雜湊:由 OP 位址索引,然後是方法名稱。每當呼叫一個 op 方法時,如果雜湊中存在值,則會傳回該值。此功能由 B::Deparse 用於「復原」一些最佳化。例如

local $B::overlay = {};
...
if ($op->name eq "foo") {
    $B::overlay->{$$op} = {
            name => 'bar',
            next => $op->next->next,
    };
}
...
$op->name # returns "bar"
$op->next # returns the next op but one

AUTHOR

Malcolm Beattie,mbeattie@sable.ox.ac.uk