opcode.h
opcode.hには、それぞれのオペレーションに関する情報が記載されている。Perl言語研究では、「OP型」のデータのことを、オペレーションと呼ぶことにしています。Perlは、構文解析が終わると、構文木に変換されますが、このそれぞれのノードは「OP型」になっています。
オペレーションは、オペレーションコードによって、分類され、それぞれが情報を持ちます。その情報が記述されています。
オペレーションの名前
たとえば、オペレーションの名前が記述されています。
EXTCONST char* const PL_op_name[] = { "null", "stub", "scalar", "pushmark", "wantarray", "const", "gvsv", ... };
=====
オペレーションの解説
次に、オペレーションの解説が記述されています。
EXTCONST char* const PL_op_desc[] = { "null operation", "stub", "scalar", "pushmark", "wantarray", "constant item", "scalar variable", "glob value", ... };
オペレーションが実行する関数のアドレス
各オペレーションは、対応する関数がありますが、その関数へのアドレスが記述されています。
EXT Perl_ppaddr_t PL_ppaddr[] /* or perlvars.h */ # endif #endif /* PERL_GLOBAL_STRUCT */ #if (defined(DOINIT) && !defined(PERL_GLOBAL_STRUCT)) || defined(PERL_GLOBAL_STRUCT_INIT) # define PERL_PPADDR_INITED = { Perl_pp_null, Perl_pp_stub, Perl_pp_scalar, /* implemented by Perl_pp_null */ Perl_pp_pushmark, Perl_pp_wantarray, Perl_pp_const, Perl_pp_gvsv, Perl_pp_gv, ... }
「pp」というプレフィックスは、「push pop」という意味で、実行される関数は、引数スタックを操作する関数です。
オペレーションの最適化を行う関数
各オペレーションは「ck」というプレフィックスがつく関数で、最適化されます。その関数のアドレスが記述されています。「ck」は「check」の略です。
#if (defined(DOINIT) && !defined(PERL_GLOBAL_STRUCT)) || defined(PERL_GLOBAL_STRUCT_INIT) # define PERL_CHECK_INITED = { Perl_ck_null, /* null */ Perl_ck_null, /* stub */ Perl_ck_fun, /* scalar */ Perl_ck_null, /* pushmark */ Perl_ck_null, /* wantarray */ Perl_ck_svconst, /* const */ Perl_ck_null, /* gvsv */ };
関数の引数の情報
実行される関数の引数情報が、記述されています。
EXTCONST U32 PL_opargs[] = { 0x00000000, /* null */ 0x00000000, /* stub */ 0x00001b04, /* scalar */ 0x00000004, /* pushmark */ 0x00000004, /* wantarray */ 0x00000604, /* const */ 0x00000644, /* gvsv */ 0x00000644, /* gv */ ... };
これは、数値で記述されていて、なにがなんだかわかりませんね。これは「op.h」で定義されています。上記の値は、以下の値の、ビット演算の論理和の値です。
/* op.h */ /* Lowest byte of PL_opargs */ #define OA_MARK 1 #define OA_FOLDCONST 2 #define OA_RETSCALAR 4 #define OA_TARGET 8 #define OA_TARGLEX 16 #define OA_OTHERINT 32 #define OA_DANGEROUS 64 #define OA_DEFGV 128 /* The next 4 bits (8..11) encode op class information */ #define OCSHIFT 8 #define OA_CLASS_MASK (15 << OCSHIFT) #define OA_BASEOP (0 << OCSHIFT) #define OA_UNOP (1 << OCSHIFT) #define OA_BINOP (2 << OCSHIFT) #define OA_LOGOP (3 << OCSHIFT) #define OA_LISTOP (4 << OCSHIFT) #define OA_PMOP (5 << OCSHIFT) #define OA_SVOP (6 << OCSHIFT) #define OA_PADOP (7 << OCSHIFT) #define OA_PVOP_OR_SVOP (8 << OCSHIFT) #define OA_LOOP (9 << OCSHIFT) #define OA_COP (10 << OCSHIFT) #define OA_BASEOP_OR_UNOP (11 << OCSHIFT) #define OA_FILESTATOP (12 << OCSHIFT) #define OA_LOOPEXOP (13 << OCSHIFT) #define OA_METHOP (14 << OCSHIFT) #define OA_UNOP_AUX (15 << OCSHIFT) /* Each remaining nybble of PL_opargs (i.e. bits 12..15, 16..19 etc) * encode the type for each arg */ #define OASHIFT 12 #define OA_SCALAR 1 #define OA_LIST 2 #define OA_AVREF 3 #define OA_HVREF 4 #define OA_CVREF 5 #define OA_FILEREF 6 #define OA_SCALARREF 7 #define OA_OPTIONAL 8
そして、上記には、この値の説明がありませんが、それは「regen/opcodes」にあります。
# Other options are: # needs stack mark - m (OA_MARK) # needs constant folding - f (OA_FOLDCONST) # produces a scalar - s (OA_RETSCALAR) # produces an integer - i (unused) # needs a target - t (OA_TARGET) # target can be in a pad - T (OA_TARGET|OA_TARGLEX) # has a corresponding integer version - I (OA_OTHERINT) # make temp copy in list assignment - d (OA_DANGEROUS) # uses $_ if no argument given - u (OA_DEFGV)
オペレーションに関するプライベートなフラグ
そして、オペレーションに関するプライベートなフラグ情報があります。これらの詳細な説明は「regen/op_private」にあります。
#define OPpLVREF_SV 0x00 #define OPpARG1_MASK 0x01 #define OPpCOREARGS_DEREF1 0x01 #define OPpENTERSUB_INARGS 0x01 #define OPpSORT_NUMERIC 0x01 #define OPpTRANS_FROM_UTF 0x01 #define OPpCONST_NOVER 0x02 #define OPpCOREARGS_DEREF2 0x02 #define OPpEVAL_HAS_HH 0x02 #define OPpFT_ACCESS 0x02 #define OPpHINT_STRICT_REFS 0x02 #define OPpITER_REVERSED 0x02 ...