aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/contact.html2
-rw-r--r--doc/ext_buffer.html275
-rw-r--r--doc/ext_c_api.html2
-rw-r--r--doc/ext_ffi.html2
-rw-r--r--doc/ext_ffi_api.html2
-rw-r--r--doc/ext_ffi_semantics.html2
-rw-r--r--doc/ext_ffi_tutorial.html2
-rw-r--r--doc/ext_jit.html2
-rw-r--r--doc/ext_profiler.html2
-rw-r--r--doc/extensions.html2
-rw-r--r--doc/faq.html2
-rw-r--r--doc/install.html2
-rw-r--r--doc/luajit.html2
-rw-r--r--doc/running.html2
-rw-r--r--doc/status.html2
-rw-r--r--src/Makefile6
-rw-r--r--src/Makefile.dep36
-rw-r--r--src/lib_buffer.c66
-rw-r--r--src/lib_string.c3
-rw-r--r--src/lj_arch.h7
-rw-r--r--src/lj_buf.h9
-rw-r--r--src/lj_errmsg.h10
-rw-r--r--src/lj_serialize.c351
-rw-r--r--src/lj_serialize.h21
-rw-r--r--src/ljamalg.c2
-rw-r--r--src/lualib.h1
26 files changed, 797 insertions, 18 deletions
diff --git a/doc/contact.html b/doc/contact.html
index b7980091..c253a08b 100644
--- a/doc/contact.html
+++ b/doc/contact.html
@@ -37,6 +37,8 @@
37<a href="ext_ffi_semantics.html">FFI Semantics</a> 37<a href="ext_ffi_semantics.html">FFI Semantics</a>
38</li></ul> 38</li></ul>
39</li><li> 39</li><li>
40<a href="ext_buffer.html">String Buffers</a>
41</li><li>
40<a href="ext_jit.html">jit.* Library</a> 42<a href="ext_jit.html">jit.* Library</a>
41</li><li> 43</li><li>
42<a href="ext_c_api.html">Lua/C API</a> 44<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_buffer.html b/doc/ext_buffer.html
new file mode 100644
index 00000000..455c298d
--- /dev/null
+++ b/doc/ext_buffer.html
@@ -0,0 +1,275 @@
1<!DOCTYPE html>
2<html>
3<head>
4<title>String Buffers</title>
5<meta charset="utf-8">
6<meta name="Copyright" content="Copyright (C) 2005-2021">
7<meta name="Language" content="en">
8<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
9<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
10</head>
11<body>
12<div id="site">
13<a href="https://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
14</div>
15<div id="head">
16<h1>String Buffers</h1>
17</div>
18<div id="nav">
19<ul><li>
20<a href="luajit.html">LuaJIT</a>
21<ul><li>
22<a href="https://luajit.org/download.html">Download <span class="ext">&raquo;</span></a>
23</li><li>
24<a href="install.html">Installation</a>
25</li><li>
26<a href="running.html">Running</a>
27</li></ul>
28</li><li>
29<a href="extensions.html">Extensions</a>
30<ul><li>
31<a href="ext_ffi.html">FFI Library</a>
32<ul><li>
33<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
34</li><li>
35<a href="ext_ffi_api.html">ffi.* API</a>
36</li><li>
37<a href="ext_ffi_semantics.html">FFI Semantics</a>
38</li></ul>
39</li><li>
40<a class="current" href="ext_buffer.html">String Buffers</a>
41</li><li>
42<a href="ext_jit.html">jit.* Library</a>
43</li><li>
44<a href="ext_c_api.html">Lua/C API</a>
45</li><li>
46<a href="ext_profiler.html">Profiler</a>
47</li></ul>
48</li><li>
49<a href="status.html">Status</a>
50</li><li>
51<a href="faq.html">FAQ</a>
52</li><li>
53<a href="http://wiki.luajit.org/">Wiki <span class="ext">&raquo;</span></a>
54</li><li>
55<a href="https://luajit.org/list.html">Mailing List <span class="ext">&raquo;</span></a>
56</li></ul>
57</div>
58<div id="main">
59<p>
60
61The string buffer library allows <b>high-performance manipulation of
62string-like data</b>.
63
64</p>
65<p>
66
67Unlike Lua strings, which are constants, string buffers are
68<b>mutable</b> sequences of 8-bit (binary-transparent) characters. Data
69can be stored, formatted and encoded into a string buffer and later
70converted, decoded or extracted.
71
72</p>
73<p>
74
75The convenient string buffer API simplifies common string manipulation
76tasks, that would otherwise require creating many intermediate strings.
77String buffers improve performance by eliminating redundant memory
78copies, object creation, string interning and garbage collection
79overhead. In conjunction with the FFI library, they allow zero-copy
80operations.
81
82</p>
83
84<h2 id="load">Using the String Buffer Library</h2>
85<p>
86The string buffer library is built into LuaJIT by default, but it's not
87loaded by default. Add this to the start of every Lua file that needs
88one of its functions:
89</p>
90<pre class="code">
91local buffer = require("string.buffer")
92</pre>
93
94<h2 id="wip" style="color:#ff0000">Work in Progress</h2>
95
96<p>
97
98<b style="color:#ff0000">This library is a work in progress. More
99functions will be added soon.</b>
100
101</p>
102
103<h2 id="serialize">Serialization of Lua Objects</h2>
104<p>
105
106The following functions and methods allow <b>high-speed serialization</b>
107(encoding) of a Lua object into a string and decoding it back to a Lua
108object. This allows convenient storage and transport of <b>structured
109data</b>.
110
111</p>
112<p>
113
114The encoded data is in an <a href="#serialize_format">internal binary
115format</a>. The data can be stored in files, binary-transparent
116databases or transmitted to other LuaJIT instances across threads,
117processes or networks.
118
119</p>
120<p>
121
122Encoding speed can reach up to 1 Gigabyte/second on a modern desktop- or
123server-class system, even when serializing many small objects. Decoding
124speed is mostly constrained by object creation cost.
125
126</p>
127<p>
128
129The serializer handles most Lua types, common FFI number types and
130nested structures. Functions, thread objects, other FFI cdata, full
131userdata and associated metatables cannot be serialized (yet).
132
133</p>
134<p>
135
136The encoder serializes nested structures as trees. Multiple references
137to a single object will be stored separately and create distinct objects
138after decoding. Circular references cause an error.
139
140
141</p>
142
143<h3 id="buffer_encode"><tt>str = buffer.encode(obj)</tt></h3>
144<p>
145
146Serializes (encodes) the Lua object <tt>obj</tt> into the string
147<tt>str</tt>.
148
149</p>
150<p>
151
152<tt>obj</tt> can be any of the supported Lua types &mdash; it doesn't
153need to be a Lua table.
154
155</p>
156<p>
157
158This function may throw an error when attempting to serialize
159unsupported object types, circular references or deeply nested tables.
160
161</p>
162
163<h3 id="buffer_decode"><tt>obj = buffer.decode(str)</tt></h3>
164<p>
165
166De-serializes (decodes) the string <tt>str</tt> into the Lua object
167<tt>obj</tt>.
168
169</p>
170<p>
171
172The returned object may be any of the supported Lua types &mdash;
173even <tt>nil</tt>.
174
175</p>
176<p>
177
178This function may throw an error when fed with malformed or incomplete
179encoded data. The standalone function throws when there's left-over data
180after decoding a single top-level object.
181
182</p>
183
184<h2 id="serialize_format">Serialization Format Specification</h2>
185<p>
186
187This serialization format is designed for <b>internal use</b> by LuaJIT
188applications. Serialized data is upwards-compatible and portable across
189all supported LuaJIT platforms.
190
191</p>
192<p>
193
194It's an <b>8-bit binary format</b> and not human-readable. It uses e.g.
195embedded zeroes and stores embedded Lua string objects unmodified, which
196are 8-bit-clean, too. Encoded data can be safely concatenated for
197streaming and later decoded one top-level object at a time.
198
199</p>
200<p>
201
202The encoding is reasonably compact, but tuned for maximum performance,
203not for minimum space usage. It compresses well with any of the common
204byte-oriented data compression algorithms.
205
206</p>
207<p>
208
209Although documented here for reference, this format is explicitly
210<b>not</b> intended to be a 'public standard' for structured data
211interchange across computer languages (like JSON or MessagePack). Please
212do not use it as such.
213
214</p>
215<p>
216
217The specification is given below as a context-free grammar with a
218top-level <tt>object</tt> as the starting point. Alternatives are
219separated by the <tt>|</tt> symbol and <tt>*</tt> indicates repeats.
220Grouping is implicit or indicated by <tt>{…}</tt>. Terminals are
221either plain hex numbers, encoded as bytes, or have a <tt>.format</tt>
222suffix.
223
224</p>
225<pre>
226object → nil | false | true
227 | null | lightud32 | lightud64
228 | int | num | tab
229 | int64 | uint64 | complex
230 | string
231
232nil → 0x00
233false → 0x01
234true → 0x02
235
236null → 0x03 // NULL lightuserdata
237lightud32 → 0x04 data.I // 32 bit lightuserdata
238lightud64 → 0x05 data.L // 64 bit lightuserdata
239
240int → 0x06 int.I // int32_t
241num → 0x07 double.L
242
243tab → 0x08 // Empty table
244 | 0x09 h.U h*{object object} // Key/value hash
245 | 0x0a a.U a*object // 0-based array
246 | 0x0b a.U a*object h.U h*{object object} // Mixed
247 | 0x0c a.U (a-1)*object // 1-based array
248 | 0x0d a.U (a-1)*object h.U h*{object object} // Mixed
249
250int64 → 0x10 int.L // FFI int64_t
251uint64 → 0x11 uint.L // FFI uint64_t
252complex → 0x12 re.L im.L // FFI complex
253
254string → (0x20+len).U len*char.B
255
256.B = 8 bit
257.I = 32 bit little-endian
258.L = 64 bit little-endian
259.U = prefix-encoded 32 bit unsigned number n:
260 0x00..0xdf → n.B
261 0xe0..0x1fdf → (0xe0|(((n-0xe0)>>8)&0x1f)).B ((n-0xe0)&0xff).B
262 0x1fe0.. → 0xff n.I
263</pre>
264<br class="flush">
265</div>
266<div id="foot">
267<hr class="hide">
268Copyright &copy; 2005-2021
269<span class="noprint">
270&middot;
271<a href="contact.html">Contact</a>
272</span>
273</div>
274</body>
275</html>
diff --git a/doc/ext_c_api.html b/doc/ext_c_api.html
index 6079e5ac..9f1ad212 100644
--- a/doc/ext_c_api.html
+++ b/doc/ext_c_api.html
@@ -37,6 +37,8 @@
37<a href="ext_ffi_semantics.html">FFI Semantics</a> 37<a href="ext_ffi_semantics.html">FFI Semantics</a>
38</li></ul> 38</li></ul>
39</li><li> 39</li><li>
40<a href="ext_buffer.html">String Buffers</a>
41</li><li>
40<a href="ext_jit.html">jit.* Library</a> 42<a href="ext_jit.html">jit.* Library</a>
41</li><li> 43</li><li>
42<a class="current" href="ext_c_api.html">Lua/C API</a> 44<a class="current" href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_ffi.html b/doc/ext_ffi.html
index 13b75bda..b934dc78 100644
--- a/doc/ext_ffi.html
+++ b/doc/ext_ffi.html
@@ -37,6 +37,8 @@
37<a href="ext_ffi_semantics.html">FFI Semantics</a> 37<a href="ext_ffi_semantics.html">FFI Semantics</a>
38</li></ul> 38</li></ul>
39</li><li> 39</li><li>
40<a href="ext_buffer.html">String Buffers</a>
41</li><li>
40<a href="ext_jit.html">jit.* Library</a> 42<a href="ext_jit.html">jit.* Library</a>
41</li><li> 43</li><li>
42<a href="ext_c_api.html">Lua/C API</a> 44<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html
index b7ace808..061cc42a 100644
--- a/doc/ext_ffi_api.html
+++ b/doc/ext_ffi_api.html
@@ -42,6 +42,8 @@ td.abiparam { font-weight: bold; width: 6em; }
42<a href="ext_ffi_semantics.html">FFI Semantics</a> 42<a href="ext_ffi_semantics.html">FFI Semantics</a>
43</li></ul> 43</li></ul>
44</li><li> 44</li><li>
45<a href="ext_buffer.html">String Buffers</a>
46</li><li>
45<a href="ext_jit.html">jit.* Library</a> 47<a href="ext_jit.html">jit.* Library</a>
46</li><li> 48</li><li>
47<a href="ext_c_api.html">Lua/C API</a> 49<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_ffi_semantics.html b/doc/ext_ffi_semantics.html
index 904ee51d..fef39c32 100644
--- a/doc/ext_ffi_semantics.html
+++ b/doc/ext_ffi_semantics.html
@@ -42,6 +42,8 @@ td.convop { font-style: italic; width: 40%; }
42<a class="current" href="ext_ffi_semantics.html">FFI Semantics</a> 42<a class="current" href="ext_ffi_semantics.html">FFI Semantics</a>
43</li></ul> 43</li></ul>
44</li><li> 44</li><li>
45<a href="ext_buffer.html">String Buffers</a>
46</li><li>
45<a href="ext_jit.html">jit.* Library</a> 47<a href="ext_jit.html">jit.* Library</a>
46</li><li> 48</li><li>
47<a href="ext_c_api.html">Lua/C API</a> 49<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_ffi_tutorial.html b/doc/ext_ffi_tutorial.html
index 8ed61364..ca71be4d 100644
--- a/doc/ext_ffi_tutorial.html
+++ b/doc/ext_ffi_tutorial.html
@@ -44,6 +44,8 @@ td.idiomlua b { font-weight: normal; color: #2142bf; }
44<a href="ext_ffi_semantics.html">FFI Semantics</a> 44<a href="ext_ffi_semantics.html">FFI Semantics</a>
45</li></ul> 45</li></ul>
46</li><li> 46</li><li>
47<a href="ext_buffer.html">String Buffers</a>
48</li><li>
47<a href="ext_jit.html">jit.* Library</a> 49<a href="ext_jit.html">jit.* Library</a>
48</li><li> 50</li><li>
49<a href="ext_c_api.html">Lua/C API</a> 51<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_jit.html b/doc/ext_jit.html
index 84302fa0..6dd54c70 100644
--- a/doc/ext_jit.html
+++ b/doc/ext_jit.html
@@ -37,6 +37,8 @@
37<a href="ext_ffi_semantics.html">FFI Semantics</a> 37<a href="ext_ffi_semantics.html">FFI Semantics</a>
38</li></ul> 38</li></ul>
39</li><li> 39</li><li>
40<a href="ext_buffer.html">String Buffers</a>
41</li><li>
40<a class="current" href="ext_jit.html">jit.* Library</a> 42<a class="current" href="ext_jit.html">jit.* Library</a>
41</li><li> 43</li><li>
42<a href="ext_c_api.html">Lua/C API</a> 44<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/ext_profiler.html b/doc/ext_profiler.html
index 0e8d3691..2783abdb 100644
--- a/doc/ext_profiler.html
+++ b/doc/ext_profiler.html
@@ -37,6 +37,8 @@
37<a href="ext_ffi_semantics.html">FFI Semantics</a> 37<a href="ext_ffi_semantics.html">FFI Semantics</a>
38</li></ul> 38</li></ul>
39</li><li> 39</li><li>
40<a href="ext_buffer.html">String Buffers</a>
41</li><li>
40<a href="ext_jit.html">jit.* Library</a> 42<a href="ext_jit.html">jit.* Library</a>
41</li><li> 43</li><li>
42<a href="ext_c_api.html">Lua/C API</a> 44<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/extensions.html b/doc/extensions.html
index 77cf444c..799679a3 100644
--- a/doc/extensions.html
+++ b/doc/extensions.html
@@ -54,6 +54,8 @@ td.excinterop {
54<a href="ext_ffi_semantics.html">FFI Semantics</a> 54<a href="ext_ffi_semantics.html">FFI Semantics</a>
55</li></ul> 55</li></ul>
56</li><li> 56</li><li>
57<a href="ext_buffer.html">String Buffers</a>
58</li><li>
57<a href="ext_jit.html">jit.* Library</a> 59<a href="ext_jit.html">jit.* Library</a>
58</li><li> 60</li><li>
59<a href="ext_c_api.html">Lua/C API</a> 61<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/faq.html b/doc/faq.html
index b71e6e7c..a5d744d2 100644
--- a/doc/faq.html
+++ b/doc/faq.html
@@ -40,6 +40,8 @@ dd { margin-left: 1.5em; }
40<a href="ext_ffi_semantics.html">FFI Semantics</a> 40<a href="ext_ffi_semantics.html">FFI Semantics</a>
41</li></ul> 41</li></ul>
42</li><li> 42</li><li>
43<a href="ext_buffer.html">String Buffers</a>
44</li><li>
43<a href="ext_jit.html">jit.* Library</a> 45<a href="ext_jit.html">jit.* Library</a>
44</li><li> 46</li><li>
45<a href="ext_c_api.html">Lua/C API</a> 47<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/install.html b/doc/install.html
index fab0b2ca..e4af9dde 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -65,6 +65,8 @@ td.compatno {
65<a href="ext_ffi_semantics.html">FFI Semantics</a> 65<a href="ext_ffi_semantics.html">FFI Semantics</a>
66</li></ul> 66</li></ul>
67</li><li> 67</li><li>
68<a href="ext_buffer.html">String Buffers</a>
69</li><li>
68<a href="ext_jit.html">jit.* Library</a> 70<a href="ext_jit.html">jit.* Library</a>
69</li><li> 71</li><li>
70<a href="ext_c_api.html">Lua/C API</a> 72<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/luajit.html b/doc/luajit.html
index 42c0ac83..a25267a6 100644
--- a/doc/luajit.html
+++ b/doc/luajit.html
@@ -122,6 +122,8 @@ table.feature small {
122<a href="ext_ffi_semantics.html">FFI Semantics</a> 122<a href="ext_ffi_semantics.html">FFI Semantics</a>
123</li></ul> 123</li></ul>
124</li><li> 124</li><li>
125<a href="ext_buffer.html">String Buffers</a>
126</li><li>
125<a href="ext_jit.html">jit.* Library</a> 127<a href="ext_jit.html">jit.* Library</a>
126</li><li> 128</li><li>
127<a href="ext_c_api.html">Lua/C API</a> 129<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/running.html b/doc/running.html
index ae4911d5..b55b8439 100644
--- a/doc/running.html
+++ b/doc/running.html
@@ -59,6 +59,8 @@ td.param_default {
59<a href="ext_ffi_semantics.html">FFI Semantics</a> 59<a href="ext_ffi_semantics.html">FFI Semantics</a>
60</li></ul> 60</li></ul>
61</li><li> 61</li><li>
62<a href="ext_buffer.html">String Buffers</a>
63</li><li>
62<a href="ext_jit.html">jit.* Library</a> 64<a href="ext_jit.html">jit.* Library</a>
63</li><li> 65</li><li>
64<a href="ext_c_api.html">Lua/C API</a> 66<a href="ext_c_api.html">Lua/C API</a>
diff --git a/doc/status.html b/doc/status.html
index e1f024bf..1d3ba984 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -40,6 +40,8 @@ ul li { padding-bottom: 0.3em; }
40<a href="ext_ffi_semantics.html">FFI Semantics</a> 40<a href="ext_ffi_semantics.html">FFI Semantics</a>
41</li></ul> 41</li></ul>
42</li><li> 42</li><li>
43<a href="ext_buffer.html">String Buffers</a>
44</li><li>
43<a href="ext_jit.html">jit.* Library</a> 45<a href="ext_jit.html">jit.* Library</a>
44</li><li> 46</li><li>
45<a href="ext_c_api.html">Lua/C API</a> 47<a href="ext_c_api.html">Lua/C API</a>
diff --git a/src/Makefile b/src/Makefile
index 6f17bafd..a6e25ba1 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -482,13 +482,15 @@ LJVM_BOUT= $(LJVM_S)
482LJVM_MODE= elfasm 482LJVM_MODE= elfasm
483 483
484LJLIB_O= lib_base.o lib_math.o lib_bit.o lib_string.o lib_table.o \ 484LJLIB_O= lib_base.o lib_math.o lib_bit.o lib_string.o lib_table.o \
485 lib_io.o lib_os.o lib_package.o lib_debug.o lib_jit.o lib_ffi.o 485 lib_io.o lib_os.o lib_package.o lib_debug.o lib_jit.o lib_ffi.o \
486 lib_buffer.o
486LJLIB_C= $(LJLIB_O:.o=.c) 487LJLIB_C= $(LJLIB_O:.o=.c)
487 488
488LJCORE_O= lj_assert.o lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \ 489LJCORE_O= lj_assert.o lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
489 lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \ 490 lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
490 lj_prng.o lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o \ 491 lj_prng.o lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o \
491 lj_strscan.o lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \ 492 lj_strscan.o lj_strfmt.o lj_strfmt_num.o lj_serialize.o \
493 lj_api.o lj_profile.o \
492 lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \ 494 lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
493 lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ 495 lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
494 lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \ 496 lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
diff --git a/src/Makefile.dep b/src/Makefile.dep
index 3f26599e..315bf632 100644
--- a/src/Makefile.dep
+++ b/src/Makefile.dep
@@ -10,6 +10,9 @@ lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
10 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \ 10 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \
11 lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \ 11 lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \
12 lj_ffdef.h lj_lib.h lj_libdef.h 12 lj_ffdef.h lj_lib.h lj_libdef.h
13lib_buffer.o: lib_buffer.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
14 lj_def.h lj_arch.h lj_gc.h lj_buf.h lj_str.h lj_serialize.h lj_lib.h \
15 lj_libdef.h
13lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ 16lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
14 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \ 17 lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \
15 lj_libdef.h 18 lj_libdef.h
@@ -170,15 +173,18 @@ lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
170 lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \ 173 lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_str.h lj_tab.h \
171 lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \ 174 lj_func.h lj_state.h lj_bc.h lj_ctype.h lj_strfmt.h lj_lex.h lj_parse.h \
172 lj_vm.h lj_vmevent.h 175 lj_vm.h lj_vmevent.h
176lj_prng.o: lj_prng.c lj_def.h lua.h luaconf.h lj_arch.h lj_prng.h
173lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 177lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
174 lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \ 178 lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
175 lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h 179 lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
176lj_prng.o: lj_prng.c lj_def.h lua.h luaconf.h lj_arch.h lj_prng.h
177lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 180lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
178 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ 181 lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
179 lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \ 182 lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
180 lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \ 183 lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
181 lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h 184 lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h
185lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \
186 lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \
187 lj_udata.h lj_ctype.h lj_cdata.h lj_serialize.h
182lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 188lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
183 lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \ 189 lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
184 lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \ 190 lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
@@ -189,7 +195,7 @@ lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
189 lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_prng.h lj_lex.h \ 195 lj_ir.h lj_dispatch.h lj_traceerr.h lj_vm.h lj_prng.h lj_lex.h \
190 lj_alloc.h luajit.h 196 lj_alloc.h luajit.h
191lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 197lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
192 lj_err.h lj_errmsg.h lj_str.h lj_char.h 198 lj_err.h lj_errmsg.h lj_str.h lj_char.h lj_prng.h
193lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 199lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
194 lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h 200 lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h
195lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \ 201lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \
@@ -204,7 +210,7 @@ lj_trace.o: lj_trace.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
204 lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \ 210 lj_dispatch.h lj_traceerr.h lj_snap.h lj_gdbjit.h lj_record.h lj_asm.h \
205 lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h lj_prng.h 211 lj_vm.h lj_vmevent.h lj_target.h lj_target_*.h lj_prng.h
206lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 212lj_udata.o: lj_udata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
207 lj_gc.h lj_udata.h 213 lj_gc.h lj_err.h lj_errmsg.h lj_udata.h
208lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 214lj_vmevent.o: lj_vmevent.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
209 lj_str.h lj_tab.h lj_state.h lj_dispatch.h lj_bc.h lj_jit.h lj_ir.h \ 215 lj_str.h lj_tab.h lj_state.h lj_dispatch.h lj_bc.h lj_jit.h lj_ir.h \
210 lj_vm.h lj_vmevent.h 216 lj_vm.h lj_vmevent.h
@@ -216,23 +222,23 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_assert.c lj_obj.h \
216 lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \ 222 lj_bc.h lj_ctype.h lj_cdata.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
217 lj_traceerr.h lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h \ 223 lj_traceerr.h lj_vm.h lj_err.c lj_debug.h lj_ff.h lj_ffdef.h lj_strfmt.h \
218 lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c \ 224 lj_char.c lj_char.h lj_bc.c lj_bcdef.h lj_obj.c lj_buf.c lj_str.c \
219 lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h lj_debug.c \ 225 lj_prng.h lj_tab.c lj_func.c lj_udata.c lj_meta.c lj_strscan.h lj_lib.h \
220 lj_prng.c lj_prng.h lj_state.c lj_lex.h lj_alloc.h luajit.h \ 226 lj_debug.c lj_prng.c lj_state.c lj_lex.h lj_alloc.h luajit.h \
221 lj_dispatch.c lj_ccallback.h lj_profile.h lj_vmevent.c lj_vmevent.h \ 227 lj_dispatch.c lj_ccallback.h lj_profile.h lj_vmevent.c lj_vmevent.h \
222 lj_vmmath.c lj_strscan.c lj_strfmt.c lj_strfmt_num.c lj_api.c \ 228 lj_vmmath.c lj_strscan.c lj_strfmt.c lj_strfmt_num.c lj_serialize.c \
223 lj_profile.c lj_lex.c lualib.h lj_parse.h lj_parse.c lj_bcread.c \ 229 lj_serialize.h lj_api.c lj_profile.c lj_lex.c lualib.h lj_parse.h \
224 lj_bcdump.h lj_bcwrite.c lj_load.c lj_ctype.c lj_cdata.c lj_cconv.h \ 230 lj_parse.c lj_bcread.c lj_bcdump.h lj_bcwrite.c lj_load.c lj_ctype.c \
225 lj_cconv.c lj_ccall.c lj_ccall.h lj_ccallback.c lj_target.h \ 231 lj_cdata.c lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_ccallback.c \
226 lj_target_*.h lj_mcode.h lj_carith.c lj_carith.h lj_clib.c lj_clib.h \ 232 lj_target.h lj_target_*.h lj_mcode.h lj_carith.c lj_carith.h lj_clib.c \
227 lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c lj_ircall.h lj_iropt.h \ 233 lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_ir.c lj_ircall.h \
228 lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \ 234 lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c \
229 lj_opt_loop.c lj_snap.h lj_opt_split.c lj_opt_sink.c lj_mcode.c \ 235 lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_opt_split.c lj_opt_sink.c \
230 lj_snap.c lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \ 236 lj_mcode.c lj_snap.c lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
231 lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h \ 237 lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_emit_*.h \
232 lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \ 238 lj_asm_*.h lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c \
233 lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c \ 239 lib_base.c lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c \
234 lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_ffi.c \ 240 lib_os.c lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_ffi.c \
235 lib_init.c 241 lib_buffer.c lib_init.c
236luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h 242luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h
237host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \ 243host/buildvm.o: host/buildvm.c host/buildvm.h lj_def.h lua.h luaconf.h \
238 lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \ 244 lj_arch.h lj_obj.h lj_def.h lj_arch.h lj_gc.h lj_obj.h lj_bc.h lj_ir.h \
diff --git a/src/lib_buffer.c b/src/lib_buffer.c
new file mode 100644
index 00000000..e4555596
--- /dev/null
+++ b/src/lib_buffer.c
@@ -0,0 +1,66 @@
1/*
2** Buffer library.
3** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lib_buffer_c
7#define LUA_LIB
8
9#include "lua.h"
10#include "lauxlib.h"
11#include "lualib.h"
12
13#include "lj_obj.h"
14
15#if LJ_HASBUFFER
16#include "lj_gc.h"
17#include "lj_buf.h"
18#include "lj_serialize.h"
19#include "lj_lib.h"
20
21/* ------------------------------------------------------------------------ */
22
23#define LJLIB_MODULE_buffer
24
25/* Note: this uses interim structs until the SBuf reorg. */
26
27LJLIB_CF(buffer_encode)
28{
29 cTValue *o = lj_lib_checkany(L, 1);
30 StrBuf sbuf;
31 sbuf.sb = lj_buf_tmp_(L);
32 lj_serialize_put(&sbuf, o);
33 setstrV(L, L->top++, lj_buf_str(L, sbuf.sb));
34 lj_gc_check(L);
35 return 1;
36}
37
38LJLIB_CF(buffer_decode)
39{
40 GCstr *str = lj_lib_checkstr(L, 1);
41 const char *p = strdata(str);
42 SBuf sb;
43 StrBuf sbuf;
44 setsbufL(&sb, L);
45 setmref(sb.b, p);
46 setmref(sb.p, p + str->len);
47 setmref(sb.e, p + str->len);
48 sbuf.sb = &sb;
49 sbuf.r = (char *)p;
50 setnilV(L->top++);
51 lj_serialize_get(&sbuf, L->top-1);
52 lj_gc_check(L);
53 return 1;
54}
55
56/* ------------------------------------------------------------------------ */
57
58#include "lj_libdef.h"
59
60int luaopen_string_buffer(lua_State *L)
61{
62 LJ_LIB_REG(L, NULL, buffer);
63 return 1;
64}
65
66#endif
diff --git a/src/lib_string.c b/src/lib_string.c
index 51d1c4b0..4a3ff372 100644
--- a/src/lib_string.c
+++ b/src/lib_string.c
@@ -743,6 +743,9 @@ LUALIB_API int luaopen_string(lua_State *L)
743 setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt)); 743 setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
744 settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1)); 744 settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
745 mt->nomm = (uint8_t)(~(1u<<MM_index)); 745 mt->nomm = (uint8_t)(~(1u<<MM_index));
746#if LJ_HASBUFFER
747 lj_lib_prereg(L, LUA_STRLIBNAME ".buffer", luaopen_string_buffer, tabV(L->top-1));
748#endif
746 return 1; 749 return 1;
747} 750}
748 751
diff --git a/src/lj_arch.h b/src/lj_arch.h
index 0a6e1b9f..ae999467 100644
--- a/src/lj_arch.h
+++ b/src/lj_arch.h
@@ -549,6 +549,13 @@
549#define LJ_HASFFI 1 549#define LJ_HASFFI 1
550#endif 550#endif
551 551
552/* Disable or enable the string buffer extension. */
553#if defined(LUAJIT_DISABLE_BUFFER)
554#define LJ_HASBUFFER 0
555#else
556#define LJ_HASBUFFER 1
557#endif
558
552#if defined(LUAJIT_DISABLE_PROFILE) 559#if defined(LUAJIT_DISABLE_PROFILE)
553#define LJ_HASPROFILE 0 560#define LJ_HASPROFILE 0
554#elif LJ_TARGET_POSIX 561#elif LJ_TARGET_POSIX
diff --git a/src/lj_buf.h b/src/lj_buf.h
index ae875298..a720f83b 100644
--- a/src/lj_buf.h
+++ b/src/lj_buf.h
@@ -10,7 +10,7 @@
10#include "lj_gc.h" 10#include "lj_gc.h"
11#include "lj_str.h" 11#include "lj_str.h"
12 12
13/* Resizable string buffers. Struct definition in lj_obj.h. */ 13/* Resizable string buffers. SBuf struct definition in lj_obj.h. */
14#define sbufB(sb) (mref((sb)->b, char)) 14#define sbufB(sb) (mref((sb)->b, char))
15#define sbufP(sb) (mref((sb)->p, char)) 15#define sbufP(sb) (mref((sb)->p, char))
16#define sbufE(sb) (mref((sb)->e, char)) 16#define sbufE(sb) (mref((sb)->e, char))
@@ -100,4 +100,11 @@ static LJ_AINLINE GCstr *lj_buf_str(lua_State *L, SBuf *sb)
100 return lj_str_new(L, sbufB(sb), sbuflen(sb)); 100 return lj_str_new(L, sbufB(sb), sbuflen(sb));
101} 101}
102 102
103/* Interim user-accessible string buffer. */
104typedef struct StrBuf {
105 SBuf *sb; /* Pointer to system buffer. */
106 char *r; /* String buffer read pointer. */
107 int depth; /* Remaining recursion depth. */
108} StrBuf;
109
103#endif 110#endif
diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h
index 9ff4553d..a6f638ce 100644
--- a/src/lj_errmsg.h
+++ b/src/lj_errmsg.h
@@ -179,6 +179,16 @@ ERRDEF(FFI_NYIPACKBIT, "NYI: packed bit fields")
179ERRDEF(FFI_NYICALL, "NYI: cannot call this C function (yet)") 179ERRDEF(FFI_NYICALL, "NYI: cannot call this C function (yet)")
180#endif 180#endif
181 181
182#if LJ_HASBUFFER
183/* String buffer errors. */
184ERRDEF(BUFFER_BADENC, "cannot serialize " LUA_QS)
185ERRDEF(BUFFER_BADDEC, "cannot deserialize tag 0x%02x")
186ERRDEF(BUFFER_DEPTH, "too deep to serialize")
187ERRDEF(BUFFER_DUPKEY, "duplicate table key")
188ERRDEF(BUFFER_EOB, "unexpected end of buffer")
189ERRDEF(BUFFER_LEFTOV, "left-over data in buffer")
190#endif
191
182#undef ERRDEF 192#undef ERRDEF
183 193
184/* Detecting unused error messages: 194/* Detecting unused error messages:
diff --git a/src/lj_serialize.c b/src/lj_serialize.c
new file mode 100644
index 00000000..5d7b7721
--- /dev/null
+++ b/src/lj_serialize.c
@@ -0,0 +1,351 @@
1/*
2** Object de/serialization.
3** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_serialize_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10#include "lj_err.h"
11#include "lj_buf.h"
12#include "lj_str.h"
13#include "lj_tab.h"
14#include "lj_udata.h"
15#if LJ_HASFFI
16#include "lj_ctype.h"
17#include "lj_cdata.h"
18#endif
19#include "lj_serialize.h"
20
21/* Tags for internal serialization format. */
22enum {
23 SER_TAG_NIL, /* 0x00 */
24 SER_TAG_FALSE,
25 SER_TAG_TRUE,
26 SER_TAG_NULL,
27 SER_TAG_LIGHTUD32,
28 SER_TAG_LIGHTUD64,
29 SER_TAG_INT,
30 SER_TAG_NUM,
31 SER_TAG_TAB, /* 0x08 */
32 SER_TAG_0x0e = SER_TAG_TAB+6,
33 SER_TAG_0x0f,
34 SER_TAG_INT64, /* 0x10 */
35 SER_TAG_UINT64,
36 SER_TAG_COMPLEX,
37 SER_TAG_0x13,
38 SER_TAG_0x14,
39 SER_TAG_0x15,
40 SER_TAG_0x16,
41 SER_TAG_0x17,
42 SER_TAG_0x18, /* 0x18 */
43 SER_TAG_0x19,
44 SER_TAG_0x1a,
45 SER_TAG_0x1b,
46 SER_TAG_0x1c,
47 SER_TAG_0x1d,
48 SER_TAG_0x1e,
49 SER_TAG_0x1f,
50 SER_TAG_STR, /* 0x20 + str->len */
51};
52LJ_STATIC_ASSERT((SER_TAG_TAB & 7) == 0);
53
54/* -- Helper functions ---------------------------------------------------- */
55
56static LJ_AINLINE char *serialize_more(char *w, StrBuf *sbuf, MSize sz)
57{
58 if (LJ_UNLIKELY(sz > (MSize)(sbufE(sbuf->sb) - w))) {
59 setsbufP(sbuf->sb, w);
60 w = lj_buf_more2(sbuf->sb, sz);
61 }
62 return w;
63}
64
65/* Write U124 to buffer. */
66static LJ_NOINLINE char *serialize_wu124_(char *w, uint32_t v)
67{
68 if (v < 0x1fe0) {
69 v -= 0xe0;
70 *w++ = (char)(0xe0 | (v >> 8)); *w++ = (char)v;
71 } else {
72 *w++ = (char)0xff;
73#if LJ_BE
74 v = lj_bswap(v);
75#endif
76 memcpy(w, &v, 4); w += 4;
77 }
78 return w;
79}
80
81static LJ_AINLINE char *serialize_wu124(char *w, uint32_t v)
82{
83 if (LJ_LIKELY(v < 0xe0)) {
84 *w++ = (char)v;
85 return w;
86 } else {
87 return serialize_wu124_(w, v);
88 }
89}
90
91static LJ_NOINLINE char *serialize_ru124_(char *r, char *e, uint32_t *pv)
92{
93 uint32_t v = *pv;
94 if (v != 0xff) {
95 if (r >= e) return NULL;
96 v = ((v & 0x1f) << 8) + *(uint8_t *)r + 0xe0; r++;
97 } else {
98 if (r + 4 > e) return NULL;
99 v = lj_getu32(r); r += 4;
100#if LJ_BE
101 v = lj_bswap(v);
102#endif
103 }
104 *pv = v;
105 return r;
106}
107
108static LJ_AINLINE char *serialize_ru124(char *r, char *e, uint32_t *pv)
109{
110 if (LJ_LIKELY(r < e)) {
111 uint32_t v = *(uint8_t *)r; r++;
112 *pv = v;
113 if (LJ_UNLIKELY(v >= 0xe0)) {
114 r = serialize_ru124_(r, e, pv);
115 }
116 return r;
117 }
118 return NULL;
119}
120
121/* -- Internal serializer ------------------------------------------------- */
122
123/* Put serialized object into buffer. */
124static char *serialize_put(char *w, StrBuf *sbuf, cTValue *o)
125{
126 if (LJ_LIKELY(tvisstr(o))) {
127 const GCstr *str = strV(o);
128 MSize len = str->len;
129 w = serialize_more(w, sbuf, 5+len);
130 w = serialize_wu124(w, SER_TAG_STR + len);
131 w = lj_buf_wmem(w, strdata(str), len);
132 } else if (tvisint(o)) {
133 uint32_t x = LJ_BE ? lj_bswap((uint32_t)intV(o)) : (uint32_t)intV(o);
134 w = serialize_more(w, sbuf, 1+4);
135 *w++ = SER_TAG_INT; memcpy(w, &x, 4); w += 4;
136 } else if (tvisnum(o)) {
137 uint64_t x = LJ_BE ? lj_bswap64(o->u64) : o->u64;
138 w = serialize_more(w, sbuf, 1+sizeof(lua_Number));
139 *w++ = SER_TAG_NUM; memcpy(w, &x, 8); w += 8;
140 } else if (tvispri(o)) {
141 w = serialize_more(w, sbuf, 1);
142 *w++ = (char)(SER_TAG_NIL + ~itype(o));
143 } else if (tvistab(o)) {
144 const GCtab *t = tabV(o);
145 uint32_t narray = 0, nhash = 0, one = 2;
146 if (sbuf->depth <= 0) lj_err_caller(sbufL(sbuf->sb), LJ_ERR_BUFFER_DEPTH);
147 sbuf->depth--;
148 if (t->asize > 0) { /* Determine max. length of array part. */
149 ptrdiff_t i;
150 TValue *array = tvref(t->array);
151 for (i = (ptrdiff_t)t->asize-1; i >= 0; i--)
152 if (!tvisnil(&array[i]))
153 break;
154 narray = (uint32_t)(i+1);
155 if (narray && tvisnil(&array[0])) one = 4;
156 }
157 if (t->hmask > 0) { /* Count number of used hash slots. */
158 uint32_t i, hmask = t->hmask;
159 Node *node = noderef(t->node);
160 for (i = 0; i <= hmask; i++)
161 nhash += !tvisnil(&node[i].val);
162 }
163 /* Write number of array slots and hash slots. */
164 w = serialize_more(w, sbuf, 1+2*5);
165 *w++ = (char)(SER_TAG_TAB + (nhash ? 1 : 0) + (narray ? one : 0));
166 if (narray) w = serialize_wu124(w, narray);
167 if (nhash) w = serialize_wu124(w, nhash);
168 if (narray) { /* Write array entries. */
169 cTValue *oa = tvref(t->array) + (one >> 2);
170 cTValue *oe = tvref(t->array) + narray;
171 while (oa < oe) w = serialize_put(w, sbuf, oa++);
172 }
173 if (nhash) { /* Write hash entries. */
174 const Node *node = noderef(t->node) + t->hmask;
175 for (;; node--)
176 if (!tvisnil(&node->val)) {
177 w = serialize_put(w, sbuf, &node->key);
178 w = serialize_put(w, sbuf, &node->val);
179 if (--nhash == 0) break;
180 }
181 }
182 sbuf->depth++;
183#if LJ_HASFFI
184 } else if (tviscdata(o)) {
185 CTState *cts = ctype_cts(sbufL(sbuf->sb));
186 CType *s = ctype_raw(cts, cdataV(o)->ctypeid);
187 uint8_t *sp = cdataptr(cdataV(o));
188 if (ctype_isinteger(s->info) && s->size == 8) {
189 w = serialize_more(w, sbuf, 1+8);
190 *w++ = (s->info & CTF_UNSIGNED) ? SER_TAG_UINT64 : SER_TAG_INT64;
191#if LJ_BE
192 { uint64_t u = lj_bswap64(*(uint64_t *)sp); memcpy(w, &u, 8); }
193#else
194 memcpy(w, sp, 8);
195#endif
196 w += 8;
197 } else if (ctype_iscomplex(s->info) && s->size == 16) {
198 w = serialize_more(w, sbuf, 1+16);
199 *w++ = SER_TAG_COMPLEX;
200#if LJ_BE
201 { /* Only swap the doubles. The re/im order stays the same. */
202 uint64_t u = lj_bswap64(((uint64_t *)sp)[0]); memcpy(w, &u, 8);
203 u = lj_bswap64(((uint64_t *)sp)[1]); memcpy(w+8, &u, 8);
204 }
205#else
206 memcpy(w, sp, 16);
207#endif
208 w += 16;
209 } else {
210 goto badenc; /* NYI other cdata */
211 }
212#endif
213 } else if (tvislightud(o)) {
214 uintptr_t ud = (uintptr_t)lightudV(G(sbufL(sbuf->sb)), o);
215 w = serialize_more(w, sbuf, 1+sizeof(ud));
216 if (ud == 0) {
217 *w++ = SER_TAG_NULL;
218 } else if (LJ_32 || checku32(ud)) {
219#if LJ_BE && LJ_64
220 ud = lj_bswap64(ud);
221#elif LJ_BE
222 ud = lj_bswap(ud);
223#endif
224 *w++ = SER_TAG_LIGHTUD32; memcpy(w, &ud, 4); w += 4;
225 } else {
226#if LJ_BE
227 ud = lj_bswap64(ud);
228#endif
229 *w++ = SER_TAG_LIGHTUD64; memcpy(w, &ud, 8); w += 8;
230 }
231 } else {
232 /* NYI userdata */
233#if LJ_HASFFI
234 badenc:
235#endif
236 lj_err_callerv(sbufL(sbuf->sb), LJ_ERR_BUFFER_BADENC, lj_typename(o));
237 }
238 return w;
239}
240
241/* Get serialized object from buffer. */
242static char *serialize_get(char *r, StrBuf *sbuf, TValue *o)
243{
244 char *e = sbufE(sbuf->sb);
245 uint32_t tp;
246 r = serialize_ru124(r, e, &tp); if (LJ_UNLIKELY(!r)) goto eob;
247 if (LJ_LIKELY(tp >= SER_TAG_STR)) {
248 uint32_t len = tp - SER_TAG_STR;
249 if (LJ_UNLIKELY(len > (uint32_t)(e - r))) goto eob;
250 setstrV(sbufL(sbuf->sb), o, lj_str_new(sbufL(sbuf->sb), r, len));
251 r += len;
252 } else if (tp == SER_TAG_INT) {
253 if (LJ_UNLIKELY(r + 4 > e)) goto eob;
254 setintV(o, (int32_t)(LJ_BE ? lj_bswap(lj_getu32(r)) : lj_getu32(r)));
255 r += 4;
256 } else if (tp == SER_TAG_NUM) {
257 if (LJ_UNLIKELY(r + 8 > e)) goto eob;
258 memcpy(o, r, 8); r += 8;
259#if LJ_BE
260 o->u64 = lj_bswap64(o->u64);
261#endif
262 if (!tvisnum(o)) setnanV(o);
263 } else if (tp <= SER_TAG_TRUE) {
264 setpriV(o, ~tp);
265 } else if (tp >= SER_TAG_TAB && tp < SER_TAG_TAB+6) {
266 uint32_t narray = 0, nhash = 0;
267 GCtab *t;
268 if (tp >= SER_TAG_TAB+2) {
269 r = serialize_ru124(r, e, &narray); if (LJ_UNLIKELY(!r)) goto eob;
270 }
271 if ((tp & 1)) {
272 r = serialize_ru124(r, e, &nhash); if (LJ_UNLIKELY(!r)) goto eob;
273 }
274 t = lj_tab_new(sbufL(sbuf->sb), narray, hsize2hbits(nhash));
275 settabV(sbufL(sbuf->sb), o, t);
276 if (narray) {
277 TValue *oa = tvref(t->array) + (tp >= SER_TAG_TAB+4);
278 TValue *oe = tvref(t->array) + narray;
279 while (oa < oe) r = serialize_get(r, sbuf, oa++);
280 }
281 if (nhash) {
282 do {
283 TValue k, *v;
284 r = serialize_get(r, sbuf, &k);
285 v = lj_tab_set(sbufL(sbuf->sb), t, &k);
286 if (LJ_UNLIKELY(!tvisnil(v)))
287 lj_err_caller(sbufL(sbuf->sb), LJ_ERR_BUFFER_DUPKEY);
288 r = serialize_get(r, sbuf, v);
289 } while (--nhash);
290 }
291#if LJ_HASFFI
292 } else if (tp >= SER_TAG_INT64 && tp <= SER_TAG_COMPLEX) {
293 uint32_t sz = tp == SER_TAG_COMPLEX ? 16 : 8;
294 GCcdata *cd;
295 if (LJ_UNLIKELY(r + sz > e)) goto eob;
296 cd = lj_cdata_new_(sbufL(sbuf->sb),
297 tp == SER_TAG_INT64 ? CTID_INT64 :
298 tp == SER_TAG_UINT64 ? CTID_UINT64 : CTID_COMPLEX_DOUBLE,
299 sz);
300 memcpy(cdataptr(cd), r, sz); r += sz;
301#if LJ_BE
302 *(uint64_t *)cdataptr(cd) = lj_bswap64(*(uint64_t *)cdataptr(cd));
303 if (sz == 16)
304 ((uint64_t *)cdataptr(cd))[1] = lj_bswap64(((uint64_t *)cdataptr(cd))[1]);
305#endif
306 setcdataV(sbufL(sbuf->sb), o, cd);
307#endif
308 } else if (tp <= (LJ_64 ? SER_TAG_LIGHTUD64 : SER_TAG_LIGHTUD32)) {
309 uintptr_t ud = 0;
310 if (tp == SER_TAG_LIGHTUD32) {
311 if (LJ_UNLIKELY(r + 4 > e)) goto eob;
312 ud = (uintptr_t)(LJ_BE ? lj_bswap(lj_getu32(r)) : lj_getu32(r));
313 r += 4;
314 }
315#if LJ_64
316 else if (tp == SER_TAG_LIGHTUD64) {
317 if (LJ_UNLIKELY(r + 8 > e)) goto eob;
318 memcpy(&ud, r, 8); r += 8;
319#if LJ_BE
320 ud = lj_bswap64(ud);
321#endif
322 }
323 setrawlightudV(o, lj_lightud_intern(sbufL(sbuf->sb), (void *)ud));
324#else
325 setrawlightudV(o, (void *)ud);
326#endif
327 } else {
328 lj_err_callerv(sbufL(sbuf->sb), LJ_ERR_BUFFER_BADDEC, tp);
329 }
330 return r;
331eob:
332 lj_err_caller(sbufL(sbuf->sb), LJ_ERR_BUFFER_EOB);
333 return NULL;
334}
335
336StrBuf * LJ_FASTCALL lj_serialize_put(StrBuf *sbuf, cTValue *o)
337{
338 sbuf->depth = LJ_SERIALIZE_DEPTH;
339 setsbufP(sbuf->sb, serialize_put(sbufP(sbuf->sb), sbuf, o));
340 return sbuf;
341}
342
343StrBuf * LJ_FASTCALL lj_serialize_get(StrBuf *sbuf, TValue *o)
344{
345 char *r = serialize_get(sbuf->r, sbuf, o);
346 if (r != sbufP(sbuf->sb))
347 lj_err_caller(sbufL(sbuf->sb), LJ_ERR_BUFFER_LEFTOV);
348 sbuf->r = r;
349 return sbuf;
350}
351
diff --git a/src/lj_serialize.h b/src/lj_serialize.h
new file mode 100644
index 00000000..95d62f4e
--- /dev/null
+++ b/src/lj_serialize.h
@@ -0,0 +1,21 @@
1/*
2** Object de/serialization.
3** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#ifndef _LJ_SERIALIZE_H
7#define _LJ_SERIALIZE_H
8
9#include "lj_obj.h"
10#include "lj_buf.h"
11
12#if LJ_HASBUFFER
13
14#define LJ_SERIALIZE_DEPTH 100 /* Default depth. */
15
16LJ_FUNC StrBuf * LJ_FASTCALL lj_serialize_put(StrBuf *sb, cTValue *o);
17LJ_FUNC StrBuf * LJ_FASTCALL lj_serialize_get(StrBuf *sb, TValue *o);
18
19#endif
20
21#endif
diff --git a/src/ljamalg.c b/src/ljamalg.c
index 8e2d4937..384b3cc1 100644
--- a/src/ljamalg.c
+++ b/src/ljamalg.c
@@ -39,6 +39,7 @@
39#include "lj_strscan.c" 39#include "lj_strscan.c"
40#include "lj_strfmt.c" 40#include "lj_strfmt.c"
41#include "lj_strfmt_num.c" 41#include "lj_strfmt_num.c"
42#include "lj_serialize.c"
42#include "lj_api.c" 43#include "lj_api.c"
43#include "lj_profile.c" 44#include "lj_profile.c"
44#include "lj_lex.c" 45#include "lj_lex.c"
@@ -85,5 +86,6 @@
85#include "lib_bit.c" 86#include "lib_bit.c"
86#include "lib_jit.c" 87#include "lib_jit.c"
87#include "lib_ffi.c" 88#include "lib_ffi.c"
89#include "lib_buffer.c"
88#include "lib_init.c" 90#include "lib_init.c"
89 91
diff --git a/src/lualib.h b/src/lualib.h
index 9cd39880..5c18e9ec 100644
--- a/src/lualib.h
+++ b/src/lualib.h
@@ -33,6 +33,7 @@ LUALIB_API int luaopen_debug(lua_State *L);
33LUALIB_API int luaopen_bit(lua_State *L); 33LUALIB_API int luaopen_bit(lua_State *L);
34LUALIB_API int luaopen_jit(lua_State *L); 34LUALIB_API int luaopen_jit(lua_State *L);
35LUALIB_API int luaopen_ffi(lua_State *L); 35LUALIB_API int luaopen_ffi(lua_State *L);
36LUALIB_API int luaopen_string_buffer(lua_State *L);
36 37
37LUALIB_API void luaL_openlibs(lua_State *L); 38LUALIB_API void luaL_openlibs(lua_State *L);
38 39