/src/tarantool/third_party/luajit/src/lj_wbuf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** Low-level writer for LuaJIT. |
3 | | ** |
4 | | ** Major portions taken verbatim or adapted from the LuaVela. |
5 | | ** Copyright (C) 2015-2019 IPONWEB Ltd. |
6 | | */ |
7 | | |
8 | | #define lj_wbuf_c |
9 | | #define LUA_CORE |
10 | | |
11 | | #include <errno.h> |
12 | | |
13 | | #include "lj_obj.h" |
14 | | #include "lj_wbuf.h" |
15 | | #include "lj_utils.h" |
16 | | |
17 | | static LJ_AINLINE void wbuf_set_flag(struct lj_wbuf *buf, uint8_t flag) |
18 | 0 | { |
19 | 0 | buf->flags |= flag; |
20 | 0 | } |
21 | | |
22 | | static LJ_AINLINE void wbuf_save_errno(struct lj_wbuf *buf) |
23 | 0 | { |
24 | 0 | buf->saved_errno = errno; |
25 | 0 | } |
26 | | |
27 | | static LJ_AINLINE size_t wbuf_len(const struct lj_wbuf *buf) |
28 | 0 | { |
29 | 0 | return (size_t)(buf->pos - buf->buf); |
30 | 0 | } |
31 | | |
32 | | static LJ_AINLINE size_t wbuf_left(const struct lj_wbuf *buf) |
33 | 0 | { |
34 | 0 | return buf->size - wbuf_len(buf); |
35 | 0 | } |
36 | | |
37 | | void lj_wbuf_init(struct lj_wbuf *buf, lj_wbuf_writer writer, |
38 | | void *ctx, uint8_t *mem, size_t size) |
39 | 0 | { |
40 | 0 | buf->ctx = ctx; |
41 | 0 | buf->writer = writer; |
42 | 0 | buf->buf = mem; |
43 | 0 | buf->pos = mem; |
44 | 0 | buf->size = size; |
45 | 0 | buf->flags = 0; |
46 | 0 | buf->saved_errno = 0; |
47 | 0 | } |
48 | | |
49 | | void LJ_FASTCALL lj_wbuf_terminate(struct lj_wbuf *buf) |
50 | 0 | { |
51 | 0 | lj_wbuf_init(buf, NULL, NULL, NULL, 0); |
52 | 0 | } |
53 | | |
54 | | static LJ_AINLINE void wbuf_reserve(struct lj_wbuf *buf, size_t n) |
55 | 0 | { |
56 | 0 | lj_assertX(n <= buf->size, "wbuf overflow"); |
57 | 0 | if (LJ_UNLIKELY(wbuf_left(buf) < n)) |
58 | 0 | lj_wbuf_flush(buf); |
59 | 0 | } |
60 | | |
61 | | /* Writes a byte to the output buffer. */ |
62 | | void LJ_FASTCALL lj_wbuf_addbyte(struct lj_wbuf *buf, uint8_t b) |
63 | 0 | { |
64 | 0 | if (LJ_UNLIKELY(lj_wbuf_test_flag(buf, STREAM_STOP))) |
65 | 0 | return; |
66 | 0 | wbuf_reserve(buf, sizeof(b)); |
67 | 0 | *buf->pos++ = b; |
68 | 0 | } |
69 | | |
70 | | /* Writes an unsigned integer which is at most 64 bits long to the output. */ |
71 | | void LJ_FASTCALL lj_wbuf_addu64(struct lj_wbuf *buf, uint64_t n) |
72 | 0 | { |
73 | 0 | if (LJ_UNLIKELY(lj_wbuf_test_flag(buf, STREAM_STOP))) |
74 | 0 | return; |
75 | 0 | wbuf_reserve(buf, LEB128_U64_MAXSIZE); |
76 | 0 | buf->pos += (ptrdiff_t)lj_utils_write_uleb128(buf->pos, n); |
77 | 0 | } |
78 | | |
79 | | /* Writes n bytes from an arbitrary buffer src to the buffer. */ |
80 | | void lj_wbuf_addn(struct lj_wbuf *buf, const void *src, size_t n) |
81 | 0 | { |
82 | 0 | if (LJ_UNLIKELY(lj_wbuf_test_flag(buf, STREAM_STOP))) |
83 | 0 | return; |
84 | | /* |
85 | | ** Very unlikely: We are told to write a large buffer at once. |
86 | | ** Buffer doesn't belong to us so we must to pump data |
87 | | ** through the buffer. |
88 | | */ |
89 | 0 | while (LJ_UNLIKELY(n > buf->size)) { |
90 | 0 | const size_t left = wbuf_left(buf); |
91 | 0 | memcpy(buf->pos, src, left); |
92 | 0 | buf->pos += (ptrdiff_t)left; |
93 | 0 | lj_wbuf_flush(buf); |
94 | 0 | src = (uint8_t *)src + (ptrdiff_t)left; |
95 | 0 | n -= left; |
96 | 0 | } |
97 | |
|
98 | 0 | wbuf_reserve(buf, n); |
99 | 0 | memcpy(buf->pos, src, n); |
100 | 0 | buf->pos += (ptrdiff_t)n; |
101 | 0 | } |
102 | | |
103 | | /* Writes a \0-terminated C string to the output buffer. */ |
104 | | void LJ_FASTCALL lj_wbuf_addstring(struct lj_wbuf *buf, const char *s) |
105 | 0 | { |
106 | 0 | const size_t l = strlen(s); |
107 | | |
108 | | /* Check that profiling is still active is made in the callee's scope. */ |
109 | 0 | lj_wbuf_addu64(buf, (uint64_t)l); |
110 | 0 | lj_wbuf_addn(buf, s, l); |
111 | 0 | } |
112 | | |
113 | | void LJ_FASTCALL lj_wbuf_flush(struct lj_wbuf *buf) |
114 | 0 | { |
115 | 0 | const size_t len = wbuf_len(buf); |
116 | 0 | size_t written; |
117 | |
|
118 | 0 | if (LJ_UNLIKELY(lj_wbuf_test_flag(buf, STREAM_STOP))) |
119 | 0 | return; |
120 | | |
121 | 0 | written = buf->writer((const void **)&buf->buf, len, buf->ctx); |
122 | |
|
123 | 0 | if (LJ_UNLIKELY(written < len)) { |
124 | 0 | wbuf_set_flag(buf, STREAM_ERRIO); |
125 | 0 | wbuf_save_errno(buf); |
126 | 0 | } |
127 | 0 | if (LJ_UNLIKELY(buf->buf == NULL)) { |
128 | 0 | wbuf_set_flag(buf, STREAM_STOP); |
129 | 0 | wbuf_save_errno(buf); |
130 | 0 | } |
131 | 0 | buf->pos = buf->buf; |
132 | 0 | } |
133 | | |
134 | | int LJ_FASTCALL lj_wbuf_test_flag(const struct lj_wbuf *buf, uint8_t flag) |
135 | 0 | { |
136 | 0 | return buf->flags & flag; |
137 | 0 | } |
138 | | |
139 | | int LJ_FASTCALL lj_wbuf_errno(const struct lj_wbuf *buf) |
140 | 0 | { |
141 | 0 | return buf->saved_errno; |
142 | 0 | } |