From 9a7037a2fa4f909eea561d6d89997b0b4203df9e Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 31 Mar 2012 19:51:17 -0700 Subject: [PATCH] Got decoder & textprinter compiling in kernel mode. --- bindings/linux/Makefile | 3 +++ bindings/linux/ctype.h | 8 +++++++ bindings/linux/inttypes.h | 22 ++++++++++++++++++++ bindings/linux/setjmp.h | 44 +++++++++++++++++++++++++++++++++++++++ upb/pb/decoder.c | 37 +++++++++++++++++++++++--------- upb/pb/decoder.h | 2 +- upb/pb/textprinter.c | 4 ++-- upb/pb/textprinter.h | 2 +- 8 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 bindings/linux/ctype.h create mode 100644 bindings/linux/inttypes.h create mode 100644 bindings/linux/setjmp.h diff --git a/bindings/linux/Makefile b/bindings/linux/Makefile index 1736b61f36..cf0cc7ad44 100644 --- a/bindings/linux/Makefile +++ b/bindings/linux/Makefile @@ -8,6 +8,9 @@ upb-objs = \ ../../upb/table.o \ ../../upb/refcount.o \ ../../upb/msg.o \ + ../../upb/pb/decoder.o \ + ../../upb/pb/textprinter.o \ + ../../upb/pb/varint.o \ KVERSION = $(shell uname -r) diff --git a/bindings/linux/ctype.h b/bindings/linux/ctype.h new file mode 100644 index 0000000000..b6cbda548e --- /dev/null +++ b/bindings/linux/ctype.h @@ -0,0 +1,8 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman + */ + +#include diff --git a/bindings/linux/inttypes.h b/bindings/linux/inttypes.h new file mode 100644 index 0000000000..e7a6e4263c --- /dev/null +++ b/bindings/linux/inttypes.h @@ -0,0 +1,22 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman + */ + +#ifndef PRId64 +#define PRId64 "ld" +#endif + +#ifndef PRIu64 +#define PRIu64 "lu" +#endif + +#ifndef PRId32 +#define PRId32 "d" +#endif + +#ifndef PRIu32 +#define PRIu32 "u" +#endif diff --git a/bindings/linux/setjmp.h b/bindings/linux/setjmp.h new file mode 100644 index 0000000000..6da4313ec5 --- /dev/null +++ b/bindings/linux/setjmp.h @@ -0,0 +1,44 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman + */ + +// Linux doesn't provide setjmp/longjmp, boo. + +typedef void *jmp_buf[3]; // rsp, rbp, rip + +static inline int _setjmp(jmp_buf env) { + register int ret asm ("%eax"); + __asm__ __volatile__ goto ( + " movq %%rsp, 0(%0)\n" // Save rsp + " movq %%rbp, 8(%0)\n" // Save rbp + " movq $1f, 16(%0)\n" // Save rip + " jmp %l[setup]\n" + "1:" + : // No outputs allowed (GCC limitation). + : "b" (env) // Input + : // All registers clobbered except rsp, which save in env. + "%rcx", "%rdx", "%rdi", "%rsi", "memory", "cc", + "%r8" , "%r9" , "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + : setup // Target labels. + ); + return ret; + +setup: + return 0; +} + +__attribute__((__noreturn__)) +static inline void _longjmp(jmp_buf env, int val) { + __asm__ __volatile__ ( + " movq 0(%0), %%rsp\n" // Restore rsp + " movq 8(%0), %%rbp\n" // Restore rbp + " movq %0, %%rbx\n" // Restore rbx + " jmpq *16(%0)\n" // Jump to saved rip + : // No output. + : "r" (env), "a" (val) // Move val to %eax + ); + __builtin_unreachable(); +} diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c index b0e2392ab5..30f7c65607 100644 --- a/upb/pb/decoder.c +++ b/upb/pb/decoder.c @@ -5,7 +5,6 @@ * Author: Josh Haberman */ -#include #include #include #include "upb/bytestream.h" @@ -13,6 +12,10 @@ #include "upb/pb/decoder.h" #include "upb/pb/varint.h" +#ifndef UINT32_MAX +#define UINT32_MAX 0xffffffff +#endif + typedef struct { uint8_t native_wire_type; bool is_numeric; @@ -97,13 +100,13 @@ bool upb_decoderplan_hasjitcode(upb_decoderplan *p) { // configuration. But emperically on a Core i7, performance increases 30-50% // with these annotations. Every instance where these appear, gcc 4.2.1 made // the wrong decision and degraded performance in benchmarks. -#define FORCEINLINE static __attribute__((always_inline)) -#define NOINLINE static __attribute__((noinline)) +#define FORCEINLINE static __attribute__((__always_inline__)) +#define NOINLINE static __attribute__((__noinline__)) UPB_NORETURN static void upb_decoder_exitjmp(upb_decoder *d) { // Resumable decoder would back out to completed_ptr (and possibly get a // previous buffer). - siglongjmp(d->exitjmp, 1); + _longjmp(d->exitjmp, 1); } UPB_NORETURN static void upb_decoder_exitjmp2(void *d) { upb_decoder_exitjmp(d); @@ -348,9 +351,6 @@ INLINE void upb_push_msg(upb_decoder *d, upb_fhandlers *f, uint64_t end) { upb_dispatch_value(&d->dispatcher, f, val); \ } \ -static double upb_asdouble(uint64_t n) { double d; memcpy(&d, &n, 8); return d; } -static float upb_asfloat(uint32_t n) { float f; memcpy(&f, &n, 4); return f; } - T(INT32, varint, int32, int32_t) T(INT64, varint, int64, int64_t) T(UINT32, varint, uint32, uint32_t) @@ -361,13 +361,30 @@ T(SFIXED32, fixed32, int32, int32_t) T(SFIXED64, fixed64, int64, int64_t) T(BOOL, varint, bool, bool) T(ENUM, varint, int32, int32_t) -T(DOUBLE, fixed64, double, upb_asdouble) -T(FLOAT, fixed32, float, upb_asfloat) T(SINT32, varint, int32, upb_zzdec_32) T(SINT64, varint, int64, upb_zzdec_64) T(STRING, string, byteregion, upb_byteregion*) + #undef T +INLINE void upb_decode_DOUBLE(upb_decoder *d, upb_fhandlers *f) { + upb_value val; + double dbl; + uint64_t wireval = upb_decode_fixed64(d); + memcpy(&dbl, &wireval, 8); + upb_value_setdouble(&val, dbl); + upb_dispatch_value(&d->dispatcher, f, val); +} + +INLINE void upb_decode_FLOAT(upb_decoder *d, upb_fhandlers *f) { + upb_value val; + float flt; + uint64_t wireval = upb_decode_fixed32(d); + memcpy(&flt, &wireval, 4); + upb_value_setfloat(&val, flt); + upb_dispatch_value(&d->dispatcher, f, val); +} + static void upb_decode_GROUP(upb_decoder *d, upb_fhandlers *f) { upb_push_msg(d, f, UPB_NONDELIMITED); } @@ -474,7 +491,7 @@ INLINE upb_fhandlers *upb_decode_tag(upb_decoder *d) { upb_success_t upb_decoder_decode(upb_decoder *d) { assert(d->input); - if (sigsetjmp(d->exitjmp, 0)) { + if (_setjmp(d->exitjmp)) { assert(!upb_ok(&d->status)); return UPB_ERROR; } diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h index 13e5774936..df654682bd 100644 --- a/upb/pb/decoder.h +++ b/upb/pb/decoder.h @@ -74,7 +74,7 @@ typedef struct _upb_decoder { #endif // For exiting the decoder on error. - sigjmp_buf exitjmp; + jmp_buf exitjmp; } upb_decoder; void upb_decoder_init(upb_decoder *d); diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c index 0d9c96745c..2fe3452ca8 100644 --- a/upb/pb/textprinter.c +++ b/upb/pb/textprinter.c @@ -41,7 +41,7 @@ static int upb_textprinter_putescaped(upb_textprinter *p, // Based on CEscapeInternal() from Google's protobuf release. // TODO; we could read directly from a bytesrc's buffer instead. // TODO; we could write byteregions to the sink when possible. - char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); + char dstbuf[512], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); char *buf = malloc(upb_byteregion_len(bytes)), *src = buf; char *end = src + upb_byteregion_len(bytes); upb_byteregion_copyall(bytes, buf); @@ -182,7 +182,7 @@ err: return UPB_BREAK; } -upb_textprinter *upb_textprinter_new() { +upb_textprinter *upb_textprinter_new(void) { upb_textprinter *p = malloc(sizeof(*p)); return p; } diff --git a/upb/pb/textprinter.h b/upb/pb/textprinter.h index 25f364e5f6..174148e61e 100644 --- a/upb/pb/textprinter.h +++ b/upb/pb/textprinter.h @@ -18,7 +18,7 @@ extern "C" { struct _upb_textprinter; typedef struct _upb_textprinter upb_textprinter; -upb_textprinter *upb_textprinter_new(); +upb_textprinter *upb_textprinter_new(void); void upb_textprinter_free(upb_textprinter *p); void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, bool single_line);