summaryrefslogtreecommitdiff
path: root/upb/pb
diff options
context:
space:
mode:
Diffstat (limited to 'upb/pb')
-rw-r--r--upb/pb/compile_decoder_x64.c3
-rw-r--r--upb/pb/compile_decoder_x64.dasc27
-rw-r--r--upb/pb/decoder.c19
-rw-r--r--upb/pb/decoder.h1
-rw-r--r--upb/pb/decoder.int.h4
-rw-r--r--upb/pb/textprinter.c158
-rw-r--r--upb/pb/textprinter.h80
7 files changed, 219 insertions, 73 deletions
diff --git a/upb/pb/compile_decoder_x64.c b/upb/pb/compile_decoder_x64.c
index 429f690..44331b8 100644
--- a/upb/pb/compile_decoder_x64.c
+++ b/upb/pb/compile_decoder_x64.c
@@ -56,8 +56,6 @@ typedef struct {
// Used by DynASM to store globals.
void **globals;
-
- bool chkret;
} jitcompiler;
// Functions called by codegen.
@@ -72,7 +70,6 @@ static int pcofs(jitcompiler* jc);
static jitcompiler *newjitcompiler(mgroup *group) {
jitcompiler *jc = malloc(sizeof(jitcompiler));
- jc->chkret = false;
jc->group = group;
jc->pclabel_count = 0;
jc->lastlabelofs = -1;
diff --git a/upb/pb/compile_decoder_x64.dasc b/upb/pb/compile_decoder_x64.dasc
index fec822a..571aa9b 100644
--- a/upb/pb/compile_decoder_x64.dasc
+++ b/upb/pb/compile_decoder_x64.dasc
@@ -23,6 +23,7 @@
|.define ARG3_32, edx
|.define ARG3_64, rdx
|.define ARG4_64, rcx
+|.define ARG5_64, r8
|.define XMMARG1, xmm0
|
|// Register allocation / type map.
@@ -159,6 +160,16 @@ static upb_func *gethandler(const upb_handlers *h, upb_selector_t sel) {
return h ? upb_handlers_gethandler(h, sel) : NULL;
}
+// Should only be called when the associated handler is known to exist.
+static bool alwaysok(const upb_handlers *h, upb_selector_t sel) {
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ bool ok = upb_handlers_getattr(h, sel, &attr);
+ UPB_ASSERT_VAR(ok, ok);
+ bool ret = upb_handlerattr_alwaysok(&attr);
+ upb_handlerattr_uninit(&attr);
+ return ret;
+}
+
// Emit static assembly routines; code that does not vary based on the message
// schema. Since it's not input-dependent, we only need one single copy of it.
// For the moment we generate a single copy per generated handlers. Eventually
@@ -623,9 +634,9 @@ static void jitprimitive(jitcompiler *jc, opcode op,
| mov ARG1_64, CLOSURE
| load_handler_data h, sel
| callp handler
- if (jc->chkret) {
+ if (!alwaysok(h, sel)) {
| test al, al
- | jz >5
+ | jnz >5
| call ->suspend
| jmp <1
|5:
@@ -887,10 +898,11 @@ static void jitbytecode(jitcompiler *jc) {
| mov ARG1_64, CLOSURE
| load_handler_data h, UPB_STARTMSG_SELECTOR
| callp startmsg
- if (jc->chkret) {
+ if (!alwaysok(h, UPB_STARTMSG_SELECTOR)) {
| test al, al
- | jnz <2
+ | jnz >2
| call ->suspend
+ | jmp <1
|2:
}
}
@@ -960,7 +972,7 @@ static void jitbytecode(jitcompiler *jc) {
| sub ARG3_64, PTR
}
| callp start
- if (jc->chkret) {
+ if (!alwaysok(h, arg)) {
| test rax, rax
| jnz >2
| call ->suspend
@@ -986,7 +998,7 @@ static void jitbytecode(jitcompiler *jc) {
| mov ARG1_64, CLOSURE
| load_handler_data h, arg
| callp end
- if (jc->chkret) {
+ if (!alwaysok(h, arg)) {
| test al, al
| jnz >2
| call ->suspend
@@ -1016,9 +1028,10 @@ static void jitbytecode(jitcompiler *jc) {
| mov ARG3_64, PTR
| mov ARG4_64, DATAEND
| sub ARG4_64, PTR
+ | mov ARG5_64, qword DECODER->handle
| callp str
| add PTR, rax
- if (jc->chkret) {
+ if (!alwaysok(h, arg)) {
| cmp PTR, DATAEND
| je >3
| call ->strret_fallback
diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c
index 6fd6576..c5fae0e 100644
--- a/upb/pb/decoder.c
+++ b/upb/pb/decoder.c
@@ -148,10 +148,11 @@ static void checkpoint(upb_pbdecoder *d) {
// Resumes the decoder from an initial state or from a previous suspend.
void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
- size_t size) {
+ size_t size, const upb_bufhandle *handle) {
UPB_UNUSED(p); // Useless; just for the benefit of the JIT.
d->buf_param = buf;
d->size_param = size;
+ d->handle = handle;
d->skip = 0;
if (d->residual_end > d->residual) {
// We have residual bytes from the last buffer.
@@ -488,11 +489,11 @@ upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
/* The main decoding loop *****************************************************/
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
- size_t size) {
+ size_t size, const upb_bufhandle *handle) {
upb_pbdecoder *d = closure;
const mgroup *group = hd;
assert(buf);
- upb_pbdecoder_resume(d, NULL, buf, size);
+ upb_pbdecoder_resume(d, NULL, buf, size, handle);
UPB_UNUSED(group);
#define VMCASE(op, code) \
@@ -578,7 +579,8 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
)
VMCASE(OP_STRING,
uint32_t len = curbufleft(d);
- CHECK_SUSPEND(upb_sink_putstring(&d->top->sink, arg, ptr(d), len));
+ CHECK_SUSPEND(
+ upb_sink_putstring(&d->top->sink, arg, ptr(d), len, handle));
advance(d, len);
if (d->delim_end == NULL) { // String extends beyond this buf?
d->pc--;
@@ -683,6 +685,7 @@ void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
UPB_UNUSED(hd);
+ UPB_UNUSED(size_hint);
upb_pbdecoder *d = closure;
d->call_len = 0;
return d;
@@ -712,7 +715,7 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) {
if (group->jit_code) {
if (d->top != d->stack)
d->stack->end_ofs = 0;
- group->jit_code(closure, method->code_base.ptr, &dummy, 0);
+ group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL);
} else {
#endif
d->stack->end_ofs = end;
@@ -726,7 +729,7 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) {
getop(*d->pc) == OP_TAGN);
d->pc = p;
}
- upb_pbdecoder_decode(closure, handler_data, &dummy, 0);
+ upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL);
#ifdef UPB_USE_JIT_X64
}
#endif
@@ -762,7 +765,9 @@ void upb_pbdecoder_reset(upb_pbdecoder *d) {
// Not currently required, but to support outgrowing the static stack we need
// this.
-void upb_pbdecoder_uninit(upb_pbdecoder *d) {}
+void upb_pbdecoder_uninit(upb_pbdecoder *d) {
+ UPB_UNUSED(d);
+}
const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
return d->method_;
diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h
index 4529324..4313bb3 100644
--- a/upb/pb/decoder.h
+++ b/upb/pb/decoder.h
@@ -234,6 +234,7 @@ struct upb_pbdecoder {
// Stores the user buffer passed to our decode function.
const char *buf_param;
size_t size_param;
+ const upb_bufhandle *handle;
#ifdef UPB_USE_JIT_X64
// Used momentarily by the generated code to store a value while a user
diff --git a/upb/pb/decoder.int.h b/upb/pb/decoder.int.h
index 1c10eb3..20afa68 100644
--- a/upb/pb/decoder.int.h
+++ b/upb/pb/decoder.int.h
@@ -108,12 +108,12 @@ typedef struct {
void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
- size_t size);
+ size_t size, const upb_bufhandle *handle);
bool upb_pbdecoder_end(void *closure, const void *handler_data);
// Decoder-internal functions that the JIT calls to handle fallback paths.
void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
- size_t size);
+ size_t size, const upb_bufhandle *handle);
size_t upb_pbdecoder_suspend(upb_pbdecoder *d);
int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum,
uint8_t wire_type);
diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c
index 0c12571..8a49c73 100644
--- a/upb/pb/textprinter.c
+++ b/upb/pb/textprinter.c
@@ -3,6 +3,9 @@
*
* Copyright (c) 2009 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * OPT: This is not optimized at all. It uses printf() which parses the format
+ * string every time, and it allocates memory for every put.
*/
#include "upb/pb/textprinter.h"
@@ -16,29 +19,29 @@
#include "upb/sink.h"
-struct _upb_textprinter {
- int indent_depth;
- bool single_line;
- upb_status status;
-};
-
#define CHECK(x) if ((x) < 0) goto err;
+static const char *shortname(const char *longname) {
+ const char *last = strrchr(longname, '.');
+ return last ? last + 1 : longname;
+}
+
static int indent(upb_textprinter *p) {
int i;
- if (!p->single_line)
- for (i = 0; i < p->indent_depth * 2; i++)
- putchar(' ');
+ if (!p->single_line_)
+ for (i = 0; i < p->indent_depth_; i++)
+ upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL);
return 0;
- return -1;
}
static int endfield(upb_textprinter *p) {
- putchar(p->single_line ? ' ' : '\n');
+ const char ch = (p->single_line_ ? ' ' : '\n');
+ upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL);
return 0;
}
-static int putescaped(const char* buf, size_t len, bool preserve_utf8) {
+static int putescaped(upb_textprinter *p, const char *buf, size_t len,
+ bool preserve_utf8) {
// Based on CEscapeInternal() from Google's protobuf release.
char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf);
const char *end = buf + len;
@@ -50,7 +53,7 @@ static int putescaped(const char* buf, size_t len, bool preserve_utf8) {
for (; buf < end; buf++) {
if (dstend - dst < 4) {
- fwrite(dstbuf, dst - dstbuf, 1, stdout);
+ upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
dst = dstbuf;
}
@@ -78,18 +81,57 @@ static int putescaped(const char* buf, size_t len, bool preserve_utf8) {
last_hex_escape = is_hex_escape;
}
// Flush remaining data.
- fwrite(dst, dst - dstbuf, 1, stdout);
+ upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
return 0;
}
+bool putf(upb_textprinter *p, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+ // Run once to get the length of the string.
+ va_list args_copy;
+ va_copy(args_copy, args);
+ int len = vsnprintf(NULL, 0, fmt, args_copy);
+ va_end(args_copy);
+
+ // + 1 for NULL terminator (vsnprintf() requires it even if we don't).
+ char *str = malloc(len + 1);
+ if (!str) return false;
+ int written = vsnprintf(str, len + 1, fmt, args);
+ va_end(args);
+ UPB_ASSERT_VAR(written, written == len);
+
+ bool ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
+ free(str);
+ return ok;
+}
+
+
+/* handlers *******************************************************************/
+
+static bool startmsg(void *c, const void *hd) {
+ upb_textprinter *p = c;
+ if (p->indent_depth_ == 0) {
+ upb_bytessink_start(p->output_, 0, &p->subc);
+ }
+ return true;
+}
+
+static bool endmsg(void *c, const void *hd, upb_status *s) {
+ upb_textprinter *p = c;
+ if (p->indent_depth_ == 0) {
+ upb_bytessink_end(p->output_);
+ }
+ return true;
+}
+
#define TYPE(name, ctype, fmt) \
static bool put ## name(void *closure, const void *handler_data, ctype val) {\
upb_textprinter *p = closure; \
const upb_fielddef *f = handler_data; \
CHECK(indent(p)); \
- puts(upb_fielddef_name(f)); \
- puts(": "); \
- printf(fmt, val); \
+ putf(p, "%s: " fmt, upb_fielddef_name(f), val); \
CHECK(endfield(p)); \
return true; \
err: \
@@ -100,9 +142,7 @@ static bool putbool(void *closure, const void *handler_data, bool val) {
upb_textprinter *p = closure;
const upb_fielddef *f = handler_data;
CHECK(indent(p));
- puts(upb_fielddef_name(f));
- puts(": ");
- puts(val ? "true" : "false");
+ putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false");
CHECK(endfield(p));
return true;
err:
@@ -121,11 +161,14 @@ TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
// Output a symbolic value from the enum if found, else just print as int32.
static bool putenum(void *closure, const void *handler_data, int32_t val) {
+ upb_textprinter *p = closure;
const upb_fielddef *f = handler_data;
const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
const char *label = upb_enumdef_iton(enum_def, val);
if (label) {
- puts(label);
+ indent(p);
+ putf(p, "%s: %s", upb_fielddef_name(f), label);
+ endfield(p);
} else {
CHECK(putint32(closure, handler_data, val));
}
@@ -136,25 +179,27 @@ err:
static void *startstr(void *closure, const void *handler_data,
size_t size_hint) {
- UPB_UNUSED(handler_data);
+ const upb_fielddef *f = handler_data;
UPB_UNUSED(size_hint);
upb_textprinter *p = closure;
- putchar('"');
+ putf(p, "%s: \"", upb_fielddef_name(f));
return p;
}
static bool endstr(void *closure, const void *handler_data) {
- UPB_UNUSED(closure);
UPB_UNUSED(handler_data);
- putchar('"');
+ upb_textprinter *p = closure;
+ putf(p, "\"");
+ endfield(p);
return true;
}
static size_t putstr(void *closure, const void *hd, const char *buf,
- size_t len) {
- UPB_UNUSED(closure);
+ size_t len, const upb_bufhandle *handle) {
+ UPB_UNUSED(handle);
+ upb_textprinter *p = closure;
const upb_fielddef *f = hd;
- CHECK(putescaped(buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
+ CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
return len;
err:
return 0;
@@ -162,12 +207,10 @@ err:
static void *startsubmsg(void *closure, const void *handler_data) {
upb_textprinter *p = closure;
- const upb_fielddef *f = handler_data;
+ const char *name = handler_data;
CHECK(indent(p));
- printf("%s {", upb_fielddef_name(f));
- if (!p->single_line)
- putchar('\n');
- p->indent_depth++;
+ putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n');
+ p->indent_depth_++;
return p;
err:
return UPB_BREAK;
@@ -176,30 +219,36 @@ err:
static bool endsubmsg(void *closure, const void *handler_data) {
UPB_UNUSED(handler_data);
upb_textprinter *p = closure;
- p->indent_depth--;
+ p->indent_depth_--;
CHECK(indent(p));
- putchar('}');
+ upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL);
CHECK(endfield(p));
return true;
err:
return false;
}
-upb_textprinter *upb_textprinter_new() {
- upb_textprinter *p = malloc(sizeof(*p));
- return p;
+
+/* Public API *****************************************************************/
+
+void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h) {
+ p->single_line_ = false;
+ p->indent_depth_ = 0;
+ upb_sink_reset(&p->input_, h, p);
}
-void upb_textprinter_free(upb_textprinter *p) { free(p); }
+void upb_textprinter_uninit(upb_textprinter *p) {}
void upb_textprinter_reset(upb_textprinter *p, bool single_line) {
- p->single_line = single_line;
- p->indent_depth = 0;
+ p->single_line_ = single_line;
+ p->indent_depth_ = 0;
}
static void onmreg(void *c, upb_handlers *h) {
(void)c;
const upb_msgdef *m = upb_handlers_msgdef(h);
+ upb_handlers_setstartmsg(h, startmsg, NULL);
+ upb_handlers_setendmsg(h, endmsg, NULL);
upb_msg_iter i;
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
upb_fielddef *f = upb_msg_iter_field(&i);
@@ -233,20 +282,37 @@ static void onmreg(void *c, upb_handlers *h) {
upb_handlers_setstring(h, f, putstr, &attr);
upb_handlers_setendstr(h, f, endstr, &attr);
break;
- case UPB_TYPE_MESSAGE:
+ case UPB_TYPE_MESSAGE: {
+ const char *name =
+ upb_fielddef_istagdelim(f)
+ ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))
+ : upb_fielddef_name(f);
+ // TODO(haberman): add "setconsthandlerdata"? If we pass NULL for
+ // cleanup then we don't need a non-const pointer.
+ upb_handlerattr_sethandlerdata(&attr, (void*)name, NULL);
upb_handlers_setstartsubmsg(h, f, startsubmsg, &attr);
upb_handlers_setendsubmsg(h, f, endsubmsg, &attr);
break;
+ }
case UPB_TYPE_ENUM:
upb_handlers_setint32(h, f, putenum, &attr);
- default:
- assert(false);
break;
}
}
}
-const upb_handlers *upb_textprinter_newhandlers(const void *owner,
- const upb_msgdef *m) {
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+ const void *owner) {
return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
}
+
+upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; }
+
+bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output) {
+ p->output_ = output;
+ return true;
+}
+
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
+ p->single_line_ = single_line;
+}
diff --git a/upb/pb/textprinter.h b/upb/pb/textprinter.h
index 7b653e7..eb3e132 100644
--- a/upb/pb/textprinter.h
+++ b/upb/pb/textprinter.h
@@ -8,23 +8,87 @@
#ifndef UPB_TEXT_H_
#define UPB_TEXT_H_
-#include "upb/handlers.h"
+#include "upb/sink.h"
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class TextPrinter;
+} // namespace pb
+} // namespace upb
+
+typedef upb::pb::TextPrinter upb_textprinter;
+#else
+struct upb_textprinter;
+typedef struct upb_textprinter upb_textprinter;
+#endif
+
+#ifdef __cplusplus
+class upb::pb::TextPrinter {
+ public:
+ // The given handlers must have come from NewHandlers(). It must outlive the
+ // TextPrinter.
+ explicit TextPrinter(const upb::Handlers* handlers);
+
+ void SetSingleLineMode(bool single_line);
+
+ bool ResetOutput(BytesSink* output);
+ Sink* input();
+
+ // If handler caching becomes a requirement we can add a code cache as in
+ // decoder.h
+ static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md);
+
+ private:
+#else
+struct upb_textprinter {
+#endif
+ upb_sink input_;
+ upb_bytessink *output_;
+ int indent_depth_;
+ bool single_line_;
+ void *subc;
+};
#ifdef __cplusplus
extern "C" {
#endif
-struct _upb_textprinter;
-typedef struct _upb_textprinter upb_textprinter;
+// C API.
+void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h);
+void upb_textprinter_uninit(upb_textprinter *p);
+bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output);
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line);
+upb_sink *upb_textprinter_input(upb_textprinter *p);
-upb_textprinter *upb_textprinter_new();
-void upb_textprinter_free(upb_textprinter *p);
-void upb_textprinter_reset(upb_textprinter *p, bool single_line);
-const upb_handlers *upb_textprinter_newhandlers(const void *owner,
- const upb_msgdef *m);
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+ const void *owner);
#ifdef __cplusplus
} /* extern "C" */
+
+namespace upb {
+namespace pb {
+inline TextPrinter::TextPrinter(const upb::Handlers* handlers) {
+ upb_textprinter_init(this, handlers);
+}
+inline void TextPrinter::SetSingleLineMode(bool single_line) {
+ upb_textprinter_setsingleline(this, single_line);
+}
+inline bool TextPrinter::ResetOutput(BytesSink* output) {
+ return upb_textprinter_resetoutput(this, output);
+}
+inline Sink* TextPrinter::input() {
+ return upb_textprinter_input(this);
+}
+inline reffed_ptr<const Handlers> TextPrinter::NewHandlers(
+ const MessageDef *md) {
+ const Handlers* h = upb_textprinter_newhandlers(md, &h);
+ return reffed_ptr<const Handlers>(h, &h);
+}
+} // namespace pb
+} // namespace upb
+
#endif
#endif /* UPB_TEXT_H_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback