diff options
Diffstat (limited to 'upb/pb')
-rw-r--r-- | upb/pb/compile_decoder_x64.c | 3 | ||||
-rw-r--r-- | upb/pb/compile_decoder_x64.dasc | 27 | ||||
-rw-r--r-- | upb/pb/decoder.c | 19 | ||||
-rw-r--r-- | upb/pb/decoder.h | 1 | ||||
-rw-r--r-- | upb/pb/decoder.int.h | 4 | ||||
-rw-r--r-- | upb/pb/textprinter.c | 158 | ||||
-rw-r--r-- | upb/pb/textprinter.h | 80 |
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_ */ |