Commit b919612b authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

Cut down on conditional jumps

parent dcb783ab
...@@ -48,6 +48,18 @@ static const char * strstate[] = { ...@@ -48,6 +48,18 @@ static const char * strstate[] = {
}; };
#undef _ENUM_GEN #undef _ENUM_GEN
#define TRANSITION(st) do { \
state = s_##st; \
pos++; nread++; \
if (pos < end) { \
ch = *pos; \
goto l_##st; \
} \
\
/* No more data */ \
goto finalize; \
} while(0)
#ifdef DEBUG #ifdef DEBUG
#define LOG(fmt, args...) do { \ #define LOG(fmt, args...) do { \
fprintf(stderr, fmt "\n" , ## args); \ fprintf(stderr, fmt "\n" , ## args); \
...@@ -147,24 +159,19 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -147,24 +159,19 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
switch (ch) { switch (ch) {
case '$': case '$':
cur->type = REDIS_STRING_T; cur->type = REDIS_STRING_T;
state = s_integer_sign; TRANSITION(integer_sign);
break;
case '*': case '*':
cur->type = REDIS_ARRAY_T; cur->type = REDIS_ARRAY_T;
state = s_integer_sign; TRANSITION(integer_sign);
break;
case ':': case ':':
cur->type = REDIS_INTEGER_T; cur->type = REDIS_INTEGER_T;
state = s_integer_sign; TRANSITION(integer_sign);
break;
case '+': case '+':
cur->type = REDIS_STATUS_T; cur->type = REDIS_STATUS_T;
state = s_line; assert(NULL);
break;
case '-': case '-':
cur->type = REDIS_ERROR_T; cur->type = REDIS_ERROR_T;
state = s_line; assert(NULL);
break;
default: default:
goto error; goto error;
} }
...@@ -172,17 +179,23 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -172,17 +179,23 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
} }
case s_integer_sign: case s_integer_sign:
l_integer_sign:
{ {
i64.neg = (ch == '-'); i64.neg = (ch == '-');
i64.ui64 = 0; i64.ui64 = 0;
state = s_integer_start;
/* Break when char was consumed */ /* Break when char was consumed */
if (ch == '-' || ch == '+') if (ch == '-' || ch == '+') {
break; TRANSITION(integer_start);
}
/* First integer character */
if (ch >= '1' && ch <= '9') {
i64.ui64 = ch - '0';
TRANSITION(integer_body);
}
/* Char was not consumed, jump to s_integer_start */ goto error;
goto l_integer_start;
} }
case s_integer_start: case s_integer_start:
...@@ -190,14 +203,14 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -190,14 +203,14 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
{ {
if (ch >= '1' && ch <= '9') { if (ch >= '1' && ch <= '9') {
i64.ui64 = ch - '0'; i64.ui64 = ch - '0';
state = s_integer_body; TRANSITION(integer_body);
} else {
goto error;
} }
break;
goto error;
} }
case s_integer_body: case s_integer_body:
l_integer_body:
{ {
if (ch >= '0' && ch <= '9') { if (ch >= '0' && ch <= '9') {
if (i64.ui64 > (UINT64_MAX / 10)) /* Overflow */ if (i64.ui64 > (UINT64_MAX / 10)) /* Overflow */
...@@ -206,6 +219,7 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -206,6 +219,7 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
if (i64.ui64 > (UINT64_MAX - (ch-'0'))) /* Overflow */ if (i64.ui64 > (UINT64_MAX - (ch-'0'))) /* Overflow */
goto error; goto error;
i64.ui64 += ch - '0'; i64.ui64 += ch - '0';
TRANSITION(integer_body);
} else if (ch == '\r') { } else if (ch == '\r') {
/* Check if the uint64_t can be safely casted to int64_t */ /* Check if the uint64_t can be safely casted to int64_t */
if (i64.neg) { if (i64.neg) {
...@@ -217,15 +231,14 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -217,15 +231,14 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
goto error; goto error;
i64.i64 = i64.ui64; i64.i64 = i64.ui64;
} }
TRANSITION(integer_lf);
}
state = s_integer_lf;
} else {
goto error; goto error;
} }
break;
}
case s_integer_lf: case s_integer_lf:
l_integer_lf:
{ {
if (ch != '\n') { if (ch != '\n') {
goto error; goto error;
...@@ -241,7 +254,7 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -241,7 +254,7 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
case REDIS_ARRAY_T: goto l_integer_lf_array_t; case REDIS_ARRAY_T: goto l_integer_lf_array_t;
case REDIS_INTEGER_T: goto l_integer_lf_integer_t; case REDIS_INTEGER_T: goto l_integer_lf_integer_t;
default: default:
assert(NULL); assert(NULL && "unexpected object type in s_integer_lf");
goto error; goto error;
} }
...@@ -284,6 +297,7 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -284,6 +297,7 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
} }
case s_bulk: case s_bulk:
l_bulk:
{ {
size_t len = cur->remaining; size_t len = cur->remaining;
...@@ -300,11 +314,11 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons ...@@ -300,11 +314,11 @@ size_t redis_parser_execute(redis_parser_t *parser, redis_protocol_t **dst, cons
goto error; goto error;
} }
state = s_bulk_lf; TRANSITION(bulk_lf);
break;
} }
case s_bulk_lf: case s_bulk_lf:
l_bulk_lf:
{ {
if (ch != '\n') { if (ch != '\n') {
goto error; goto error;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment