From 7402bf98620ce675d9172a1d6db8902d29e79365 Mon Sep 17 00:00:00 2001 From: antares Date: Tue, 10 Dec 2024 01:27:53 +0800 Subject: [PATCH 01/12] Refactor first step --- src/decode/decode.c | 147 +++++++++++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 57 deletions(-) diff --git a/src/decode/decode.c b/src/decode/decode.c index dc76b38..9ac49b5 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -174,6 +174,34 @@ force_inline PyObject *make_string(const char *utf8_str, Py_ssize_t len, op_type return obj; } +typedef struct DecodeStackVars { + pyyjson_op *op; + PyObject **result_stack; + PyObject **cur_write_result_addr; + pyyjson_container_op *op_container; +#ifndef NDEBUG + PyObject **result_stack_end; +#endif +}DecodeStackVars; + + +force_inline bool init_decode_stack_vars(DecodeStackVars* restrict decode_stack_vars, pyyjson_op *restrict op_head, size_t obj_stack_maxsize){ + decode_stack_vars->op = op_head; + decode_stack_vars->result_stack = pyobject_stack_buffer; + if (unlikely(obj_stack_maxsize > PYYJSON_OBJSTACK_BUFFER_SIZE)) { + decode_stack_vars->result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); + if (unlikely(decode_stack_vars->result_stack == NULL)) { + PyErr_NoMemory(); + return false; + } + } + decode_stack_vars->cur_write_result_addr = decode_stack_vars->result_stack; +#ifndef NDEBUG + decode_stack_vars->result_stack_end = decode_stack_vars->result_stack + obj_stack_maxsize; +#endif + return true; +} + PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsize) { #if PYYJSON_ENABLE_TRACE size_t __op_counter = 0; @@ -203,22 +231,27 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz #define PYYJSON_SHOW_OP_TRACE() (void) (0) #define PYYJSON_SHOW_STR_TRACE() (void) (0) #endif // PYYJSON_ENABLE_TRACE - pyyjson_op *op = op_head; - PyObject **result_stack; - result_stack = pyobject_stack_buffer; - if (unlikely(obj_stack_maxsize > PYYJSON_OBJSTACK_BUFFER_SIZE)) { - result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); - if (unlikely(result_stack == NULL)) { - PyErr_NoMemory(); - return NULL; - } - } - PyObject **cur_write_result_addr = result_stack; -#ifndef NDEBUG - PyObject **result_stack_end = result_stack + obj_stack_maxsize; -#endif - // - pyyjson_container_op *op_container; + DecodeStackVars _decode_stack_vars; + DecodeStackVars* const decode_stack_vars = &_decode_stack_vars; + if(unlikely(!init_decode_stack_vars(decode_stack_vars, op_head, obj_stack_maxsize))){ + return NULL; + } +// pyyjson_op *op = op_head; +// PyObject **result_stack; +// result_stack = pyobject_stack_buffer; +// if (unlikely(obj_stack_maxsize > PYYJSON_OBJSTACK_BUFFER_SIZE)) { +// result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); +// if (unlikely(result_stack == NULL)) { +// PyErr_NoMemory(); +// return NULL; +// } +// } +// PyObject **cur_write_result_addr = result_stack; +// #ifndef NDEBUG +// PyObject **result_stack_end = result_stack + obj_stack_maxsize; +// #endif +// // +// pyyjson_container_op *op_container; #define PYYJSON_RESULT_STACK_REALLOC_CHECK() \ do { \ @@ -230,7 +263,7 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz #ifndef NDEBUG #define PYYJSON_RESULT_STACK_GROW() \ - if (unlikely(cur_write_result_addr >= result_stack_end)) { \ + if (unlikely(decode_stack_vars->cur_write_result_addr >= decode_stack_vars->result_stack_end)) { \ assert(false); \ Py_UNREACHABLE(); \ } @@ -239,8 +272,8 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz #endif #define PUSH_STACK_NO_CHECK(obj) \ do { \ - *cur_write_result_addr = obj; \ - cur_write_result_addr++; \ + *decode_stack_vars->cur_write_result_addr = obj; \ + decode_stack_vars->cur_write_result_addr++; \ } while (0) #define PYYJSON_PUSH_STACK(obj) \ @@ -251,10 +284,10 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz #ifndef NDEBUG #define PYYJSON_POP_STACK_PRE_CHECK(size) \ do { \ - if (unlikely((size) > (Py_ssize_t) (cur_write_result_addr - result_stack))) { \ + if (unlikely((size) > (Py_ssize_t) (decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack))) { \ PyErr_Format(PyExc_RuntimeError, \ "Stack underflow: expected to have at least %lld, got %lld", \ - (size), (Py_ssize_t) (cur_write_result_addr - result_stack)); \ + (size), (Py_ssize_t) (decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack)); \ goto fail; \ } \ } while (0) @@ -262,21 +295,21 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz #define PYYJSON_POP_STACK_PRE_CHECK(size) (void) (0) #endif // NDEBUG while (1) { - switch (PYYJSON_READ_OP(op) & PYYJSON_OP_MASK) { + switch (PYYJSON_READ_OP(decode_stack_vars->op) & PYYJSON_OP_MASK) { case PYYJSON_OP_STRING: { PYYJSON_TRACE_OP(PYYJSON_OP_STRING); - pyyjson_string_op *op_str = (pyyjson_string_op *) op; - PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(op)); + pyyjson_string_op *op_str = (pyyjson_string_op *) decode_stack_vars->op; + PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(decode_stack_vars->op)); if (new_val == NULL) goto fail; PYYJSON_PUSH_STACK(new_val); op_str++; - op = (pyyjson_op *) op_str; + decode_stack_vars->op = (pyyjson_op *) op_str; break; } case PYYJSON_OP_NUMBER: { PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); - pyyjson_number_op *op_num = (pyyjson_number_op *) op; - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(op), PYYJSON_NUM_FLAG_MASK)) { + pyyjson_number_op *op_num = (pyyjson_number_op *) decode_stack_vars->op; + switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_NUM_FLAG_MASK)) { PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_FLOAT) : { PYYJSON_PUSH_STACK(PyFloat_FromDouble(op_num->data.f)); break; @@ -294,12 +327,12 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz Py_UNREACHABLE(); } op_num++; - op = (pyyjson_op *) op_num; + decode_stack_vars->op = (pyyjson_op *) op_num; break; } case PYYJSON_OP_CONTAINER: { PYYJSON_TRACE_OP(PYYJSON_OP_CONTAINER); - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(op), PYYJSON_CONTAINER_FLAG_MASK)) { + switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_CONTAINER_FLAG_MASK)) { PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_ARRAY) : { goto container_array; } @@ -314,8 +347,8 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz Py_UNREACHABLE(); { container_array: - op_container = (pyyjson_container_op *) op; - Py_ssize_t len = op_container->len; + decode_stack_vars->op_container = (pyyjson_container_op *) decode_stack_vars->op; + Py_ssize_t len = decode_stack_vars->op_container->len; PyObject *list = PyList_New(len); if (unlikely(list == NULL)) goto fail; if (unlikely(len == 0)) { @@ -323,22 +356,22 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz goto arr_end; } PYYJSON_POP_STACK_PRE_CHECK(len - 1); - PyObject **list_val_start = cur_write_result_addr - len; + PyObject **list_val_start = decode_stack_vars->cur_write_result_addr - len; for (size_t j = 0; j < len; j++) { PyObject *val = list_val_start[j]; PyList_SET_ITEM(list, j, val); // this never fails } - cur_write_result_addr -= len; + decode_stack_vars->cur_write_result_addr -= len; PUSH_STACK_NO_CHECK(list); arr_end: - op_container++; - op = (pyyjson_op *) op_container; + decode_stack_vars->op_container++; + decode_stack_vars->op = (pyyjson_op *) decode_stack_vars->op_container; break; } { container_dict: - op_container = (pyyjson_container_op *) op; - Py_ssize_t len = op_container->len; + decode_stack_vars->op_container = (pyyjson_container_op *) decode_stack_vars->op; + Py_ssize_t len = decode_stack_vars->op_container->len; PyObject *dict = _PyDict_NewPresized(len); if (unlikely(dict == NULL)) goto fail; if (unlikely(len == 0)) { @@ -346,7 +379,7 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz goto dict_end; } PYYJSON_POP_STACK_PRE_CHECK(len * 2 - 1); - PyObject **dict_val_start = cur_write_result_addr - len * 2; + PyObject **dict_val_start = decode_stack_vars->cur_write_result_addr - len * 2; for (size_t j = 0; j < len; j++) { PyObject *key = dict_val_start[j * 2]; assert(PyUnicode_Check(key)); @@ -363,37 +396,37 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz Py_DECREF(dict_val_start[k]); } // move cur_write_result_addr to the first key addr, avoid double decref - cur_write_result_addr = dict_val_start; + decode_stack_vars->cur_write_result_addr = dict_val_start; goto fail; } } - cur_write_result_addr -= len * 2; + decode_stack_vars->cur_write_result_addr -= len * 2; PUSH_STACK_NO_CHECK(dict); dict_end: - op_container++; - op = (pyyjson_op *) op_container; + decode_stack_vars->op_container++; + decode_stack_vars->op = (pyyjson_op *) decode_stack_vars->op_container; break; } } case PYYJSON_OP_CONSTANTS: { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(op), PYYJSON_CONSTANTS_FLAG_MASK)) { + switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_CONSTANTS_FLAG_MASK)) { PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_NULL) : { Py_Immortal_IncRef(Py_None); PYYJSON_PUSH_STACK(Py_None); - op++; + decode_stack_vars->op++; break; } PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_FALSE) : { Py_Immortal_IncRef(Py_False); PYYJSON_PUSH_STACK(Py_False); - op++; + decode_stack_vars->op++; break; } PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_TRUE) : { Py_Immortal_IncRef(Py_True); PYYJSON_PUSH_STACK(Py_True); - op++; + decode_stack_vars->op++; break; } default: @@ -405,21 +438,21 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz } case PYYJSON_OP_NAN_INF: { PYYJSON_TRACE_OP(PYYJSON_OP_NAN_INF); - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(op), PYYJSON_NAN_INF_FLAG_MASK_WITHOUT_SIGNED)) { + switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_NAN_INF_FLAG_MASK_WITHOUT_SIGNED)) { PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_NAN) : { - double val = (PYYJSON_READ_OP(op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -fabs(Py_NAN) : fabs(Py_NAN); + double val = (PYYJSON_READ_OP(decode_stack_vars->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -fabs(Py_NAN) : fabs(Py_NAN); PyObject *o = PyFloat_FromDouble(val); assert(o); PYYJSON_PUSH_STACK(o); - op++; + decode_stack_vars->op++; break; } PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_INF) : { - double val = (PYYJSON_READ_OP(op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -Py_HUGE_VAL : Py_HUGE_VAL; + double val = (PYYJSON_READ_OP(decode_stack_vars->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -Py_HUGE_VAL : Py_HUGE_VAL; PyObject *o = PyFloat_FromDouble(val); assert(o); PYYJSON_PUSH_STACK(o); - op++; + decode_stack_vars->op++; break; } default: @@ -438,20 +471,20 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz } } success: - assert(cur_write_result_addr - result_stack == 1); - PyObject *result = *result_stack; - if (unlikely(result_stack != pyobject_stack_buffer)) free(result_stack); + assert(decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack == 1); + PyObject *result = *decode_stack_vars->result_stack; + if (unlikely(decode_stack_vars->result_stack != pyobject_stack_buffer)) free(decode_stack_vars->result_stack); PYYJSON_SHOW_OP_TRACE(); PYYJSON_SHOW_STR_TRACE(); return result; fail: // decref all objects in the stack - for (PyObject **p = result_stack; p < cur_write_result_addr; p++) { + for (PyObject **p = decode_stack_vars->result_stack; p < decode_stack_vars->cur_write_result_addr; p++) { Py_DECREF(*p); } - if (unlikely(result_stack != pyobject_stack_buffer)) free(result_stack); + if (unlikely(decode_stack_vars->result_stack != pyobject_stack_buffer)) free(decode_stack_vars->result_stack); if (PyErr_Occurred() == NULL) { - PyErr_Format(PyExc_RuntimeError, "Analyze pyyjson opcode failed at %lld", cur_write_result_addr - result_stack); + PyErr_Format(PyExc_RuntimeError, "Analyze pyyjson opcode failed at %lld", decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack); } return NULL; } From 785136a225e4a4984df71fb2e5ca3637bdbe3fbd Mon Sep 17 00:00:00 2001 From: antares Date: Wed, 11 Dec 2024 22:08:07 +0800 Subject: [PATCH 02/12] Update clang-format --- .clang-format | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index 7551917..3b188b2 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,3 @@ -# Generated from CLion C/C++ Code Style settings BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: Align @@ -37,7 +36,7 @@ ColumnLimit: 0 CompactNamespaces: false ContinuationIndentWidth: 8 IndentCaseLabels: true -IndentPPDirectives: None +IndentPPDirectives: AfterHash IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: true MaxEmptyLinesToKeep: 2 From 7792188db72cc51aad9d1ff6be9d43126ba0ca1e Mon Sep 17 00:00:00 2001 From: antares Date: Sat, 14 Dec 2024 17:00:00 +0800 Subject: [PATCH 03/12] Revert "Update clang-format" This reverts commit 785136a225e4a4984df71fb2e5ca3637bdbe3fbd. --- .clang-format | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 3b188b2..7551917 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,4 @@ +# Generated from CLion C/C++ Code Style settings BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: Align @@ -36,7 +37,7 @@ ColumnLimit: 0 CompactNamespaces: false ContinuationIndentWidth: 8 IndentCaseLabels: true -IndentPPDirectives: AfterHash +IndentPPDirectives: None IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: true MaxEmptyLinesToKeep: 2 From 2a356d688bb16aee96499a27e12cdc92aff311aa Mon Sep 17 00:00:00 2001 From: antares Date: Sat, 14 Dec 2024 17:42:41 +0800 Subject: [PATCH 04/12] decode container_type -> DecodeCtnWithSize --- src/decode/decode.c | 148 ++++++++++++++++++++++------------- src/encode/encode_impl.c | 2 +- src/encode/encode_impl.inl.h | 12 +-- src/pyyjson_config.h | 8 ++ src/tls.c | 12 ++- src/tls.h | 74 +++++++++++++----- 6 files changed, 173 insertions(+), 83 deletions(-) diff --git a/src/decode/decode.c b/src/decode/decode.c index 9ac49b5..31bba97 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -8,11 +8,28 @@ #include #include #include +#include "tls.h" + thread_local char pyyjson_string_buffer[PYYJSON_STRING_BUFFER_SIZE]; +force_inline bool decode_ctn_is_arr(DecodeCtnWithSize*ctn){ + return ctn->raw < 0; +} + +force_inline Py_ssize_t get_decode_ctn_len(DecodeCtnWithSize*ctn){ + return ctn->raw & PY_SSIZE_T_MAX; +} +force_inline void set_decode_ctn(DecodeCtnWithSize*ctn, Py_ssize_t len, bool is_arr){ + assert(len >= 0); + ctn->raw = len | (is_arr ? PY_SSIZE_T_MIN : 0); +} +force_inline void incr_decode_ctn_size(DecodeCtnWithSize*ctn){ + assert(ctn->raw != PY_SSIZE_T_MAX); + ctn->raw++; +} #if PY_MINOR_VERSION >= 13 // these are hidden in Python 3.13 @@ -202,6 +219,18 @@ force_inline bool init_decode_stack_vars(DecodeStackVars* restrict decode_stack_ return true; } +// bool pyyjson_decode_string(){ +// PYYJSON_TRACE_OP(PYYJSON_OP_STRING); +// pyyjson_string_op *op_str = (pyyjson_string_op *) decode_stack_vars->op; +// PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(decode_stack_vars->op)); +// if (new_val == NULL) goto fail; +// PYYJSON_PUSH_STACK(new_val); +// op_str++; +// decode_stack_vars->op = (pyyjson_op *) op_str; +// break; +// } + + PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsize) { #if PYYJSON_ENABLE_TRACE size_t __op_counter = 0; @@ -1629,16 +1658,16 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto failed_cleanup; \ } while (0) - typedef struct container_type { - union { - struct { - Py_ssize_t size : sizeof(Py_ssize_t) * 8 - 1; - Py_ssize_t tag : 1; - }; - Py_ssize_t raw; - }; - } container_type; - static_assert(sizeof(container_type) == sizeof(Py_ssize_t), "size of container_type must be equal to size of Py_ssize_t"); + // typedef struct container_type { + // union { + // struct { + // Py_ssize_t size : sizeof(Py_ssize_t) * 8 - 1; + // Py_ssize_t tag : 1; + // }; + // Py_ssize_t raw; + // }; + // } container_type; + // static_assert(sizeof(container_type) == sizeof(Py_ssize_t), "size of container_type must be equal to size of Py_ssize_t"); #define CONTAINER_ARR_TYPE (~0) #define CONTAINER_OBJ_TYPE 0 @@ -1648,12 +1677,12 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { #define COMMON_OPSIZE_RATIO (sizeof(pyyjson_string_op) / sizeof(pyyjson_op)) #define OP_BUFFER_INIT_SIZE (STACK_BUFFER_SIZE * COMMON_OPSIZE_RATIO) // stack buffer - container_type __stack_ctn_buffer[STACK_BUFFER_SIZE]; + DecodeCtnWithSize __stack_ctn_buffer[STACK_BUFFER_SIZE]; pyyjson_op pyobject_stack_buffer[OP_BUFFER_INIT_SIZE]; // buffer start pointer pyyjson_op *py_operations; char *string_buffer_head = pyyjson_string_buffer; - container_type *ctn_start = __stack_ctn_buffer; + DecodeCtnWithSize *ctn_start = __stack_ctn_buffer; usize required_len = PYYJSON_MAX( OP_BUFFER_INIT_SIZE, @@ -1718,8 +1747,8 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { } while (0) // container ptr - container_type *ctn_end = __stack_ctn_buffer + STACK_BUFFER_SIZE; - container_type *ctn = ctn_start; + DecodeCtnWithSize *ctn_end = __stack_ctn_buffer + STACK_BUFFER_SIZE; + DecodeCtnWithSize *ctn = ctn_start; // container buffer grow macros #define CTN_REALLOC_CHECK() \ @@ -1734,13 +1763,13 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (unlikely(ctn + 1 >= ctn_end)) { \ size_t old_capacity = ctn_end - ctn_start; \ size_t new_capacity = old_capacity + old_capacity / 2; \ - container_type *new_ctn_start; \ + DecodeCtnWithSize *new_ctn_start; \ if (likely(ctn_start == __stack_ctn_buffer)) { \ - new_ctn_start = (container_type *) malloc(new_capacity * sizeof(container_type)); \ + new_ctn_start = (DecodeCtnWithSize *) malloc(new_capacity * sizeof(DecodeCtnWithSize)); \ CTN_REALLOC_CHECK(); \ - memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(container_type)); \ + memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(DecodeCtnWithSize)); \ } else { \ - new_ctn_start = (container_type *) realloc(ctn_start, new_capacity * sizeof(container_type)); \ + new_ctn_start = (DecodeCtnWithSize *) realloc(ctn_start, new_capacity * sizeof(DecodeCtnWithSize)); \ CTN_REALLOC_CHECK(); \ } \ ctn_start = new_ctn_start; \ @@ -1779,14 +1808,16 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { static_assert(STACK_BUFFER_SIZE > 0, "STACK_BUFFER_SIZE should be greater than 0"); if (*cur++ == '{') { - ctn->tag = CONTAINER_OBJ_TYPE; - ctn->size = 0; + set_decode_ctn(ctn, 0, false); + // ctn->tag = CONTAINER_OBJ_TYPE; + // ctn->size = 0; // ctn++; if (*cur == '\n') cur++; goto obj_key_begin; } else { - ctn->tag = CONTAINER_ARR_TYPE; - ctn->size = 0; + set_decode_ctn(ctn, 0, true); + // ctn->tag = CONTAINER_ARR_TYPE; + // ctn->size = 0; // ctn++; if (*cur == '\n') cur++; goto arr_val_begin; @@ -1796,8 +1827,10 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { /* save current container */ /* create a new array value, save parent container offset */ CTN_BUFFER_GROW(); - ctn->tag = CONTAINER_ARR_TYPE; - ctn->size = 0; + // ctn->tag = CONTAINER_ARR_TYPE; + // ctn->size = 0; + set_decode_ctn(ctn, 0, true); + /* push the new array value as current container */ if (*cur == '\n') cur++; @@ -1830,7 +1863,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { pyyjson_op *now_write_op = cur_write_op; if (likely(read_number(&cur, &cur_write_op))) { OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } goto fail_number; @@ -1841,7 +1874,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (likely(read_string(&cur, &cur_write_op, &string_buffer))) { CHECK_STRING_BUFFER_OVERFLOW(); OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } goto fail_string; @@ -1852,7 +1885,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); OBJ_STACK_MAX_SIZE_UPDATE(1); cur_write_op++; - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } goto fail_literal_true; @@ -1863,7 +1896,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); OBJ_STACK_MAX_SIZE_UPDATE(1); cur_write_op++; - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } goto fail_literal_false; @@ -1874,11 +1907,11 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); OBJ_STACK_MAX_SIZE_UPDATE(1); cur_write_op++; - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } if (read_nan(false, &cur, &cur_write_op)) { - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } goto fail_literal_null; @@ -1886,7 +1919,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (*cur == ']') { cur++; // if (likely(ctn_len == 0)) goto arr_end; - if (likely(ctn->size == 0)) goto arr_end; + if (likely(get_decode_ctn_len(ctn) == 0)) goto arr_end; //if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto arr_end; while (*cur != ',') cur--; goto fail_trailing_comma; @@ -1900,7 +1933,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { OP_BUFFER_GROW(sizeof(pyyjson_op)); if (read_inf_or_nan(false, &cur, &cur_write_op)) { OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto arr_val_end; } goto fail_character_val; @@ -1933,18 +1966,21 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { OP_BUFFER_GROW(sizeof(pyyjson_container_op)); pyyjson_container_op *list_op = (pyyjson_container_op *) cur_write_op; PYYJSON_WRITE_OP(list_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_ARRAY); - OBJ_STACK_MAX_SIZE_UPDATE(1 - ctn->size); - list_op->len = ctn->size; + { + Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); + OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); + list_op->len = cur_ctn_size; + } cur_write_op = (pyyjson_op *) (list_op + 1); - assert(ctn->tag != CONTAINER_OBJ_TYPE); + assert(decode_ctn_is_arr(ctn)); /* pop parent as current container */ if (unlikely(ctn-- == ctn_start)) { goto doc_end; } - ctn->size++; + incr_decode_ctn_size(ctn); if (*cur == '\n') cur++; - if (ctn->tag == CONTAINER_OBJ_TYPE) { + if (!decode_ctn_is_arr(ctn)) { goto obj_val_end; } else { goto arr_val_end; @@ -1953,8 +1989,9 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { obj_begin: /* push container */ CTN_BUFFER_GROW(); - ctn->tag = CONTAINER_OBJ_TYPE; - ctn->size = 0; + set_decode_ctn(ctn, 0, false); + // ctn->tag = CONTAINER_OBJ_TYPE; + // ctn->size = 0; if (*cur == '\n') cur++; obj_key_begin: @@ -1985,7 +2022,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { } if (likely(*cur == '}')) { cur++; - if (likely(ctn->size == 0)) goto obj_end; + if (likely(get_decode_ctn_len(ctn) == 0)) goto obj_end; goto fail_trailing_comma; } if (char_is_space(*cur)) { @@ -2018,7 +2055,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (likely(read_string(&cur, &cur_write_op, &string_buffer))) { CHECK_STRING_BUFFER_OVERFLOW(); OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto obj_val_end; } goto fail_string; @@ -2028,7 +2065,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { pyyjson_op *now_write_op = cur_write_op; if (likely(read_number(&cur, &cur_write_op))) { OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto obj_val_end; } goto fail_number; @@ -2047,7 +2084,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); cur_write_op++; OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto obj_val_end; } goto fail_literal_true; @@ -2058,7 +2095,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); cur_write_op++; OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto obj_val_end; } goto fail_literal_false; @@ -2069,11 +2106,11 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); cur_write_op++; OBJ_STACK_MAX_SIZE_UPDATE(1); - ctn->size++; + incr_decode_ctn_size(ctn); goto obj_val_end; } if (read_nan(false, &cur, &cur_write_op)) { - ctn->size++; + incr_decode_ctn_size(ctn); goto obj_val_end; } goto fail_literal_null; @@ -2086,7 +2123,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if ((*cur == 'i' || *cur == 'I' || *cur == 'N')) { OP_BUFFER_GROW(sizeof(pyyjson_op)); if (read_inf_or_nan(false, &cur, &cur_write_op)) { - ctn->size++; + incr_decode_ctn_size(ctn); OBJ_STACK_MAX_SIZE_UPDATE(1); goto obj_val_end; } @@ -2120,21 +2157,24 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { OP_BUFFER_GROW(sizeof(pyyjson_container_op)); pyyjson_container_op *dict_op = (pyyjson_container_op *) cur_write_op; PYYJSON_WRITE_OP(dict_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_DICT); - OBJ_STACK_MAX_SIZE_UPDATE(1 - ctn->size); - dict_op->len = ctn->size; + { + Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); + OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); + dict_op->len = cur_ctn_size; + } cur_write_op = (pyyjson_op *) (dict_op + 1); - assert(ctn->tag == CONTAINER_OBJ_TYPE); + assert(!decode_ctn_is_arr(ctn)); /* pop container */ /* point to the next value */ if (unlikely(ctn-- == ctn_start)) { goto doc_end; } - ctn->size++; + incr_decode_ctn_size(ctn); if (*cur == '\n') cur++; - if (ctn->tag == CONTAINER_OBJ_TYPE) { - goto obj_val_end; - } else { + if (decode_ctn_is_arr(ctn)) { goto arr_val_end; + } else { + goto obj_val_end; } doc_end: diff --git a/src/encode/encode_impl.c b/src/encode/encode_impl.c index 92ad518..ed748ed 100644 --- a/src/encode/encode_impl.c +++ b/src/encode/encode_impl.c @@ -58,7 +58,7 @@ typedef struct EncodeStackVars { Py_ssize_t cur_nested_depth; //= 0; Py_ssize_t cur_list_size; // alias thread local buffer - CtnType *ctn_stack; //= obj_viewer->ctn_stack; + EncodeCtnWithIndex *ctn_stack; //= obj_viewer->ctn_stack; UnicodeInfo unicode_info; } EncodeStackVars; diff --git a/src/encode/encode_impl.inl.h b/src/encode/encode_impl.inl.h index 65514a5..30d803f 100644 --- a/src/encode/encode_impl.inl.h +++ b/src/encode/encode_impl.inl.h @@ -544,7 +544,7 @@ force_inline EncodeValJumpFlag ENCODE_PROCESS_VAL( _c = VECTOR_APPEND_ARR_BEGIN(&GET_VEC(stack_vars), stack_vars->cur_nested_depth, is_in_obj); RETURN_JUMP_FAIL_ON_UNLIKELY_ERR(!_c); CTN_SIZE_GROW(); - CtnType *cur_write_ctn = _CTN_STACK(stack_vars) + (stack_vars->cur_nested_depth++); + EncodeCtnWithIndex *cur_write_ctn = _CTN_STACK(stack_vars) + (stack_vars->cur_nested_depth++); cur_write_ctn->ctn = stack_vars->cur_obj; cur_write_ctn->index = stack_vars->cur_pos; stack_vars->cur_obj = val; @@ -562,7 +562,7 @@ force_inline EncodeValJumpFlag ENCODE_PROCESS_VAL( _c = VECTOR_APPEND_OBJ_BEGIN(&GET_VEC(stack_vars), stack_vars->cur_nested_depth, is_in_obj); RETURN_JUMP_FAIL_ON_UNLIKELY_ERR(!_c); CTN_SIZE_GROW(); - CtnType *cur_write_ctn = _CTN_STACK(stack_vars) + (stack_vars->cur_nested_depth++); + EncodeCtnWithIndex *cur_write_ctn = _CTN_STACK(stack_vars) + (stack_vars->cur_nested_depth++); cur_write_ctn->ctn = stack_vars->cur_obj; cur_write_ctn->index = stack_vars->cur_pos; stack_vars->cur_obj = val; @@ -580,7 +580,7 @@ force_inline EncodeValJumpFlag ENCODE_PROCESS_VAL( bool _c = VECTOR_APPEND_ARR_BEGIN(&GET_VEC(stack_vars), stack_vars->cur_nested_depth, is_in_obj); RETURN_JUMP_FAIL_ON_UNLIKELY_ERR(!_c); CTN_SIZE_GROW(); - CtnType *cur_write_ctn = _CTN_STACK(stack_vars) + (stack_vars->cur_nested_depth++); + EncodeCtnWithIndex *cur_write_ctn = _CTN_STACK(stack_vars) + (stack_vars->cur_nested_depth++); cur_write_ctn->ctn = stack_vars->cur_obj; cur_write_ctn->index = stack_vars->cur_pos; stack_vars->cur_obj = val; @@ -787,7 +787,7 @@ dict_pair_begin:; } else { // dict end assert(stack_vars->cur_nested_depth); - CtnType *last_pos = _CTN_STACK(stack_vars) + (--stack_vars->cur_nested_depth); + EncodeCtnWithIndex *last_pos = _CTN_STACK(stack_vars) + (--stack_vars->cur_nested_depth); bool _c = VECTOR_APPEND_OBJ_END(&GET_VEC(stack_vars), stack_vars->cur_nested_depth); GOTO_FAIL_ON_UNLIKELY_ERR(!_c); @@ -861,7 +861,7 @@ arr_val_begin:; } else { // list end assert(stack_vars->cur_nested_depth); - CtnType *last_pos = _CTN_STACK(stack_vars) + (--stack_vars->cur_nested_depth); + EncodeCtnWithIndex *last_pos = _CTN_STACK(stack_vars) + (--stack_vars->cur_nested_depth); bool _c = VECTOR_APPEND_ARR_END(&GET_VEC(stack_vars), stack_vars->cur_nested_depth); GOTO_FAIL_ON_UNLIKELY_ERR(!_c); @@ -934,7 +934,7 @@ tuple_val_begin:; } else { // list end assert(stack_vars->cur_nested_depth); - CtnType *last_pos = _CTN_STACK(stack_vars) + (--stack_vars->cur_nested_depth); + EncodeCtnWithIndex *last_pos = _CTN_STACK(stack_vars) + (--stack_vars->cur_nested_depth); bool _c = VECTOR_APPEND_ARR_END(&GET_VEC(stack_vars), stack_vars->cur_nested_depth); GOTO_FAIL_ON_UNLIKELY_ERR(!_c); diff --git a/src/pyyjson_config.h b/src/pyyjson_config.h index 678a325..1a7dffa 100644 --- a/src/pyyjson_config.h +++ b/src/pyyjson_config.h @@ -52,6 +52,14 @@ #define PYYJSON_READER_ESTIMATED_PRETTY_RATIO 16 #endif +/* + Init buffer size for decode container buffer. + Cost: PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE * sizeof(Py_ssize_t) bytes per thread. + */ +#ifndef PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE +#define PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE (1024) +#endif + /* Init buffer size for dst buffer. Must be multiple of 64. Cost: PYYJSON_ENCODE_DST_BUFFER_INIT_SIZE bytes per thread. diff --git a/src/tls.c b/src/tls.c index 5160beb..26e7f7b 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3,8 +3,9 @@ TLS_KEY_TYPE _EncodeObjStackBuffer_Key; +TLS_KEY_TYPE _DecodeObjStackBuffer_Key; -void _encode_obj_stack_destructor(void *ptr) { +void _tls_buffer_destructor(void *ptr) { if (ptr) free(ptr); } @@ -12,10 +13,13 @@ void _encode_obj_stack_destructor(void *ptr) { bool pyyjson_tls_init(void) { bool success = true; #if defined(_POSIX_THREADS) - success = success && (0 == pthread_key_create(&_EncodeObjStackBuffer_Key, _encode_obj_stack_destructor)); + success = success && (0 == pthread_key_create(&_EncodeObjStackBuffer_Key, _tls_buffer_destructor)); + success = success && (0 == pthread_key_create(&_DecodeObjStackBuffer_Key, _tls_buffer_destructor)); #else - if (success) _EncodeObjStackBuffer_Key = FlsAlloc(_encode_obj_stack_destructor); + if (success) _EncodeObjStackBuffer_Key = FlsAlloc(_tls_buffer_destructor); if (_EncodeObjStackBuffer_Key == FLS_OUT_OF_INDEXES) success = false; + if (success) _DecodeObjStackBuffer_Key = FlsAlloc(_tls_buffer_destructor); + if (_DecodeObjStackBuffer_Key == FLS_OUT_OF_INDEXES) success = false; #endif return success; } @@ -24,8 +28,10 @@ bool pyyjson_tls_free(void) { bool success = true; #if defined(_POSIX_THREADS) success = success && (0 == pthread_key_delete(_EncodeObjStackBuffer_Key)); + success = success && (0 == pthread_key_delete(_DecodeObjStackBuffer_Key)); #else success = success && FlsFree(_EncodeObjStackBuffer_Key); + success = success && FlsFree(_DecodeObjStackBuffer_Key); #endif return success; } diff --git a/src/tls.h b/src/tls.h index 3997b26..67be1a7 100644 --- a/src/tls.h +++ b/src/tls.h @@ -4,6 +4,28 @@ #include "pyyjson.h" #include +/*============================================================================== + * TLS related macros + *============================================================================*/ +#if defined(_POSIX_THREADS) +#define PYYJSON_DECLARE_TLS_GETTER(_key, _getter_name) \ + force_inline void *_getter_name(void) { \ + return pthread_getspecific((_key)); \ + } +#define PYYJSON_DECLARE_TLS_SETTER(_key, _setter_name) \ + force_inline bool _setter_name(void *ptr) { \ + return 0 == pthread_setspecific(_key, ptr); \ + } +#else +#define PYYJSON_DECLARE_TLS_GETTER(_key, _getter_name) \ + force_inline void *_getter_name(void) { \ + return FlsGetValue((_key)); \ + } +#define PYYJSON_DECLARE_TLS_SETTER(_key, _setter_name) \ + force_inline bool _setter_name(void *ptr) { \ + return FlsSetValue(_key, ptr); \ + } +#endif /*============================================================================== * TLS related API @@ -19,31 +41,19 @@ bool pyyjson_tls_free(void); extern TLS_KEY_TYPE _EncodeObjStackBuffer_Key; /* The underlying data type to be stored. */ -typedef struct CtnType { +typedef struct EncodeCtnWithIndex { PyObject *ctn; Py_ssize_t index; -} CtnType; +} EncodeCtnWithIndex; -force_inline void *_get_encode_obj_stack_buffer_pointer(void) { -#if defined(_POSIX_THREADS) - return pthread_getspecific(_EncodeObjStackBuffer_Key); -#else - return FlsGetValue(_EncodeObjStackBuffer_Key); -#endif -} +PYYJSON_DECLARE_TLS_GETTER(_EncodeObjStackBuffer_Key, _get_encode_obj_stack_buffer_pointer) +PYYJSON_DECLARE_TLS_SETTER(_EncodeObjStackBuffer_Key, _set_encode_obj_stack_buffer_pointer) -force_inline bool _set_encode_obj_stack_buffer_pointer(void *ptr) { -#if defined(_POSIX_THREADS) - return 0 == pthread_setspecific(_EncodeObjStackBuffer_Key, ptr); -#else - return FlsSetValue(_EncodeObjStackBuffer_Key, ptr); -#endif -} -force_inline CtnType *get_encode_obj_stack_buffer(void) { +force_inline EncodeCtnWithIndex *get_encode_obj_stack_buffer(void) { void *value = _get_encode_obj_stack_buffer_pointer(); if (unlikely(value == NULL)) { - value = malloc(PYYJSON_ENCODE_MAX_RECURSION * sizeof(CtnType)); + value = malloc(PYYJSON_ENCODE_MAX_RECURSION * sizeof(EncodeCtnWithIndex)); if (unlikely(value == NULL)) return NULL; bool succ = _set_encode_obj_stack_buffer_pointer(value); if (unlikely(!succ)) { @@ -51,8 +61,34 @@ force_inline CtnType *get_encode_obj_stack_buffer(void) { return NULL; } } - return (CtnType *) value; + return (EncodeCtnWithIndex *) value; } +/*============================================================================== + * Thread Local Decode buffer + *============================================================================*/ +/* Decode TLS buffer key. */ +extern TLS_KEY_TYPE _DecodeObjStackBuffer_Key; + +typedef struct DecodeCtnWithSize { + Py_ssize_t raw; +} DecodeCtnWithSize; + +PYYJSON_DECLARE_TLS_GETTER(_DecodeObjStackBuffer_Key, _get_decode_obj_stack_buffer_pointer) +PYYJSON_DECLARE_TLS_SETTER(_DecodeObjStackBuffer_Key, _set_decode_obj_stack_buffer_pointer) + +force_inline DecodeCtnWithSize *get_decode_obj_stack_buffer(void) { + void *value = _get_decode_obj_stack_buffer_pointer(); + if (unlikely(value == NULL)) { + value = malloc(PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE * sizeof(DecodeCtnWithSize)); + if (unlikely(value == NULL)) return NULL; + bool succ = _set_decode_obj_stack_buffer_pointer(value); + if (unlikely(!succ)) { + free(value); + return NULL; + } + } + return (DecodeCtnWithSize *) value; +} #endif // PYYJSON_TLS_H From 34f057d598538c4005ad7432ead86adc8c72fdb5 Mon Sep 17 00:00:00 2001 From: antares Date: Sat, 14 Dec 2024 17:55:56 +0800 Subject: [PATCH 05/12] make __stack_ctn_buffer tls --- src/decode/decode.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/decode/decode.c b/src/decode/decode.c index 31bba97..8b7d7fb 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -1677,7 +1677,8 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { #define COMMON_OPSIZE_RATIO (sizeof(pyyjson_string_op) / sizeof(pyyjson_op)) #define OP_BUFFER_INIT_SIZE (STACK_BUFFER_SIZE * COMMON_OPSIZE_RATIO) // stack buffer - DecodeCtnWithSize __stack_ctn_buffer[STACK_BUFFER_SIZE]; + DecodeCtnWithSize *const __stack_ctn_buffer = get_decode_obj_stack_buffer(); + assert(__stack_ctn_buffer); pyyjson_op pyobject_stack_buffer[OP_BUFFER_INIT_SIZE]; // buffer start pointer pyyjson_op *py_operations; @@ -1747,7 +1748,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { } while (0) // container ptr - DecodeCtnWithSize *ctn_end = __stack_ctn_buffer + STACK_BUFFER_SIZE; + DecodeCtnWithSize *ctn_end = __stack_ctn_buffer + PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE; DecodeCtnWithSize *ctn = ctn_start; // container buffer grow macros @@ -1758,25 +1759,25 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto fail_alloc; \ } \ } while (0) -#define CTN_BUFFER_GROW() \ - do { \ - if (unlikely(ctn + 1 >= ctn_end)) { \ - size_t old_capacity = ctn_end - ctn_start; \ - size_t new_capacity = old_capacity + old_capacity / 2; \ - DecodeCtnWithSize *new_ctn_start; \ - if (likely(ctn_start == __stack_ctn_buffer)) { \ +#define CTN_BUFFER_GROW() \ + do { \ + if (unlikely(ctn + 1 >= ctn_end)) { \ + size_t old_capacity = ctn_end - ctn_start; \ + size_t new_capacity = old_capacity << 1; \ + DecodeCtnWithSize *new_ctn_start; \ + if (likely(old_capacity == PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE)) { \ new_ctn_start = (DecodeCtnWithSize *) malloc(new_capacity * sizeof(DecodeCtnWithSize)); \ - CTN_REALLOC_CHECK(); \ - memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(DecodeCtnWithSize)); \ - } else { \ + CTN_REALLOC_CHECK(); \ + memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(DecodeCtnWithSize)); \ + } else { \ new_ctn_start = (DecodeCtnWithSize *) realloc(ctn_start, new_capacity * sizeof(DecodeCtnWithSize)); \ - CTN_REALLOC_CHECK(); \ - } \ - ctn_start = new_ctn_start; \ - ctn = new_ctn_start + old_capacity; \ - ctn_end = new_ctn_start + new_capacity; \ - } \ - ctn++; \ + CTN_REALLOC_CHECK(); \ + } \ + ctn_start = new_ctn_start; \ + ctn = new_ctn_start + old_capacity; \ + ctn_end = new_ctn_start + new_capacity; \ + } \ + ctn++; \ } while (0) #ifdef NDEBUG #define CHECK_STRING_BUFFER_OVERFLOW() ((void) 0) From efdd8f939bb69e8fc81b9018fcf9dddf5d07a856 Mon Sep 17 00:00:00 2001 From: antares Date: Sun, 15 Dec 2024 23:23:31 +0800 Subject: [PATCH 06/12] Refactor decode --- CMakeLists.txt | 2 +- src/decode/decode.c | 1419 +++++++++++++++++++-------------- src/decode/decode.h | 78 +- src/decode/decode_float.inl.h | 162 ++-- src/encode/encode_impl.c | 7 +- src/pyyjson.c | 4 +- src/pyyjson.h | 8 + src/pyyjson_config.h | 22 +- src/tls.c | 6 + src/tls.h | 37 +- 10 files changed, 1061 insertions(+), 684 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3db9c7b..b33f6d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set(PYYJSON_SOVERSION 0) # Search Python Package find_package(Python3 COMPONENTS Development) -# check for python3 +# check for python3ss if((NOT Python3_INCLUDE_DIRS) OR (NOT Python3_LIBRARIES)) message(FATAL_ERROR "Python3 not found") endif() diff --git a/src/decode/decode.c b/src/decode/decode.c index 8b7d7fb..17d6dfa 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -10,7 +10,7 @@ #include #include "tls.h" -thread_local char pyyjson_string_buffer[PYYJSON_STRING_BUFFER_SIZE]; +thread_local u8 pyyjson_string_buffer[PYYJSON_STRING_BUFFER_SIZE]; force_inline bool decode_ctn_is_arr(DecodeCtnWithSize*ctn){ @@ -31,6 +31,10 @@ force_inline void incr_decode_ctn_size(DecodeCtnWithSize*ctn){ ctn->raw++; } +force_inline bool ctn_grow_check(DecodeCtnStackInfo *decode_ctn_info) { + return ++decode_ctn_info->ctn < decode_ctn_info->ctn_end; +} + #if PY_MINOR_VERSION >= 13 // these are hidden in Python 3.13 #if PY_MINOR_VERSION == 13 @@ -56,7 +60,7 @@ PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key, PyObject typedef XXH64_hash_t pyyjson_hash_t; -thread_local PyObject *pyobject_stack_buffer[PYYJSON_OBJSTACK_BUFFER_SIZE]; +// thread_local PyObject *pyobject_stack_buffer[PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE]; #if PYYJSON_ENABLE_TRACE @@ -126,7 +130,7 @@ force_inline void add_key_cache(pyyjson_hash_t hash, PyObject *obj) { AssociativeKeyCache[index] = obj; } -force_inline PyObject *get_key_cache(const char *utf8_str, pyyjson_hash_t hash, size_t real_len) { +force_inline PyObject *get_key_cache(const u8 *utf8_str, pyyjson_hash_t hash, size_t real_len) { assert(real_len <= 64); pyyjson_cache_type cache = AssociativeKeyCache[REHASHER(hash)]; if (!cache) return NULL; @@ -137,32 +141,40 @@ force_inline PyObject *get_key_cache(const char *utf8_str, pyyjson_hash_t hash, return NULL; } -force_inline PyObject *make_string(const char *utf8_str, Py_ssize_t len, op_type flag) { +force_inline PyObject *make_string(const u8 *utf8_str, Py_ssize_t len, int type_flag, bool is_key) { PYYJSON_TRACE_STR_LEN(len); PyObject *obj; Py_UCS4 max_char; size_t real_len; XXH64_hash_t hash; - switch (PYYJSON_GET_FLAG(flag, PYYJSON_STRING_FLAG_UCS_TYPE_MASK)) { - PYYJSON_MATCH_FLAG(PYYJSON_STRING_FLAG_ASCII) : max_char = 0x7f; - real_len = len; - break; - PYYJSON_MATCH_FLAG(PYYJSON_STRING_FLAG_LATIN1) : max_char = 0xff; - real_len = len; - break; - PYYJSON_MATCH_FLAG(PYYJSON_STRING_FLAG_UCS2) : max_char = 0xffff; - real_len = len * 2; - break; - PYYJSON_MATCH_FLAG(PYYJSON_STRING_FLAG_UCS4) : max_char = 0x10ffff; - real_len = len * 4; - break; + switch (type_flag) { + case PYYJSON_STRING_TYPE_ASCII: { + max_char = 0x7f; + real_len = len; + break; + } + case PYYJSON_STRING_TYPE_LATIN1: { + max_char = 0xff; + real_len = len; + break; + } + case PYYJSON_STRING_TYPE_UCS2: { + max_char = 0xffff; + real_len = len * 2; + break; + } + case PYYJSON_STRING_TYPE_UCS4: { + max_char = 0x10ffff; + real_len = len * 4; + break; + } default: assert(false); Py_UNREACHABLE(); } - bool should_cache = ((flag & PYYJSON_STRING_FLAG_OBJ_KEY) && likely(real_len <= 64)); + bool should_cache = (is_key && likely(real_len <= 64)); if (should_cache) { hash = XXH3_64bits(utf8_str, real_len); @@ -180,7 +192,7 @@ force_inline PyObject *make_string(const char *utf8_str, Py_ssize_t len, op_type add_key_cache(hash, obj); } success: - if (flag & PYYJSON_STRING_FLAG_OBJ_KEY) { + if (is_key) { assert(((PyASCIIObject *) obj)->hash == -1); #if PY_MINOR_VERSION >= 14 ((PyASCIIObject *) obj)->hash = PyUnicode_Type.tp_hash(obj); @@ -191,49 +203,44 @@ force_inline PyObject *make_string(const char *utf8_str, Py_ssize_t len, op_type return obj; } -typedef struct DecodeStackVars { - pyyjson_op *op; - PyObject **result_stack; - PyObject **cur_write_result_addr; - pyyjson_container_op *op_container; -#ifndef NDEBUG - PyObject **result_stack_end; -#endif -}DecodeStackVars; - +force_inline bool init_decode_obj_stack_info(DecodeObjStackInfo *restrict decode_obj_stack_info) { + PyObject **new_buffer = get_decode_obj_stack_buffer(); + if (unlikely(!new_buffer)) { + PyErr_NoMemory(); + return false; + } + decode_obj_stack_info->result_stack = new_buffer; + decode_obj_stack_info->cur_write_result_addr = new_buffer; + decode_obj_stack_info->result_stack_end = new_buffer + PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE; + // decode_obj_stack_info->op = op_head; + // decode_obj_stack_info->result_stack = pyobject_stack_buffer; + // if (unlikely(obj_stack_maxsize > PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE)) { + // decode_obj_stack_info->result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); + // if (unlikely(decode_obj_stack_info->result_stack == NULL)) { + // PyErr_NoMemory(); + // return false; + // } + // } + // decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack; + // // #ifndef NDEBUG + // decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + obj_stack_maxsize; + // #endif + return true; +} -force_inline bool init_decode_stack_vars(DecodeStackVars* restrict decode_stack_vars, pyyjson_op *restrict op_head, size_t obj_stack_maxsize){ - decode_stack_vars->op = op_head; - decode_stack_vars->result_stack = pyobject_stack_buffer; - if (unlikely(obj_stack_maxsize > PYYJSON_OBJSTACK_BUFFER_SIZE)) { - decode_stack_vars->result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); - if (unlikely(decode_stack_vars->result_stack == NULL)) { - PyErr_NoMemory(); - return false; - } +force_inline bool init_decode_ctn_stack_info(DecodeCtnStackInfo *restrict decode_ctn_stack_info) { + DecodeCtnWithSize *new_buffer = get_decode_ctn_stack_buffer(); + if (unlikely(!new_buffer)) { + PyErr_NoMemory(); + return false; } - decode_stack_vars->cur_write_result_addr = decode_stack_vars->result_stack; -#ifndef NDEBUG - decode_stack_vars->result_stack_end = decode_stack_vars->result_stack + obj_stack_maxsize; -#endif + decode_ctn_stack_info->ctn_start = new_buffer; + decode_ctn_stack_info->ctn = new_buffer; + decode_ctn_stack_info->ctn_end = new_buffer + PYYJSON_DECODE_MAX_RECURSION; return true; } -// bool pyyjson_decode_string(){ -// PYYJSON_TRACE_OP(PYYJSON_OP_STRING); -// pyyjson_string_op *op_str = (pyyjson_string_op *) decode_stack_vars->op; -// PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(decode_stack_vars->op)); -// if (new_val == NULL) goto fail; -// PYYJSON_PUSH_STACK(new_val); -// op_str++; -// decode_stack_vars->op = (pyyjson_op *) op_str; -// break; -// } - - -PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsize) { #if PYYJSON_ENABLE_TRACE - size_t __op_counter = 0; #define PYYJSON_TRACE_OP(x) \ do { \ for (int i = 0; i < PYYJSON_OP_BITCOUNT_MAX; i++) { \ @@ -244,280 +251,487 @@ PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsiz } \ __op_counter++; \ } while (0) -#define PYYJSON_SHOW_OP_TRACE() \ - do { \ - for (int i = 0; i < PYYJSON_OP_BITCOUNT_MAX; i++) { \ - if (__count_trace[i] > 0) { \ - printf("op %d: %d\n", i, __count_trace[i]); \ - } \ - } \ - printf("total op: %lld\n", (long long int) __op_counter); \ - } while (0) - -#define PYYJSON_SHOW_STR_TRACE() printf("max str len: %lld\n", (long long int) max_str_len) -#else // PYYJSON_ENABLE_TRACE -#define PYYJSON_TRACE_OP(x) (void) (0) -#define PYYJSON_SHOW_OP_TRACE() (void) (0) -#define PYYJSON_SHOW_STR_TRACE() (void) (0) -#endif // PYYJSON_ENABLE_TRACE - DecodeStackVars _decode_stack_vars; - DecodeStackVars* const decode_stack_vars = &_decode_stack_vars; - if(unlikely(!init_decode_stack_vars(decode_stack_vars, op_head, obj_stack_maxsize))){ - return NULL; - } -// pyyjson_op *op = op_head; -// PyObject **result_stack; -// result_stack = pyobject_stack_buffer; -// if (unlikely(obj_stack_maxsize > PYYJSON_OBJSTACK_BUFFER_SIZE)) { -// result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); -// if (unlikely(result_stack == NULL)) { -// PyErr_NoMemory(); -// return NULL; -// } -// } -// PyObject **cur_write_result_addr = result_stack; -// #ifndef NDEBUG -// PyObject **result_stack_end = result_stack + obj_stack_maxsize; -// #endif -// // -// pyyjson_container_op *op_container; - -#define PYYJSON_RESULT_STACK_REALLOC_CHECK() \ - do { \ - if (new_result_stack == NULL) { \ - PyErr_NoMemory(); \ - goto fail; \ - } \ - } while (0) +#else +#define PYYJSON_TRACE_OP(x) (void)0 +#endif #ifndef NDEBUG #define PYYJSON_RESULT_STACK_GROW() \ - if (unlikely(decode_stack_vars->cur_write_result_addr >= decode_stack_vars->result_stack_end)) { \ + if (unlikely(decode_obj_stack_info->cur_write_result_addr >= decode_obj_stack_info->result_stack_end)) { \ assert(false); \ Py_UNREACHABLE(); \ } #else #define PYYJSON_RESULT_STACK_GROW() (void) (0) #endif + #define PUSH_STACK_NO_CHECK(obj) \ do { \ - *decode_stack_vars->cur_write_result_addr = obj; \ - decode_stack_vars->cur_write_result_addr++; \ + *decode_obj_stack_info->cur_write_result_addr = obj; \ + decode_obj_stack_info->cur_write_result_addr++; \ } while (0) + #define PYYJSON_PUSH_STACK(obj) \ do { \ PYYJSON_RESULT_STACK_GROW(); \ PUSH_STACK_NO_CHECK(obj); \ } while (0) -#ifndef NDEBUG -#define PYYJSON_POP_STACK_PRE_CHECK(size) \ - do { \ - if (unlikely((size) > (Py_ssize_t) (decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack))) { \ - PyErr_Format(PyExc_RuntimeError, \ - "Stack underflow: expected to have at least %lld, got %lld", \ - (size), (Py_ssize_t) (decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack)); \ - goto fail; \ - } \ - } while (0) -#else // NDEBUG -#define PYYJSON_POP_STACK_PRE_CHECK(size) (void) (0) -#endif // NDEBUG - while (1) { - switch (PYYJSON_READ_OP(decode_stack_vars->op) & PYYJSON_OP_MASK) { - case PYYJSON_OP_STRING: { - PYYJSON_TRACE_OP(PYYJSON_OP_STRING); - pyyjson_string_op *op_str = (pyyjson_string_op *) decode_stack_vars->op; - PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(decode_stack_vars->op)); - if (new_val == NULL) goto fail; - PYYJSON_PUSH_STACK(new_val); - op_str++; - decode_stack_vars->op = (pyyjson_op *) op_str; - break; - } - case PYYJSON_OP_NUMBER: { - PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); - pyyjson_number_op *op_num = (pyyjson_number_op *) decode_stack_vars->op; - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_NUM_FLAG_MASK)) { - PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_FLOAT) : { - PYYJSON_PUSH_STACK(PyFloat_FromDouble(op_num->data.f)); - break; - } - PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_INT) : { - PYYJSON_PUSH_STACK(PyLong_FromLongLong(op_num->data.i)); - break; - } - PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_UINT) : { - PYYJSON_PUSH_STACK(PyLong_FromUnsignedLongLong(op_num->data.u)); - break; - } - default: - assert(false); - Py_UNREACHABLE(); - } - op_num++; - decode_stack_vars->op = (pyyjson_op *) op_num; - break; - } - case PYYJSON_OP_CONTAINER: { - PYYJSON_TRACE_OP(PYYJSON_OP_CONTAINER); - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_CONTAINER_FLAG_MASK)) { - PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_ARRAY) : { - goto container_array; - } - PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_DICT) : { - goto container_dict; - } - default: - assert(false); - Py_UNREACHABLE(); - } - assert(false); - Py_UNREACHABLE(); - { - container_array: - decode_stack_vars->op_container = (pyyjson_container_op *) decode_stack_vars->op; - Py_ssize_t len = decode_stack_vars->op_container->len; - PyObject *list = PyList_New(len); - if (unlikely(list == NULL)) goto fail; - if (unlikely(len == 0)) { - PYYJSON_PUSH_STACK(list); - goto arr_end; - } - PYYJSON_POP_STACK_PRE_CHECK(len - 1); - PyObject **list_val_start = decode_stack_vars->cur_write_result_addr - len; - for (size_t j = 0; j < len; j++) { - PyObject *val = list_val_start[j]; - PyList_SET_ITEM(list, j, val); // this never fails - } - decode_stack_vars->cur_write_result_addr -= len; - PUSH_STACK_NO_CHECK(list); - arr_end: - decode_stack_vars->op_container++; - decode_stack_vars->op = (pyyjson_op *) decode_stack_vars->op_container; - break; - } - { - container_dict: - decode_stack_vars->op_container = (pyyjson_container_op *) decode_stack_vars->op; - Py_ssize_t len = decode_stack_vars->op_container->len; - PyObject *dict = _PyDict_NewPresized(len); - if (unlikely(dict == NULL)) goto fail; - if (unlikely(len == 0)) { - PYYJSON_PUSH_STACK(dict); - goto dict_end; - } - PYYJSON_POP_STACK_PRE_CHECK(len * 2 - 1); - PyObject **dict_val_start = decode_stack_vars->cur_write_result_addr - len * 2; - for (size_t j = 0; j < len; j++) { - PyObject *key = dict_val_start[j * 2]; - assert(PyUnicode_Check(key)); - PyObject *val = dict_val_start[j * 2 + 1]; - assert(((PyASCIIObject *) key)->hash != -1); - int retcode = _PyDict_SetItem_KnownHash(dict, key, val, ((PyASCIIObject *) key)->hash); // this may fail - if (likely(0 == retcode)) { - Py_DecRef_NoCheck(key); - Py_DecRef_NoCheck(val); - } else { - Py_DECREF(dict); - // also need to clean up the rest k-v pairs - for (size_t k = j * 2; k < len * 2; k++) { - Py_DECREF(dict_val_start[k]); - } - // move cur_write_result_addr to the first key addr, avoid double decref - decode_stack_vars->cur_write_result_addr = dict_val_start; - goto fail; - } - } - decode_stack_vars->cur_write_result_addr -= len * 2; - PUSH_STACK_NO_CHECK(dict); - dict_end: - decode_stack_vars->op_container++; - decode_stack_vars->op = (pyyjson_op *) decode_stack_vars->op_container; - break; - } - } - case PYYJSON_OP_CONSTANTS: { - PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_CONSTANTS_FLAG_MASK)) { - PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_NULL) : { - Py_Immortal_IncRef(Py_None); - PYYJSON_PUSH_STACK(Py_None); - decode_stack_vars->op++; - break; - } - PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_FALSE) : { - Py_Immortal_IncRef(Py_False); - PYYJSON_PUSH_STACK(Py_False); - decode_stack_vars->op++; - break; - } - PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_TRUE) : { - Py_Immortal_IncRef(Py_True); - PYYJSON_PUSH_STACK(Py_True); - decode_stack_vars->op++; - break; - } - default: - assert(false); - Py_UNREACHABLE(); - break; - } - break; + +bool pyyjson_push_stack(DecodeObjStackInfo *restrict decode_obj_stack_info, PyObject *obj) { + static_assert((PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1) > 0, "(PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE << 1) > 0"); + if (unlikely(decode_obj_stack_info->cur_write_result_addr >= decode_obj_stack_info->result_stack_end)) { + // resize + if (likely(PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE == decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack)) { + void *new_buffer = malloc(sizeof(PyObject *) * (PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1)); + if (unlikely(!new_buffer)) { + PyErr_NoMemory(); + return false; } - case PYYJSON_OP_NAN_INF: { - PYYJSON_TRACE_OP(PYYJSON_OP_NAN_INF); - switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_stack_vars->op), PYYJSON_NAN_INF_FLAG_MASK_WITHOUT_SIGNED)) { - PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_NAN) : { - double val = (PYYJSON_READ_OP(decode_stack_vars->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -fabs(Py_NAN) : fabs(Py_NAN); - PyObject *o = PyFloat_FromDouble(val); - assert(o); - PYYJSON_PUSH_STACK(o); - decode_stack_vars->op++; - break; - } - PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_INF) : { - double val = (PYYJSON_READ_OP(decode_stack_vars->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -Py_HUGE_VAL : Py_HUGE_VAL; - PyObject *o = PyFloat_FromDouble(val); - assert(o); - PYYJSON_PUSH_STACK(o); - decode_stack_vars->op++; - break; - } - default: - assert(false); - Py_UNREACHABLE(); - break; - } - break; + memcpy(new_buffer, decode_obj_stack_info->result_stack, sizeof(PyObject *) * PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE); + decode_obj_stack_info->result_stack = (PyObject **) new_buffer; + decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack + PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE; + decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + (PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1); + } else { + Py_ssize_t old_capacity = decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack; + if (unlikely((PY_SSIZE_T_MAX >> 1) < old_capacity)) { + PyErr_NoMemory(); + return false; } - case PYYJSON_NO_OP: { - goto success; + Py_ssize_t new_capacity = old_capacity << 1; + void *new_buffer = realloc(decode_obj_stack_info->result_stack, sizeof(PyObject *) * new_capacity); + if (unlikely(!new_buffer)) { + PyErr_NoMemory(); + return false; } - default: - assert(false); - Py_UNREACHABLE(); + decode_obj_stack_info->result_stack = (PyObject **) new_buffer; + decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack + old_capacity; + decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + new_capacity; } } -success: - assert(decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack == 1); - PyObject *result = *decode_stack_vars->result_stack; - if (unlikely(decode_stack_vars->result_stack != pyobject_stack_buffer)) free(decode_stack_vars->result_stack); - PYYJSON_SHOW_OP_TRACE(); - PYYJSON_SHOW_STR_TRACE(); - return result; -fail: - // decref all objects in the stack - for (PyObject **p = decode_stack_vars->result_stack; p < decode_stack_vars->cur_write_result_addr; p++) { - Py_DECREF(*p); - } - if (unlikely(decode_stack_vars->result_stack != pyobject_stack_buffer)) free(decode_stack_vars->result_stack); - if (PyErr_Occurred() == NULL) { - PyErr_Format(PyExc_RuntimeError, "Analyze pyyjson opcode failed at %lld", decode_stack_vars->cur_write_result_addr - decode_stack_vars->result_stack); + *decode_obj_stack_info->cur_write_result_addr++ = obj; + return true; +} + +bool pyyjson_decode_string(DecodeObjStackInfo* restrict decode_obj_stack_info, const u8 *utf8_str, Py_ssize_t len, int type_flag, bool is_key) { + PYYJSON_TRACE_OP(PYYJSON_OP_STRING); + // pyyjson_string_op *op_str = (pyyjson_string_op *) decode_obj_stack_info->op; + PyObject *new_val = make_string(utf8_str, len, type_flag, is_key); + RETURN_ON_UNLIKELY_ERR(!new_val); + return pyyjson_push_stack(decode_obj_stack_info, new_val); + // op_str++; + // decode_obj_stack_info->op = (pyyjson_op *) op_str; + // return true; +} + +force_inline bool pyyjson_decode_double(DecodeObjStackInfo* restrict decode_obj_stack_info, double val) { + PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); + PyObject* obj = PyFloat_FromDouble(val); + RETURN_ON_UNLIKELY_ERR(!obj); + return pyyjson_push_stack(decode_obj_stack_info, obj); +} + +bool pyyjson_decode_longlong(DecodeObjStackInfo* restrict decode_obj_stack_info, i64 val) { + PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); + PyObject* obj = PyLong_FromLongLong(val); + RETURN_ON_UNLIKELY_ERR(!obj); + return pyyjson_push_stack(decode_obj_stack_info, obj); +} + +bool pyyjson_decode_unsignedlonglong(DecodeObjStackInfo* restrict decode_obj_stack_info, u64 val) { + PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); + PyObject* obj = PyLong_FromUnsignedLongLong(val); + RETURN_ON_UNLIKELY_ERR(!obj); + return pyyjson_push_stack(decode_obj_stack_info, obj); +} + +bool pyyjson_decode_arr(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t arr_len) { + assert(arr_len >= 0); + // pyyjson_container_op* op_container; + //decode_obj_stack_info-> + // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; + // Py_ssize_t len = //decode_obj_stack_info-> + // op_container->len; + PyObject *list = PyList_New(arr_len); + RETURN_ON_UNLIKELY_ERR(!list); + // if (unlikely(list == NULL)) goto fail; + // if (unlikely(arr_len == 0)) { + // // goto arr_end; + // return pyyjson_push_stack(decode_obj_stack_info, list); + // } + PyObject **list_val_start = decode_obj_stack_info->cur_write_result_addr - arr_len; + assert(list_val_start >= decode_obj_stack_info->result_stack); + for (Py_ssize_t j = 0; j < arr_len; j++) { + PyObject *val = list_val_start[j]; + assert(val); + PyList_SET_ITEM(list, j, val); // this never fails + } + decode_obj_stack_info->cur_write_result_addr -= arr_len; + return pyyjson_push_stack(decode_obj_stack_info, list); + // arr_end: + //decode_obj_stack_info-> + // op_container++; + // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> + // op_container; + // return true; +} + +bool pyyjson_decode_obj(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t dict_len) { + // pyyjson_container_op* op_container; + // //decode_obj_stack_info-> + // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; + // Py_ssize_t len = //decode_obj_stack_info-> + // op_container->len; + PyObject *dict = _PyDict_NewPresized(dict_len); + RETURN_ON_UNLIKELY_ERR(!dict); + // if (unlikely(dict == NULL)) goto fail; + // if (unlikely(len == 0)) { + // PYYJSON_PUSH_STACK(dict); + // goto dict_end; + // } + // PYYJSON_POP_STACK_PRE_CHECK(len * 2 - 1); + PyObject **dict_val_start = decode_obj_stack_info->cur_write_result_addr - dict_len * 2; + PyObject **dict_val_view = dict_val_start; + for (size_t j = 0; j < dict_len; j++) { + PyObject *key = *dict_val_view++; + assert(PyUnicode_Check(key)); + PyObject *val = *dict_val_view++; + assert(((PyASCIIObject *) key)->hash != -1); + int retcode = _PyDict_SetItem_KnownHash(dict, key, val, ((PyASCIIObject *) key)->hash); // this may fail + if (likely(0 == retcode)) { + Py_DecRef_NoCheck(key); + Py_DecRef_NoCheck(val); + } else { + // we already decrefed some objects, have to manually handle all refcnt here + Py_DECREF(dict); + // also need to clean up the rest k-v pairs + for (size_t k = j * 2; k < dict_len * 2; k++) { + Py_DECREF(dict_val_start[k]); + } + // move cur_write_result_addr to the first key addr, avoid double decref + decode_obj_stack_info->cur_write_result_addr = dict_val_start; + return false; + } } - return NULL; + decode_obj_stack_info->cur_write_result_addr -= dict_len * 2; + return pyyjson_push_stack(decode_obj_stack_info, dict); + // dict_end: + //decode_obj_stack_info-> + // op_container++; + // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> + // op_container; + // break; + // return true; +} + +bool pyyjson_decode_null(DecodeObjStackInfo *restrict decode_obj_stack_info) { + PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); + Py_Immortal_IncRef(Py_None); + return pyyjson_push_stack(decode_obj_stack_info, Py_None); } +bool pyyjson_decode_false(DecodeObjStackInfo *restrict decode_obj_stack_info) { + PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); + Py_Immortal_IncRef(Py_False); + return pyyjson_push_stack(decode_obj_stack_info, Py_False); +} + +bool pyyjson_decode_true(DecodeObjStackInfo *restrict decode_obj_stack_info) { + PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); + Py_Immortal_IncRef(Py_True); + return pyyjson_push_stack(decode_obj_stack_info, Py_True); +} + +force_inline bool pyyjson_decode_nan(DecodeObjStackInfo *restrict decode_obj_stack_info, bool is_signed) { + PYYJSON_TRACE_OP(PYYJSON_OP_NAN_INF); + double val = is_signed ? -fabs(Py_NAN) : fabs(Py_NAN); + PyObject *o = PyFloat_FromDouble(val); + RETURN_ON_UNLIKELY_ERR(!o); + return pyyjson_push_stack(decode_obj_stack_info, o); + // decode_obj_stack_info->op++; + // break; +} + +force_inline bool pyyjson_decode_inf(DecodeObjStackInfo *restrict decode_obj_stack_info, bool is_signed) { + PYYJSON_TRACE_OP(PYYJSON_OP_NAN_INF); + double val = is_signed ? -fabs(Py_HUGE_VAL) : fabs(Py_HUGE_VAL); + PyObject *o = PyFloat_FromDouble(val); + RETURN_ON_UNLIKELY_ERR(!o); + return pyyjson_push_stack(decode_obj_stack_info, o); + // decode_obj_stack_info->op++; + // break; +} + +// PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsize) { +// #if PYYJSON_ENABLE_TRACE +// size_t __op_counter = 0; + +// #define PYYJSON_SHOW_OP_TRACE() \ +// do { \ +// for (int i = 0; i < PYYJSON_OP_BITCOUNT_MAX; i++) { \ +// if (__count_trace[i] > 0) { \ +// printf("op %d: %d\n", i, __count_trace[i]); \ +// } \ +// } \ +// printf("total op: %lld\n", (long long int) __op_counter); \ +// } while (0) + +// #define PYYJSON_SHOW_STR_TRACE() printf("max str len: %lld\n", (long long int) max_str_len) +// #else // PYYJSON_ENABLE_TRACE +// #define PYYJSON_SHOW_OP_TRACE() (void) (0) +// #define PYYJSON_SHOW_STR_TRACE() (void) (0) +// #endif // PYYJSON_ENABLE_TRACE +// DecodeObjStackInfo _decode_obj_stack_info; +// DecodeObjStackInfo* const decode_obj_stack_info = &_decode_obj_stack_info; +// // if(unlikely(!init_decode_obj_stack_info(decode_obj_stack_info, op_head, obj_stack_maxsize))){ +// // return NULL; +// // } +// // pyyjson_op *op = op_head; +// // PyObject **result_stack; +// // result_stack = pyobject_stack_buffer; +// // if (unlikely(obj_stack_maxsize > PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE)) { +// // result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); +// // if (unlikely(result_stack == NULL)) { +// // PyErr_NoMemory(); +// // return NULL; +// // } +// // } +// // PyObject **cur_write_result_addr = result_stack; +// // #ifndef NDEBUG +// // PyObject **result_stack_end = result_stack + obj_stack_maxsize; +// // #endif +// // // +// // pyyjson_container_op *op_container; + +// #define PYYJSON_RESULT_STACK_REALLOC_CHECK() \ +// do { \ +// if (new_result_stack == NULL) { \ +// PyErr_NoMemory(); \ +// goto fail; \ +// } \ +// } while (0) + + + +// #ifndef NDEBUG +// #define PYYJSON_POP_STACK_PRE_CHECK(size) \ +// do { \ +// if (unlikely((size) > (Py_ssize_t) (decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack))) { \ +// PyErr_Format(PyExc_RuntimeError, \ +// "Stack underflow: expected to have at least %lld, got %lld", \ +// (size), (Py_ssize_t) (decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack)); \ +// goto fail; \ +// } \ +// } while (0) +// #else // NDEBUG +// #define PYYJSON_POP_STACK_PRE_CHECK(size) (void) (0) +// #endif // NDEBUG +// while (1) { +// switch (PYYJSON_READ_OP(decode_obj_stack_info->op) & PYYJSON_OP_MASK) { +// case PYYJSON_OP_STRING: { +// // PYYJSON_TRACE_OP(PYYJSON_OP_STRING); +// // pyyjson_string_op *op_str = (pyyjson_string_op *) decode_obj_stack_info->op; +// // PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(decode_obj_stack_info->op)); +// // if (new_val == NULL) goto fail; +// // PYYJSON_PUSH_STACK(new_val); +// // op_str++; +// // decode_obj_stack_info->op = (pyyjson_op *) op_str; +// break; +// } +// case PYYJSON_OP_NUMBER: { +// PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); +// pyyjson_number_op *op_num = (pyyjson_number_op *) decode_obj_stack_info->op; +// switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_NUM_FLAG_MASK)) { +// PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_FLOAT) : { +// PYYJSON_PUSH_STACK(PyFloat_FromDouble(op_num->data.f)); +// break; +// } +// PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_INT) : { +// PYYJSON_PUSH_STACK(PyLong_FromLongLong(op_num->data.i)); +// break; +// } +// PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_UINT) : { +// PYYJSON_PUSH_STACK(PyLong_FromUnsignedLongLong(op_num->data.u)); +// break; +// } +// default: +// assert(false); +// Py_UNREACHABLE(); +// } +// op_num++; +// decode_obj_stack_info->op = (pyyjson_op *) op_num; +// break; +// } +// case PYYJSON_OP_CONTAINER: { +// // PYYJSON_TRACE_OP(PYYJSON_OP_CONTAINER); +// // switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_CONTAINER_FLAG_MASK)) { +// // PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_ARRAY) : { +// // goto container_array; +// // } +// // PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_DICT) : { +// // goto container_dict; +// // } +// // default: +// // assert(false); +// // Py_UNREACHABLE(); +// // } +// // assert(false); +// // Py_UNREACHABLE(); +// // { +// // container_array: +// // pyyjson_container_op* op_container; +// // //decode_obj_stack_info-> +// // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; +// // Py_ssize_t len = //decode_obj_stack_info-> +// // op_container->len; +// // PyObject *list = PyList_New(len); +// // if (unlikely(list == NULL)) goto fail; +// // if (unlikely(len == 0)) { +// // PYYJSON_PUSH_STACK(list); +// // goto arr_end; +// // } +// // PYYJSON_POP_STACK_PRE_CHECK(len - 1); +// // PyObject **list_val_start = decode_obj_stack_info->cur_write_result_addr - len; +// // for (size_t j = 0; j < len; j++) { +// // PyObject *val = list_val_start[j]; +// // PyList_SET_ITEM(list, j, val); // this never fails +// // } +// // decode_obj_stack_info->cur_write_result_addr -= len; +// // PUSH_STACK_NO_CHECK(list); +// // arr_end: +// // //decode_obj_stack_info-> +// // op_container++; +// // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> +// // op_container; +// // break; +// // } +// // { +// // pyyjson_container_op* op_container; +// // container_dict: +// // //decode_obj_stack_info-> +// // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; +// // Py_ssize_t len = //decode_obj_stack_info-> +// // op_container->len; +// // PyObject *dict = _PyDict_NewPresized(len); +// // if (unlikely(dict == NULL)) goto fail; +// // if (unlikely(len == 0)) { +// // PYYJSON_PUSH_STACK(dict); +// // goto dict_end; +// // } +// // PYYJSON_POP_STACK_PRE_CHECK(len * 2 - 1); +// // PyObject **dict_val_start = decode_obj_stack_info->cur_write_result_addr - len * 2; +// // for (size_t j = 0; j < len; j++) { +// // PyObject *key = dict_val_start[j * 2]; +// // assert(PyUnicode_Check(key)); +// // PyObject *val = dict_val_start[j * 2 + 1]; +// // assert(((PyASCIIObject *) key)->hash != -1); +// // int retcode = _PyDict_SetItem_KnownHash(dict, key, val, ((PyASCIIObject *) key)->hash); // this may fail +// // if (likely(0 == retcode)) { +// // Py_DecRef_NoCheck(key); +// // Py_DecRef_NoCheck(val); +// // } else { +// // Py_DECREF(dict); +// // // also need to clean up the rest k-v pairs +// // for (size_t k = j * 2; k < len * 2; k++) { +// // Py_DECREF(dict_val_start[k]); +// // } +// // // move cur_write_result_addr to the first key addr, avoid double decref +// // decode_obj_stack_info->cur_write_result_addr = dict_val_start; +// // goto fail; +// // } +// // } +// // decode_obj_stack_info->cur_write_result_addr -= len * 2; +// // PUSH_STACK_NO_CHECK(dict); +// // dict_end: +// // //decode_obj_stack_info-> +// // op_container++; +// // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> +// // op_container; +// // break; +// // } +// break; +// } +// case PYYJSON_OP_CONSTANTS: { +// // PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); +// // switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_CONSTANTS_FLAG_MASK)) { +// // PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_NULL) : { +// // Py_Immortal_IncRef(Py_None); +// // PYYJSON_PUSH_STACK(Py_None); +// // decode_obj_stack_info->op++; +// // break; +// // } +// // PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_FALSE) : { +// // Py_Immortal_IncRef(Py_False); +// // PYYJSON_PUSH_STACK(Py_False); +// // decode_obj_stack_info->op++; +// // break; +// // } +// // PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_TRUE) : { +// // Py_Immortal_IncRef(Py_True); +// // PYYJSON_PUSH_STACK(Py_True); +// // decode_obj_stack_info->op++; +// // break; +// // } +// // default: +// // assert(false); +// // Py_UNREACHABLE(); +// // break; +// // } +// break; +// } +// case PYYJSON_OP_NAN_INF: { +// // PYYJSON_TRACE_OP(PYYJSON_OP_NAN_INF); +// // switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_NAN_INF_FLAG_MASK_WITHOUT_SIGNED)) { +// // PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_NAN) : { +// // double val = (PYYJSON_READ_OP(decode_obj_stack_info->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -fabs(Py_NAN) : fabs(Py_NAN); +// // PyObject *o = PyFloat_FromDouble(val); +// // assert(o); +// // PYYJSON_PUSH_STACK(o); +// // decode_obj_stack_info->op++; +// // break; +// // } +// // PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_INF) : { +// // double val = (PYYJSON_READ_OP(decode_obj_stack_info->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -Py_HUGE_VAL : Py_HUGE_VAL; +// // PyObject *o = PyFloat_FromDouble(val); +// // assert(o); +// // PYYJSON_PUSH_STACK(o); +// // decode_obj_stack_info->op++; +// // break; +// // } +// // default: +// // assert(false); +// // Py_UNREACHABLE(); +// // break; +// // } +// break; +// } +// case PYYJSON_NO_OP: { +// goto success; +// } +// default: +// assert(false); +// Py_UNREACHABLE(); +// } +// } +// success: +// assert(decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack == 1); +// PyObject *result = *decode_obj_stack_info->result_stack; +// if (unlikely(decode_obj_stack_info->result_stack != pyobject_stack_buffer)) free(decode_obj_stack_info->result_stack); +// PYYJSON_SHOW_OP_TRACE(); +// PYYJSON_SHOW_STR_TRACE(); +// return result; +// fail: +// // decref all objects in the stack +// for (PyObject **p = decode_obj_stack_info->result_stack; p < decode_obj_stack_info->cur_write_result_addr; p++) { +// Py_DECREF(*p); +// } +// if (unlikely(decode_obj_stack_info->result_stack != pyobject_stack_buffer)) free(decode_obj_stack_info->result_stack); +// if (PyErr_Occurred() == NULL) { +// PyErr_Format(PyExc_RuntimeError, "Analyze pyyjson opcode failed at %lld", decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack); +// } +// return NULL; +// } + /** Character type table (generate with misc/make_tables.c) */ static const u8 char_table[256] = { 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, @@ -632,7 +846,7 @@ force_inline u32 read_b4_unicode(u32 uni) { @param msg The error message pointer. @return Whether success. */ -force_inline bool read_string(u8 **ptr, pyyjson_op **op, char **buffer) { +force_inline bool read_string(DecodeObjStackInfo *restrict decode_obj_stack_info, u8 **ptr, u8 *write_buffer, bool is_key) { /* Each unicode code point is encoded as 1 to 4 bytes in UTF-8 encoding, we use 4-byte mask and pattern value to validate UTF-8 byte sequence, @@ -742,7 +956,7 @@ force_inline bool read_string(u8 **ptr, pyyjson_op **op, char **buffer) { // } while (false) u8 *cur = (u8 *)*ptr; - u8 **end = (u8 **)ptr; + // u8 **end = (u8 **)ptr; /* modified BEGIN */ // u8 *src = ++cur, *dst, *pos; u8 *src = ++cur, *pos; @@ -752,8 +966,8 @@ force_inline bool read_string(u8 **ptr, pyyjson_op **op, char **buffer) { /* modified BEGIN */ u8* const src_start = src; size_t len_ucs1 = 0, len_ucs2 = 0, len_ucs4 = 0; - char* temp_string_buf = *buffer; - u8* dst = (u8*)temp_string_buf; + u8* temp_string_buf = write_buffer;//(u8*)*buffer; + u8* dst = temp_string_buf; u8 cur_max_ucs_size = 1; u16* dst_ucs2; u32* dst_ucs4; @@ -809,13 +1023,14 @@ force_inline bool read_string(u8 **ptr, pyyjson_op **op, char **buffer) { /* modified BEGIN */ // this is a fast path for ascii strings. directly copy the buffer to pyobject *ptr = src + 1; - pyyjson_string_op* string_op =(pyyjson_string_op*) *op; - PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_ASCII); - string_op->data = (char *)src_start; - string_op->len = src - src_start; - *op = (pyyjson_op*)(string_op + 1); - // buffer unchanged - return true; + return pyyjson_decode_string(decode_obj_stack_info, src_start, src - src_start, PYYJSON_STRING_TYPE_ASCII, is_key); + // pyyjson_string_op* string_op =(pyyjson_string_op*) *op; + // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_ASCII); + // string_op->data = (char *)src_start; + // string_op->len = src - src_start; + // *op = (pyyjson_op*)(string_op + 1); + // // buffer unchanged + // return true; } else if(src != src_start){ memcpy(temp_string_buf, src_start, src - src_start); @@ -1606,13 +1821,14 @@ force_inline bool read_string(u8 **ptr, pyyjson_op **op, char **buffer) { *start-- = *ucs1_back--; len_ucs1--; } - pyyjson_string_op* string_op = (pyyjson_string_op*)*op; - PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_UCS4); - string_op->data = temp_string_buf; - string_op->len = dst_ucs4 - (u32*)temp_string_buf; - *op = (pyyjson_op*)(string_op + 1); - *buffer = (char*)dst_ucs4; - return true;//create_py_unicode(temp_string_buf, dst_ucs4 - (u32*)temp_string_buf, false, 4); + return pyyjson_decode_string(decode_obj_stack_info, temp_string_buf, dst_ucs4 - (u32*)temp_string_buf, PYYJSON_STRING_TYPE_UCS4, is_key); + // pyyjson_string_op* string_op = (pyyjson_string_op*)*op; + // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_UCS4); + // string_op->data = temp_string_buf; + // string_op->len = dst_ucs4 - (u32*)temp_string_buf; + // *op = (pyyjson_op*)(string_op + 1); + // *buffer = (char*)dst_ucs4; + // return true;//create_py_unicode(temp_string_buf, dst_ucs4 - (u32*)temp_string_buf, false, 4); } else if (unlikely(cur_max_ucs_size==2)) { u16* start = (u16*)temp_string_buf + len_ucs1 - 1; u8* ucs1_back = (u8*)temp_string_buf + len_ucs1 - 1; @@ -1620,21 +1836,23 @@ force_inline bool read_string(u8 **ptr, pyyjson_op **op, char **buffer) { *start-- = *ucs1_back--; len_ucs1--; } - pyyjson_string_op* string_op = (pyyjson_string_op*) *op; - PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_UCS2); - string_op->data = temp_string_buf; - string_op->len = dst_ucs2 - (u16*)temp_string_buf; - *op = (pyyjson_op*)(string_op + 1); - *buffer = (char*)dst_ucs2; - return true;//create_py_unicode(temp_string_buf, dst_ucs2 - (u16*)temp_string_buf, false, 2); + return pyyjson_decode_string(decode_obj_stack_info, temp_string_buf, dst_ucs2 - (u16*)temp_string_buf, PYYJSON_STRING_TYPE_UCS2, is_key); + // pyyjson_string_op* string_op = (pyyjson_string_op*) *op; + // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_UCS2); + // string_op->data = temp_string_buf; + // string_op->len = dst_ucs2 - (u16*)temp_string_buf; + // *op = (pyyjson_op*)(string_op + 1); + // *buffer = (char*)dst_ucs2; + // return true;//create_py_unicode(temp_string_buf, dst_ucs2 - (u16*)temp_string_buf, false, 2); } else { - pyyjson_string_op* string_op = (pyyjson_string_op*) *op; - PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | (is_ascii ? PYYJSON_STRING_FLAG_ASCII : PYYJSON_STRING_FLAG_LATIN1)); - string_op->data = temp_string_buf; - string_op->len = dst - (u8*)temp_string_buf; - *op = (pyyjson_op*)(string_op + 1); - *buffer = (char*)dst; - return true;//create_py_unicode(temp_string_buf, dst - (u8*)temp_string_buf, false, 1); + return pyyjson_decode_string(decode_obj_stack_info, temp_string_buf, dst - (u8*)temp_string_buf, is_ascii?PYYJSON_STRING_TYPE_ASCII:PYYJSON_STRING_TYPE_LATIN1, is_key); + // pyyjson_string_op* string_op = (pyyjson_string_op*) *op; + // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | (is_ascii ? PYYJSON_STRING_FLAG_ASCII : PYYJSON_STRING_FLAG_LATIN1)); + // string_op->data = temp_string_buf; + // string_op->len = dst - (u8*)temp_string_buf; + // *op = (pyyjson_op*)(string_op + 1); + // *buffer = (char*)dst; + // return true;//create_py_unicode(temp_string_buf, dst - (u8*)temp_string_buf, false, 1); } #undef return_err @@ -1669,131 +1887,139 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { // } container_type; // static_assert(sizeof(container_type) == sizeof(Py_ssize_t), "size of container_type must be equal to size of Py_ssize_t"); -#define CONTAINER_ARR_TYPE (~0) -#define CONTAINER_OBJ_TYPE 0 +// #define CONTAINER_ARR_TYPE (~0) +// #define CONTAINER_OBJ_TYPE 0 // stack buffer length -#define STACK_BUFFER_SIZE 1024 -#define COMMON_OPSIZE_RATIO (sizeof(pyyjson_string_op) / sizeof(pyyjson_op)) -#define OP_BUFFER_INIT_SIZE (STACK_BUFFER_SIZE * COMMON_OPSIZE_RATIO) - // stack buffer - DecodeCtnWithSize *const __stack_ctn_buffer = get_decode_obj_stack_buffer(); - assert(__stack_ctn_buffer); - pyyjson_op pyobject_stack_buffer[OP_BUFFER_INIT_SIZE]; - // buffer start pointer - pyyjson_op *py_operations; - char *string_buffer_head = pyyjson_string_buffer; - DecodeCtnWithSize *ctn_start = __stack_ctn_buffer; - - usize required_len = PYYJSON_MAX( - OP_BUFFER_INIT_SIZE, - (len / PYYJSON_READER_ESTIMATED_PRETTY_RATIO) * COMMON_OPSIZE_RATIO); +// #define STACK_BUFFER_SIZE 1024 +// #define COMMON_OPSIZE_RATIO (sizeof(pyyjson_string_op) / sizeof(pyyjson_op)) +// #define OP_BUFFER_INIT_SIZE (STACK_BUFFER_SIZE * COMMON_OPSIZE_RATIO) +// #ifdef NDEBUG +// #define OBJ_STACK_MAX_SIZE_UPDATE(update_val) \ +// do { \ +// object_stack_cur_size += (update_val); \ +// object_stack_max_size = PYYJSON_MAX(object_stack_max_size, object_stack_cur_size); \ +// } while (0) +// #else +// #define OBJ_STACK_MAX_SIZE_UPDATE(update_val) \ +// do { \ +// if ((update_val) < 0 && object_stack_cur_size < (usize) (-(update_val))) { \ +// assert(false); \ +// Py_UNREACHABLE(); \ +// } \ +// object_stack_cur_size += (update_val); \ +// object_stack_max_size = PYYJSON_MAX(object_stack_max_size, object_stack_cur_size); \ +// } while (0) +// #endif +// #define OP_BUFFER_REALLOC_CHECK() \ +// do { \ +// if (new_py_operations == NULL) { \ +// PyErr_NoMemory(); \ +// goto fail_alloc; \ +// } \ +// } while (0) +// #define OP_BUFFER_GROW(offset) \ +// do { \ +// if (unlikely(offset + (u8 *) cur_write_op > (u8 *) py_operations_end)) { \ +// size_t write_offset = cur_write_op - py_operations; \ +// size_t old_capacity = py_operations_end - py_operations; \ +// size_t new_capacity = old_capacity + old_capacity / 2; \ +// pyyjson_op *new_py_operations; \ +// if (likely(py_operations == pyobject_stack_buffer)) { \ +// new_py_operations = (pyyjson_op *) malloc(new_capacity * sizeof(pyyjson_op)); \ +// OP_BUFFER_REALLOC_CHECK(); \ +// memcpy(new_py_operations, py_operations, old_capacity * sizeof(pyyjson_op)); \ +// } else { \ +// new_py_operations = (pyyjson_op *) realloc(py_operations, new_capacity * sizeof(pyyjson_op)); \ +// OP_BUFFER_REALLOC_CHECK(); \ +// } \ +// py_operations = new_py_operations; \ +// cur_write_op = new_py_operations + write_offset; \ +// py_operations_end = new_py_operations + new_capacity; \ +// } \ +// } while (0) + // container stack info + DecodeCtnStackInfo _decode_ctn_info; + DecodeCtnStackInfo* decode_ctn_info = &_decode_ctn_info; + // object stack info + DecodeObjStackInfo _decode_obj_stack_info; + DecodeObjStackInfo * const decode_obj_stack_info = &_decode_obj_stack_info; + memset(decode_ctn_info, 0, sizeof(DecodeCtnStackInfo)); + memset(decode_obj_stack_info, 0, sizeof(DecodeObjStackInfo)); + // init + if(!init_decode_ctn_stack_info(decode_ctn_info) || !init_decode_obj_stack_info(decode_obj_stack_info)) goto failed_cleanup; + // DecodeCtnWithSize *const __stack_ctn_buffer = get_decode_obj_stack_buffer(); + // assert(__stack_ctn_buffer); + // DecodeCtnWithSize *ctn_start = __stack_ctn_buffer; + // // container ptr + // DecodeCtnWithSize *const ctn_end = __stack_ctn_buffer + PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE; + // DecodeCtnWithSize *ctn = ctn_start; + // pyyjson_op pyobject_stack_buffer[OP_BUFFER_INIT_SIZE]; + // // buffer start pointer + // pyyjson_op *py_operations; + u8 * string_buffer_head =(u8 *)pyyjson_string_buffer; + + // usize required_len = PYYJSON_MAX( + // OP_BUFFER_INIT_SIZE, + // (len / PYYJSON_READER_ESTIMATED_PRETTY_RATIO) * COMMON_OPSIZE_RATIO); // py_operations ptr - pyyjson_op *py_operations_end; - if (unlikely(required_len > OP_BUFFER_INIT_SIZE)) { - py_operations = (pyyjson_op *) malloc(required_len * sizeof(pyyjson_op)); - if (!py_operations) goto fail_alloc; - py_operations_end = py_operations + required_len; - } else { - py_operations = pyobject_stack_buffer; - py_operations_end = pyobject_stack_buffer + OP_BUFFER_INIT_SIZE; - } - pyyjson_op *cur_write_op = py_operations; - usize object_stack_max_size = 0; - usize object_stack_cur_size = 0; -#ifdef NDEBUG -#define OBJ_STACK_MAX_SIZE_UPDATE(update_val) \ - do { \ - object_stack_cur_size += (update_val); \ - object_stack_max_size = PYYJSON_MAX(object_stack_max_size, object_stack_cur_size); \ - } while (0) -#else -#define OBJ_STACK_MAX_SIZE_UPDATE(update_val) \ - do { \ - if ((update_val) < 0 && object_stack_cur_size < (usize) (-(update_val))) { \ - assert(false); \ - Py_UNREACHABLE(); \ - } \ - object_stack_cur_size += (update_val); \ - object_stack_max_size = PYYJSON_MAX(object_stack_max_size, object_stack_cur_size); \ - } while (0) -#endif -#define OP_BUFFER_REALLOC_CHECK() \ - do { \ - if (new_py_operations == NULL) { \ - PyErr_NoMemory(); \ - goto fail_alloc; \ - } \ - } while (0) -#define OP_BUFFER_GROW(offset) \ - do { \ - if (unlikely(offset + (u8 *) cur_write_op > (u8 *) py_operations_end)) { \ - size_t write_offset = cur_write_op - py_operations; \ - size_t old_capacity = py_operations_end - py_operations; \ - size_t new_capacity = old_capacity + old_capacity / 2; \ - pyyjson_op *new_py_operations; \ - if (likely(py_operations == pyobject_stack_buffer)) { \ - new_py_operations = (pyyjson_op *) malloc(new_capacity * sizeof(pyyjson_op)); \ - OP_BUFFER_REALLOC_CHECK(); \ - memcpy(new_py_operations, py_operations, old_capacity * sizeof(pyyjson_op)); \ - } else { \ - new_py_operations = (pyyjson_op *) realloc(py_operations, new_capacity * sizeof(pyyjson_op)); \ - OP_BUFFER_REALLOC_CHECK(); \ - } \ - py_operations = new_py_operations; \ - cur_write_op = new_py_operations + write_offset; \ - py_operations_end = new_py_operations + new_capacity; \ - } \ - } while (0) - - // container ptr - DecodeCtnWithSize *ctn_end = __stack_ctn_buffer + PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE; - DecodeCtnWithSize *ctn = ctn_start; + // pyyjson_op *py_operations_end; + // if (unlikely(required_len > OP_BUFFER_INIT_SIZE)) { + // py_operations = (pyyjson_op *) malloc(required_len * sizeof(pyyjson_op)); + // if (!py_operations) goto fail_alloc; + // py_operations_end = py_operations + required_len; + // } else { + // py_operations = pyobject_stack_buffer; + // py_operations_end = pyobject_stack_buffer + OP_BUFFER_INIT_SIZE; + // } + // pyyjson_op *cur_write_op = py_operations; + // usize object_stack_max_size = 0; + // usize object_stack_cur_size = 0; // container buffer grow macros -#define CTN_REALLOC_CHECK() \ - do { \ - if (new_ctn_start == NULL) { \ - PyErr_NoMemory(); \ - goto fail_alloc; \ - } \ - } while (0) -#define CTN_BUFFER_GROW() \ - do { \ - if (unlikely(ctn + 1 >= ctn_end)) { \ - size_t old_capacity = ctn_end - ctn_start; \ - size_t new_capacity = old_capacity << 1; \ - DecodeCtnWithSize *new_ctn_start; \ - if (likely(old_capacity == PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE)) { \ - new_ctn_start = (DecodeCtnWithSize *) malloc(new_capacity * sizeof(DecodeCtnWithSize)); \ - CTN_REALLOC_CHECK(); \ - memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(DecodeCtnWithSize)); \ - } else { \ - new_ctn_start = (DecodeCtnWithSize *) realloc(ctn_start, new_capacity * sizeof(DecodeCtnWithSize)); \ - CTN_REALLOC_CHECK(); \ - } \ - ctn_start = new_ctn_start; \ - ctn = new_ctn_start + old_capacity; \ - ctn_end = new_ctn_start + new_capacity; \ - } \ - ctn++; \ - } while (0) -#ifdef NDEBUG -#define CHECK_STRING_BUFFER_OVERFLOW() ((void) 0) -#else -#define CHECK_STRING_BUFFER_OVERFLOW() \ - do { \ - if ((((size_t) string_buffer) + 3) / 4 * 4 > ((size_t) string_buffer_head) + 4 * len) { \ - assert(false); \ - Py_UNREACHABLE(); \ - } \ - } while (0) -#endif -#define MOVE_STRING_BUFFER_ALIGNED_4() \ - do { \ - string_buffer = (char *) ((((size_t) string_buffer) + 3) / 4 * 4); \ - } while (0) +// #define CTN_REALLOC_CHECK() \ +// do { \ +// if (new_ctn_start == NULL) { \ +// PyErr_NoMemory(); \ +// goto fail_alloc; \ +// } \ +// } while (0) +// #define CTN_BUFFER_GROW() \ +// do { \ +// if (unlikely(ctn + 1 >= ctn_end)) { \ +// size_t old_capacity = ctn_end - ctn_start; \ +// size_t new_capacity = old_capacity << 1; \ +// DecodeCtnWithSize *new_ctn_start; \ +// if (likely(old_capacity == PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE)) { \ +// new_ctn_start = (DecodeCtnWithSize *) malloc(new_capacity * sizeof(DecodeCtnWithSize)); \ +// CTN_REALLOC_CHECK(); \ +// memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(DecodeCtnWithSize)); \ +// } else { \ +// new_ctn_start = (DecodeCtnWithSize *) realloc(ctn_start, new_capacity * sizeof(DecodeCtnWithSize)); \ +// CTN_REALLOC_CHECK(); \ +// } \ +// ctn_start = new_ctn_start; \ +// ctn = new_ctn_start + old_capacity; \ +// ctn_end = new_ctn_start + new_capacity; \ +// } \ +// ctn++; \ +// } while (0) +// #ifdef NDEBUG +// #define CHECK_STRING_BUFFER_OVERFLOW() ((void) 0) +// #else +// #define CHECK_STRING_BUFFER_OVERFLOW() \ +// do { \ +// if ((((size_t) string_buffer) + 3) / 4 * 4 > ((size_t) string_buffer_head) + 4 * len) { \ +// assert(false); \ +// Py_UNREACHABLE(); \ +// } \ +// } while (0) +// #endif +// #define MOVE_STRING_BUFFER_ALIGNED_4() \ +// do { \ +// string_buffer = (char *) ((((size_t) string_buffer) + 3) / 4 * 4); \ +// } while (0) // if (unlikely(len > ((size_t) (-1)) / 4)) { goto fail_alloc; @@ -1802,21 +2028,21 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { string_buffer_head = malloc(4 * len); if (!string_buffer_head) goto fail_alloc; } - char *string_buffer = string_buffer_head; + // char *string_buffer = string_buffer_head; // u8 *cur = (u8 *) dat; u8 *end = (u8 *) dat + len; - static_assert(STACK_BUFFER_SIZE > 0, "STACK_BUFFER_SIZE should be greater than 0"); + // static_assert(STACK_BUFFER_SIZE > 0, "STACK_BUFFER_SIZE should be greater than 0"); if (*cur++ == '{') { - set_decode_ctn(ctn, 0, false); + set_decode_ctn(decode_ctn_info->ctn, 0, false); // ctn->tag = CONTAINER_OBJ_TYPE; // ctn->size = 0; // ctn++; if (*cur == '\n') cur++; goto obj_key_begin; } else { - set_decode_ctn(ctn, 0, true); + set_decode_ctn(decode_ctn_info->ctn, 0, true); // ctn->tag = CONTAINER_ARR_TYPE; // ctn->size = 0; // ctn++; @@ -1827,10 +2053,10 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { arr_begin: /* save current container */ /* create a new array value, save parent container offset */ - CTN_BUFFER_GROW(); + if(unlikely(!ctn_grow_check(decode_ctn_info))) goto fail_ctn_grow; // ctn->tag = CONTAINER_ARR_TYPE; // ctn->size = 0; - set_decode_ctn(ctn, 0, true); + set_decode_ctn(decode_ctn_info->ctn, 0, true); /* push the new array value as current container */ @@ -1860,59 +2086,59 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto arr_begin; } if (char_is_number(*cur)) { - OP_BUFFER_GROW(sizeof(pyyjson_number_op)); - pyyjson_op *now_write_op = cur_write_op; - if (likely(read_number(&cur, &cur_write_op))) { - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_number_op)); + // pyyjson_op *now_write_op = cur_write_op; + if (likely(read_number(decode_obj_stack_info, &cur))) { + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_number; } if (*cur == '"') { - OP_BUFFER_GROW(sizeof(pyyjson_string_op)); - MOVE_STRING_BUFFER_ALIGNED_4(); - if (likely(read_string(&cur, &cur_write_op, &string_buffer))) { - CHECK_STRING_BUFFER_OVERFLOW(); - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_string_op)); + // MOVE_STRING_BUFFER_ALIGNED_4(); + if (likely(read_string(decode_obj_stack_info, &cur, string_buffer_head, false))) { + // CHECK_STRING_BUFFER_OVERFLOW(); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_string; } if (*cur == 't') { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (likely(read_true(&cur))) { - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); - OBJ_STACK_MAX_SIZE_UPDATE(1); - cur_write_op++; - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (likely(_read_true(&cur) && pyyjson_decode_true(decode_obj_stack_info))) { + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + // cur_write_op++; + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_literal_true; } if (*cur == 'f') { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (likely(read_false(&cur))) { - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); - OBJ_STACK_MAX_SIZE_UPDATE(1); - cur_write_op++; - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (likely(_read_false(&cur) && pyyjson_decode_false(decode_obj_stack_info))) { + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + // cur_write_op++; + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_literal_false; } if (*cur == 'n') { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (likely(read_null(&cur))) { - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); - OBJ_STACK_MAX_SIZE_UPDATE(1); - cur_write_op++; - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (likely(_read_null(&cur) && pyyjson_decode_null(decode_obj_stack_info))) { + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + // cur_write_op++; + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } - if (read_nan(false, &cur, &cur_write_op)) { - incr_decode_ctn_size(ctn); + if (likely(_read_nan(false, &cur) && pyyjson_decode_nan(decode_obj_stack_info, false))) { + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_literal_null; @@ -1920,7 +2146,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (*cur == ']') { cur++; // if (likely(ctn_len == 0)) goto arr_end; - if (likely(get_decode_ctn_len(ctn) == 0)) goto arr_end; + if (likely(get_decode_ctn_len(decode_ctn_info->ctn) == 0)) goto arr_end; //if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto arr_end; while (*cur != ',') cur--; goto fail_trailing_comma; @@ -1931,10 +2157,10 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto arr_val_begin; } if ((*cur == 'i' || *cur == 'I' || *cur == 'N')) { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (read_inf_or_nan(false, &cur, &cur_write_op)) { - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (read_inf_or_nan(decode_obj_stack_info, false, &cur)) { + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_character_val; @@ -1964,24 +2190,25 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto fail_character_arr_end; arr_end: - OP_BUFFER_GROW(sizeof(pyyjson_container_op)); - pyyjson_container_op *list_op = (pyyjson_container_op *) cur_write_op; - PYYJSON_WRITE_OP(list_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_ARRAY); + assert(decode_ctn_is_arr(decode_ctn_info->ctn)); + if(!pyyjson_decode_arr(decode_obj_stack_info, get_decode_ctn_len(decode_ctn_info->ctn))) goto failed_cleanup; + // OP_BUFFER_GROW(sizeof(pyyjson_container_op)); + // pyyjson_container_op *list_op = (pyyjson_container_op *) cur_write_op; + // PYYJSON_WRITE_OP(list_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_ARRAY); { - Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); - OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); - list_op->len = cur_ctn_size; + // Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); + // OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); + // list_op->len = cur_ctn_size; } - cur_write_op = (pyyjson_op *) (list_op + 1); - assert(decode_ctn_is_arr(ctn)); + // cur_write_op = (pyyjson_op *) (list_op + 1); /* pop parent as current container */ - if (unlikely(ctn-- == ctn_start)) { + if (unlikely(decode_ctn_info->ctn-- == decode_ctn_info->ctn_start)) { goto doc_end; } - incr_decode_ctn_size(ctn); + incr_decode_ctn_size(decode_ctn_info->ctn); if (*cur == '\n') cur++; - if (!decode_ctn_is_arr(ctn)) { + if (!decode_ctn_is_arr(decode_ctn_info->ctn)) { goto obj_val_end; } else { goto arr_val_end; @@ -1989,8 +2216,9 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { obj_begin: /* push container */ - CTN_BUFFER_GROW(); - set_decode_ctn(ctn, 0, false); + // CTN_BUFFER_GROW(); + ctn_grow_check(decode_ctn_info); + set_decode_ctn(decode_ctn_info->ctn, 0, false); // ctn->tag = CONTAINER_OBJ_TYPE; // ctn->size = 0; if (*cur == '\n') cur++; @@ -2009,21 +2237,21 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { break; }) #endif - if (likely(*cur == '"')) { - OP_BUFFER_GROW(sizeof(pyyjson_string_op)); - pyyjson_op *write_key_op = cur_write_op; - MOVE_STRING_BUFFER_ALIGNED_4(); - if (likely(read_string(&cur, &cur_write_op, &string_buffer))) { - CHECK_STRING_BUFFER_OVERFLOW(); - OBJ_STACK_MAX_SIZE_UPDATE(1); - ((pyyjson_op_base *) write_key_op)->op |= PYYJSON_STRING_FLAG_OBJ_KEY; + if (likely(*cur == '"')) { + // OP_BUFFER_GROW(sizeof(pyyjson_string_op)); + // pyyjson_op *write_key_op = cur_write_op; + // MOVE_STRING_BUFFER_ALIGNED_4(); + if (likely(read_string(decode_obj_stack_info, &cur, string_buffer_head, true))) { + // CHECK_STRING_BUFFER_OVERFLOW(); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + // ((pyyjson_op_base *) write_key_op)->op |= PYYJSON_STRING_FLAG_OBJ_KEY; goto obj_key_end; } goto fail_string; } if (likely(*cur == '}')) { cur++; - if (likely(get_decode_ctn_len(ctn) == 0)) goto obj_end; + if (likely(get_decode_ctn_len(decode_ctn_info->ctn) == 0)) goto obj_end; goto fail_trailing_comma; } if (char_is_space(*cur)) { @@ -2051,22 +2279,22 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { obj_val_begin: if (*cur == '"') { - OP_BUFFER_GROW(sizeof(pyyjson_string_op)); - MOVE_STRING_BUFFER_ALIGNED_4(); - if (likely(read_string(&cur, &cur_write_op, &string_buffer))) { - CHECK_STRING_BUFFER_OVERFLOW(); - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_string_op)); + // MOVE_STRING_BUFFER_ALIGNED_4(); + if (likely(read_string(decode_obj_stack_info, &cur, string_buffer_head, false))) { + // CHECK_STRING_BUFFER_OVERFLOW(); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_string; } if (char_is_number(*cur)) { - OP_BUFFER_GROW(PYYJSON_MAX(sizeof(pyyjson_op), sizeof(pyyjson_number_op))); - pyyjson_op *now_write_op = cur_write_op; - if (likely(read_number(&cur, &cur_write_op))) { - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(PYYJSON_MAX(sizeof(pyyjson_op), sizeof(pyyjson_number_op))); + // pyyjson_op *now_write_op = cur_write_op; + if (likely(read_number(decode_obj_stack_info, &cur))) { + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_number; @@ -2080,38 +2308,38 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto arr_begin; } if (*cur == 't') { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (likely(read_true(&cur))) { - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); - cur_write_op++; - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (likely(_read_true(&cur) && pyyjson_decode_true(decode_obj_stack_info))) { + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); + // cur_write_op++; + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_literal_true; } if (*cur == 'f') { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (likely(read_false(&cur))) { - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); - cur_write_op++; - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (likely(_read_false(&cur) && pyyjson_decode_false(decode_obj_stack_info))) { + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); + // cur_write_op++; + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_literal_false; } if (*cur == 'n') { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (likely(read_null(&cur))) { - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); - cur_write_op++; - OBJ_STACK_MAX_SIZE_UPDATE(1); - incr_decode_ctn_size(ctn); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (likely(_read_null(&cur) && pyyjson_decode_null(decode_obj_stack_info))) { + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); + // cur_write_op++; + // OBJ_STACK_MAX_SIZE_UPDATE(1); + incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } - if (read_nan(false, &cur, &cur_write_op)) { - incr_decode_ctn_size(ctn); + if (likely(_read_nan(false, &cur) && pyyjson_decode_nan(decode_obj_stack_info, false))) { + incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_literal_null; @@ -2122,10 +2350,10 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto obj_val_begin; } if ((*cur == 'i' || *cur == 'I' || *cur == 'N')) { - OP_BUFFER_GROW(sizeof(pyyjson_op)); - if (read_inf_or_nan(false, &cur, &cur_write_op)) { - incr_decode_ctn_size(ctn); - OBJ_STACK_MAX_SIZE_UPDATE(1); + // OP_BUFFER_GROW(sizeof(pyyjson_op)); + if (read_inf_or_nan(decode_obj_stack_info, false, &cur)) { + incr_decode_ctn_size(decode_ctn_info->ctn); + // OBJ_STACK_MAX_SIZE_UPDATE(1); goto obj_val_end; } goto fail_character_val; @@ -2155,24 +2383,25 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto fail_character_obj_end; obj_end: - OP_BUFFER_GROW(sizeof(pyyjson_container_op)); - pyyjson_container_op *dict_op = (pyyjson_container_op *) cur_write_op; - PYYJSON_WRITE_OP(dict_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_DICT); - { - Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); - OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); - dict_op->len = cur_ctn_size; - } - cur_write_op = (pyyjson_op *) (dict_op + 1); - assert(!decode_ctn_is_arr(ctn)); + assert(!decode_ctn_is_arr(decode_ctn_info->ctn)); + if(unlikely(!pyyjson_decode_obj(decode_obj_stack_info, get_decode_ctn_len(decode_ctn_info->ctn)))) goto failed_cleanup; + // OP_BUFFER_GROW(sizeof(pyyjson_container_op)); + // pyyjson_container_op *dict_op = (pyyjson_container_op *) cur_write_op; + // PYYJSON_WRITE_OP(dict_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_DICT); + // { + // Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); + // OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); + // dict_op->len = cur_ctn_size; + // } + // cur_write_op = (pyyjson_op *) (dict_op + 1); /* pop container */ /* point to the next value */ - if (unlikely(ctn-- == ctn_start)) { + if (unlikely(decode_ctn_info->ctn-- == decode_ctn_info->ctn_start)) { goto doc_end; } - incr_decode_ctn_size(ctn); + incr_decode_ctn_size(decode_ctn_info->ctn); if (*cur == '\n') cur++; - if (decode_ctn_is_arr(ctn)) { + if (decode_ctn_is_arr(decode_ctn_info->ctn)) { goto arr_val_end; } else { goto obj_val_end; @@ -2186,25 +2415,32 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (unlikely(cur < end)) goto fail_garbage; } - assert(ctn == ctn_start - 1); + assert(decode_ctn_info->ctn == decode_ctn_info->ctn_start - 1); // free ctn buffer before calling pyyjson_op_loads. - if (unlikely(ctn_start != __stack_ctn_buffer)) { - free(ctn_start); - } + // if (unlikely(decode_ctn_info->ctn_start != __stack_ctn_buffer)) { + // free(ctn_start); + // } // add null terminate to op buffer - OP_BUFFER_GROW(sizeof(pyyjson_op_base)); - PYYJSON_WRITE_OP(cur_write_op, PYYJSON_NO_OP); - OBJ_STACK_MAX_SIZE_UPDATE(1); - PyObject *obj; - obj = pyyjson_op_loads(py_operations, object_stack_max_size); + // OP_BUFFER_GROW(sizeof(pyyjson_op_base)); + // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_NO_OP); + // OBJ_STACK_MAX_SIZE_UPDATE(1); + assert(decode_obj_stack_info->cur_write_result_addr == decode_obj_stack_info->result_stack + 1); + PyObject *obj = *decode_obj_stack_info->result_stack; + assert(obj); + assert(obj->ob_refcnt == 1); + // TODO + // obj = pyyjson_op_loads(py_operations, object_stack_max_size); // free py_operations - if (py_operations != pyobject_stack_buffer) { - free(py_operations); - } + // if (py_operations != pyobject_stack_buffer) { + // free(py_operations); + // } // free string buffer if (unlikely(string_buffer_head != pyyjson_string_buffer)) { free(string_buffer_head); } + if(unlikely(decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack > PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE)){ + free(decode_obj_stack_info->result_stack); + } // check if (!obj && !PyErr_Occurred()) { PyErr_SetString(PyExc_RuntimeError, "Unknown error: pyyjson_op_loads() failed"); @@ -2252,16 +2488,19 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { fail_garbage: return_err(cur, JSONDecodeError, "unexpected content after document"); +fail_ctn_grow: + return_err(cur, JSONDecodeError, + "max recursion exceeded"); failed_cleanup: // free ctn_start - if (ctn_start != __stack_ctn_buffer) { - free(ctn_start); - } + // if (ctn_start != __stack_ctn_buffer) { + // free(ctn_start); + // } // free py_operations - if (py_operations != pyobject_stack_buffer) { - free(py_operations); - } + // if (py_operations != pyobject_stack_buffer) { + // free(py_operations); + // } // free string buffer. this need NULL check if (unlikely(string_buffer_head != pyyjson_string_buffer)) { free(string_buffer_head); @@ -2275,11 +2514,11 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { #undef OP_BUFFER_GROW #undef OP_BUFFER_REALLOC_CHECK #undef OBJ_STACK_MAX_SIZE_UPDATE -#undef OP_BUFFER_INIT_SIZE -#undef COMMON_OPSIZE_RATIO -#undef STACK_BUFFER_SIZE -#undef CONTAINER_OBJ_TYPE -#undef CONTAINER_ARR_TYPE +// #undef OP_BUFFER_INIT_SIZE +// #undef COMMON_OPSIZE_RATIO +// #undef STACK_BUFFER_SIZE +// #undef CONTAINER_OBJ_TYPE +// #undef CONTAINER_ARR_TYPE #undef return_err } diff --git a/src/decode/decode.h b/src/decode/decode.h index c9ffa64..471c8b5 100644 --- a/src/decode/decode.h +++ b/src/decode/decode.h @@ -3,6 +3,14 @@ #include "pyyjson.h" #include +#define PYYJSON_STRING_TYPE_ASCII 0 +#define PYYJSON_STRING_TYPE_LATIN1 1 +#define PYYJSON_STRING_TYPE_UCS2 2 +#define PYYJSON_STRING_TYPE_UCS4 3 + +#define PYYJSON_NUM_TYPE_FLOAT 0 +#define PYYJSON_NUM_TYPE_INT 1 +#define PYYJSON_NUM_TYPE_UINT 2 // hot spot: // string -> float,int->array,dict->null,false,true. least: uint, nan, inf #define PYYJSON_NO_OP (0) @@ -18,17 +26,17 @@ // higher start: 8 #define PYYJSON_OP_HIGHER_START (1 << PYYJSON_OP_BITCOUNT_MAX) //string flags ~~ -#define PYYJSON_STRING_FLAG_ASCII (0 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_LATIN1 (1 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_UCS2 (2 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_UCS4 (3 << PYYJSON_OP_BITCOUNT_MAX) +#define PYYJSON_STRING_FLAG_ASCII (PYYJSON_STRING_TYPE_ASCII << PYYJSON_OP_BITCOUNT_MAX) +#define PYYJSON_STRING_FLAG_LATIN1 (PYYJSON_STRING_TYPE_LATIN1 << PYYJSON_OP_BITCOUNT_MAX) +#define PYYJSON_STRING_FLAG_UCS2 (PYYJSON_STRING_TYPE_UCS2 << PYYJSON_OP_BITCOUNT_MAX) +#define PYYJSON_STRING_FLAG_UCS4 (PYYJSON_STRING_TYPE_UCS4 << PYYJSON_OP_BITCOUNT_MAX) #define PYYJSON_STRING_FLAG_UCS_TYPE_MASK (3 << PYYJSON_OP_BITCOUNT_MAX) // is key ~~ #define PYYJSON_STRING_FLAG_OBJ_KEY (4 << PYYJSON_OP_BITCOUNT_MAX) // num flags ~~ #define PYYJSON_NUM_FLAG_FLOAT (0 << PYYJSON_OP_BITCOUNT_MAX) #define PYYJSON_NUM_FLAG_INT (1 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_NUM_FLAG_UINT (2 << PYYJSON_OP_BITCOUNT_MAX) +// #define PYYJSON_NUM_FLAG_UINT (2 << PYYJSON_OP_BITCOUNT_MAX) #define PYYJSON_NUM_FLAG_MASK (3 << PYYJSON_OP_BITCOUNT_MAX) // container flags ~~ #define PYYJSON_CONTAINER_FLAG_ARRAY (0 << PYYJSON_OP_BITCOUNT_MAX) @@ -74,6 +82,12 @@ typedef struct pyyjson_op { PYYJSON_OP_PADDING } pyyjson_op; +typedef union { + int64_t i; + uint64_t u; + double f; +} num_data; + // size = 12 / 16 typedef struct pyyjson_number_op { PYYJSON_OP_HEAD @@ -109,12 +123,28 @@ typedef union v32_uni { v32 v; u32 u; } v32_uni; typedef union v64_uni { v64 v; u64 u; } v64_uni; +typedef struct DecodeObjStackInfo { + // pyyjson_op *op; + PyObject **cur_write_result_addr; + PyObject **result_stack; + // pyyjson_container_op *op_container; + PyObject **result_stack_end; +} DecodeObjStackInfo; + +typedef struct DecodeCtnWithSize DecodeCtnWithSize; + +typedef struct DecodeCtnStackInfo { + DecodeCtnWithSize *ctn; + DecodeCtnWithSize *ctn_start; + DecodeCtnWithSize *ctn_end; +} DecodeCtnStackInfo; + + PyObject *pyyjson_op_loads(pyyjson_op *op_sequence, size_t obj_stack_maxsize); extern PyObject *JSONDecodeError; typedef PyObject *pyyjson_cache_type; -extern pyyjson_cache_type AssociativeKeyCache[PYYJSON_KEY_CACHE_SIZE]; // static assertions static_assert((sizeof(pyyjson_number_op) % sizeof(pyyjson_op)) == 0, "size of pyyjson_number_op must be multiple of size of pyyjson_op"); @@ -326,8 +356,12 @@ force_inline u32 byte_load_4(const void *src) { * These functions are used by JSON reader to read literals and comments. *============================================================================*/ +force_inline bool pyyjson_decode_inf(DecodeObjStackInfo *restrict decode_obj_stack_info, bool is_signed); + +force_inline bool pyyjson_decode_nan(DecodeObjStackInfo *restrict decode_obj_stack_info, bool is_signed); + /** Read 'true' literal, '*cur' should be 't'. */ -force_inline bool read_true(u8 **ptr) { +force_inline bool _read_true(u8 **ptr) { u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; if (likely(byte_match_4(cur, "true"))) { @@ -339,7 +373,7 @@ force_inline bool read_true(u8 **ptr) { } /** Read 'false' literal, '*cur' should be 'f'. */ -force_inline bool read_false(u8 **ptr) { +force_inline bool _read_false(u8 **ptr) { u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; if (likely(byte_match_4(cur + 1, "alse"))) { @@ -351,7 +385,7 @@ force_inline bool read_false(u8 **ptr) { } /** Read 'null' literal, '*cur' should be 'n'. */ -force_inline bool read_null(u8 **ptr) { +force_inline bool _read_null(u8 **ptr) { u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; if (likely(byte_match_4(cur, "null"))) { @@ -363,7 +397,7 @@ force_inline bool read_null(u8 **ptr) { } /** Read 'Inf' or 'Infinity' literal (ignoring case). */ -force_inline bool read_inf(bool sign, u8 **ptr, pyyjson_op **op) { +force_inline bool _read_inf(bool sign, u8 **ptr) { u8 *hdr = (u8 *)(*ptr - sign); u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; @@ -390,16 +424,16 @@ force_inline bool read_inf(bool sign, u8 **ptr, pyyjson_op **op) { // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; // val->uni.u64 = f64_raw_get_inf(sign); // } - pyyjson_op* op_inf = *op; - PYYJSON_WRITE_OP(op_inf, PYYJSON_OP_NAN_INF | PYYJSON_NAN_INF_FLAG_INF | (sign ? PYYJSON_NAN_INF_FLAG_SIGNED : 0)); - *op = (op_inf + 1); + // pyyjson_op* op_inf = *op; + // PYYJSON_WRITE_OP(op_inf, PYYJSON_OP_NAN_INF | PYYJSON_NAN_INF_FLAG_INF | (sign ? PYYJSON_NAN_INF_FLAG_SIGNED : 0)); + // *op = (op_inf + 1); return true; } return false; } /** Read 'NaN' literal (ignoring case). */ -force_inline bool read_nan(bool sign, u8 **ptr, pyyjson_op **op) { +force_inline bool _read_nan(bool sign, u8 **ptr) { u8 *hdr = (u8 *)(*ptr - sign); u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; @@ -418,18 +452,22 @@ force_inline bool read_nan(bool sign, u8 **ptr, pyyjson_op **op) { // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; // val->uni.u64 = f64_raw_get_nan(sign); // } - pyyjson_op* op_nan = *op; - PYYJSON_WRITE_OP(op_nan, PYYJSON_OP_NAN_INF | PYYJSON_NAN_INF_FLAG_NAN | (sign ? PYYJSON_NAN_INF_FLAG_SIGNED : 0)); - *op = (op_nan + 1); + // pyyjson_op* op_nan = *op; + // PYYJSON_WRITE_OP(op_nan, PYYJSON_OP_NAN_INF | PYYJSON_NAN_INF_FLAG_NAN | (sign ? PYYJSON_NAN_INF_FLAG_SIGNED : 0)); + // *op = (op_nan + 1); return true; } return false; } /** Read 'Inf', 'Infinity' or 'NaN' literal (ignoring case). */ -force_inline bool read_inf_or_nan(bool sign, u8 **ptr, pyyjson_op **op) { - if (read_inf(sign, ptr, op)) return true; - if (read_nan(sign, ptr, op)) return true; +force_inline bool read_inf_or_nan(DecodeObjStackInfo *decode_obj_stack_info, bool sign, u8 **ptr) { + if (_read_inf(sign, ptr)) { + return pyyjson_decode_inf(decode_obj_stack_info, sign); + } + if (_read_nan(sign, ptr)) { + return pyyjson_decode_nan(decode_obj_stack_info, sign); + } return false; } diff --git a/src/decode/decode_float.inl.h b/src/decode/decode_float.inl.h index 9555799..1eb69e2 100644 --- a/src/decode/decode_float.inl.h +++ b/src/decode/decode_float.inl.h @@ -1,7 +1,6 @@ #include "decode.h" - /** Microsoft Visual C++ 6.0 doesn't support converting number from u64 to f64: error C2520: conversion from unsigned __int64 to double not implemented. @@ -95,7 +94,9 @@ force_inline f64 normalized_u64_to_f64(u64 val) { #endif } +force_inline bool pyyjson_decode_double(DecodeObjStackInfo* restrict decode_obj_stack_info, double val); +force_inline bool pyyjson_decode_longlong(DecodeObjStackInfo* restrict decode_obj_stack_info, i64 val); /*============================================================================== * 128-bit Integer Utils @@ -427,7 +428,7 @@ static const f64 f64_pow10_table[] = { number is infinite, the return value is based on flag. 3. This function (with inline attribute) may generate a lot of instructions. */ -force_inline bool read_number(u8 **ptr, pyyjson_op **op) { +force_inline bool read_number(DecodeObjStackInfo *decode_obj_stack_info, u8 **ptr) { #define return_err(_end, _msg) \ do { \ @@ -435,36 +436,57 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { return false; \ } while (0) +// #define return_0() do { \ +// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ +// op_int->data.i = 0; \ +// *op = (pyyjson_op*)(op_int + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_0() do { \ - pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ - op_int->data.i = 0; \ - *op = (pyyjson_op*)(op_int + 1); \ - *end = cur; return true; \ + *end = cur; \ + return pyyjson_decode_longlong(decode_obj_stack_info, 0); \ } while (false) +// #define return_i64(_v) do { \ +// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ +// op_int->data.u = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ +// *op = (pyyjson_op*)(op_int + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_i64(_v) do { \ - pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ - op_int->data.u = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ - *op = (pyyjson_op*)(op_int + 1); \ - *end = cur; return true; \ + *end = cur; \ + return pyyjson_decode_longlong(decode_obj_stack_info, (i64)(sign ? (u64)(~(_v) + 1) : (u64)(_v))); \ } while (false) - + +// #define return_f64(_v) do { \ +// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ +// op_float->data.f = sign ? -(f64)(_v) : (f64)(_v); \ +// *op = (pyyjson_op*)(op_float + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_f64(_v) do { \ - pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ - op_float->data.f = sign ? -(f64)(_v) : (f64)(_v); \ - *op = (pyyjson_op*)(op_float + 1); \ - *end = cur; return true; \ + *end = cur; \ + return pyyjson_decode_double(decode_obj_stack_info, sign ? -(f64)(_v) : (f64)(_v)); \ } while (false) +// #define return_f64_bin(_v) do { \ +// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ +// op_float->data.u = ((u64)sign << 63) | (u64)(_v); \ +// *op = (pyyjson_op*)(op_float + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_f64_bin(_v) do { \ - pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ - op_float->data.u = ((u64)sign << 63) | (u64)(_v); \ - *op = (pyyjson_op*)(op_float + 1); \ - *end = cur; return true; \ + *end = cur; \ + u64 temp = ((u64)sign << 63) | (u64)(_v); \ + return pyyjson_decode_double(decode_obj_stack_info, *(double *)&temp); \ } while (false) #define return_inf() do { \ @@ -508,12 +530,15 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { if (unlikely(!digi_is_nonzero(*cur))) { /* 0 or non-digit char */ if (unlikely(*cur != '0')) { /* non-digit char */ //if (has_read_flag(ALLOW_INF_AND_NAN)) { - if (read_inf_or_nan(sign, &cur, op)) { + if (read_inf_or_nan(decode_obj_stack_info, sign, &cur)) { *end = cur; return true; } //} - return_err(cur, "no digit after minus sign"); + if(unlikely(!PyErr_Occurred())){ + return_err(cur, "no digit after minus sign"); + } + return false; } /* begin with 0 */ if (likely(!digi_is_digit_or_fp(*++cur))) return_0(); @@ -1041,7 +1066,7 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { This is a fallback function if the custom number reader is disabled. This function use libc's strtod() to read floating-point number. */ -force_inline bool read_number(u8 **ptr, pyyjson_op **op) { +force_inline bool read_number(DecodeObjStackInfo *decode_obj_stack_info, u8 **ptr) { #define return_err(_end, _msg) \ do { \ @@ -1049,36 +1074,57 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { return false; \ } while (0) +// #define return_0() do { \ +// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ +// op_int->data.i = 0; \ +// *op = (pyyjson_op*)(op_int + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_0() do { \ - pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ - op_int->data.i = 0; \ - *op = (pyyjson_op*)(op_int + 1); \ - *end = cur; return true; \ + *end = cur; \ + return pyyjson_decode_longlong(decode_obj_stack_info, 0); \ } while (false) +// #define return_i64(_v) do { \ +// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ +// op_int->data.u = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ +// *op = (pyyjson_op*)(op_int + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_i64(_v) do { \ - pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ - op_int->data.u = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ - *op = (pyyjson_op*)(op_int + 1); \ - *end = cur; return true; \ + *end = cur; \ + return pyyjson_decode_longlong(decode_obj_stack_info, (i64)(sign ? (u64)(~(_v) + 1) : (u64)(_v))); \ } while (false) - + +// #define return_f64(_v) do { \ +// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ +// op_float->data.f = sign ? -(f64)(_v) : (f64)(_v); \ +// *op = (pyyjson_op*)(op_float + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_f64(_v) do { \ - pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ - op_float->data.f = sign ? -(f64)(_v) : (f64)(_v); \ - *op = (pyyjson_op*)(op_float + 1); \ - *end = cur; return true; \ + *end = cur; \ + return pyyjson_decode_double(decode_obj_stack_info, sign ? -(f64)(_v) : (f64)(_v)); \ } while (false) +// #define return_f64_bin(_v) do { \ +// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ +// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ +// op_float->data.u = ((u64)sign << 63) | (u64)(_v); \ +// *op = (pyyjson_op*)(op_float + 1); \ +// *end = cur; return true; \ +// } while (false) + #define return_f64_bin(_v) do { \ - pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ - PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ - op_float->data.u = ((u64)sign << 63) | (u64)(_v); \ - *op = (pyyjson_op*)(op_float + 1); \ - *end = cur; return true; \ + *end = cur; \ + u64 temp = ((u64)sign << 63) | (u64)(_v); \ + return pyyjson_decode_double(decode_obj_stack_info, *(double *)&temp); \ } while (false) #define return_inf() do { \ @@ -1100,12 +1146,15 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { /* read first digit, check leading zero */ if (unlikely(!digi_is_digit(*cur))) { // if (has_read_flag(ALLOW_INF_AND_NAN)) { - if (read_inf_or_nan(sign, &cur, op)) { + if (read_inf_or_nan(decode_obj_stack_info, sign, &cur)) { *end = cur; return true; } // } - return_err(cur, "no digit after minus sign"); + if(unlikely(!PyErr_Occurred())){ + return_err(cur, "no digit after minus sign"); + } + return false; } if (*cur == '0') { cur++; @@ -1189,14 +1238,15 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { Here strtod() is called twice for different locales, but if another thread happens calls setlocale() between two strtod(), parsing may still fail. */ - pyyjson_number_op* op_float_final = (pyyjson_number_op*)*op; - op_float_final->data.f = strtod((const char *)hdr, (char **)&f64_end); + // pyyjson_number_op* op_float_final = (pyyjson_number_op*)*op; + double f = strtod((const char *)hdr, (char **)&f64_end); if (unlikely(f64_end != cur)) { /* replace '.' with ',' for locale */ bool cut = (*cur == ','); if (cut) *cur = ' '; if (dot) *dot = ','; - op_float_final->data.f = strtod((const char *)hdr, (char **)&f64_end); + // op_float_final->data. + f = strtod((const char *)hdr, (char **)&f64_end); /* restore ',' to '.' */ if (cut) *cur = ','; if (dot) *dot = '.'; @@ -1204,13 +1254,15 @@ force_inline bool read_number(u8 **ptr, pyyjson_op **op) { return_err(hdr, "strtod() failed to parse the number"); } } - if (unlikely(op_float_final->data.f >= HUGE_VAL || op_float_final->data.f <= -HUGE_VAL)) { + if (unlikely(f >= HUGE_VAL || f <= -HUGE_VAL)) { return_inf(); } - PYYJSON_WRITE_OP(op_float_final, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); - *op = (pyyjson_op*)(op_float_final + 1); + + // PYYJSON_WRITE_OP(op_float_final, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); + // *op = (pyyjson_op*)(op_float_final + 1); // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; *end = cur; + return pyyjson_decode_double(decode_obj_stack_info, f); return true; #undef return_err diff --git a/src/encode/encode_impl.c b/src/encode/encode_impl.c index ed748ed..ab6912d 100644 --- a/src/encode/encode_impl.c +++ b/src/encode/encode_impl.c @@ -228,12 +228,7 @@ force_inline PyFastTypes fast_type_check(PyObject *val) { } } -#define RETURN_ON_UNLIKELY_ERR(x) \ - do { \ - if (unlikely((x))) { \ - return false; \ - } \ - } while (0) + #define TAIL_PADDING (512 / 8) diff --git a/src/pyyjson.c b/src/pyyjson.c index 83287d1..f531e03 100644 --- a/src/pyyjson.c +++ b/src/pyyjson.c @@ -1,7 +1,6 @@ #define PY_SSIZE_T_CLEAN #include "pyyjson.h" #include "tls.h" -#include "decode/decode.h" #if defined(_MSC_VER) #include @@ -15,6 +14,9 @@ void cpuid(int info[4], int x) { #define MODULE_STATE(o) ((modulestate *) PyModule_GetState(o)) +typedef PyObject *pyyjson_cache_type; + +extern pyyjson_cache_type AssociativeKeyCache[PYYJSON_KEY_CACHE_SIZE]; PyObject *yyjson_read_opts(const char *dat, size_t len); // bool is_lzcnt_supported(void); diff --git a/src/pyyjson.h b/src/pyyjson.h index fb00026..837865d 100644 --- a/src/pyyjson.h +++ b/src/pyyjson.h @@ -247,6 +247,14 @@ static_assert(false, "false"); #endif +/* Helper for quickly write an err handle. */ +#define RETURN_ON_UNLIKELY_ERR(x) \ + do { \ + if (unlikely((x))) { \ + return false; \ + } \ + } while (0) + /*============================================================================== * Digit Character Matcher *============================================================================*/ diff --git a/src/pyyjson_config.h b/src/pyyjson_config.h index 1a7dffa..602cc31 100644 --- a/src/pyyjson_config.h +++ b/src/pyyjson_config.h @@ -43,21 +43,29 @@ #define PYYJSON_KEY_CACHE_SIZE (1 << 11) #endif -/* Stack buffer for PyObject*. Default cost: 8 * 1024 = 8kb (per thread). */ -#ifndef PYYJSON_OBJSTACK_BUFFER_SIZE -#define PYYJSON_OBJSTACK_BUFFER_SIZE (1024) -#endif +// /* Stack buffer for PyObject*. Default cost: 8 * 1024 = 8kb (per thread). */ +// #ifndef PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE +// #define PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE (1024) +// #endif #ifndef PYYJSON_READER_ESTIMATED_PRETTY_RATIO #define PYYJSON_READER_ESTIMATED_PRETTY_RATIO 16 #endif /* - Init buffer size for decode container buffer. + Init buffer size for decode object buffer. + Cost: PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE * sizeof(void*) bytes per thread. + */ +#ifndef PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE +#define PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE (1024) +#endif + +/* + Buffer size for decode container buffer. Cost: PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE * sizeof(Py_ssize_t) bytes per thread. */ -#ifndef PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE -#define PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE (1024) +#ifndef PYYJSON_DECODE_MAX_RECURSION +#define PYYJSON_DECODE_MAX_RECURSION (1024) #endif /* diff --git a/src/tls.c b/src/tls.c index 26e7f7b..e5e86e6 100644 --- a/src/tls.c +++ b/src/tls.c @@ -4,6 +4,7 @@ TLS_KEY_TYPE _EncodeObjStackBuffer_Key; TLS_KEY_TYPE _DecodeObjStackBuffer_Key; +TLS_KEY_TYPE _DecodeCtnStackBuffer_Key; void _tls_buffer_destructor(void *ptr) { if (ptr) free(ptr); @@ -15,11 +16,14 @@ bool pyyjson_tls_init(void) { #if defined(_POSIX_THREADS) success = success && (0 == pthread_key_create(&_EncodeObjStackBuffer_Key, _tls_buffer_destructor)); success = success && (0 == pthread_key_create(&_DecodeObjStackBuffer_Key, _tls_buffer_destructor)); + success = success && (0 == pthread_key_create(&_DecodeCtnStackBuffer_Key, _tls_buffer_destructor)); #else if (success) _EncodeObjStackBuffer_Key = FlsAlloc(_tls_buffer_destructor); if (_EncodeObjStackBuffer_Key == FLS_OUT_OF_INDEXES) success = false; if (success) _DecodeObjStackBuffer_Key = FlsAlloc(_tls_buffer_destructor); if (_DecodeObjStackBuffer_Key == FLS_OUT_OF_INDEXES) success = false; + if (success) _DecodeCtnStackBuffer_Key = FlsAlloc(_tls_buffer_destructor); + if (_DecodeCtnStackBuffer_Key == FLS_OUT_OF_INDEXES) success = false; #endif return success; } @@ -29,9 +33,11 @@ bool pyyjson_tls_free(void) { #if defined(_POSIX_THREADS) success = success && (0 == pthread_key_delete(_EncodeObjStackBuffer_Key)); success = success && (0 == pthread_key_delete(_DecodeObjStackBuffer_Key)); + success = success && (0 == pthread_key_delete(_DecodeCtnStackBuffer_Key)); #else success = success && FlsFree(_EncodeObjStackBuffer_Key); success = success && FlsFree(_DecodeObjStackBuffer_Key); + success = success && FlsFree(_DecodeCtnStackBuffer_Key); #endif return success; } diff --git a/src/tls.h b/src/tls.h index 67be1a7..fe9bb77 100644 --- a/src/tls.h +++ b/src/tls.h @@ -68,19 +68,47 @@ force_inline EncodeCtnWithIndex *get_encode_obj_stack_buffer(void) { * Thread Local Decode buffer *============================================================================*/ /* Decode TLS buffer key. */ -extern TLS_KEY_TYPE _DecodeObjStackBuffer_Key; +extern TLS_KEY_TYPE _DecodeCtnStackBuffer_Key; typedef struct DecodeCtnWithSize { Py_ssize_t raw; } DecodeCtnWithSize; +PYYJSON_DECLARE_TLS_GETTER(_DecodeCtnStackBuffer_Key, _get_decode_ctn_stack_buffer_pointer) +PYYJSON_DECLARE_TLS_SETTER(_DecodeCtnStackBuffer_Key, _set_decode_ctn_stack_buffer_pointer) + +force_inline DecodeCtnWithSize *get_decode_ctn_stack_buffer(void) { + void *value = _get_decode_ctn_stack_buffer_pointer(); + if (unlikely(value == NULL)) { + value = malloc(PYYJSON_DECODE_MAX_RECURSION * sizeof(DecodeCtnWithSize)); + if (unlikely(value == NULL)) return NULL; + bool succ = _set_decode_ctn_stack_buffer_pointer(value); + if (unlikely(!succ)) { + free(value); + return NULL; + } + } + return (DecodeCtnWithSize *) value; +} + + +/*============================================================================== + * Thread Local Decode buffer + *============================================================================*/ +/* Decode TLS buffer key. */ +extern TLS_KEY_TYPE _DecodeObjStackBuffer_Key; + +// typedef struct DecodeCtnWithSize { +// Py_ssize_t raw; +// } DecodeCtnWithSize; + PYYJSON_DECLARE_TLS_GETTER(_DecodeObjStackBuffer_Key, _get_decode_obj_stack_buffer_pointer) PYYJSON_DECLARE_TLS_SETTER(_DecodeObjStackBuffer_Key, _set_decode_obj_stack_buffer_pointer) -force_inline DecodeCtnWithSize *get_decode_obj_stack_buffer(void) { +force_inline PyObject **get_decode_obj_stack_buffer(void) { void *value = _get_decode_obj_stack_buffer_pointer(); if (unlikely(value == NULL)) { - value = malloc(PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE * sizeof(DecodeCtnWithSize)); + value = malloc(PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE * sizeof(PyObject *)); if (unlikely(value == NULL)) return NULL; bool succ = _set_decode_obj_stack_buffer_pointer(value); if (unlikely(!succ)) { @@ -88,7 +116,8 @@ force_inline DecodeCtnWithSize *get_decode_obj_stack_buffer(void) { return NULL; } } - return (DecodeCtnWithSize *) value; + return (PyObject **) value; } + #endif // PYYJSON_TLS_H From 6026def6b39f10a0c05b452ca444514538e30b43 Mon Sep 17 00:00:00 2001 From: antares Date: Tue, 17 Dec 2024 23:38:15 +0800 Subject: [PATCH 07/12] fix performance: force inlining decode functions --- src/decode/decode.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/decode/decode.c b/src/decode/decode.c index 17d6dfa..113107e 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -278,7 +278,8 @@ force_inline bool init_decode_ctn_stack_info(DecodeCtnStackInfo *restrict decode PUSH_STACK_NO_CHECK(obj); \ } while (0) -bool pyyjson_push_stack(DecodeObjStackInfo *restrict decode_obj_stack_info, PyObject *obj) { + +force_inline bool pyyjson_push_stack(DecodeObjStackInfo *restrict decode_obj_stack_info, PyObject *obj) { static_assert((PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1) > 0, "(PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE << 1) > 0"); if (unlikely(decode_obj_stack_info->cur_write_result_addr >= decode_obj_stack_info->result_stack_end)) { // resize @@ -313,7 +314,7 @@ bool pyyjson_push_stack(DecodeObjStackInfo *restrict decode_obj_stack_info, PyOb return true; } -bool pyyjson_decode_string(DecodeObjStackInfo* restrict decode_obj_stack_info, const u8 *utf8_str, Py_ssize_t len, int type_flag, bool is_key) { +force_inline bool pyyjson_decode_string(DecodeObjStackInfo* restrict decode_obj_stack_info, const u8 *utf8_str, Py_ssize_t len, int type_flag, bool is_key) { PYYJSON_TRACE_OP(PYYJSON_OP_STRING); // pyyjson_string_op *op_str = (pyyjson_string_op *) decode_obj_stack_info->op; PyObject *new_val = make_string(utf8_str, len, type_flag, is_key); @@ -331,21 +332,21 @@ force_inline bool pyyjson_decode_double(DecodeObjStackInfo* restrict decode_obj_ return pyyjson_push_stack(decode_obj_stack_info, obj); } -bool pyyjson_decode_longlong(DecodeObjStackInfo* restrict decode_obj_stack_info, i64 val) { +force_inline bool pyyjson_decode_longlong(DecodeObjStackInfo* restrict decode_obj_stack_info, i64 val) { PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); PyObject* obj = PyLong_FromLongLong(val); RETURN_ON_UNLIKELY_ERR(!obj); return pyyjson_push_stack(decode_obj_stack_info, obj); } -bool pyyjson_decode_unsignedlonglong(DecodeObjStackInfo* restrict decode_obj_stack_info, u64 val) { +force_inline bool pyyjson_decode_unsignedlonglong(DecodeObjStackInfo* restrict decode_obj_stack_info, u64 val) { PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); PyObject* obj = PyLong_FromUnsignedLongLong(val); RETURN_ON_UNLIKELY_ERR(!obj); return pyyjson_push_stack(decode_obj_stack_info, obj); } -bool pyyjson_decode_arr(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t arr_len) { +force_inline bool pyyjson_decode_arr(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t arr_len) { assert(arr_len >= 0); // pyyjson_container_op* op_container; //decode_obj_stack_info-> @@ -376,7 +377,7 @@ bool pyyjson_decode_arr(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_s // return true; } -bool pyyjson_decode_obj(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t dict_len) { +force_inline bool pyyjson_decode_obj(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t dict_len) { // pyyjson_container_op* op_container; // //decode_obj_stack_info-> // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; @@ -424,19 +425,19 @@ bool pyyjson_decode_obj(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_s // return true; } -bool pyyjson_decode_null(DecodeObjStackInfo *restrict decode_obj_stack_info) { +force_inline bool pyyjson_decode_null(DecodeObjStackInfo *restrict decode_obj_stack_info) { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); Py_Immortal_IncRef(Py_None); return pyyjson_push_stack(decode_obj_stack_info, Py_None); } -bool pyyjson_decode_false(DecodeObjStackInfo *restrict decode_obj_stack_info) { +force_inline bool pyyjson_decode_false(DecodeObjStackInfo *restrict decode_obj_stack_info) { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); Py_Immortal_IncRef(Py_False); return pyyjson_push_stack(decode_obj_stack_info, Py_False); } -bool pyyjson_decode_true(DecodeObjStackInfo *restrict decode_obj_stack_info) { +force_inline bool pyyjson_decode_true(DecodeObjStackInfo *restrict decode_obj_stack_info) { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); Py_Immortal_IncRef(Py_True); return pyyjson_push_stack(decode_obj_stack_info, Py_True); From 738ecee3bc1c671f06058fb815430838298dd27d Mon Sep 17 00:00:00 2001 From: antares Date: Wed, 18 Dec 2024 01:20:23 +0800 Subject: [PATCH 08/12] Remove old code --- src/decode/decode.c | 435 -------------------------------------------- src/decode/decode.h | 74 -------- 2 files changed, 509 deletions(-) diff --git a/src/decode/decode.c b/src/decode/decode.c index 113107e..7c532d4 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -60,9 +60,6 @@ PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key, PyObject typedef XXH64_hash_t pyyjson_hash_t; -// thread_local PyObject *pyobject_stack_buffer[PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE]; - - #if PYYJSON_ENABLE_TRACE Py_ssize_t max_str_len = 0; int __count_trace[PYYJSON_OP_BITCOUNT_MAX] = {0}; @@ -255,29 +252,6 @@ force_inline bool init_decode_ctn_stack_info(DecodeCtnStackInfo *restrict decode #define PYYJSON_TRACE_OP(x) (void)0 #endif -#ifndef NDEBUG -#define PYYJSON_RESULT_STACK_GROW() \ - if (unlikely(decode_obj_stack_info->cur_write_result_addr >= decode_obj_stack_info->result_stack_end)) { \ - assert(false); \ - Py_UNREACHABLE(); \ - } -#else -#define PYYJSON_RESULT_STACK_GROW() (void) (0) -#endif - -#define PUSH_STACK_NO_CHECK(obj) \ - do { \ - *decode_obj_stack_info->cur_write_result_addr = obj; \ - decode_obj_stack_info->cur_write_result_addr++; \ - } while (0) - - -#define PYYJSON_PUSH_STACK(obj) \ - do { \ - PYYJSON_RESULT_STACK_GROW(); \ - PUSH_STACK_NO_CHECK(obj); \ - } while (0) - force_inline bool pyyjson_push_stack(DecodeObjStackInfo *restrict decode_obj_stack_info, PyObject *obj) { static_assert((PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1) > 0, "(PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE << 1) > 0"); @@ -320,9 +294,6 @@ force_inline bool pyyjson_decode_string(DecodeObjStackInfo* restrict decode_obj_ PyObject *new_val = make_string(utf8_str, len, type_flag, is_key); RETURN_ON_UNLIKELY_ERR(!new_val); return pyyjson_push_stack(decode_obj_stack_info, new_val); - // op_str++; - // decode_obj_stack_info->op = (pyyjson_op *) op_str; - // return true; } force_inline bool pyyjson_decode_double(DecodeObjStackInfo* restrict decode_obj_stack_info, double val) { @@ -459,280 +430,8 @@ force_inline bool pyyjson_decode_inf(DecodeObjStackInfo *restrict decode_obj_sta PyObject *o = PyFloat_FromDouble(val); RETURN_ON_UNLIKELY_ERR(!o); return pyyjson_push_stack(decode_obj_stack_info, o); - // decode_obj_stack_info->op++; - // break; } -// PyObject *pyyjson_op_loads(pyyjson_op *restrict op_head, size_t obj_stack_maxsize) { -// #if PYYJSON_ENABLE_TRACE -// size_t __op_counter = 0; - -// #define PYYJSON_SHOW_OP_TRACE() \ -// do { \ -// for (int i = 0; i < PYYJSON_OP_BITCOUNT_MAX; i++) { \ -// if (__count_trace[i] > 0) { \ -// printf("op %d: %d\n", i, __count_trace[i]); \ -// } \ -// } \ -// printf("total op: %lld\n", (long long int) __op_counter); \ -// } while (0) - -// #define PYYJSON_SHOW_STR_TRACE() printf("max str len: %lld\n", (long long int) max_str_len) -// #else // PYYJSON_ENABLE_TRACE -// #define PYYJSON_SHOW_OP_TRACE() (void) (0) -// #define PYYJSON_SHOW_STR_TRACE() (void) (0) -// #endif // PYYJSON_ENABLE_TRACE -// DecodeObjStackInfo _decode_obj_stack_info; -// DecodeObjStackInfo* const decode_obj_stack_info = &_decode_obj_stack_info; -// // if(unlikely(!init_decode_obj_stack_info(decode_obj_stack_info, op_head, obj_stack_maxsize))){ -// // return NULL; -// // } -// // pyyjson_op *op = op_head; -// // PyObject **result_stack; -// // result_stack = pyobject_stack_buffer; -// // if (unlikely(obj_stack_maxsize > PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE)) { -// // result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); -// // if (unlikely(result_stack == NULL)) { -// // PyErr_NoMemory(); -// // return NULL; -// // } -// // } -// // PyObject **cur_write_result_addr = result_stack; -// // #ifndef NDEBUG -// // PyObject **result_stack_end = result_stack + obj_stack_maxsize; -// // #endif -// // // -// // pyyjson_container_op *op_container; - -// #define PYYJSON_RESULT_STACK_REALLOC_CHECK() \ -// do { \ -// if (new_result_stack == NULL) { \ -// PyErr_NoMemory(); \ -// goto fail; \ -// } \ -// } while (0) - - - -// #ifndef NDEBUG -// #define PYYJSON_POP_STACK_PRE_CHECK(size) \ -// do { \ -// if (unlikely((size) > (Py_ssize_t) (decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack))) { \ -// PyErr_Format(PyExc_RuntimeError, \ -// "Stack underflow: expected to have at least %lld, got %lld", \ -// (size), (Py_ssize_t) (decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack)); \ -// goto fail; \ -// } \ -// } while (0) -// #else // NDEBUG -// #define PYYJSON_POP_STACK_PRE_CHECK(size) (void) (0) -// #endif // NDEBUG -// while (1) { -// switch (PYYJSON_READ_OP(decode_obj_stack_info->op) & PYYJSON_OP_MASK) { -// case PYYJSON_OP_STRING: { -// // PYYJSON_TRACE_OP(PYYJSON_OP_STRING); -// // pyyjson_string_op *op_str = (pyyjson_string_op *) decode_obj_stack_info->op; -// // PyObject *new_val = make_string(op_str->data, op_str->len, PYYJSON_READ_OP(decode_obj_stack_info->op)); -// // if (new_val == NULL) goto fail; -// // PYYJSON_PUSH_STACK(new_val); -// // op_str++; -// // decode_obj_stack_info->op = (pyyjson_op *) op_str; -// break; -// } -// case PYYJSON_OP_NUMBER: { -// PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); -// pyyjson_number_op *op_num = (pyyjson_number_op *) decode_obj_stack_info->op; -// switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_NUM_FLAG_MASK)) { -// PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_FLOAT) : { -// PYYJSON_PUSH_STACK(PyFloat_FromDouble(op_num->data.f)); -// break; -// } -// PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_INT) : { -// PYYJSON_PUSH_STACK(PyLong_FromLongLong(op_num->data.i)); -// break; -// } -// PYYJSON_MATCH_FLAG(PYYJSON_NUM_FLAG_UINT) : { -// PYYJSON_PUSH_STACK(PyLong_FromUnsignedLongLong(op_num->data.u)); -// break; -// } -// default: -// assert(false); -// Py_UNREACHABLE(); -// } -// op_num++; -// decode_obj_stack_info->op = (pyyjson_op *) op_num; -// break; -// } -// case PYYJSON_OP_CONTAINER: { -// // PYYJSON_TRACE_OP(PYYJSON_OP_CONTAINER); -// // switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_CONTAINER_FLAG_MASK)) { -// // PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_ARRAY) : { -// // goto container_array; -// // } -// // PYYJSON_MATCH_FLAG(PYYJSON_CONTAINER_FLAG_DICT) : { -// // goto container_dict; -// // } -// // default: -// // assert(false); -// // Py_UNREACHABLE(); -// // } -// // assert(false); -// // Py_UNREACHABLE(); -// // { -// // container_array: -// // pyyjson_container_op* op_container; -// // //decode_obj_stack_info-> -// // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; -// // Py_ssize_t len = //decode_obj_stack_info-> -// // op_container->len; -// // PyObject *list = PyList_New(len); -// // if (unlikely(list == NULL)) goto fail; -// // if (unlikely(len == 0)) { -// // PYYJSON_PUSH_STACK(list); -// // goto arr_end; -// // } -// // PYYJSON_POP_STACK_PRE_CHECK(len - 1); -// // PyObject **list_val_start = decode_obj_stack_info->cur_write_result_addr - len; -// // for (size_t j = 0; j < len; j++) { -// // PyObject *val = list_val_start[j]; -// // PyList_SET_ITEM(list, j, val); // this never fails -// // } -// // decode_obj_stack_info->cur_write_result_addr -= len; -// // PUSH_STACK_NO_CHECK(list); -// // arr_end: -// // //decode_obj_stack_info-> -// // op_container++; -// // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> -// // op_container; -// // break; -// // } -// // { -// // pyyjson_container_op* op_container; -// // container_dict: -// // //decode_obj_stack_info-> -// // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; -// // Py_ssize_t len = //decode_obj_stack_info-> -// // op_container->len; -// // PyObject *dict = _PyDict_NewPresized(len); -// // if (unlikely(dict == NULL)) goto fail; -// // if (unlikely(len == 0)) { -// // PYYJSON_PUSH_STACK(dict); -// // goto dict_end; -// // } -// // PYYJSON_POP_STACK_PRE_CHECK(len * 2 - 1); -// // PyObject **dict_val_start = decode_obj_stack_info->cur_write_result_addr - len * 2; -// // for (size_t j = 0; j < len; j++) { -// // PyObject *key = dict_val_start[j * 2]; -// // assert(PyUnicode_Check(key)); -// // PyObject *val = dict_val_start[j * 2 + 1]; -// // assert(((PyASCIIObject *) key)->hash != -1); -// // int retcode = _PyDict_SetItem_KnownHash(dict, key, val, ((PyASCIIObject *) key)->hash); // this may fail -// // if (likely(0 == retcode)) { -// // Py_DecRef_NoCheck(key); -// // Py_DecRef_NoCheck(val); -// // } else { -// // Py_DECREF(dict); -// // // also need to clean up the rest k-v pairs -// // for (size_t k = j * 2; k < len * 2; k++) { -// // Py_DECREF(dict_val_start[k]); -// // } -// // // move cur_write_result_addr to the first key addr, avoid double decref -// // decode_obj_stack_info->cur_write_result_addr = dict_val_start; -// // goto fail; -// // } -// // } -// // decode_obj_stack_info->cur_write_result_addr -= len * 2; -// // PUSH_STACK_NO_CHECK(dict); -// // dict_end: -// // //decode_obj_stack_info-> -// // op_container++; -// // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> -// // op_container; -// // break; -// // } -// break; -// } -// case PYYJSON_OP_CONSTANTS: { -// // PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); -// // switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_CONSTANTS_FLAG_MASK)) { -// // PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_NULL) : { -// // Py_Immortal_IncRef(Py_None); -// // PYYJSON_PUSH_STACK(Py_None); -// // decode_obj_stack_info->op++; -// // break; -// // } -// // PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_FALSE) : { -// // Py_Immortal_IncRef(Py_False); -// // PYYJSON_PUSH_STACK(Py_False); -// // decode_obj_stack_info->op++; -// // break; -// // } -// // PYYJSON_MATCH_FLAG(PYYJSON_CONSTANTS_FLAG_TRUE) : { -// // Py_Immortal_IncRef(Py_True); -// // PYYJSON_PUSH_STACK(Py_True); -// // decode_obj_stack_info->op++; -// // break; -// // } -// // default: -// // assert(false); -// // Py_UNREACHABLE(); -// // break; -// // } -// break; -// } -// case PYYJSON_OP_NAN_INF: { -// // PYYJSON_TRACE_OP(PYYJSON_OP_NAN_INF); -// // switch (PYYJSON_GET_FLAG(PYYJSON_READ_OP(decode_obj_stack_info->op), PYYJSON_NAN_INF_FLAG_MASK_WITHOUT_SIGNED)) { -// // PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_NAN) : { -// // double val = (PYYJSON_READ_OP(decode_obj_stack_info->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -fabs(Py_NAN) : fabs(Py_NAN); -// // PyObject *o = PyFloat_FromDouble(val); -// // assert(o); -// // PYYJSON_PUSH_STACK(o); -// // decode_obj_stack_info->op++; -// // break; -// // } -// // PYYJSON_MATCH_FLAG(PYYJSON_NAN_INF_FLAG_INF) : { -// // double val = (PYYJSON_READ_OP(decode_obj_stack_info->op) & PYYJSON_NAN_INF_FLAG_SIGNED) ? -Py_HUGE_VAL : Py_HUGE_VAL; -// // PyObject *o = PyFloat_FromDouble(val); -// // assert(o); -// // PYYJSON_PUSH_STACK(o); -// // decode_obj_stack_info->op++; -// // break; -// // } -// // default: -// // assert(false); -// // Py_UNREACHABLE(); -// // break; -// // } -// break; -// } -// case PYYJSON_NO_OP: { -// goto success; -// } -// default: -// assert(false); -// Py_UNREACHABLE(); -// } -// } -// success: -// assert(decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack == 1); -// PyObject *result = *decode_obj_stack_info->result_stack; -// if (unlikely(decode_obj_stack_info->result_stack != pyobject_stack_buffer)) free(decode_obj_stack_info->result_stack); -// PYYJSON_SHOW_OP_TRACE(); -// PYYJSON_SHOW_STR_TRACE(); -// return result; -// fail: -// // decref all objects in the stack -// for (PyObject **p = decode_obj_stack_info->result_stack; p < decode_obj_stack_info->cur_write_result_addr; p++) { -// Py_DECREF(*p); -// } -// if (unlikely(decode_obj_stack_info->result_stack != pyobject_stack_buffer)) free(decode_obj_stack_info->result_stack); -// if (PyErr_Occurred() == NULL) { -// PyErr_Format(PyExc_RuntimeError, "Analyze pyyjson opcode failed at %lld", decode_obj_stack_info->cur_write_result_addr - decode_obj_stack_info->result_stack); -// } -// return NULL; -// } - /** Character type table (generate with misc/make_tables.c) */ static const u8 char_table[256] = { 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, @@ -1877,68 +1576,6 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto failed_cleanup; \ } while (0) - // typedef struct container_type { - // union { - // struct { - // Py_ssize_t size : sizeof(Py_ssize_t) * 8 - 1; - // Py_ssize_t tag : 1; - // }; - // Py_ssize_t raw; - // }; - // } container_type; - // static_assert(sizeof(container_type) == sizeof(Py_ssize_t), "size of container_type must be equal to size of Py_ssize_t"); - -// #define CONTAINER_ARR_TYPE (~0) -// #define CONTAINER_OBJ_TYPE 0 - - // stack buffer length -// #define STACK_BUFFER_SIZE 1024 -// #define COMMON_OPSIZE_RATIO (sizeof(pyyjson_string_op) / sizeof(pyyjson_op)) -// #define OP_BUFFER_INIT_SIZE (STACK_BUFFER_SIZE * COMMON_OPSIZE_RATIO) -// #ifdef NDEBUG -// #define OBJ_STACK_MAX_SIZE_UPDATE(update_val) \ -// do { \ -// object_stack_cur_size += (update_val); \ -// object_stack_max_size = PYYJSON_MAX(object_stack_max_size, object_stack_cur_size); \ -// } while (0) -// #else -// #define OBJ_STACK_MAX_SIZE_UPDATE(update_val) \ -// do { \ -// if ((update_val) < 0 && object_stack_cur_size < (usize) (-(update_val))) { \ -// assert(false); \ -// Py_UNREACHABLE(); \ -// } \ -// object_stack_cur_size += (update_val); \ -// object_stack_max_size = PYYJSON_MAX(object_stack_max_size, object_stack_cur_size); \ -// } while (0) -// #endif -// #define OP_BUFFER_REALLOC_CHECK() \ -// do { \ -// if (new_py_operations == NULL) { \ -// PyErr_NoMemory(); \ -// goto fail_alloc; \ -// } \ -// } while (0) -// #define OP_BUFFER_GROW(offset) \ -// do { \ -// if (unlikely(offset + (u8 *) cur_write_op > (u8 *) py_operations_end)) { \ -// size_t write_offset = cur_write_op - py_operations; \ -// size_t old_capacity = py_operations_end - py_operations; \ -// size_t new_capacity = old_capacity + old_capacity / 2; \ -// pyyjson_op *new_py_operations; \ -// if (likely(py_operations == pyobject_stack_buffer)) { \ -// new_py_operations = (pyyjson_op *) malloc(new_capacity * sizeof(pyyjson_op)); \ -// OP_BUFFER_REALLOC_CHECK(); \ -// memcpy(new_py_operations, py_operations, old_capacity * sizeof(pyyjson_op)); \ -// } else { \ -// new_py_operations = (pyyjson_op *) realloc(py_operations, new_capacity * sizeof(pyyjson_op)); \ -// OP_BUFFER_REALLOC_CHECK(); \ -// } \ -// py_operations = new_py_operations; \ -// cur_write_op = new_py_operations + write_offset; \ -// py_operations_end = new_py_operations + new_capacity; \ -// } \ -// } while (0) // container stack info DecodeCtnStackInfo _decode_ctn_info; DecodeCtnStackInfo* decode_ctn_info = &_decode_ctn_info; @@ -1949,78 +1586,8 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { memset(decode_obj_stack_info, 0, sizeof(DecodeObjStackInfo)); // init if(!init_decode_ctn_stack_info(decode_ctn_info) || !init_decode_obj_stack_info(decode_obj_stack_info)) goto failed_cleanup; - // DecodeCtnWithSize *const __stack_ctn_buffer = get_decode_obj_stack_buffer(); - // assert(__stack_ctn_buffer); - // DecodeCtnWithSize *ctn_start = __stack_ctn_buffer; - // // container ptr - // DecodeCtnWithSize *const ctn_end = __stack_ctn_buffer + PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE; - // DecodeCtnWithSize *ctn = ctn_start; - // pyyjson_op pyobject_stack_buffer[OP_BUFFER_INIT_SIZE]; - // // buffer start pointer - // pyyjson_op *py_operations; u8 * string_buffer_head =(u8 *)pyyjson_string_buffer; - // usize required_len = PYYJSON_MAX( - // OP_BUFFER_INIT_SIZE, - // (len / PYYJSON_READER_ESTIMATED_PRETTY_RATIO) * COMMON_OPSIZE_RATIO); - - // py_operations ptr - // pyyjson_op *py_operations_end; - // if (unlikely(required_len > OP_BUFFER_INIT_SIZE)) { - // py_operations = (pyyjson_op *) malloc(required_len * sizeof(pyyjson_op)); - // if (!py_operations) goto fail_alloc; - // py_operations_end = py_operations + required_len; - // } else { - // py_operations = pyobject_stack_buffer; - // py_operations_end = pyobject_stack_buffer + OP_BUFFER_INIT_SIZE; - // } - // pyyjson_op *cur_write_op = py_operations; - // usize object_stack_max_size = 0; - // usize object_stack_cur_size = 0; - - // container buffer grow macros -// #define CTN_REALLOC_CHECK() \ -// do { \ -// if (new_ctn_start == NULL) { \ -// PyErr_NoMemory(); \ -// goto fail_alloc; \ -// } \ -// } while (0) -// #define CTN_BUFFER_GROW() \ -// do { \ -// if (unlikely(ctn + 1 >= ctn_end)) { \ -// size_t old_capacity = ctn_end - ctn_start; \ -// size_t new_capacity = old_capacity << 1; \ -// DecodeCtnWithSize *new_ctn_start; \ -// if (likely(old_capacity == PYYJSON_DECODE_CONTAINER_BUFFER_INIT_SIZE)) { \ -// new_ctn_start = (DecodeCtnWithSize *) malloc(new_capacity * sizeof(DecodeCtnWithSize)); \ -// CTN_REALLOC_CHECK(); \ -// memcpy(new_ctn_start, ctn_start, old_capacity * sizeof(DecodeCtnWithSize)); \ -// } else { \ -// new_ctn_start = (DecodeCtnWithSize *) realloc(ctn_start, new_capacity * sizeof(DecodeCtnWithSize)); \ -// CTN_REALLOC_CHECK(); \ -// } \ -// ctn_start = new_ctn_start; \ -// ctn = new_ctn_start + old_capacity; \ -// ctn_end = new_ctn_start + new_capacity; \ -// } \ -// ctn++; \ -// } while (0) -// #ifdef NDEBUG -// #define CHECK_STRING_BUFFER_OVERFLOW() ((void) 0) -// #else -// #define CHECK_STRING_BUFFER_OVERFLOW() \ -// do { \ -// if ((((size_t) string_buffer) + 3) / 4 * 4 > ((size_t) string_buffer_head) + 4 * len) { \ -// assert(false); \ -// Py_UNREACHABLE(); \ -// } \ -// } while (0) -// #endif -// #define MOVE_STRING_BUFFER_ALIGNED_4() \ -// do { \ -// string_buffer = (char *) ((((size_t) string_buffer) + 3) / 4 * 4); \ -// } while (0) // if (unlikely(len > ((size_t) (-1)) / 4)) { goto fail_alloc; @@ -2029,12 +1596,10 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { string_buffer_head = malloc(4 * len); if (!string_buffer_head) goto fail_alloc; } - // char *string_buffer = string_buffer_head; // u8 *cur = (u8 *) dat; u8 *end = (u8 *) dat + len; - // static_assert(STACK_BUFFER_SIZE > 0, "STACK_BUFFER_SIZE should be greater than 0"); if (*cur++ == '{') { set_decode_ctn(decode_ctn_info->ctn, 0, false); // ctn->tag = CONTAINER_OBJ_TYPE; diff --git a/src/decode/decode.h b/src/decode/decode.h index 471c8b5..43a6a4c 100644 --- a/src/decode/decode.h +++ b/src/decode/decode.h @@ -56,60 +56,6 @@ #define PYYJSON_MATCH_FLAG(x) case ((x) >> PYYJSON_OP_BITCOUNT_MAX) #define PYYJSON_GET_FLAG(x, mask) (((x) & (mask)) >> PYYJSON_OP_BITCOUNT_MAX) // end flags -typedef uint32_t op_type; -#define PYYJSON_OP_HEAD pyyjson_op_base op_base; -#define PYYJSON_READ_OP(_op) (((pyyjson_op_base *) (_op))->op) -#define PYYJSON_WRITE_OP(_ptr, _code) \ - do { \ - ((pyyjson_op_base *) (_ptr))->op = (_code); \ - } while (0) - - -#ifdef PYYJSON_64BIT -#define PYYJSON_OP_PADDING char pad[4]; -#else -#define PYYJSON_OP_PADDING -#endif - -// size = 4. This should not be used directly -typedef struct pyyjson_op_base { - op_type op; -} pyyjson_op_base; - -// size = 4 / 8 -typedef struct pyyjson_op { - PYYJSON_OP_HEAD - PYYJSON_OP_PADDING -} pyyjson_op; - -typedef union { - int64_t i; - uint64_t u; - double f; -} num_data; - -// size = 12 / 16 -typedef struct pyyjson_number_op { - PYYJSON_OP_HEAD - union { - int64_t i; - uint64_t u; - double f; - } data; -} pyyjson_number_op; - -// size = 12 / 24 -typedef struct pyyjson_string_op { - PYYJSON_OP_HEAD - char *data; - Py_ssize_t len; -} pyyjson_string_op; - -// size = 8 / 16 -typedef struct pyyjson_container_op { - PYYJSON_OP_HEAD - Py_ssize_t len; -} pyyjson_container_op; /** 16/32/64-bit vector */ @@ -124,10 +70,8 @@ typedef union v64_uni { v64 v; u64 u; } v64_uni; typedef struct DecodeObjStackInfo { - // pyyjson_op *op; PyObject **cur_write_result_addr; PyObject **result_stack; - // pyyjson_container_op *op_container; PyObject **result_stack_end; } DecodeObjStackInfo; @@ -140,22 +84,10 @@ typedef struct DecodeCtnStackInfo { } DecodeCtnStackInfo; -PyObject *pyyjson_op_loads(pyyjson_op *op_sequence, size_t obj_stack_maxsize); - extern PyObject *JSONDecodeError; typedef PyObject *pyyjson_cache_type; -// static assertions -static_assert((sizeof(pyyjson_number_op) % sizeof(pyyjson_op)) == 0, "size of pyyjson_number_op must be multiple of size of pyyjson_op"); -static_assert((sizeof(pyyjson_string_op) % sizeof(pyyjson_op)) == 0, "size of pyyjson_string_op must be multiple of size of pyyjson_op"); -static_assert((sizeof(pyyjson_container_op) % sizeof(pyyjson_op)) == 0, "size of pyyjson_container_op must be multiple of size of pyyjson_op"); -static_assert(sizeof(long long) == 8, "size of long long must be 8 bytes"); -static_assert(sizeof(unsigned long long) == 8, "size of unsigned long long must be 8 bytes"); -static_assert(sizeof(double) == 8, "size of double must be 8 bytes"); - - - /*============================================================================== * Integer Constants @@ -424,9 +356,6 @@ force_inline bool _read_inf(bool sign, u8 **ptr) { // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; // val->uni.u64 = f64_raw_get_inf(sign); // } - // pyyjson_op* op_inf = *op; - // PYYJSON_WRITE_OP(op_inf, PYYJSON_OP_NAN_INF | PYYJSON_NAN_INF_FLAG_INF | (sign ? PYYJSON_NAN_INF_FLAG_SIGNED : 0)); - // *op = (op_inf + 1); return true; } return false; @@ -452,9 +381,6 @@ force_inline bool _read_nan(bool sign, u8 **ptr) { // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; // val->uni.u64 = f64_raw_get_nan(sign); // } - // pyyjson_op* op_nan = *op; - // PYYJSON_WRITE_OP(op_nan, PYYJSON_OP_NAN_INF | PYYJSON_NAN_INF_FLAG_NAN | (sign ? PYYJSON_NAN_INF_FLAG_SIGNED : 0)); - // *op = (op_nan + 1); return true; } return false; From bad6f4ccc8bf93ef5240a77042d4728242e03eed Mon Sep 17 00:00:00 2001 From: antares Date: Thu, 19 Dec 2024 01:54:16 +0800 Subject: [PATCH 09/12] Refactor: code cleanup, fix memleak on fail path --- CMakeLists.txt | 2 +- src/decode/decode.c | 321 ++++++++++---------------------------------- src/decode/decode.h | 74 +--------- 3 files changed, 74 insertions(+), 323 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b33f6d1..3db9c7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set(PYYJSON_SOVERSION 0) # Search Python Package find_package(Python3 COMPONENTS Development) -# check for python3ss +# check for python3 if((NOT Python3_INCLUDE_DIRS) OR (NOT Python3_LIBRARIES)) message(FATAL_ERROR "Python3 not found") endif() diff --git a/src/decode/decode.c b/src/decode/decode.c index 7c532d4..be3b730 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -201,6 +201,7 @@ force_inline PyObject *make_string(const u8 *utf8_str, Py_ssize_t len, int type_ } force_inline bool init_decode_obj_stack_info(DecodeObjStackInfo *restrict decode_obj_stack_info) { + assert(!decode_obj_stack_info->result_stack); PyObject **new_buffer = get_decode_obj_stack_buffer(); if (unlikely(!new_buffer)) { PyErr_NoMemory(); @@ -209,23 +210,11 @@ force_inline bool init_decode_obj_stack_info(DecodeObjStackInfo *restrict decode decode_obj_stack_info->result_stack = new_buffer; decode_obj_stack_info->cur_write_result_addr = new_buffer; decode_obj_stack_info->result_stack_end = new_buffer + PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE; - // decode_obj_stack_info->op = op_head; - // decode_obj_stack_info->result_stack = pyobject_stack_buffer; - // if (unlikely(obj_stack_maxsize > PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE)) { - // decode_obj_stack_info->result_stack = (PyObject **) malloc(obj_stack_maxsize * sizeof(PyObject *)); - // if (unlikely(decode_obj_stack_info->result_stack == NULL)) { - // PyErr_NoMemory(); - // return false; - // } - // } - // decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack; - // // #ifndef NDEBUG - // decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + obj_stack_maxsize; - // #endif return true; } force_inline bool init_decode_ctn_stack_info(DecodeCtnStackInfo *restrict decode_ctn_stack_info) { + assert(!decode_ctn_stack_info->ctn_start); DecodeCtnWithSize *new_buffer = get_decode_ctn_stack_buffer(); if (unlikely(!new_buffer)) { PyErr_NoMemory(); @@ -252,85 +241,79 @@ force_inline bool init_decode_ctn_stack_info(DecodeCtnStackInfo *restrict decode #define PYYJSON_TRACE_OP(x) (void)0 #endif +force_noinline bool _pyyjson_decode_obj_stack_resize(DecodeObjStackInfo *restrict decode_obj_stack_info) { + // resize + if (likely(PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE == decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack)) { + void *new_buffer = malloc(sizeof(PyObject *) * (PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1)); + if (unlikely(!new_buffer)) { + PyErr_NoMemory(); + return false; + } + memcpy(new_buffer, decode_obj_stack_info->result_stack, sizeof(PyObject *) * PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE); + decode_obj_stack_info->result_stack = (PyObject **) new_buffer; + decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack + PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE; + decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + (PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1); + } else { + Py_ssize_t old_capacity = decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack; + if (unlikely((PY_SSIZE_T_MAX >> 1) < old_capacity)) { + PyErr_NoMemory(); + return false; + } + Py_ssize_t new_capacity = old_capacity << 1; + void *new_buffer = realloc(decode_obj_stack_info->result_stack, sizeof(PyObject *) * new_capacity); + if (unlikely(!new_buffer)) { + PyErr_NoMemory(); + return false; + } + decode_obj_stack_info->result_stack = (PyObject **) new_buffer; + decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack + old_capacity; + decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + new_capacity; + } + return true; +} -force_inline bool pyyjson_push_stack(DecodeObjStackInfo *restrict decode_obj_stack_info, PyObject *obj) { - static_assert((PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1) > 0, "(PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE << 1) > 0"); +force_inline bool pyyjson_push_obj(DecodeObjStackInfo *restrict decode_obj_stack_info, PyObject *obj) { + static_assert(((Py_ssize_t) PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1) > 0, "(PYYJSON_DECODE_OBJSTACK_BUFFER_SIZE << 1) > 0"); if (unlikely(decode_obj_stack_info->cur_write_result_addr >= decode_obj_stack_info->result_stack_end)) { - // resize - if (likely(PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE == decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack)) { - void *new_buffer = malloc(sizeof(PyObject *) * (PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1)); - if (unlikely(!new_buffer)) { - PyErr_NoMemory(); - return false; - } - memcpy(new_buffer, decode_obj_stack_info->result_stack, sizeof(PyObject *) * PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE); - decode_obj_stack_info->result_stack = (PyObject **) new_buffer; - decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack + PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE; - decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + (PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE << 1); - } else { - Py_ssize_t old_capacity = decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack; - if (unlikely((PY_SSIZE_T_MAX >> 1) < old_capacity)) { - PyErr_NoMemory(); - return false; - } - Py_ssize_t new_capacity = old_capacity << 1; - void *new_buffer = realloc(decode_obj_stack_info->result_stack, sizeof(PyObject *) * new_capacity); - if (unlikely(!new_buffer)) { - PyErr_NoMemory(); - return false; - } - decode_obj_stack_info->result_stack = (PyObject **) new_buffer; - decode_obj_stack_info->cur_write_result_addr = decode_obj_stack_info->result_stack + old_capacity; - decode_obj_stack_info->result_stack_end = decode_obj_stack_info->result_stack + new_capacity; - } + bool c = _pyyjson_decode_obj_stack_resize(decode_obj_stack_info); + RETURN_ON_UNLIKELY_ERR(!c); } *decode_obj_stack_info->cur_write_result_addr++ = obj; return true; } -force_inline bool pyyjson_decode_string(DecodeObjStackInfo* restrict decode_obj_stack_info, const u8 *utf8_str, Py_ssize_t len, int type_flag, bool is_key) { +force_inline bool pyyjson_decode_string(DecodeObjStackInfo *restrict decode_obj_stack_info, const u8 *utf8_str, Py_ssize_t len, int type_flag, bool is_key) { PYYJSON_TRACE_OP(PYYJSON_OP_STRING); - // pyyjson_string_op *op_str = (pyyjson_string_op *) decode_obj_stack_info->op; PyObject *new_val = make_string(utf8_str, len, type_flag, is_key); RETURN_ON_UNLIKELY_ERR(!new_val); - return pyyjson_push_stack(decode_obj_stack_info, new_val); + return pyyjson_push_obj(decode_obj_stack_info, new_val); } force_inline bool pyyjson_decode_double(DecodeObjStackInfo* restrict decode_obj_stack_info, double val) { PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); PyObject* obj = PyFloat_FromDouble(val); RETURN_ON_UNLIKELY_ERR(!obj); - return pyyjson_push_stack(decode_obj_stack_info, obj); + return pyyjson_push_obj(decode_obj_stack_info, obj); } force_inline bool pyyjson_decode_longlong(DecodeObjStackInfo* restrict decode_obj_stack_info, i64 val) { PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); PyObject* obj = PyLong_FromLongLong(val); RETURN_ON_UNLIKELY_ERR(!obj); - return pyyjson_push_stack(decode_obj_stack_info, obj); + return pyyjson_push_obj(decode_obj_stack_info, obj); } force_inline bool pyyjson_decode_unsignedlonglong(DecodeObjStackInfo* restrict decode_obj_stack_info, u64 val) { PYYJSON_TRACE_OP(PYYJSON_OP_NUMBER); PyObject* obj = PyLong_FromUnsignedLongLong(val); RETURN_ON_UNLIKELY_ERR(!obj); - return pyyjson_push_stack(decode_obj_stack_info, obj); + return pyyjson_push_obj(decode_obj_stack_info, obj); } force_inline bool pyyjson_decode_arr(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t arr_len) { assert(arr_len >= 0); - // pyyjson_container_op* op_container; - //decode_obj_stack_info-> - // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; - // Py_ssize_t len = //decode_obj_stack_info-> - // op_container->len; PyObject *list = PyList_New(arr_len); RETURN_ON_UNLIKELY_ERR(!list); - // if (unlikely(list == NULL)) goto fail; - // if (unlikely(arr_len == 0)) { - // // goto arr_end; - // return pyyjson_push_stack(decode_obj_stack_info, list); - // } PyObject **list_val_start = decode_obj_stack_info->cur_write_result_addr - arr_len; assert(list_val_start >= decode_obj_stack_info->result_stack); for (Py_ssize_t j = 0; j < arr_len; j++) { @@ -339,29 +322,12 @@ force_inline bool pyyjson_decode_arr(DecodeObjStackInfo *restrict decode_obj_sta PyList_SET_ITEM(list, j, val); // this never fails } decode_obj_stack_info->cur_write_result_addr -= arr_len; - return pyyjson_push_stack(decode_obj_stack_info, list); - // arr_end: - //decode_obj_stack_info-> - // op_container++; - // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> - // op_container; - // return true; + return pyyjson_push_obj(decode_obj_stack_info, list); } force_inline bool pyyjson_decode_obj(DecodeObjStackInfo *restrict decode_obj_stack_info, Py_ssize_t dict_len) { - // pyyjson_container_op* op_container; - // //decode_obj_stack_info-> - // op_container = (pyyjson_container_op *) decode_obj_stack_info->op; - // Py_ssize_t len = //decode_obj_stack_info-> - // op_container->len; PyObject *dict = _PyDict_NewPresized(dict_len); RETURN_ON_UNLIKELY_ERR(!dict); - // if (unlikely(dict == NULL)) goto fail; - // if (unlikely(len == 0)) { - // PYYJSON_PUSH_STACK(dict); - // goto dict_end; - // } - // PYYJSON_POP_STACK_PRE_CHECK(len * 2 - 1); PyObject **dict_val_start = decode_obj_stack_info->cur_write_result_addr - dict_len * 2; PyObject **dict_val_view = dict_val_start; for (size_t j = 0; j < dict_len; j++) { @@ -386,32 +352,25 @@ force_inline bool pyyjson_decode_obj(DecodeObjStackInfo *restrict decode_obj_sta } } decode_obj_stack_info->cur_write_result_addr -= dict_len * 2; - return pyyjson_push_stack(decode_obj_stack_info, dict); - // dict_end: - //decode_obj_stack_info-> - // op_container++; - // decode_obj_stack_info->op = (pyyjson_op *) //decode_obj_stack_info-> - // op_container; - // break; - // return true; + return pyyjson_push_obj(decode_obj_stack_info, dict); } force_inline bool pyyjson_decode_null(DecodeObjStackInfo *restrict decode_obj_stack_info) { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); Py_Immortal_IncRef(Py_None); - return pyyjson_push_stack(decode_obj_stack_info, Py_None); + return pyyjson_push_obj(decode_obj_stack_info, Py_None); } force_inline bool pyyjson_decode_false(DecodeObjStackInfo *restrict decode_obj_stack_info) { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); Py_Immortal_IncRef(Py_False); - return pyyjson_push_stack(decode_obj_stack_info, Py_False); + return pyyjson_push_obj(decode_obj_stack_info, Py_False); } force_inline bool pyyjson_decode_true(DecodeObjStackInfo *restrict decode_obj_stack_info) { PYYJSON_TRACE_OP(PYYJSON_OP_CONSTANTS); Py_Immortal_IncRef(Py_True); - return pyyjson_push_stack(decode_obj_stack_info, Py_True); + return pyyjson_push_obj(decode_obj_stack_info, Py_True); } force_inline bool pyyjson_decode_nan(DecodeObjStackInfo *restrict decode_obj_stack_info, bool is_signed) { @@ -419,9 +378,7 @@ force_inline bool pyyjson_decode_nan(DecodeObjStackInfo *restrict decode_obj_sta double val = is_signed ? -fabs(Py_NAN) : fabs(Py_NAN); PyObject *o = PyFloat_FromDouble(val); RETURN_ON_UNLIKELY_ERR(!o); - return pyyjson_push_stack(decode_obj_stack_info, o); - // decode_obj_stack_info->op++; - // break; + return pyyjson_push_obj(decode_obj_stack_info, o); } force_inline bool pyyjson_decode_inf(DecodeObjStackInfo *restrict decode_obj_stack_info, bool is_signed) { @@ -429,7 +386,7 @@ force_inline bool pyyjson_decode_inf(DecodeObjStackInfo *restrict decode_obj_sta double val = is_signed ? -fabs(Py_HUGE_VAL) : fabs(Py_HUGE_VAL); PyObject *o = PyFloat_FromDouble(val); RETURN_ON_UNLIKELY_ERR(!o); - return pyyjson_push_stack(decode_obj_stack_info, o); + return pyyjson_push_obj(decode_obj_stack_info, o); } /** Character type table (generate with misc/make_tables.c) */ @@ -1522,13 +1479,6 @@ force_inline bool read_string(DecodeObjStackInfo *restrict decode_obj_stack_info len_ucs1--; } return pyyjson_decode_string(decode_obj_stack_info, temp_string_buf, dst_ucs4 - (u32*)temp_string_buf, PYYJSON_STRING_TYPE_UCS4, is_key); - // pyyjson_string_op* string_op = (pyyjson_string_op*)*op; - // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_UCS4); - // string_op->data = temp_string_buf; - // string_op->len = dst_ucs4 - (u32*)temp_string_buf; - // *op = (pyyjson_op*)(string_op + 1); - // *buffer = (char*)dst_ucs4; - // return true;//create_py_unicode(temp_string_buf, dst_ucs4 - (u32*)temp_string_buf, false, 4); } else if (unlikely(cur_max_ucs_size==2)) { u16* start = (u16*)temp_string_buf + len_ucs1 - 1; u8* ucs1_back = (u8*)temp_string_buf + len_ucs1 - 1; @@ -1537,22 +1487,8 @@ force_inline bool read_string(DecodeObjStackInfo *restrict decode_obj_stack_info len_ucs1--; } return pyyjson_decode_string(decode_obj_stack_info, temp_string_buf, dst_ucs2 - (u16*)temp_string_buf, PYYJSON_STRING_TYPE_UCS2, is_key); - // pyyjson_string_op* string_op = (pyyjson_string_op*) *op; - // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_UCS2); - // string_op->data = temp_string_buf; - // string_op->len = dst_ucs2 - (u16*)temp_string_buf; - // *op = (pyyjson_op*)(string_op + 1); - // *buffer = (char*)dst_ucs2; - // return true;//create_py_unicode(temp_string_buf, dst_ucs2 - (u16*)temp_string_buf, false, 2); } else { return pyyjson_decode_string(decode_obj_stack_info, temp_string_buf, dst - (u8*)temp_string_buf, is_ascii?PYYJSON_STRING_TYPE_ASCII:PYYJSON_STRING_TYPE_LATIN1, is_key); - // pyyjson_string_op* string_op = (pyyjson_string_op*) *op; - // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | (is_ascii ? PYYJSON_STRING_FLAG_ASCII : PYYJSON_STRING_FLAG_LATIN1)); - // string_op->data = temp_string_buf; - // string_op->len = dst - (u8*)temp_string_buf; - // *op = (pyyjson_op*)(string_op + 1); - // *buffer = (char*)dst; - // return true;//create_py_unicode(temp_string_buf, dst - (u8*)temp_string_buf, false, 1); } #undef return_err @@ -1566,15 +1502,6 @@ force_inline bool read_string(DecodeObjStackInfo *restrict decode_obj_stack_info /** Read JSON document (accept all style, but optimized for pretty). */ force_inline PyObject *read_root_pretty(const char *dat, usize len) { -#define return_err(_pos, _type, _msg) \ - do { \ - if (_type == JSONDecodeError) { \ - PyErr_Format(JSONDecodeError, "%s, at position %zu", _msg, ((u8 *) _pos) - (u8 *) dat); \ - } else { \ - PyErr_SetString(_type, _msg); \ - } \ - goto failed_cleanup; \ - } while (0) // container stack info DecodeCtnStackInfo _decode_ctn_info; @@ -1602,16 +1529,10 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { if (*cur++ == '{') { set_decode_ctn(decode_ctn_info->ctn, 0, false); - // ctn->tag = CONTAINER_OBJ_TYPE; - // ctn->size = 0; - // ctn++; if (*cur == '\n') cur++; goto obj_key_begin; } else { set_decode_ctn(decode_ctn_info->ctn, 0, true); - // ctn->tag = CONTAINER_ARR_TYPE; - // ctn->size = 0; - // ctn++; if (*cur == '\n') cur++; goto arr_val_begin; } @@ -1620,11 +1541,8 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { /* save current container */ /* create a new array value, save parent container offset */ if(unlikely(!ctn_grow_check(decode_ctn_info))) goto fail_ctn_grow; - // ctn->tag = CONTAINER_ARR_TYPE; - // ctn->size = 0; set_decode_ctn(decode_ctn_info->ctn, 0, true); - /* push the new array value as current container */ if (*cur == '\n') cur++; @@ -1652,54 +1570,35 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto arr_begin; } if (char_is_number(*cur)) { - // OP_BUFFER_GROW(sizeof(pyyjson_number_op)); - // pyyjson_op *now_write_op = cur_write_op; if (likely(read_number(decode_obj_stack_info, &cur))) { - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_number; } if (*cur == '"') { - // OP_BUFFER_GROW(sizeof(pyyjson_string_op)); - // MOVE_STRING_BUFFER_ALIGNED_4(); if (likely(read_string(decode_obj_stack_info, &cur, string_buffer_head, false))) { - // CHECK_STRING_BUFFER_OVERFLOW(); - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_string; } if (*cur == 't') { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (likely(_read_true(&cur) && pyyjson_decode_true(decode_obj_stack_info))) { - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); - // OBJ_STACK_MAX_SIZE_UPDATE(1); - // cur_write_op++; incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_literal_true; } if (*cur == 'f') { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (likely(_read_false(&cur) && pyyjson_decode_false(decode_obj_stack_info))) { - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); - // OBJ_STACK_MAX_SIZE_UPDATE(1); - // cur_write_op++; incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } goto fail_literal_false; } if (*cur == 'n') { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (likely(_read_null(&cur) && pyyjson_decode_null(decode_obj_stack_info))) { - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); - // OBJ_STACK_MAX_SIZE_UPDATE(1); - // cur_write_op++; incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } @@ -1711,9 +1610,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { } if (*cur == ']') { cur++; - // if (likely(ctn_len == 0)) goto arr_end; if (likely(get_decode_ctn_len(decode_ctn_info->ctn) == 0)) goto arr_end; - //if (has_read_flag(ALLOW_TRAILING_COMMAS)) goto arr_end; while (*cur != ',') cur--; goto fail_trailing_comma; } @@ -1723,9 +1620,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto arr_val_begin; } if ((*cur == 'i' || *cur == 'I' || *cur == 'N')) { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (read_inf_or_nan(decode_obj_stack_info, false, &cur)) { - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto arr_val_end; } @@ -1758,15 +1653,6 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { arr_end: assert(decode_ctn_is_arr(decode_ctn_info->ctn)); if(!pyyjson_decode_arr(decode_obj_stack_info, get_decode_ctn_len(decode_ctn_info->ctn))) goto failed_cleanup; - // OP_BUFFER_GROW(sizeof(pyyjson_container_op)); - // pyyjson_container_op *list_op = (pyyjson_container_op *) cur_write_op; - // PYYJSON_WRITE_OP(list_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_ARRAY); - { - // Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); - // OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); - // list_op->len = cur_ctn_size; - } - // cur_write_op = (pyyjson_op *) (list_op + 1); /* pop parent as current container */ if (unlikely(decode_ctn_info->ctn-- == decode_ctn_info->ctn_start)) { goto doc_end; @@ -1782,11 +1668,8 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { obj_begin: /* push container */ - // CTN_BUFFER_GROW(); ctn_grow_check(decode_ctn_info); set_decode_ctn(decode_ctn_info->ctn, 0, false); - // ctn->tag = CONTAINER_OBJ_TYPE; - // ctn->size = 0; if (*cur == '\n') cur++; obj_key_begin: @@ -1804,13 +1687,7 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { }) #endif if (likely(*cur == '"')) { - // OP_BUFFER_GROW(sizeof(pyyjson_string_op)); - // pyyjson_op *write_key_op = cur_write_op; - // MOVE_STRING_BUFFER_ALIGNED_4(); if (likely(read_string(decode_obj_stack_info, &cur, string_buffer_head, true))) { - // CHECK_STRING_BUFFER_OVERFLOW(); - // OBJ_STACK_MAX_SIZE_UPDATE(1); - // ((pyyjson_op_base *) write_key_op)->op |= PYYJSON_STRING_FLAG_OBJ_KEY; goto obj_key_end; } goto fail_string; @@ -1845,21 +1722,14 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { obj_val_begin: if (*cur == '"') { - // OP_BUFFER_GROW(sizeof(pyyjson_string_op)); - // MOVE_STRING_BUFFER_ALIGNED_4(); if (likely(read_string(decode_obj_stack_info, &cur, string_buffer_head, false))) { - // CHECK_STRING_BUFFER_OVERFLOW(); - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_string; } if (char_is_number(*cur)) { - // OP_BUFFER_GROW(PYYJSON_MAX(sizeof(pyyjson_op), sizeof(pyyjson_number_op))); - // pyyjson_op *now_write_op = cur_write_op; if (likely(read_number(decode_obj_stack_info, &cur))) { - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } @@ -1874,33 +1744,21 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto arr_begin; } if (*cur == 't') { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (likely(_read_true(&cur) && pyyjson_decode_true(decode_obj_stack_info))) { - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_TRUE); - // cur_write_op++; - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_literal_true; } if (*cur == 'f') { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (likely(_read_false(&cur) && pyyjson_decode_false(decode_obj_stack_info))) { - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_FALSE); - // cur_write_op++; - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } goto fail_literal_false; } if (*cur == 'n') { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (likely(_read_null(&cur) && pyyjson_decode_null(decode_obj_stack_info))) { - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_OP_CONSTANTS | PYYJSON_CONSTANTS_FLAG_NULL); - // cur_write_op++; - // OBJ_STACK_MAX_SIZE_UPDATE(1); incr_decode_ctn_size(decode_ctn_info->ctn); goto obj_val_end; } @@ -1916,10 +1774,8 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { goto obj_val_begin; } if ((*cur == 'i' || *cur == 'I' || *cur == 'N')) { - // OP_BUFFER_GROW(sizeof(pyyjson_op)); if (read_inf_or_nan(decode_obj_stack_info, false, &cur)) { incr_decode_ctn_size(decode_ctn_info->ctn); - // OBJ_STACK_MAX_SIZE_UPDATE(1); goto obj_val_end; } goto fail_character_val; @@ -1951,15 +1807,6 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { obj_end: assert(!decode_ctn_is_arr(decode_ctn_info->ctn)); if(unlikely(!pyyjson_decode_obj(decode_obj_stack_info, get_decode_ctn_len(decode_ctn_info->ctn)))) goto failed_cleanup; - // OP_BUFFER_GROW(sizeof(pyyjson_container_op)); - // pyyjson_container_op *dict_op = (pyyjson_container_op *) cur_write_op; - // PYYJSON_WRITE_OP(dict_op, PYYJSON_OP_CONTAINER | PYYJSON_CONTAINER_FLAG_DICT); - // { - // Py_ssize_t cur_ctn_size = get_decode_ctn_len(ctn); - // OBJ_STACK_MAX_SIZE_UPDATE(1 - cur_ctn_size); - // dict_op->len = cur_ctn_size; - // } - // cur_write_op = (pyyjson_op *) (dict_op + 1); /* pop container */ /* point to the next value */ if (unlikely(decode_ctn_info->ctn-- == decode_ctn_info->ctn_start)) { @@ -1975,45 +1822,38 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { doc_end: /* check invalid contents after json document */ - if (unlikely(cur < end) // && !has_read_flag(STOP_WHEN_DONE) - ) { + if (unlikely(cur < end)) { while (char_is_space(*cur)) cur++; if (unlikely(cur < end)) goto fail_garbage; } +success:; + PyObject *obj = *decode_obj_stack_info->result_stack; assert(decode_ctn_info->ctn == decode_ctn_info->ctn_start - 1); - // free ctn buffer before calling pyyjson_op_loads. - // if (unlikely(decode_ctn_info->ctn_start != __stack_ctn_buffer)) { - // free(ctn_start); - // } - // add null terminate to op buffer - // OP_BUFFER_GROW(sizeof(pyyjson_op_base)); - // PYYJSON_WRITE_OP(cur_write_op, PYYJSON_NO_OP); - // OBJ_STACK_MAX_SIZE_UPDATE(1); assert(decode_obj_stack_info->cur_write_result_addr == decode_obj_stack_info->result_stack + 1); - PyObject *obj = *decode_obj_stack_info->result_stack; - assert(obj); + assert(obj && !PyErr_Occurred()); assert(obj->ob_refcnt == 1); - // TODO - // obj = pyyjson_op_loads(py_operations, object_stack_max_size); - // free py_operations - // if (py_operations != pyobject_stack_buffer) { - // free(py_operations); - // } // free string buffer if (unlikely(string_buffer_head != pyyjson_string_buffer)) { free(string_buffer_head); } - if(unlikely(decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack > PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE)){ + // free obj stack buffer if allocated dynamically + if (unlikely(decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack > PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE)) { free(decode_obj_stack_info->result_stack); } - // check - if (!obj && !PyErr_Occurred()) { - PyErr_SetString(PyExc_RuntimeError, "Unknown error: pyyjson_op_loads() failed"); - } return obj; +#define return_err(_pos, _type, _msg) \ + do { \ + if (_type == JSONDecodeError) { \ + PyErr_Format(JSONDecodeError, "%s, at position %zu", _msg, ((u8 *) _pos) - (u8 *) dat); \ + } else { \ + PyErr_SetString(_type, _msg); \ + } \ + goto failed_cleanup; \ + } while (0) + fail_string: return_err(cur, JSONDecodeError, "invalid string"); fail_number: @@ -2059,41 +1899,24 @@ force_inline PyObject *read_root_pretty(const char *dat, usize len) { "max recursion exceeded"); failed_cleanup: - // free ctn_start - // if (ctn_start != __stack_ctn_buffer) { - // free(ctn_start); - // } - // free py_operations - // if (py_operations != pyobject_stack_buffer) { - // free(py_operations); - // } - // free string buffer. this need NULL check + for (PyObject **obj_ptr = decode_obj_stack_info->result_stack; obj_ptr < decode_obj_stack_info->cur_write_result_addr; obj_ptr++) { + Py_XDECREF(*obj_ptr); + } + // free string buffer if (unlikely(string_buffer_head != pyyjson_string_buffer)) { free(string_buffer_head); } + // free obj stack buffer if allocated dynamically + if (unlikely(decode_obj_stack_info->result_stack_end - decode_obj_stack_info->result_stack > PYYJSON_DECODE_OBJ_BUFFER_INIT_SIZE)) { + free(decode_obj_stack_info->result_stack); + } return NULL; -// #undef val_incr -#undef MOVE_STRING_BUFFER_ALIGNED_4 -#undef CHECK_STRING_BUFFER_OVERFLOW -#undef CTN_BUFFER_GROW -#undef CTN_REALLOC_CHECK -#undef OP_BUFFER_GROW -#undef OP_BUFFER_REALLOC_CHECK -#undef OBJ_STACK_MAX_SIZE_UPDATE -// #undef OP_BUFFER_INIT_SIZE -// #undef COMMON_OPSIZE_RATIO -// #undef STACK_BUFFER_SIZE -// #undef CONTAINER_OBJ_TYPE -// #undef CONTAINER_ARR_TYPE #undef return_err } PyObject *yyjson_read_opts(const char *dat, usize len - // yyjson_read_flag flg, - // const yyjson_alc *alc_ptr, - //yyjson_read_err *err ) { #define return_err(_pos, _type, _msg) \ diff --git a/src/decode/decode.h b/src/decode/decode.h index 43a6a4c..6cdd4f5 100644 --- a/src/decode/decode.h +++ b/src/decode/decode.h @@ -6,56 +6,7 @@ #define PYYJSON_STRING_TYPE_ASCII 0 #define PYYJSON_STRING_TYPE_LATIN1 1 #define PYYJSON_STRING_TYPE_UCS2 2 -#define PYYJSON_STRING_TYPE_UCS4 3 - -#define PYYJSON_NUM_TYPE_FLOAT 0 -#define PYYJSON_NUM_TYPE_INT 1 -#define PYYJSON_NUM_TYPE_UINT 2 -// hot spot: -// string -> float,int->array,dict->null,false,true. least: uint, nan, inf -#define PYYJSON_NO_OP (0) -#define PYYJSON_OP_STRING (1) -#define PYYJSON_OP_NUMBER (2) -#define PYYJSON_OP_CONTAINER (3) -#define PYYJSON_OP_CONSTANTS (4) -#define PYYJSON_OP_NAN_INF (5) -// mask: 7 = (1 << 3) - 1, to cover 0~5 -#define PYYJSON_OP_MASK (7) -// PYYJSON_OP_BITCOUNT_MAX = 3, to cover 0~5 -#define PYYJSON_OP_BITCOUNT_MAX (3) -// higher start: 8 -#define PYYJSON_OP_HIGHER_START (1 << PYYJSON_OP_BITCOUNT_MAX) -//string flags ~~ -#define PYYJSON_STRING_FLAG_ASCII (PYYJSON_STRING_TYPE_ASCII << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_LATIN1 (PYYJSON_STRING_TYPE_LATIN1 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_UCS2 (PYYJSON_STRING_TYPE_UCS2 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_UCS4 (PYYJSON_STRING_TYPE_UCS4 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_STRING_FLAG_UCS_TYPE_MASK (3 << PYYJSON_OP_BITCOUNT_MAX) -// is key ~~ -#define PYYJSON_STRING_FLAG_OBJ_KEY (4 << PYYJSON_OP_BITCOUNT_MAX) -// num flags ~~ -#define PYYJSON_NUM_FLAG_FLOAT (0 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_NUM_FLAG_INT (1 << PYYJSON_OP_BITCOUNT_MAX) -// #define PYYJSON_NUM_FLAG_UINT (2 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_NUM_FLAG_MASK (3 << PYYJSON_OP_BITCOUNT_MAX) -// container flags ~~ -#define PYYJSON_CONTAINER_FLAG_ARRAY (0 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_CONTAINER_FLAG_DICT (1 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_CONTAINER_FLAG_MASK (1 << PYYJSON_OP_BITCOUNT_MAX) -// constants flags -#define PYYJSON_CONSTANTS_FLAG_NULL (0 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_CONSTANTS_FLAG_FALSE (1 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_CONSTANTS_FLAG_TRUE (2 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_CONSTANTS_FLAG_MASK (3 << PYYJSON_OP_BITCOUNT_MAX) -// nan inf flags -#define PYYJSON_NAN_INF_FLAG_NAN (0 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_NAN_INF_FLAG_INF (1 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_NAN_INF_FLAG_SIGNED (2 << PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_NAN_INF_FLAG_MASK_WITHOUT_SIGNED (1 << PYYJSON_OP_BITCOUNT_MAX) -//interpret flags -#define PYYJSON_MATCH_FLAG(x) case ((x) >> PYYJSON_OP_BITCOUNT_MAX) -#define PYYJSON_GET_FLAG(x, mask) (((x) & (mask)) >> PYYJSON_OP_BITCOUNT_MAX) -// end flags +#define PYYJSON_STRING_TYPE_UCS4 4 /** 16/32/64-bit vector */ @@ -297,7 +248,6 @@ force_inline bool _read_true(u8 **ptr) { u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; if (likely(byte_match_4(cur, "true"))) { - // val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_TRUE; *end = cur + 4; return true; } @@ -309,7 +259,6 @@ force_inline bool _read_false(u8 **ptr) { u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; if (likely(byte_match_4(cur + 1, "alse"))) { - // val->tag = YYJSON_TYPE_BOOL | YYJSON_SUBTYPE_FALSE; *end = cur + 5; return true; } @@ -321,7 +270,6 @@ force_inline bool _read_null(u8 **ptr) { u8 *cur = (u8 *)*ptr; u8 **end = (u8 **)ptr; if (likely(byte_match_4(cur, "null"))) { - // val->tag = YYJSON_TYPE_NULL; *end = cur + 4; return true; } @@ -346,16 +294,6 @@ force_inline bool _read_inf(bool sign, u8 **ptr) { cur += 3; } *end = cur; - // if (pre) { - // /* add null-terminator for previous raw string */ - // if (*pre) **pre = '\0'; - // *pre = cur; - // val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; - // val->uni.str = (const char *)hdr; - // } else { - // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; - // val->uni.u64 = f64_raw_get_inf(sign); - // } return true; } return false; @@ -371,16 +309,6 @@ force_inline bool _read_nan(bool sign, u8 **ptr) { (cur[2] == 'N' || cur[2] == 'n')) { cur += 3; *end = cur; - // if (pre) { - // /* add null-terminator for previous raw string */ - // if (*pre) **pre = '\0'; - // *pre = cur; - // val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; - // val->uni.str = (const char *)hdr; - // } else { - // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; - // val->uni.u64 = f64_raw_get_nan(sign); - // } return true; } return false; From c4cc4f502895358aa621821d3b3f43223318b903 Mon Sep 17 00:00:00 2001 From: antares Date: Thu, 19 Dec 2024 01:54:37 +0800 Subject: [PATCH 10/12] Update test_utils.py --- test/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_utils.py b/test/test_utils.py index d0d51df..aeb8229 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -62,7 +62,7 @@ def get_benchfiles_fullpath(): ) return sorted( - [os.path.join(benchmark_folder, f) for f in os.listdir(benchmark_folder)] + [os.path.join(benchmark_folder, f) for f in os.listdir(benchmark_folder) if f.endswith(".json")] ) From 00ad93e6ded10b5cbfdf28da19cf01adc804a612 Mon Sep 17 00:00:00 2001 From: antares Date: Thu, 19 Dec 2024 01:56:45 +0800 Subject: [PATCH 11/12] Refactor: code cleanup --- src/decode/decode_float.inl.h | 71 ----------------------------------- 1 file changed, 71 deletions(-) diff --git a/src/decode/decode_float.inl.h b/src/decode/decode_float.inl.h index 1eb69e2..3b6e729 100644 --- a/src/decode/decode_float.inl.h +++ b/src/decode/decode_float.inl.h @@ -436,53 +436,21 @@ force_inline bool read_number(DecodeObjStackInfo *decode_obj_stack_info, u8 **pt return false; \ } while (0) -// #define return_0() do { \ -// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ -// op_int->data.i = 0; \ -// *op = (pyyjson_op*)(op_int + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_0() do { \ *end = cur; \ return pyyjson_decode_longlong(decode_obj_stack_info, 0); \ } while (false) -// #define return_i64(_v) do { \ -// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ -// op_int->data.u = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ -// *op = (pyyjson_op*)(op_int + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_i64(_v) do { \ *end = cur; \ return pyyjson_decode_longlong(decode_obj_stack_info, (i64)(sign ? (u64)(~(_v) + 1) : (u64)(_v))); \ } while (false) -// #define return_f64(_v) do { \ -// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ -// op_float->data.f = sign ? -(f64)(_v) : (f64)(_v); \ -// *op = (pyyjson_op*)(op_float + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_f64(_v) do { \ *end = cur; \ return pyyjson_decode_double(decode_obj_stack_info, sign ? -(f64)(_v) : (f64)(_v)); \ } while (false) -// #define return_f64_bin(_v) do { \ -// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ -// op_float->data.u = ((u64)sign << 63) | (u64)(_v); \ -// *op = (pyyjson_op*)(op_float + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_f64_bin(_v) do { \ *end = cur; \ u64 temp = ((u64)sign << 63) | (u64)(_v); \ @@ -493,13 +461,6 @@ force_inline bool read_number(DecodeObjStackInfo *decode_obj_stack_info, u8 **pt return_f64_bin(F64_RAW_INF); \ } while (false) -// #define return_raw() do { \ -// if (*pre) **pre = '\0'; /* add null-terminator for previous raw string */ \ -// val->tag = ((u64)(cur - hdr) << YYJSON_TAG_BIT) | YYJSON_TYPE_RAW; \ -// val->uni.str = (const char *)hdr; \ -// *pre = cur; *end = cur; return true; \ -// } while (false) - u8 *sig_cut = NULL; /* significant part cutting position for long number */ u8 *sig_end = NULL; /* significant part ending position */ u8 *dot_pos = NULL; /* decimal point position */ @@ -1074,53 +1035,21 @@ force_inline bool read_number(DecodeObjStackInfo *decode_obj_stack_info, u8 **pt return false; \ } while (0) -// #define return_0() do { \ -// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ -// op_int->data.i = 0; \ -// *op = (pyyjson_op*)(op_int + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_0() do { \ *end = cur; \ return pyyjson_decode_longlong(decode_obj_stack_info, 0); \ } while (false) -// #define return_i64(_v) do { \ -// pyyjson_number_op* op_int = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_int, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_INT); \ -// op_int->data.u = (u64)(sign ? (u64)(~(_v) + 1) : (u64)(_v)); \ -// *op = (pyyjson_op*)(op_int + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_i64(_v) do { \ *end = cur; \ return pyyjson_decode_longlong(decode_obj_stack_info, (i64)(sign ? (u64)(~(_v) + 1) : (u64)(_v))); \ } while (false) -// #define return_f64(_v) do { \ -// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ -// op_float->data.f = sign ? -(f64)(_v) : (f64)(_v); \ -// *op = (pyyjson_op*)(op_float + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_f64(_v) do { \ *end = cur; \ return pyyjson_decode_double(decode_obj_stack_info, sign ? -(f64)(_v) : (f64)(_v)); \ } while (false) -// #define return_f64_bin(_v) do { \ -// pyyjson_number_op* op_float = (pyyjson_number_op*)*op; \ -// PYYJSON_WRITE_OP(op_float, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); \ -// op_float->data.u = ((u64)sign << 63) | (u64)(_v); \ -// *op = (pyyjson_op*)(op_float + 1); \ -// *end = cur; return true; \ -// } while (false) - #define return_f64_bin(_v) do { \ *end = cur; \ u64 temp = ((u64)sign << 63) | (u64)(_v); \ From fa52f4a8f0bf944698b20d56748b82d3e763b677 Mon Sep 17 00:00:00 2001 From: antares Date: Thu, 19 Dec 2024 01:58:10 +0800 Subject: [PATCH 12/12] Code cleanup, remove useless comments --- src/decode/decode.c | 8 -------- src/decode/decode_float.inl.h | 5 +---- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/decode/decode.c b/src/decode/decode.c index be3b730..ecd96fb 100644 --- a/src/decode/decode.c +++ b/src/decode/decode.c @@ -681,14 +681,6 @@ force_inline bool read_string(DecodeObjStackInfo *restrict decode_obj_stack_info // this is a fast path for ascii strings. directly copy the buffer to pyobject *ptr = src + 1; return pyyjson_decode_string(decode_obj_stack_info, src_start, src - src_start, PYYJSON_STRING_TYPE_ASCII, is_key); - // pyyjson_string_op* string_op =(pyyjson_string_op*) *op; - // PYYJSON_WRITE_OP(string_op, PYYJSON_OP_STRING | PYYJSON_STRING_FLAG_ASCII); - // string_op->data = (char *)src_start; - // string_op->len = src - src_start; - // *op = (pyyjson_op*)(string_op + 1); - // // buffer unchanged - // return true; - } else if(src != src_start){ memcpy(temp_string_buf, src_start, src - src_start); len_ucs1 = src - src_start; diff --git a/src/decode/decode_float.inl.h b/src/decode/decode_float.inl.h index 3b6e729..0790a70 100644 --- a/src/decode/decode_float.inl.h +++ b/src/decode/decode_float.inl.h @@ -1186,10 +1186,7 @@ force_inline bool read_number(DecodeObjStackInfo *decode_obj_stack_info, u8 **pt if (unlikely(f >= HUGE_VAL || f <= -HUGE_VAL)) { return_inf(); } - - // PYYJSON_WRITE_OP(op_float_final, PYYJSON_OP_NUMBER | PYYJSON_NUM_FLAG_FLOAT); - // *op = (pyyjson_op*)(op_float_final + 1); - // val->tag = YYJSON_TYPE_NUM | YYJSON_SUBTYPE_REAL; + *end = cur; return pyyjson_decode_double(decode_obj_stack_info, f); return true;