From ae103e099635e075f433d5302425673c4fe7badf Mon Sep 17 00:00:00 2001 From: Daniel Dragan Date: Thu, 7 Nov 2013 21:33:57 -0500 Subject: fix multi-eval of Perl_custom_op_xop in XopENTRY Commit 1830b3d9c8 introduced a flaw where XopENTRY calls Perl_custom_op_xop twice to retrieve the same XOP *. This is inefficient and causes extra machine code. Since I found no CPAN or upstream=blead usage of Perl_custom_op_xop, and its previous docs say it isn't 100% public, it is being converted to a macro. Most usage of Perl_custom_op_xop is to conditionally fetch a member of the XOP struct, which was previously implemented by XopENTRY. Move the XopENTRY logic and picking defaults to an expanded version of Perl_custom_op_xop. The union allows Perl_custom_op_get_field to return its result in 1 register, since the union is similar to a void * or IV, but with the machine code overhead of casting, if any, being done in the callee (Perl_custom_op_get_field), not the caller. Perl_custom_op_get_field can also return the XOP * without looking inside it to implement Perl_custom_op_xop. XopENTRYCUSTOM is a wrapper around Perl_custom_op_get_field with XopENTRY-like usage. XopENTRY is used by the OP_* macros, which are heavily used (but rarely called, since custom ops are rare) by Perl lang warnings system. The vararg warning arguments are usually evaluted no matter if the warning will be printed to STDERR or not. Since some people like to ignore warnings or run no strict; and warnings branches are frequent in pp_*, it is beneficial to make the OP_* macros smaller in machine code. The design of Perl_custom_op_get_field supports these goals. This commit does not pass judgement on Ben Morrow's unclear public or private API designation of Perl_custom_op_xop, and whether Perl_custom_op_xop should deprecated and removed from public API. It was trivial to leave a form of Perl_custom_op_xop in the new design. XOPe enums are identical to XOPf constants so no conversion has to be done between the field selector parameter and the field flag to test in machine code. ASSUME and NOT_REACHED are being introduced. The closest to the 2 previously was "assert(0)". Perl has not used ASSUME or CC specific versions of it before. Clang, GCC >= 4.5, and Visual C are supported. For completeness, ARMCC's __promise was added, but Perl is not known to have any support for ARMCC by this commiter. This patch is part of perl #115032. --- op.h | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'op.h') diff --git a/op.h b/op.h index 411b78ac2c..8b8e3d2a56 100644 --- a/op.h +++ b/op.h @@ -900,12 +900,19 @@ Return the XOP's flags. =for apidoc Am||XopENTRY|XOP *xop|which Return a member of the XOP structure. I is a cpp token indicating which entry to return. If the member is not set this will return a -default value. The return type depends on I. +default value. The return type depends on I. This macro evaluates its +arguments more than once. If you are using C to retreive a +C from a C, use the more efficient L instead. + +=for apidoc Am||XopENTRYCUSTOM|const OP *o|which +Exactly like C but more +efficient. The I parameter is identical to L. =for apidoc Am|void|XopENTRY_set|XOP *xop|which|value Set a member of the XOP structure. I is a cpp token indicating which entry to set. See L for details about -the available members and how they are used. +the available members and how they are used. This macro evaluates its argument +more than once. =for apidoc Am|void|XopDISABLE|XOP *xop|which Temporarily disable a member of the XOP, by clearing the appropriate flag. @@ -924,6 +931,17 @@ struct custom_op { void (*xop_peep)(pTHX_ OP *o, OP *oldop); }; +/* return value of Perl_custom_op_get_field, similar to void * then casting but + the U32 doesn't need truncation on 64 bit platforms in the caller, also + for easier macro writing */ +typedef union { + const char *xop_name; + const char *xop_desc; + U32 xop_class; + void (*xop_peep)(pTHX_ OP *o, OP *oldop); + XOP *xop_ptr; +} XOPRETANY; + #define XopFLAGS(xop) ((xop)->xop_flags) #define XOPf_xop_name 0x01 @@ -931,6 +949,15 @@ struct custom_op { #define XOPf_xop_class 0x04 #define XOPf_xop_peep 0x08 +/* used by Perl_custom_op_get_field for option checking */ +typedef enum { + XOPe_xop_ptr = 0, /* just get the XOP *, don't look inside it */ + XOPe_xop_name = XOPf_xop_name, + XOPe_xop_desc = XOPf_xop_desc, + XOPe_xop_class = XOPf_xop_class, + XOPe_xop_peep = XOPf_xop_peep, +} xop_flags_enum; + #define XOPd_xop_name PL_op_name[OP_CUSTOM] #define XOPd_xop_desc PL_op_desc[OP_CUSTOM] #define XOPd_xop_class OA_BASEOP @@ -945,6 +972,9 @@ struct custom_op { #define XopENTRY(xop, which) \ ((XopFLAGS(xop) & XOPf_ ## which) ? (xop)->which : XOPd_ ## which) +#define XopENTRYCUSTOM(o, which) \ + (Perl_custom_op_get_field(aTHX_ o, XOPe_ ## which).which) + #define XopDISABLE(xop, which) ((xop)->xop_flags &= ~XOPf_ ## which) #define XopENABLE(xop, which) \ STMT_START { \ @@ -952,6 +982,9 @@ struct custom_op { assert(XopENTRY(xop, which)); \ } STMT_END +#define Perl_custom_op_xop(x) \ + (Perl_custom_op_get_field(x, XOPe_xop_ptr).xop_ptr) + /* =head1 Optree Manipulation Functions @@ -974,13 +1007,13 @@ one of the OA_* constants from op.h. */ #define OP_NAME(o) ((o)->op_type == OP_CUSTOM \ - ? XopENTRY(Perl_custom_op_xop(aTHX_ o), xop_name) \ + ? XopENTRYCUSTOM(o, xop_name) \ : PL_op_name[(o)->op_type]) #define OP_DESC(o) ((o)->op_type == OP_CUSTOM \ - ? XopENTRY(Perl_custom_op_xop(aTHX_ o), xop_desc) \ + ? XopENTRYCUSTOM(o, xop_desc) \ : PL_op_desc[(o)->op_type]) #define OP_CLASS(o) ((o)->op_type == OP_CUSTOM \ - ? XopENTRY(Perl_custom_op_xop(aTHX_ o), xop_class) \ + ? XopENTRYCUSTOM(o, xop_class) \ : (PL_opargs[(o)->op_type] & OA_CLASS_MASK)) #define newSUB(f, o, p, b) Perl_newATTRSUB(aTHX_ (f), (o), (p), NULL, (b)) -- cgit v1.2.1