1 /*
2 ** upb::Encoder
3 **
4 ** Since we are implementing pure handlers (ie. without any out-of-band access
5 ** to pre-computed lengths), we have to buffer all submessages before we can
6 ** emit even their first byte.
7 **
8 ** Not knowing the size of submessages also means we can't write a perfect
9 ** zero-copy implementation, even with buffering.  Lengths are stored as
10 ** varints, which means that we don't know how many bytes to reserve for the
11 ** length until we know what the length is.
12 **
13 ** This leaves us with three main choices:
14 **
15 ** 1. buffer all submessage data in a temporary buffer, then copy it exactly
16 **    once into the output buffer.
17 **
18 ** 2. attempt to buffer data directly into the output buffer, estimating how
19 **    many bytes each length will take.  When our guesses are wrong, use
20 **    memmove() to grow or shrink the allotted space.
21 **
22 ** 3. buffer directly into the output buffer, allocating a max length
23 **    ahead-of-time for each submessage length.  If we overallocated, we waste
24 **    space, but no memcpy() or memmove() is required.  This approach requires
25 **    defining a maximum size for submessages and rejecting submessages that
26 **    exceed that size.
27 **
28 ** (2) and (3) have the potential to have better performance, but they are more
29 ** complicated and subtle to implement:
30 **
31 **   (3) requires making an arbitrary choice of the maximum message size; it
32 **       wastes space when submessages are shorter than this and fails
33 **       completely when they are longer.  This makes it more finicky and
34 **       requires configuration based on the input.  It also makes it impossible
35 **       to perfectly match the output of reference encoders that always use the
36 **       optimal amount of space for each length.
37 **
38 **   (2) requires guessing the the size upfront, and if multiple lengths are
39 **       guessed wrong the minimum required number of memmove() operations may
40 **       be complicated to compute correctly.  Implemented properly, it may have
41 **       a useful amortized or average cost, but more investigation is required
42 **       to determine this and what the optimal algorithm is to achieve it.
43 **
44 **   (1) makes you always pay for exactly one copy, but its implementation is
45 **       the simplest and its performance is predictable.
46 **
47 ** So for now, we implement (1) only.  If we wish to optimize later, we should
48 ** be able to do it without affecting users.
49 **
50 ** The strategy is to buffer the segments of data that do *not* depend on
51 ** unknown lengths in one buffer, and keep a separate buffer of segment pointers
52 ** and lengths.  When the top-level submessage ends, we can go beginning to end,
53 ** alternating the writing of lengths with memcpy() of the rest of the data.
54 ** At the top level though, no buffering is required.
55 */
56 
57 #include "upb/pb/encoder.h"
58 #include "upb/pb/varint.int.h"
59 
60 #include "upb/port_def.inc"
61 
62 /* The output buffer is divided into segments; a segment is a string of data
63  * that is "ready to go" -- it does not need any varint lengths inserted into
64  * the middle.  The seams between segments are where varints will be inserted
65  * once they are known.
66  *
67  * We also use the concept of a "run", which is a range of encoded bytes that
68  * occur at a single submessage level.  Every segment contains one or more runs.
69  *
70  * A segment can span messages.  Consider:
71  *
72  *                  .--Submessage lengths---------.
73  *                  |       |                     |
74  *                  |       V                     V
75  *                  V      | |---------------    | |-----------------
76  * Submessages:    | |-----------------------------------------------
77  * Top-level msg: ------------------------------------------------------------
78  *
79  * Segments:          -----   -------------------   -----------------
80  * Runs:              *----   *--------------*---   *----------------
81  * (* marks the start)
82  *
83  * Note that the top-level menssage is not in any segment because it does not
84  * have any length preceding it.
85  *
86  * A segment is only interrupted when another length needs to be inserted.  So
87  * observe how the second segment spans both the inner submessage and part of
88  * the next enclosing message. */
89 typedef struct {
90   uint32_t msglen;  /* The length to varint-encode before this segment. */
91   uint32_t seglen;  /* Length of the segment. */
92 } upb_pb_encoder_segment;
93 
94 struct upb_pb_encoder {
95   upb_arena *arena;
96 
97   /* Our input and output. */
98   upb_sink input_;
99   upb_bytessink output_;
100 
101   /* The "subclosure" -- used as the inner closure as part of the bytessink
102    * protocol. */
103   void *subc;
104 
105   /* The output buffer and limit, and our current write position.  "buf"
106    * initially points to "initbuf", but is dynamically allocated if we need to
107    * grow beyond the initial size. */
108   char *buf, *ptr, *limit;
109 
110   /* The beginning of the current run, or undefined if we are at the top
111    * level. */
112   char *runbegin;
113 
114   /* The list of segments we are accumulating. */
115   upb_pb_encoder_segment *segbuf, *segptr, *seglimit;
116 
117   /* The stack of enclosing submessages.  Each entry in the stack points to the
118    * segment where this submessage's length is being accumulated. */
119   int *stack, *top, *stacklimit;
120 
121   /* Depth of startmsg/endmsg calls. */
122   int depth;
123 };
124 
125 /* low-level buffering ********************************************************/
126 
127 /* Low-level functions for interacting with the output buffer. */
128 
129 /* TODO(haberman): handle pushback */
putbuf(upb_pb_encoder * e,const char * buf,size_t len)130 static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) {
131   size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL);
132   UPB_ASSERT(n == len);
133 }
134 
top(upb_pb_encoder * e)135 static upb_pb_encoder_segment *top(upb_pb_encoder *e) {
136   return &e->segbuf[*e->top];
137 }
138 
139 /* Call to ensure that at least "bytes" bytes are available for writing at
140  * e->ptr.  Returns false if the bytes could not be allocated. */
reserve(upb_pb_encoder * e,size_t bytes)141 static bool reserve(upb_pb_encoder *e, size_t bytes) {
142   if ((size_t)(e->limit - e->ptr) < bytes) {
143     /* Grow buffer. */
144     char *new_buf;
145     size_t needed = bytes + (e->ptr - e->buf);
146     size_t old_size = e->limit - e->buf;
147 
148     size_t new_size = old_size;
149 
150     while (new_size < needed) {
151       new_size *= 2;
152     }
153 
154     new_buf = upb_arena_realloc(e->arena, e->buf, old_size, new_size);
155 
156     if (new_buf == NULL) {
157       return false;
158     }
159 
160     e->ptr = new_buf + (e->ptr - e->buf);
161     e->runbegin = new_buf + (e->runbegin - e->buf);
162     e->limit = new_buf + new_size;
163     e->buf = new_buf;
164   }
165 
166   return true;
167 }
168 
169 /* Call when "bytes" bytes have been writte at e->ptr.  The caller *must* have
170  * previously called reserve() with at least this many bytes. */
encoder_advance(upb_pb_encoder * e,size_t bytes)171 static void encoder_advance(upb_pb_encoder *e, size_t bytes) {
172   UPB_ASSERT((size_t)(e->limit - e->ptr) >= bytes);
173   e->ptr += bytes;
174 }
175 
176 /* Call when all of the bytes for a handler have been written.  Flushes the
177  * bytes if possible and necessary, returning false if this failed. */
commit(upb_pb_encoder * e)178 static bool commit(upb_pb_encoder *e) {
179   if (!e->top) {
180     /* We aren't inside a delimited region.  Flush our accumulated bytes to
181      * the output.
182      *
183      * TODO(haberman): in the future we may want to delay flushing for
184      * efficiency reasons. */
185     putbuf(e, e->buf, e->ptr - e->buf);
186     e->ptr = e->buf;
187   }
188 
189   return true;
190 }
191 
192 /* Writes the given bytes to the buffer, handling reserve/advance. */
encode_bytes(upb_pb_encoder * e,const void * data,size_t len)193 static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) {
194   if (!reserve(e, len)) {
195     return false;
196   }
197 
198   memcpy(e->ptr, data, len);
199   encoder_advance(e, len);
200   return true;
201 }
202 
203 /* Finish the current run by adding the run totals to the segment and message
204  * length. */
accumulate(upb_pb_encoder * e)205 static void accumulate(upb_pb_encoder *e) {
206   size_t run_len;
207   UPB_ASSERT(e->ptr >= e->runbegin);
208   run_len = e->ptr - e->runbegin;
209   e->segptr->seglen += run_len;
210   top(e)->msglen += run_len;
211   e->runbegin = e->ptr;
212 }
213 
214 /* Call to indicate the start of delimited region for which the full length is
215  * not yet known.  All data will be buffered until the length is known.
216  * Delimited regions may be nested; their lengths will all be tracked properly. */
start_delim(upb_pb_encoder * e)217 static bool start_delim(upb_pb_encoder *e) {
218   if (e->top) {
219     /* We are already buffering, advance to the next segment and push it on the
220      * stack. */
221     accumulate(e);
222 
223     if (++e->top == e->stacklimit) {
224       /* TODO(haberman): grow stack? */
225       return false;
226     }
227 
228     if (++e->segptr == e->seglimit) {
229       /* Grow segment buffer. */
230       size_t old_size =
231           (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment);
232       size_t new_size = old_size * 2;
233       upb_pb_encoder_segment *new_buf =
234           upb_arena_realloc(e->arena, e->segbuf, old_size, new_size);
235 
236       if (new_buf == NULL) {
237         return false;
238       }
239 
240       e->segptr = new_buf + (e->segptr - e->segbuf);
241       e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment));
242       e->segbuf = new_buf;
243     }
244   } else {
245     /* We were previously at the top level, start buffering. */
246     e->segptr = e->segbuf;
247     e->top = e->stack;
248     e->runbegin = e->ptr;
249   }
250 
251   *e->top = (int)(e->segptr - e->segbuf);
252   e->segptr->seglen = 0;
253   e->segptr->msglen = 0;
254 
255   return true;
256 }
257 
258 /* Call to indicate the end of a delimited region.  We now know the length of
259  * the delimited region.  If we are not nested inside any other delimited
260  * regions, we can now emit all of the buffered data we accumulated. */
end_delim(upb_pb_encoder * e)261 static bool end_delim(upb_pb_encoder *e) {
262   size_t msglen;
263   accumulate(e);
264   msglen = top(e)->msglen;
265 
266   if (e->top == e->stack) {
267     /* All lengths are now available, emit all buffered data. */
268     char buf[UPB_PB_VARINT_MAX_LEN];
269     upb_pb_encoder_segment *s;
270     const char *ptr = e->buf;
271     for (s = e->segbuf; s <= e->segptr; s++) {
272       size_t lenbytes = upb_vencode64(s->msglen, buf);
273       putbuf(e, buf, lenbytes);
274       putbuf(e, ptr, s->seglen);
275       ptr += s->seglen;
276     }
277 
278     e->ptr = e->buf;
279     e->top = NULL;
280   } else {
281     /* Need to keep buffering; propagate length info into enclosing
282      * submessages. */
283     --e->top;
284     top(e)->msglen += msglen + upb_varint_size(msglen);
285   }
286 
287   return true;
288 }
289 
290 
291 /* tag_t **********************************************************************/
292 
293 /* A precomputed (pre-encoded) tag and length. */
294 
295 typedef struct {
296   uint8_t bytes;
297   char tag[7];
298 } tag_t;
299 
300 /* Allocates a new tag for this field, and sets it in these handlerattr. */
new_tag(upb_handlers * h,const upb_fielddef * f,upb_wiretype_t wt,upb_handlerattr * attr)301 static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt,
302                     upb_handlerattr *attr) {
303   uint32_t n = upb_fielddef_number(f);
304 
305   tag_t *tag = upb_gmalloc(sizeof(tag_t));
306   tag->bytes = upb_vencode64((n << 3) | wt, tag->tag);
307 
308   attr->handler_data = tag;
309   upb_handlers_addcleanup(h, tag, upb_gfree);
310 }
311 
encode_tag(upb_pb_encoder * e,const tag_t * tag)312 static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) {
313   return encode_bytes(e, tag->tag, tag->bytes);
314 }
315 
316 
317 /* encoding of wire types *****************************************************/
318 
encode_fixed64(upb_pb_encoder * e,uint64_t val)319 static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) {
320   /* TODO(haberman): byte-swap for big endian. */
321   return encode_bytes(e, &val, sizeof(uint64_t));
322 }
323 
encode_fixed32(upb_pb_encoder * e,uint32_t val)324 static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) {
325   /* TODO(haberman): byte-swap for big endian. */
326   return encode_bytes(e, &val, sizeof(uint32_t));
327 }
328 
encode_varint(upb_pb_encoder * e,uint64_t val)329 static bool encode_varint(upb_pb_encoder *e, uint64_t val) {
330   if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) {
331     return false;
332   }
333 
334   encoder_advance(e, upb_vencode64(val, e->ptr));
335   return true;
336 }
337 
dbl2uint64(double d)338 static uint64_t dbl2uint64(double d) {
339   uint64_t ret;
340   memcpy(&ret, &d, sizeof(uint64_t));
341   return ret;
342 }
343 
flt2uint32(float d)344 static uint32_t flt2uint32(float d) {
345   uint32_t ret;
346   memcpy(&ret, &d, sizeof(uint32_t));
347   return ret;
348 }
349 
350 
351 /* encoding of proto types ****************************************************/
352 
startmsg(void * c,const void * hd)353 static bool startmsg(void *c, const void *hd) {
354   upb_pb_encoder *e = c;
355   UPB_UNUSED(hd);
356   if (e->depth++ == 0) {
357     upb_bytessink_start(e->output_, 0, &e->subc);
358   }
359   return true;
360 }
361 
endmsg(void * c,const void * hd,upb_status * status)362 static bool endmsg(void *c, const void *hd, upb_status *status) {
363   upb_pb_encoder *e = c;
364   UPB_UNUSED(hd);
365   UPB_UNUSED(status);
366   if (--e->depth == 0) {
367     upb_bytessink_end(e->output_);
368   }
369   return true;
370 }
371 
encode_startdelimfield(void * c,const void * hd)372 static void *encode_startdelimfield(void *c, const void *hd) {
373   bool ok = encode_tag(c, hd) && commit(c) && start_delim(c);
374   return ok ? c : UPB_BREAK;
375 }
376 
encode_unknown(void * c,const void * hd,const char * buf,size_t len)377 static bool encode_unknown(void *c, const void *hd, const char *buf,
378                            size_t len) {
379   UPB_UNUSED(hd);
380   return encode_bytes(c, buf, len) && commit(c);
381 }
382 
encode_enddelimfield(void * c,const void * hd)383 static bool encode_enddelimfield(void *c, const void *hd) {
384   UPB_UNUSED(hd);
385   return end_delim(c);
386 }
387 
encode_startgroup(void * c,const void * hd)388 static void *encode_startgroup(void *c, const void *hd) {
389   return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK;
390 }
391 
encode_endgroup(void * c,const void * hd)392 static bool encode_endgroup(void *c, const void *hd) {
393   return encode_tag(c, hd) && commit(c);
394 }
395 
encode_startstr(void * c,const void * hd,size_t size_hint)396 static void *encode_startstr(void *c, const void *hd, size_t size_hint) {
397   UPB_UNUSED(size_hint);
398   return encode_startdelimfield(c, hd);
399 }
400 
encode_strbuf(void * c,const void * hd,const char * buf,size_t len,const upb_bufhandle * h)401 static size_t encode_strbuf(void *c, const void *hd, const char *buf,
402                             size_t len, const upb_bufhandle *h) {
403   UPB_UNUSED(hd);
404   UPB_UNUSED(h);
405   return encode_bytes(c, buf, len) ? len : 0;
406 }
407 
408 #define T(type, ctype, convert, encode)                                  \
409   static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \
410     return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e);  \
411   }                                                                      \
412   static bool encode_packed_##type(void *e, const void *hd, ctype val) { \
413     UPB_UNUSED(hd);                                                      \
414     return encode(e, (convert)(val));                                    \
415   }
416 
T(double,double,dbl2uint64,encode_fixed64)417 T(double,   double,   dbl2uint64,   encode_fixed64)
418 T(float,    float,    flt2uint32,   encode_fixed32)
419 T(int64,    int64_t,  uint64_t,     encode_varint)
420 T(int32,    int32_t,  int64_t,      encode_varint)
421 T(fixed64,  uint64_t, uint64_t,     encode_fixed64)
422 T(fixed32,  uint32_t, uint32_t,     encode_fixed32)
423 T(bool,     bool,     bool,         encode_varint)
424 T(uint32,   uint32_t, uint32_t,     encode_varint)
425 T(uint64,   uint64_t, uint64_t,     encode_varint)
426 T(enum,     int32_t,  uint32_t,     encode_varint)
427 T(sfixed32, int32_t,  uint32_t,     encode_fixed32)
428 T(sfixed64, int64_t,  uint64_t,     encode_fixed64)
429 T(sint32,   int32_t,  upb_zzenc_32, encode_varint)
430 T(sint64,   int64_t,  upb_zzenc_64, encode_varint)
431 
432 #undef T
433 
434 
435 /* code to build the handlers *************************************************/
436 
437 #include <stdio.h>
438 static void newhandlers_callback(const void *closure, upb_handlers *h) {
439   const upb_msgdef *m;
440   upb_msg_field_iter i;
441 
442   UPB_UNUSED(closure);
443 
444   upb_handlers_setstartmsg(h, startmsg, NULL);
445   upb_handlers_setendmsg(h, endmsg, NULL);
446   upb_handlers_setunknown(h, encode_unknown, NULL);
447 
448   m = upb_handlers_msgdef(h);
449   for(upb_msg_field_begin(&i, m);
450       !upb_msg_field_done(&i);
451       upb_msg_field_next(&i)) {
452     const upb_fielddef *f = upb_msg_iter_field(&i);
453     bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
454                   upb_fielddef_packed(f);
455     upb_handlerattr attr = UPB_HANDLERATTR_INIT;
456     upb_wiretype_t wt =
457         packed ? UPB_WIRE_TYPE_DELIMITED
458                : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
459 
460     /* Pre-encode the tag for this field. */
461     new_tag(h, f, wt, &attr);
462 
463     if (packed) {
464       upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr);
465       upb_handlers_setendseq(h, f, encode_enddelimfield, &attr);
466     }
467 
468 #define T(upper, lower, upbtype)                                     \
469   case UPB_DESCRIPTOR_TYPE_##upper:                                  \
470     if (packed) {                                                    \
471       upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \
472     } else {                                                         \
473       upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \
474     }                                                                \
475     break;
476 
477     switch (upb_fielddef_descriptortype(f)) {
478       T(DOUBLE,   double,   double);
479       T(FLOAT,    float,    float);
480       T(INT64,    int64,    int64);
481       T(INT32,    int32,    int32);
482       T(FIXED64,  fixed64,  uint64);
483       T(FIXED32,  fixed32,  uint32);
484       T(BOOL,     bool,     bool);
485       T(UINT32,   uint32,   uint32);
486       T(UINT64,   uint64,   uint64);
487       T(ENUM,     enum,     int32);
488       T(SFIXED32, sfixed32, int32);
489       T(SFIXED64, sfixed64, int64);
490       T(SINT32,   sint32,   int32);
491       T(SINT64,   sint64,   int64);
492       case UPB_DESCRIPTOR_TYPE_STRING:
493       case UPB_DESCRIPTOR_TYPE_BYTES:
494         upb_handlers_setstartstr(h, f, encode_startstr, &attr);
495         upb_handlers_setendstr(h, f, encode_enddelimfield, &attr);
496         upb_handlers_setstring(h, f, encode_strbuf, &attr);
497         break;
498       case UPB_DESCRIPTOR_TYPE_MESSAGE:
499         upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr);
500         upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
501         break;
502       case UPB_DESCRIPTOR_TYPE_GROUP: {
503         /* Endgroup takes a different tag (wire_type = END_GROUP). */
504         upb_handlerattr attr2 = UPB_HANDLERATTR_INIT;
505         new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
506 
507         upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr);
508         upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2);
509 
510         break;
511       }
512     }
513 
514 #undef T
515   }
516 }
517 
upb_pb_encoder_reset(upb_pb_encoder * e)518 void upb_pb_encoder_reset(upb_pb_encoder *e) {
519   e->segptr = NULL;
520   e->top = NULL;
521   e->depth = 0;
522 }
523 
524 
525 /* public API *****************************************************************/
526 
upb_pb_encoder_newcache(void)527 upb_handlercache *upb_pb_encoder_newcache(void) {
528   return upb_handlercache_new(newhandlers_callback, NULL);
529 }
530 
upb_pb_encoder_create(upb_arena * arena,const upb_handlers * h,upb_bytessink output)531 upb_pb_encoder *upb_pb_encoder_create(upb_arena *arena, const upb_handlers *h,
532                                       upb_bytessink output) {
533   const size_t initial_bufsize = 256;
534   const size_t initial_segbufsize = 16;
535   /* TODO(haberman): make this configurable. */
536   const size_t stack_size = 64;
537 
538   upb_pb_encoder *e = upb_arena_malloc(arena, sizeof(upb_pb_encoder));
539   if (!e) return NULL;
540 
541   e->buf = upb_arena_malloc(arena, initial_bufsize);
542   e->segbuf = upb_arena_malloc(arena, initial_segbufsize * sizeof(*e->segbuf));
543   e->stack = upb_arena_malloc(arena, stack_size * sizeof(*e->stack));
544 
545   if (!e->buf || !e->segbuf || !e->stack) {
546     return NULL;
547   }
548 
549   e->limit = e->buf + initial_bufsize;
550   e->seglimit = e->segbuf + initial_segbufsize;
551   e->stacklimit = e->stack + stack_size;
552 
553   upb_pb_encoder_reset(e);
554   upb_sink_reset(&e->input_, h, e);
555 
556   e->arena = arena;
557   e->output_ = output;
558   e->subc = output.closure;
559   e->ptr = e->buf;
560 
561   return e;
562 }
563 
upb_pb_encoder_input(upb_pb_encoder * e)564 upb_sink upb_pb_encoder_input(upb_pb_encoder *e) { return e->input_; }
565