forked from weaselab/weaseljson
Return int (not WeaselJsonStatus) from internal continuations
The no-musttail trampoline used WeaselJsonStatus(-1) as a re-dispatch sentinel, but WeaselJsonStatus has no fixed underlying type, so its valid range is only [0,3]; forming -1 is undefined behavior in C++. A compiler may assume the value is in range (e.g. -fstrict-enums) and fold the trampoline's '== WeaselJsonStatus(-1)' check to false, breaking the loop. Introduce an internal 'using ContinuationStatus = int' (a WeaselJsonStatus value, or kBounce) for the Continuation typedef, every continuation/helper function, and keepGoing. parse() converts back to WeaselJsonStatus only at the public boundary, where the value is always 0..3. The public enum is unchanged, so C consumers are unaffected.
This commit is contained in:
+59
-45
@@ -17,19 +17,28 @@
|
||||
|
||||
namespace parser3 {
|
||||
|
||||
// Calling a continuation with buf == bufEnd means end of input
|
||||
typedef PRESERVE_NONE WeaselJsonStatus (*Continuation)(struct Parser3 *,
|
||||
char *buf, char *bufEnd);
|
||||
// The internal result of a parse step: a WeaselJsonStatus value, or kBounce.
|
||||
// It's a plain int (not WeaselJsonStatus) so the no-musttail trampoline's
|
||||
// out-of-range sentinel never forms an out-of-range enum value (that would be
|
||||
// UB, since the public WeaselJsonStatus has no fixed underlying type). parse()
|
||||
// converts back to WeaselJsonStatus at the boundary, where it is always 0..3.
|
||||
using ContinuationStatus = int;
|
||||
[[maybe_unused]] inline constexpr ContinuationStatus kBounce = -1;
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_object2(Parser3 *self, char *buf,
|
||||
// Calling a continuation with buf == bufEnd means end of input
|
||||
typedef PRESERVE_NONE ContinuationStatus (*Continuation)(struct Parser3 *,
|
||||
char *buf,
|
||||
char *bufEnd);
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_array2(Parser3 *self, char *buf,
|
||||
|
||||
inline PRESERVE_NONE ContinuationStatus n_object2(Parser3 *self, char *buf,
|
||||
char *bufEnd);
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_array2(Parser3 *self, char *buf,
|
||||
char *bufEnd);
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_string(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_string2(Parser3 *self, char *buf,
|
||||
char *bufEnd);
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_number(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_string(Parser3 *self, char *buf,
|
||||
char *bufEnd);
|
||||
inline PRESERVE_NONE ContinuationStatus n_number(Parser3 *self, char *buf,
|
||||
char *bufEnd);
|
||||
|
||||
// These appear in the stack of the pushdown
|
||||
@@ -121,7 +130,7 @@ struct Parser3 {
|
||||
return *(stackPtr - 1);
|
||||
}
|
||||
|
||||
static PRESERVE_NONE WeaselJsonStatus keepGoing(Parser3 *self, char *buf,
|
||||
static PRESERVE_NONE ContinuationStatus keepGoing(Parser3 *self, char *buf,
|
||||
char *bufEnd);
|
||||
|
||||
Symbol *stack() const { return (Symbol *)(this + 1); }
|
||||
@@ -152,7 +161,8 @@ struct Parser3 {
|
||||
#endif
|
||||
};
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus skipWhitespace(char *&buf, char *bufEnd) {
|
||||
inline PRESERVE_NONE ContinuationStatus skipWhitespace(char *&buf,
|
||||
char *bufEnd) {
|
||||
constexpr int kStride = 4;
|
||||
for (;;) {
|
||||
if (bufEnd - buf < kStride) [[unlikely]] {
|
||||
@@ -171,7 +181,7 @@ inline PRESERVE_NONE WeaselJsonStatus skipWhitespace(char *&buf, char *bufEnd) {
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_whitespace(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_whitespace(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) {
|
||||
self->pop();
|
||||
@@ -184,7 +194,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_whitespace(Parser3 *self, char *buf,
|
||||
MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd);
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_number(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_number(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf != bufEnd) {
|
||||
buf = (char *)self->numDfa.scan(buf, bufEnd);
|
||||
@@ -204,7 +214,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_number(Parser3 *self, char *buf,
|
||||
// Advance buf until double quote, backslash, invalid utf8, or codepoint <
|
||||
// 0x20
|
||||
template <class V>
|
||||
inline PRESERVE_NONE WeaselJsonStatus scan_string_impl(Parser3 *self,
|
||||
inline PRESERVE_NONE ContinuationStatus scan_string_impl(Parser3 *self,
|
||||
char *&buf,
|
||||
char *bufEnd) {
|
||||
const auto before = buf;
|
||||
@@ -253,33 +263,33 @@ inline PRESERVE_NONE WeaselJsonStatus scan_string_impl(Parser3 *self,
|
||||
|
||||
#ifdef __x86_64__
|
||||
constexpr int kLanes = 32;
|
||||
template WeaselJsonStatus
|
||||
template ContinuationStatus
|
||||
scan_string_impl<simd<int8_t, kLanes, sse::Simd_x86_SSE>>(Parser3 *, char *&,
|
||||
char *);
|
||||
|
||||
template __attribute__((target("avx2"))) WeaselJsonStatus
|
||||
template __attribute__((target("avx2"))) ContinuationStatus
|
||||
scan_string_impl<simd<int8_t, kLanes, sse::Simd_x86_AVX2>>(Parser3 *, char *&,
|
||||
char *);
|
||||
|
||||
__attribute__((target("default"))) inline PRESERVE_NONE WeaselJsonStatus
|
||||
__attribute__((target("default"))) inline PRESERVE_NONE ContinuationStatus
|
||||
scan_string(Parser3 *self, char *&buf, char *bufEnd) {
|
||||
MUSTTAIL return scan_string_impl<simd<int8_t, kLanes, sse::Simd_x86_SSE>>(
|
||||
self, buf, bufEnd);
|
||||
}
|
||||
|
||||
__attribute__((target("avx2"))) inline PRESERVE_NONE WeaselJsonStatus
|
||||
__attribute__((target("avx2"))) inline PRESERVE_NONE ContinuationStatus
|
||||
scan_string(Parser3 *self, char *&buf, char *bufEnd) {
|
||||
MUSTTAIL return scan_string_impl<simd<int8_t, kLanes, sse::Simd_x86_AVX2>>(
|
||||
self, buf, bufEnd);
|
||||
}
|
||||
#else
|
||||
inline PRESERVE_NONE WeaselJsonStatus scan_string(Parser3 *self, char *&buf,
|
||||
inline PRESERVE_NONE ContinuationStatus scan_string(Parser3 *self, char *&buf,
|
||||
char *bufEnd) {
|
||||
MUSTTAIL return scan_string_impl<simd<int8_t, 32>>(self, buf, bufEnd);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_value(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_value(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -392,7 +402,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_value(Parser3 *self, char *buf,
|
||||
MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd);
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_object2(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_object2(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -428,7 +438,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_object2(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_object3(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_object3(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -474,7 +484,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_object3(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_array2(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_array2(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -500,7 +510,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_array2(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_array3(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_array3(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -532,7 +542,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_array3(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_string(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_string(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -559,7 +569,7 @@ inline int32_t read4_hex(const char *buf) {
|
||||
tables.hex[uint8_t(buf[2])] << 4 | tables.hex[uint8_t(buf[3])] << 0;
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_string2(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -661,9 +671,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_string_following_escape(Parser3 *self,
|
||||
char *buf,
|
||||
char *bufEnd) {
|
||||
inline PRESERVE_NONE ContinuationStatus
|
||||
n_string_following_escape(Parser3 *self, char *buf, char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
}
|
||||
@@ -701,7 +710,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_string_following_escape(Parser3 *self,
|
||||
MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd);
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus t_hex(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus t_hex(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -721,7 +730,7 @@ inline PRESERVE_NONE WeaselJsonStatus t_hex(Parser3 *self, char *buf,
|
||||
MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd);
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus t_hex2(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus t_hex2(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -810,7 +819,7 @@ inline PRESERVE_NONE WeaselJsonStatus t_hex2(Parser3 *self, char *buf,
|
||||
MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd);
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus t_hex3(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus t_hex3(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -872,7 +881,7 @@ inline PRESERVE_NONE WeaselJsonStatus t_hex3(Parser3 *self, char *buf,
|
||||
}
|
||||
|
||||
template <char kChar>
|
||||
inline PRESERVE_NONE WeaselJsonStatus singleCharInString(Parser3 *self,
|
||||
inline PRESERVE_NONE ContinuationStatus singleCharInString(Parser3 *self,
|
||||
char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
@@ -891,7 +900,7 @@ inline PRESERVE_NONE WeaselJsonStatus singleCharInString(Parser3 *self,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_true(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_true(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -909,7 +918,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_true(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_false(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_false(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -927,7 +936,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_false(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus n_null(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus n_null(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -946,7 +955,7 @@ inline PRESERVE_NONE WeaselJsonStatus n_null(Parser3 *self, char *buf,
|
||||
}
|
||||
|
||||
template <char kChar>
|
||||
inline PRESERVE_NONE WeaselJsonStatus singleChar(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus singleChar(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -963,7 +972,7 @@ inline PRESERVE_NONE WeaselJsonStatus singleChar(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus t_colon(Parser3 *self, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus t_colon(Parser3 *self, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf == bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -985,7 +994,7 @@ inline PRESERVE_NONE WeaselJsonStatus t_colon(Parser3 *self, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus t_eof(Parser3 *, char *buf,
|
||||
inline PRESERVE_NONE ContinuationStatus t_eof(Parser3 *, char *buf,
|
||||
char *bufEnd) {
|
||||
if (buf != bufEnd) [[unlikely]] {
|
||||
return WeaselJson_REJECT;
|
||||
@@ -997,7 +1006,8 @@ constexpr inline struct ContinuationTable {
|
||||
constexpr ContinuationTable() {
|
||||
// Defaults
|
||||
for (int i = 0; i < N_SYMBOL_COUNT; ++i) {
|
||||
continuations[i] = +[](struct Parser3 *, char *, char *) PRESERVE_NONE {
|
||||
continuations[i] = +[](struct Parser3 *, char *, char *)
|
||||
PRESERVE_NONE -> ContinuationStatus {
|
||||
printf("unimplemented\n");
|
||||
return WeaselJson_REJECT;
|
||||
};
|
||||
@@ -1035,18 +1045,22 @@ inline WeaselJsonStatus Parser3::parse(char *buf, int len) {
|
||||
this->dataBegin = this->writeBuf = buf;
|
||||
|
||||
#ifdef HAS_MUSTTAIL
|
||||
return symbolTables.continuations[top()](this, buf, buf + len);
|
||||
// The continuation returns a value in 0..3 here (kBounce is only used by the
|
||||
// no-musttail trampoline below), so the conversion back to the enum is in
|
||||
// range.
|
||||
return WeaselJsonStatus(
|
||||
symbolTables.continuations[top()](this, buf, buf + len));
|
||||
#else
|
||||
this->stashBufForTrampoline = buf;
|
||||
WeaselJsonStatus result;
|
||||
ContinuationStatus result;
|
||||
while ((result = symbolTables.continuations[top()](
|
||||
this, stashBufForTrampoline, buf + len)) == WeaselJsonStatus(-1))
|
||||
this, stashBufForTrampoline, buf + len)) == kBounce)
|
||||
;
|
||||
return result;
|
||||
return WeaselJsonStatus(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline PRESERVE_NONE WeaselJsonStatus Parser3::keepGoing(Parser3 *self,
|
||||
inline PRESERVE_NONE ContinuationStatus Parser3::keepGoing(Parser3 *self,
|
||||
char *buf,
|
||||
char *bufEnd) {
|
||||
#ifdef HAS_MUSTTAIL
|
||||
@@ -1054,7 +1068,7 @@ inline PRESERVE_NONE WeaselJsonStatus Parser3::keepGoing(Parser3 *self,
|
||||
#else
|
||||
self->stashBufForTrampoline = buf;
|
||||
(void)bufEnd;
|
||||
return WeaselJsonStatus(-1);
|
||||
return kBounce;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user