From: Lukas Mai <l.mai@web.de>
Date: Fri, 8 Mar 2013 03:41:17 +0000 (+0100)
Subject: don't allocate when parsing unknown keywords
X-Git-Tag: v1.0102~2
X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=8216fac4b4d69e9312af56c14c8c45d6e9191068;p=p5sagit%2FFunction-Parameters.git

don't allocate when parsing unknown keywords
---

diff --git a/Parameters.xs b/Parameters.xs
index 282bb03..fa8e4ee 100644
--- a/Parameters.xs
+++ b/Parameters.xs
@@ -157,67 +157,6 @@ static SV *sentinel_mortalize(Sentinel sen, SV *sv) {
 	return sv;
 }
 
-static int kw_flags(pTHX_ Sentinel sen, const char *kw_ptr, STRLEN kw_len, KWSpec *spec) {
-	HV *hints;
-	SV *sv, **psv;
-	const char *p, *kw_active;
-	STRLEN kw_active_len;
-
-	spec->flags = 0;
-	spec->shift = sentinel_mortalize(sen, newSVpvs(""));
-	spec->attrs = sentinel_mortalize(sen, newSVpvs(""));
-
-	if (!(hints = GvHV(PL_hintgv))) {
-		return FALSE;
-	}
-	if (!(psv = hv_fetchs(hints, HINTK_KEYWORDS, 0))) {
-		return FALSE;
-	}
-	sv = *psv;
-	kw_active = SvPV(sv, kw_active_len);
-	if (kw_active_len <= kw_len) {
-		return FALSE;
-	}
-	for (
-		p = kw_active;
-		(p = strchr(p, *kw_ptr)) &&
-		p < kw_active + kw_active_len - kw_len;
-		p++
-	) {
-		if (
-			(p == kw_active || p[-1] == ' ') &&
-			p[kw_len] == ' ' &&
-			memcmp(kw_ptr, p, kw_len) == 0
-		) {
-
-#define FETCH_HINTK_INTO(NAME, PTR, LEN, X) STMT_START { \
-	const char *fk_ptr_; \
-	STRLEN fk_len_; \
-	SV *fk_sv_; \
-	fk_sv_ = sentinel_mortalize(sen, newSVpvs(HINTK_ ## NAME)); \
-	sv_catpvn(fk_sv_, PTR, LEN); \
-	fk_ptr_ = SvPV(fk_sv_, fk_len_); \
-	if (!((X) = hv_fetch(hints, fk_ptr_, fk_len_, 0))) { \
-		croak("%s: internal error: $^H{'%.*s'} not set", MY_PKG, (int)fk_len_, fk_ptr_); \
-	} \
-} STMT_END
-
-			FETCH_HINTK_INTO(FLAGS_, kw_ptr, kw_len, psv);
-			spec->flags = SvIV(*psv);
-
-			FETCH_HINTK_INTO(SHIFT_, kw_ptr, kw_len, psv);
-			SvSetSV(spec->shift, *psv);
-
-			FETCH_HINTK_INTO(ATTRS_, kw_ptr, kw_len, psv);
-			SvSetSV(spec->attrs, *psv);
-
-#undef FETCH_HINTK_INTO
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
 
 #if HAVE_PERL_VERSION(5, 17, 2)
  #define MY_OP_SLABBED(O) ((O)->op_slabbed)
@@ -2003,25 +1942,86 @@ static int parse_fun(pTHX_ Sentinel sen, OP **pop, const char *keyword_ptr, STRL
 	}
 }
 
+static int kw_flags_enter(pTHX_ Sentinel sen, const char *kw_ptr, STRLEN kw_len, KWSpec *spec) {
+	HV *hints;
+	SV *sv, **psv;
+	const char *p, *kw_active;
+	STRLEN kw_active_len;
+
+	if (!(hints = GvHV(PL_hintgv))) {
+		return FALSE;
+	}
+	if (!(psv = hv_fetchs(hints, HINTK_KEYWORDS, 0))) {
+		return FALSE;
+	}
+	sv = *psv;
+	kw_active = SvPV(sv, kw_active_len);
+	if (kw_active_len <= kw_len) {
+		return FALSE;
+	}
+	for (
+		p = kw_active;
+		(p = strchr(p, *kw_ptr)) &&
+		p < kw_active + kw_active_len - kw_len;
+		p++
+	) {
+		if (
+			(p == kw_active || p[-1] == ' ') &&
+			p[kw_len] == ' ' &&
+			memcmp(kw_ptr, p, kw_len) == 0
+		) {
+			ENTER;
+			SAVETMPS;
+
+			SAVEDESTRUCTOR_X(sentinel_clear_void, sen);
+
+			spec->flags = 0;
+			spec->shift = sentinel_mortalize(sen, newSVpvs(""));
+			spec->attrs = sentinel_mortalize(sen, newSVpvs(""));
+
+#define FETCH_HINTK_INTO(NAME, PTR, LEN, X) STMT_START { \
+	const char *fk_ptr_; \
+	STRLEN fk_len_; \
+	SV *fk_sv_; \
+	fk_sv_ = sentinel_mortalize(sen, newSVpvs(HINTK_ ## NAME)); \
+	sv_catpvn(fk_sv_, PTR, LEN); \
+	fk_ptr_ = SvPV(fk_sv_, fk_len_); \
+	if (!((X) = hv_fetch(hints, fk_ptr_, fk_len_, 0))) { \
+		croak("%s: internal error: $^H{'%.*s'} not set", MY_PKG, (int)fk_len_, fk_ptr_); \
+	} \
+} STMT_END
+
+			FETCH_HINTK_INTO(FLAGS_, kw_ptr, kw_len, psv);
+			spec->flags = SvIV(*psv);
+
+			FETCH_HINTK_INTO(SHIFT_, kw_ptr, kw_len, psv);
+			SvSetSV(spec->shift, *psv);
+
+			FETCH_HINTK_INTO(ATTRS_, kw_ptr, kw_len, psv);
+			SvSetSV(spec->attrs, *psv);
+
+#undef FETCH_HINTK_INTO
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
 static int my_keyword_plugin(pTHX_ char *keyword_ptr, STRLEN keyword_len, OP **op_ptr) {
+	Sentinel sen = { NULL };
 	KWSpec spec;
 	int ret;
-	Sentinel sen = { NULL };
 
-	ENTER;
-	SAVETMPS;
-
-	SAVEDESTRUCTOR_X(sentinel_clear_void, sen);
-
-	if (kw_flags(aTHX_ sen, keyword_ptr, keyword_len, &spec)) {
+	if (kw_flags_enter(aTHX_ sen, keyword_ptr, keyword_len, &spec)) {
+		/* scope was entered, 'sen' and 'spec' are initialized */
 		ret = parse_fun(aTHX_ sen, op_ptr, keyword_ptr, keyword_len, &spec);
+		FREETMPS;
+		LEAVE;
 	} else {
+		/* not one of our keywords, no allocation done */
 		ret = next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr);
 	}
 
-	FREETMPS;
-	LEAVE;
-
 	return ret;
 }