Author: timbo
Date: Fri Mar 2 07:40:48 2012
New Revision: 15196
Modified:
dbi/trunk/DBI.xs
Log:
[PATCH 3/8] detmeine method type when installed (Dave Mitchell)
rather than doing repeated stuff like
*meth_name=='F' && strEQ(meth_name,"FETCH")
on each dispatch, just work out what typer of method it is once at install
time, and store the result as an enum in dbi_ima.
Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs (original)
+++ dbi/trunk/DBI.xs Fri Mar 2 07:40:48 2012
@@ -88,6 +88,17 @@
# define BROKEN_DUP_ANY_PTR
#endif
+/* types of method name */
+
+typedef enum {
+ methtype_ordinary, /* nothing special about this method name */
+ methtype_DESTROY,
+ methtype_FETCH,
+ methtype_can,
+ methtype_fetch_star, /* fetch*, i.e. fetch() or fetch_...() */
+ methtype_set_err
+} meth_types;
+
static imp_xxh_t *dbih_getcom _((SV *h));
static imp_xxh_t *dbih_getcom2 _((pTHX_ SV *h, MAGIC **mgp));
@@ -114,6 +125,7 @@
#endif
char *neatsvpv _((SV *sv, STRLEN maxlen));
SV * preparse(SV *dbh, const char *statement, IV ps_return, IV ps_accept, void
*foo);
+static meth_types get_meth_type(const char * const name);
DBISTATE_DECLARE;
@@ -122,6 +134,37 @@
struct imp_sth_st { dbih_stc_t com; };
struct imp_fdh_st { dbih_fdc_t com; };
+/* identify the type of a method name for dispatch behaviour */
+/* (should probably be folded into the IMA flags mechanism) */
+
+static meth_types
+get_meth_type(const char * const name)
+{
+ switch (name[0]) {
+ case 'D':
+ if strEQ(name,"DESTROY")
+ return methtype_DESTROY;
+ break;
+ case 'F':
+ if strEQ(name,"FETCH")
+ return methtype_FETCH;
+ break;
+ case 'c':
+ if strEQ(name,"can")
+ return methtype_can;
+ break;
+ case 'f':
+ if strnEQ(name,"fetch", 5) /* fetch* */
+ return methtype_fetch_star;
+ break;
+ case 's':
+ if strEQ(name,"set_err")
+ return methtype_set_err;
+ break;
+ }
+ return methtype_ordinary;
+}
+
/* Internal Method Attributes (attached to dispatch methods when installed) */
/* NOTE: when adding SVs to dbi_ima_t, update dbi_ima_dup() dbi_ima_free()
@@ -140,6 +183,7 @@
U32 method_trace;
const char *usage_msg;
U32 flags;
+ meth_types meth_type;
/* cached outer to inner method mapping */
HV *stash; /* the stash we found the GV in */
@@ -3076,6 +3120,7 @@
I32 trace_level = (trace_flags & DBIc_TRACE_LEVEL_MASK);
int is_DESTROY;
int is_FETCH;
+ meth_types meth_type;
int is_unrelated_to_Statement = 0;
int keep_error = FALSE;
UV ErrCount = UV_MAX;
@@ -3108,6 +3153,7 @@
#endif
ima_flags = ima->flags;
+ meth_type = ima->meth_type;
if (trace_level >= 9) {
PerlIO *logfp = DBILOGFP;
PerlIO_printf(logfp,"%c >> %-11s DISPATCH (%s rc%ld/%ld @%ld g%x
ima%lx pid#%ld)",
@@ -3118,7 +3164,7 @@
PerlIO_flush(logfp);
}
- if ( ( (is_DESTROY=(*meth_name=='D' && strEQ(meth_name,"DESTROY")))) ) {
+ if ( ( (is_DESTROY=(meth_type == methtype_DESTROY))) ) {
/* note that croak()'s won't propagate, only append to $@ */
keep_error = TRUE;
}
@@ -3180,7 +3226,7 @@
imp_xxh = dbih_getcom2(aTHX_ h, 0); /* get common Internal Handle
Attributes */
if (!imp_xxh) {
- if (strEQ(meth_name, "can")) { /* ref($h)->can("foo") */
+ if (meth_type == methtype_can) { /* ref($h)->can("foo") */
const char *can_meth = SvPV_nolen(st1);
SV *rv = &PL_sv_undef;
GV *gv = gv_fetchmethod_autoload(gv_stashsv(orig_h,FALSE),
can_meth, FALSE);
@@ -3244,7 +3290,7 @@
if (ima_flags &
(IMA_STUB|IMA_FUNC_REDIRECT|IMA_KEEP_ERR|IMA_KEEP_ERR_SUB|IMA_CLEAR_STMT)) {
if (ima_flags & IMA_STUB) {
- if (*meth_name == 'c' && strEQ(meth_name,"can")) {
+ if (meth_type == methtype_can) {
const char *can_meth = SvPV_nolen(st1);
SV *dbi_msv = Nullsv;
/* find handle implementors method (GV or CV) */
@@ -3274,6 +3320,7 @@
croak("%s->%s() invalid redirect method name %s",
neatsvpv(h,0), meth_name,
neatsvpv(meth_name_sv,0));
meth_name = SvPV_nolen(meth_name_sv);
+ meth_type = get_meth_type(meth_name);
is_orig_method_name = 0;
}
if (ima_flags & IMA_KEEP_ERR)
@@ -3371,7 +3418,7 @@
/* --- dispatch --- */
- if (!keep_error && !(*meth_name=='s' && strEQ(meth_name,"set_err"))) {
+ if (!keep_error && meth_type != methtype_set_err) {
SV *err_sv;
if (trace_level && SvOK(err_sv=DBIc_ERR(imp_xxh))) {
PerlIO *logfp = DBILOGFP;
@@ -3394,7 +3441,8 @@
* Other restrictions may be added over time.
* It's an undocumented hack.
*/
- || (!is_nested_call && !PL_dirty && strNE(meth_name, "set_err") &&
strNE(meth_name, "DESTROY") &&
+ || (!is_nested_call && !PL_dirty && meth_type != methtype_set_err &&
+ meth_type != methtype_DESTROY &&
(hook_svp = hv_fetch((HV*)SvRV(*tmp_svp), "*", 1, 0))
)
)
@@ -3469,7 +3517,7 @@
/* The "quick_FETCH" logic... */
/* Shortcut for fetching attributes to bypass method call overheads */
- if ( (is_FETCH = (*meth_name=='F' && strEQ(meth_name,"FETCH"))) &&
!DBIc_COMPAT(imp_xxh)) {
+ if ( (is_FETCH = (meth_type == methtype_FETCH)) && !DBIc_COMPAT(imp_xxh)) {
STRLEN kl;
const char *key = SvPV(st1, kl);
SV **attr_svp;
@@ -3549,6 +3597,7 @@
PUTBACK;
++items;
meth_name = "func";
+ meth_type = methtype_ordinary;
}
}
@@ -3664,7 +3713,7 @@
if (trace_level >= (is_nested_call ? 3 : 1)) {
PerlIO *logfp = DBILOGFP;
- const int is_fetch = (*meth_name=='f' && DBIc_TYPE(imp_xxh)==DBIt_ST
&& strnEQ(meth_name,"fetch",5));
+ const int is_fetch = (meth_type == methtype_fetch_star &&
DBIc_TYPE(imp_xxh)==DBIt_ST);
const int row_count = (is_fetch) ? DBIc_ROW_COUNT((imp_sth_t*)imp_xxh)
: 0;
if (is_fetch && row_count>=2 && trace_level<=4 && SvOK(ST(0))) {
/* skip the 'middle' rows to reduce output */
@@ -3828,7 +3877,7 @@
const char *err_meth_name = meth_name;
char intro[200];
- if (*meth_name=='s' && strEQ(meth_name,"set_err")) {
+ if (meth_type == methtype_set_err) {
SV **sem_svp = hv_fetch((HV*)SvRV(h), "dbi_set_err_method", 18,
GV_ADDWARN);
if (SvOK(*sem_svp))
err_meth_name = SvPV_nolen(*sem_svp);
@@ -4575,6 +4624,8 @@
PerlIO_printf(DBILOGFP,"%s\n", SvPV_nolen(trace_msg));
cv = newXS(meth_name, XS_DBI_dispatch, file);
CvXSUBANY(cv).any_ptr = ima;
+ ima->meth_type = get_meth_type(GvNAME(CvGV(cv)));
+
/* Attach magic to handle duping and freeing of the dbi_ima_t struct.
* Due to the poor interface of the mg dup function, sneak a pointer
* to the original CV in the mg_ptr field (we get called with a