Merge pull request #121 from haberman/minimize

Changed C API to only define structs, a table, and a few minimal inline function.
pull/13171/head
Joshua Haberman 6 years ago committed by GitHub
commit ef1246d87c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      CMakeLists.txt
  2. 1675
      google/protobuf/descriptor.upb.c
  3. 1172
      google/protobuf/descriptor.upb.h
  4. 41
      tests/conformance_upb.c
  5. 2
      third_party/protobuf
  6. 10
      tools/amalgamate.py
  7. 380
      tools/make_c_api.lua
  8. 26
      upb/bindings/lua/upb/pb.c
  9. 41
      upb/decode.c
  10. 3
      upb/decode.h
  11. 22
      upb/encode.c
  12. 2
      upb/encode.h
  13. 18
      upb/port_def.inc
  14. 5
      upb/port_undef.inc

@ -33,17 +33,22 @@ endif()
# Implement ASAN/UBSAN options
if(UPB_ENABLE_ASAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
endif()
if(UPB_ENABLE_UBSAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=undefined")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address")
endif()
include_directories(.)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_CXX_FLAGS "-std=c++11 -W -Wall -Wno-sign-compare")
set(CMAKE_C_FLAGS "-std=c89 -W -Wall -Wno-sign-compare")
if(APPLE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup -flat_namespace")
@ -148,7 +153,9 @@ if(LUA_FOUND AND PROTOBUF_FOUND)
add_custom_target(
upbc ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tools/upbc
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/make_c_api.lua
${CMAKE_CURRENT_SOURCE_DIR}/tools/upbc.lua
${CMAKE_CURRENT_BINARY_DIR}/tools/upbc
${CMAKE_CURRENT_BINARY_DIR}/lua/upb.lua
${CMAKE_CURRENT_BINARY_DIR}/lua/upb/pb.lua
)
@ -164,7 +171,8 @@ if(LUA_FOUND AND PROTOBUF_FOUND)
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/timestamp.upb.c
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/wrappers.upb.c
${CMAKE_CURRENT_BINARY_DIR}/conformance.upb.c
DEPENDS upbc ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/conformance/conformance.proto
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tools/upbc
${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/conformance/conformance.proto
COMMAND protoc --include_imports
${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/conformance/conformance.proto
${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/src/google/protobuf/test_messages_proto3.proto
@ -177,7 +185,8 @@ if(LUA_FOUND AND PROTOBUF_FOUND)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/descriptor.upb.h
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/descriptor.upb.c
DEPENDS upbc ${CMAKE_CURRENT_SOURCE_DIR}/google/protobuf/descriptor.proto
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tools/upbc
${CMAKE_CURRENT_SOURCE_DIR}/google/protobuf/descriptor.proto
COMMAND protoc
${CMAKE_CURRENT_SOURCE_DIR}/google/protobuf/descriptor.proto
-I${CMAKE_CURRENT_SOURCE_DIR}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -49,10 +49,9 @@ static const char *proto3_msg =
void DoTest(
const conformance_ConformanceRequest* request,
conformance_ConformanceResponse *response,
upb_env *env) {
upb_stringview message_type =
conformance_ConformanceRequest_message_type(request);
if (!stringview_eql(message_type, proto3_msg)) {
upb_arena *arena) {
if (!stringview_eql(conformance_ConformanceRequest_message_type(request),
proto3_msg)) {
static const char msg[] = "Only proto3 for now.";
conformance_ConformanceResponse_set_skipped(
response, upb_stringview_make(msg, sizeof(msg)));
@ -63,14 +62,12 @@ void DoTest(
switch (conformance_ConformanceRequest_payload_case(request)) {
case conformance_ConformanceRequest_payload_protobuf_payload: {
upb_stringview payload =
conformance_ConformanceRequest_protobuf_payload(request);
upb_stringview payload = conformance_ConformanceRequest_protobuf_payload(request);
test_message = protobuf_test_messages_proto3_TestAllTypesProto3_parsenew(
payload, env);
payload, arena);
if (!test_message) {
/* TODO(haberman): return details. */
static const char msg[] = "Parse error (no more details available).";
static const char msg[] = "Parse error";
conformance_ConformanceResponse_set_parse_error(
response, upb_stringview_make(msg, sizeof(msg)));
return;
@ -88,6 +85,11 @@ void DoTest(
case conformance_ConformanceRequest_payload_NOT_SET:
fprintf(stderr, "conformance_upb: Request didn't have payload.\n");
return;
default:
fprintf(stderr, "conformance_upb: Unexpected case: %d\n",
conformance_ConformanceRequest_payload_case(request));
exit(1);
}
switch (conformance_ConformanceRequest_requested_output_format(request)) {
@ -99,7 +101,7 @@ void DoTest(
size_t serialized_len;
char *serialized =
protobuf_test_messages_proto3_TestAllTypesProto3_serialize(
test_message, env, &serialized_len);
test_message, arena, &serialized_len);
if (!serialized) {
static const char msg[] = "Error serializing.";
conformance_ConformanceResponse_set_serialize_error(
@ -128,7 +130,8 @@ void DoTest(
}
bool DoTestIo() {
upb_env env;
upb_arena arena;
upb_alloc *alloc;
upb_status status;
char *serialized_input;
char *serialized_output;
@ -138,13 +141,13 @@ bool DoTestIo() {
conformance_ConformanceResponse *response;
if (!CheckedRead(STDIN_FILENO, &input_size, sizeof(uint32_t))) {
// EOF.
/* EOF. */
return false;
}
upb_env_init(&env);
upb_env_reporterrorsto(&env, &status);
serialized_input = upb_env_malloc(&env, input_size);
upb_arena_init(&arena);
alloc = upb_arena_alloc(&arena);
serialized_input = upb_malloc(alloc, input_size);
if (!CheckedRead(STDIN_FILENO, serialized_input, input_size)) {
fprintf(stderr, "conformance_upb: unexpected EOF on stdin.\n");
@ -152,18 +155,18 @@ bool DoTestIo() {
}
request = conformance_ConformanceRequest_parsenew(
upb_stringview_make(serialized_input, input_size), &env);
response = conformance_ConformanceResponse_new(&env);
upb_stringview_make(serialized_input, input_size), &arena);
response = conformance_ConformanceResponse_new(&arena);
if (request) {
DoTest(request, response, &env);
DoTest(request, response, &arena);
} else {
fprintf(stderr, "conformance_upb: parse of ConformanceRequest failed: %s\n",
upb_status_errmsg(&status));
}
serialized_output = conformance_ConformanceResponse_serialize(
response, &env, &output_size);
response, &arena, &output_size);
CheckedWrite(STDOUT_FILENO, &output_size, sizeof(uint32_t));
CheckedWrite(STDOUT_FILENO, serialized_output, output_size);

@ -1 +1 @@
Subproject commit d340bdf50821e6db173a9e41bc7bde740275ba33
Subproject commit fd90f4536045bc881b8b895731fe72d89450b6b4

@ -12,14 +12,20 @@ def parse_include(line):
class Amalgamator:
def __init__(self, include_path, output_path):
self.include_path = include_path
self.included = set()
self.included = set(["upb/port_def.inc", "upb/port_undef.inc"])
self.output_h = open(output_path + "upb.h", "w")
self.output_c = open(output_path + "upb.c", "w")
self.output_c.write("// Amalgamated source file\n")
self.output_c.write('#include "upb.h"\n')
self.output_c.write('#include "upb/port_def.inc"\n')
self.output_h.write("// Amalgamated source file\n")
self.output_h.write('#include "upb/port_def.inc"\n')
def finish(self):
self.output_c.write('#include "upb/port_undef.inc"\n')
self.output_h.write('#include "upb/port_undef.inc"\n')
def _process_file(self, infile_name, outfile):
for line in open(infile_name):
@ -46,3 +52,5 @@ amalgamator = Amalgamator(include_path, output_path)
for filename in sys.argv[3:]:
amalgamator.add_src(filename.strip())
amalgamator.finish()

@ -186,6 +186,80 @@ local function field_layout_rank(field)
return (rank * 2^29) + field:number()
end
local function sizeof(field)
if field:label() == upb.LABEL_REPEATED or
field:type() == upb.TYPE_MESSAGE then
return {4, 8}
elseif field:type() == upb.TYPE_STRING or field:type() == upb.TYPE_BYTES then
-- upb_stringview
return {8, 16}
elseif field:type() == upb.TYPE_BOOL then
return {1, 1}
elseif field:type() == upb.TYPE_FLOAT or
field:type() == upb.TYPE_INT32 or
field:type() == upb.TYPE_UINT32 then
return {4, 4}
else
return {8, 8}
end
end
local function sizemax(size, max)
max[1] = math.max(max[1], size[1])
max[2] = math.max(max[2], size[2])
end
local function alignup(val, align)
val[1] = math.ceil(val[1] / align[1]) * align[1]
val[2] = math.ceil(val[2] / align[2]) * align[2]
end
local function copysize(size)
return {size[1], size[2]}
end
local function place(offset, size, max)
alignup(offset, size)
local ret = copysize(offset)
-- add size
offset[1] = offset[1] + size[1]
offset[2] = offset[2] + size[2]
-- track max size
sizemax(size, max)
return ret
end
local function get_field_layout_order(msg)
local field_order = {}
-- Sort fields by rank.
for field in msg:fields() do
table.insert(field_order, field)
end
table.sort(field_order, function(a, b)
return field_layout_rank(a) < field_layout_rank(b)
end)
return field_order
end
local function get_oneof_layout_order(msg)
local oneof_order = {}
-- Sort oneofs by name.
for oneof in msg:oneofs() do
table.insert(oneof_order, oneof)
end
table.sort(oneof_order, function(a, b)
return a:name() < b:name()
end)
return oneof_order
end
local function has_hasbit(field)
if field:containing_type():file():syntax() == upb.SYNTAX_PROTO2 then
return field:label() ~= upb.LABEL_REPEATED and not field:containing_oneof()
@ -194,6 +268,65 @@ local function has_hasbit(field)
end
end
local function get_message_layout(msg)
local hasbit_count = 0
local hasbit_indexes = {}
local field_order = get_field_layout_order(msg)
local maxsize = {0, 0}
-- Count hasbits.
for _, field in ipairs(field_order) do
if has_hasbit(field) then
hasbit_indexes[field] = hasbit_count
hasbit_count = hasbit_count + 1
end
end
-- Place hasbits at the beginning.
local offset = math.ceil(hasbit_count / 8)
offset = {offset, offset} -- 32, 64 bit
local offsets = {}
-- Place non-oneof fields.
for _, field in ipairs(field_order) do
if not field:containing_oneof() then
offsets[field] = place(offset, sizeof(field), maxsize)
end
end
-- Place oneof fields.
for oneof in msg:oneofs() do
local oneof_maxsize = {0, 0}
-- Calculate max size.
for field in oneof:fields() do
local size = sizeof(field)
sizemax(size, oneof_maxsize)
end
-- Place discriminator enum and data.
local data = place(offset, oneof_maxsize, maxsize)
local case = place(offset, {4, 4}, maxsize)
offsets[oneof] = {data, case}
end
-- Align overall size up to max size.
alignup(offset, maxsize)
local size = copysize(offset)
-- Place oneof defaults.
for oneof in msg:oneofs() do
for field in oneof:fields() do
offsets[field] = place(offset, sizeof(field), maxsize)
end
end
return hasbit_indexes, offsets, size
end
function get_sizeinit(size)
return string.format("UPB_SIZE(%s, %s)", size[1], size[2])
end
local function write_h_file(filedef, append)
emit_file_warning(filedef, append)
local basename_preproc = to_preproc(filedef:name())
@ -201,18 +334,32 @@ local function write_h_file(filedef, append)
append('#define %s_UPB_H_\n\n', basename_preproc)
append('#include "upb/msg.h"\n\n')
append('#include "upb/decode.h"\n')
append('#include "upb/encode.h"\n')
append('#include "upb/port_def.inc"\n')
append('UPB_BEGIN_EXTERN_C\n\n')
-- Forward-declare types defined in this file.
for msg in filedef:defs(upb.DEF_MSG) do
-- TODO(haberman): forward declare C++ type names so we can use
-- UPB_DECLARE_TYPE().
local msgname = to_cident(msg:full_name())
append('struct %s;\n', msgname)
append('typedef struct %s %s;\n', msgname, msgname)
append('typedef struct %s { int a; } %s;\n', msgname, msgname)
end
-- Forward-declare types not in this file, but used as submessages.
for msg in filedef:defs(upb.DEF_MSG) do
for field in msg:fields() do
if field:type() == upb.TYPE_MESSAGE and
field:subdef():file() ~= filedef then
-- Forward declaration for message type declared in another file.
append('struct %s;\n', to_cident(field:subdef():full_name()))
end
end
end
append('\n')
append("/* Enums */\n\n")
for _, def in ipairs(sorted_defs(filedef:defs(upb.DEF_ENUM))) do
local cident = to_cident(def:full_name())
append('typedef enum {\n')
@ -221,54 +368,78 @@ local function write_h_file(filedef, append)
end
for msg in filedef:defs(upb.DEF_MSG) do
local hasbit_indexes, offsets, size = get_message_layout(msg)
append("/* %s */\n\n", msg:full_name())
local msgname = to_cident(msg:full_name())
append('/* %s */\n', msgname)
append('extern const upb_msglayout %s_msginit;\n', msgname)
append('%s *%s_new(upb_env *env);\n', msgname, msgname)
append('%s *%s_parsenew(upb_stringview buf, upb_env *env);\n',
append('UPB_INLINE %s *%s_new(upb_arena *arena) {\n', msgname, msgname)
append(' return upb_msg_new(&%s_msginit, arena);\n', msgname)
append('}\n')
append('UPB_INLINE %s *%s_parsenew(upb_stringview buf, upb_arena *arena) {\n',
msgname, msgname)
append('char *%s_serialize(%s *msg, upb_env *env, size_t *len);\n',
append(' %s *ret = %s_new(arena);\n', msgname, msgname)
append(' return (ret && upb_decode(buf, ret, &%s_msginit)) ? ret : NULL;\n', msgname)
append('}\n')
append('UPB_INLINE char *%s_serialize(const %s *msg, upb_arena *arena, size_t *len) {\n',
msgname, msgname)
append('void %s_free(%s *msg, upb_env *env);\n', msgname, msgname)
append(' return upb_encode(msg, &%s_msginit, arena, len);\n', msgname)
append('}\n')
append('\n')
append('/* getters. */\n')
local setters, get_setters = dump_cinit.str_appender()
for field in msg:fields() do
local fieldname = to_cident(field:name())
if field:type() == upb.TYPE_MESSAGE and
field:subdef():file() ~= filedef then
-- Forward declaration for message type declared in another file.
append('struct %s;\n', to_cident(field:subdef():full_name()))
end
append('%s %s_%s(const %s *msg);\n',
ctype(field, true), msgname, fieldname, msgname)
setters('void %s_set_%s(%s *msg, %s value);\n',
msgname, fieldname, msgname, ctype(field))
end
for oneof in msg:oneofs() do
local fullname = to_cident(oneof:containing_type():full_name() .. "." .. oneof:name())
local offset = offsets[oneof]
append('typedef enum {\n')
for field in oneof:fields() do
append(' %s = %d,\n', fullname .. "_" .. field:name(), field:number())
end
append(' %s_NOT_SET = 0,\n', fullname)
append('} %s_oneofcases;\n', fullname)
append('%s_oneofcases %s_case(const %s *msg);\n', fullname, fullname, msgname)
append('UPB_INLINE %s_oneofcases %s_%s_case(const %s* msg) { ' ..
'return UPB_FIELD_AT(msg, int, %s); }\n',
fullname, msgname, oneof:name(), msgname, get_sizeinit(offset[2]))
append('\n')
end
append('\n')
append('/* setters. */\n')
append(get_setters())
for field in msg:fields() do
append('UPB_INLINE %s %s_%s(const %s *msg) {',
ctype(field, true), msgname, field:name(), msgname)
if field:containing_oneof() then
local offset = offsets[field:containing_oneof()]
append(' return UPB_READ_ONEOF(msg, %s, %s, %s, %s, %s); }\n',
ctype(field, true), get_sizeinit(offset[1]),
get_sizeinit(offset[2]), field:number(), field_default(field))
else
append(' return UPB_FIELD_AT(msg, %s, %s); }\n',
ctype(field, true), get_sizeinit(offsets[field]))
end
end
append('\n')
append('\n')
for field in msg:fields() do
append('UPB_INLINE void %s_set_%s(%s *msg, %s value) { ',
msgname, field:name(), msgname, ctype(field))
if field:containing_oneof() then
local offset = offsets[field:containing_oneof()]
append('UPB_WRITE_ONEOF(msg, %s, %s, value, %s, %s); }\n',
ctype(field), get_sizeinit(offset[1]), get_sizeinit(offset[2]),
field:number())
else
append('UPB_FIELD_AT(msg, %s, %s) = value; }\n',
ctype(field), get_sizeinit(offsets[field]))
end
end
append('\n\n')
end
append('UPB_END_EXTERN_C')
append('UPB_END_EXTERN_C\n')
append('\n')
append('#include "upb/port_undef.inc"\n');
append('\n')
append('#endif /* %s_UPB_H_ */\n', basename_preproc)
@ -278,17 +449,16 @@ local function write_c_file(filedef, hfilename, append)
emit_file_warning(filedef, append)
append('#include <stddef.h>\n')
append('#include "upb/decode.h"\n')
append('#include "upb/encode.h"\n')
append('#include "upb/msg.h"\n')
append('#include "upb/upb.h"\n')
append('#include "%s"\n\n', hfilename)
append('#include "%s"\n', hfilename)
for dep in filedef:dependencies() do
local outbase = strip_proto(dep:name())
append('#include "%s.upb.h"\n', outbase)
end
append('\n')
append('#include "upb/port_def.inc"\n')
append('\n')
for msg in filedef:defs(upb.DEF_MSG) do
@ -301,79 +471,31 @@ local function write_c_file(filedef, hfilename, append)
local submsg_count = 0
local submsg_set = {}
local submsg_indexes = {}
local hasbit_count = 0
local hasbit_indexes = {}
local hasbit_indexes, offsets, size = get_message_layout(msg)
local oneofs_layout_order = get_oneof_layout_order(msg)
local oneof_count = 0
local oneof_indexes = {}
-- Create a layout order for oneofs.
local oneofs_layout_order = {}
for oneof in msg:oneofs() do
table.insert(oneofs_layout_order, oneof)
end
table.sort(oneofs_layout_order, function(a, b)
return a:name() < b:name()
end)
for _, oneof in ipairs(oneofs_layout_order) do
oneof_indexes[oneof] = oneof_count
oneof_count = oneof_count + 1
end
-- Create a layout order for fields. We use this order for the struct and
-- for offsets, but our list of fields we keep in field number order.
local fields_layout_order = {}
for field in msg:fields() do
table.insert(fields_layout_order, field)
end
table.sort(fields_layout_order, function(a, b)
return field_layout_rank(a) < field_layout_rank(b)
end)
-- Another sorted array in field number order.
local fields_number_order = {}
for field in msg:fields() do
table.insert(fields_number_order, field)
end
table.sort(fields_number_order, function(a, b)
return a:number() < b:number()
end)
append('struct %s {\n', msgname)
-- Non-oneof fields.
for _, field in ipairs(fields_layout_order) do
for field in msg:fields() do
field_count = field_count + 1
table.insert(fields_number_order, field)
if field:type() == upb.TYPE_MESSAGE then
submsg_count = submsg_count + 1
submsg_set[field:subdef()] = true
end
if field:containing_oneof() then
-- Handled below.
else
if has_hasbit(field) then
hasbit_indexes[field] = hasbit_count
hasbit_count = hasbit_count + 1
end
append(' %s %s;\n', ctype(field), field:name())
end
end
-- Oneof fields.
for oneof in msg:oneofs() do
local fullname = to_cident(oneof:containing_type():full_name() .. "." .. oneof:name())
append(' union {\n')
for field in oneof:fields() do
append(' %s %s;\n', ctype(field), field:name())
end
append(' } %s;\n', oneof:name())
append(' %s_oneofcases %s_case;\n', fullname, oneof:name())
end
table.sort(fields_number_order, function(a, b)
return a:number() < b:number()
end)
append('};\n\n')
for _, oneof in ipairs(oneofs_layout_order) do
oneof_indexes[oneof] = oneof_count
oneof_count = oneof_count + 1
end
if oneof_count > 0 then
local oneofs_array_name = msgname .. "_oneofs"
@ -381,8 +503,8 @@ local function write_c_file(filedef, hfilename, append)
append('static const upb_msglayout_oneof %s[%s] = {\n',
oneofs_array_name, oneof_count)
for _, oneof in ipairs(oneofs_layout_order) do
append(' {offsetof(%s, %s), offsetof(%s, %s_case)},\n',
msgname, oneof:name(), msgname, oneof:name())
local offset = offsets[oneof]
append(' {%s, %s},\n', get_sizeinit(offset[1]), get_sizeinit(offset[2]))
end
append('};\n\n')
end
@ -426,10 +548,9 @@ local function write_c_file(filedef, hfilename, append)
if field:containing_oneof() then
oneof_index = oneof_indexes[field:containing_oneof()]
end
append(' {%s, offsetof(%s, %s), %s, %s, %s, %s, %s},\n',
append(' {%s, %s, %s, %s, %s, %s, %s},\n',
field:number(),
msgname,
(field:containing_oneof() and field:containing_oneof():name()) or field:name(),
get_sizeinit(offsets[field]),
hasbit_indexes[field] or "UPB_NO_HASBIT",
oneof_index,
submsg_index,
@ -444,67 +565,18 @@ local function write_c_file(filedef, hfilename, append)
append(' %s,\n', fields_array_ref)
append(' %s,\n', oneofs_array_ref)
append(' NULL, /* TODO. default_msg */\n')
append(' UPB_ALIGNED_SIZEOF(%s), %s, %s, %s, %s\n',
msgname, field_count,
0, -- TODO: oneof_count
append(' %s, %s, %s, %s, %s\n',
get_sizeinit(size), field_count,
oneof_count,
'false', -- TODO: extendable
msg:file():syntax() == upb.SYNTAX_PROTO2
)
append('};\n\n')
append('%s *%s_new(upb_env *env) {\n', msgname, msgname)
append(' %s *msg = upb_env_malloc(env, sizeof(*msg));\n',
msgname)
append(' memset(msg, 0, sizeof(*msg)); /* TODO: defaults */\n')
append(' return msg;\n')
append('}\n')
append('%s *%s_parsenew(upb_stringview buf, upb_env *env) {\n',
msgname, msgname)
append(' %s *msg = %s_new(env);\n', msgname, msgname)
append(' if (upb_decode(buf, msg, &%s_msginit, env)) {\n', msgname)
append(' return msg;\n')
append(' } else {\n')
append(' return NULL;\n')
append(' }\n')
append('}\n')
append('char *%s_serialize(%s *msg, upb_env *env, size_t *size) {\n',
msgname, msgname)
append(' return upb_encode(msg, &%s_msginit, env, size);\n', msgname)
append('}\n')
for field in msg:fields() do
append('%s %s_%s(const %s *msg) {\n',
ctype(field, true), msgname, field:name(), msgname);
if field:containing_oneof() then
local oneof = field:containing_oneof()
append(' return msg->%s_case == %s ? msg->%s.%s : %s;\n',
oneof:name(), field:number(), oneof:name(), field:name(),
field_default(field))
else
append(' return msg->%s;\n', field:name())
end
append('}\n')
append('void %s_set_%s(%s *msg, %s value) {\n',
msgname, field:name(), msgname, ctype(field));
if field:containing_oneof() then
local oneof = field:containing_oneof()
append(' msg->%s.%s = value;\n', oneof:name(), field:name())
append(' msg->%s_case = %s;\n', oneof:name(), field:number())
else
append(' msg->%s = value;\n', field:name())
end
append('}\n')
end
for oneof in msg:oneofs() do
local fullname = to_cident(oneof:containing_type():full_name() .. "." .. oneof:name())
append('%s_oneofcases %s_case(const %s *msg) {\n', fullname, fullname, msgname)
append(' return msg->%s_case;\n', oneof:name())
append('}\n')
end
append('};\n\n')
end
append('#include "upb/port_undef.inc"\n')
append('\n')
end
function export.write_gencode(filedef, hfilename, append_h, append_c)

@ -13,21 +13,13 @@
static int lupb_pb_decode(lua_State *L) {
size_t len;
upb_status status = UPB_STATUS_INIT;
const upb_msglayout *layout;
upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout);
const char *pb = lua_tolstring(L, 2, &len);
upb_stringview buf = upb_stringview_make(pb, len);
upb_env env;
upb_env_init(&env);
upb_env_reporterrorsto(&env, &status);
upb_decode(buf, msg, (const void*)layout, &env);
/* Free resources before we potentially bail on error. */
upb_env_uninit(&env);
lupb_checkstatus(L, &status);
upb_decode(buf, msg, layout);
/* TODO(haberman): check for error. */
return 0;
}
@ -35,21 +27,19 @@ static int lupb_pb_decode(lua_State *L) {
static int lupb_pb_encode(lua_State *L) {
const upb_msglayout *layout;
const upb_msg *msg = lupb_msg_checkmsg2(L, 1, &layout);
upb_env env;
upb_arena arena;
size_t size;
upb_status status = UPB_STATUS_INIT;
char *result;
upb_env_init(&env);
upb_env_reporterrorsto(&env, &status);
upb_arena_init(&arena);
result = upb_encode(msg, (const void*)layout, &env, &size);
result = upb_encode(msg, (const void*)layout, &arena, &size);
/* Free resources before we potentially bail on error. */
upb_env_uninit(&env);
lupb_checkstatus(L, &status);
lua_pushlstring(L, result, size);
upb_arena_uninit(&arena);
/* TODO(haberman): check for error. */
return 1;
}

@ -28,7 +28,6 @@ const uint8_t upb_desctype_to_fieldtype[] = {
/* Data pertaining to the parse. */
typedef struct {
upb_env *env;
/* Current decoding pointer. Points to the beginning of a field until we
* have finished decoding the whole field. */
const char *ptr;
@ -201,19 +200,29 @@ static void *upb_array_add(upb_array *arr, size_t elements) {
return ret;
}
static size_t get_field_offset(const upb_decframe *frame,
const upb_msglayout_field *field) {
if (field->oneof_index == UPB_NOT_IN_ONEOF) {
return field->offset;
} else {
return frame->m->oneofs[field->oneof_index].data_offset;
}
}
static upb_array *upb_getarr(upb_decframe *frame,
const upb_msglayout_field *field) {
UPB_ASSERT(field->label == UPB_LABEL_REPEATED);
UPB_ASSERT(field->oneof_index == UPB_NOT_IN_ONEOF);
return *(upb_array**)&frame->msg[field->offset];
}
static upb_array *upb_getorcreatearr(upb_decstate *d, upb_decframe *frame,
static upb_array *upb_getorcreatearr(upb_decframe *frame,
const upb_msglayout_field *field) {
upb_array *arr = upb_getarr(frame, field);
if (!arr) {
upb_fieldtype_t type = upb_desctype_to_fieldtype[field->descriptortype];
arr = upb_array_new(type, upb_env_arena(d->env));
arr = upb_array_new(type, upb_msg_arena(frame->msg));
if (!arr) {
return NULL;
}
@ -236,13 +245,13 @@ static void upb_setoneofcase(upb_decframe *frame,
field->number);
}
static char *upb_decode_prepareslot(upb_decstate *d, upb_decframe *frame,
static char *upb_decode_prepareslot(upb_decframe *frame,
const upb_msglayout_field *field) {
char *field_mem = frame->msg + field->offset;
char *field_mem = frame->msg + get_field_offset(frame, field);
upb_array *arr;
if (field->label == UPB_LABEL_REPEATED) {
arr = upb_getorcreatearr(d, frame, field);
arr = upb_getorcreatearr(frame, field);
field_mem = upb_array_reserve(arr, 1);
}
@ -266,7 +275,7 @@ static bool upb_decode_submsg(upb_decstate *d, upb_decframe *frame,
const char *limit,
const upb_msglayout_field *field,
int group_number) {
char *submsg_slot = upb_decode_prepareslot(d, frame, field);
char *submsg_slot = upb_decode_prepareslot(frame, field);
char *submsg = *(void **)submsg_slot;
const upb_msglayout *subm;
@ -275,7 +284,7 @@ static bool upb_decode_submsg(upb_decstate *d, upb_decframe *frame,
UPB_ASSERT(subm);
if (!submsg) {
submsg = upb_msg_new((upb_msglayout *)subm, upb_env_arena(d->env));
submsg = upb_msg_new(subm, upb_msg_arena(frame->msg));
CHK(submsg);
*(void**)submsg_slot = submsg;
}
@ -291,7 +300,7 @@ static bool upb_decode_varintfield(upb_decstate *d, upb_decframe *frame,
uint64_t val;
void *field_mem;
field_mem = upb_decode_prepareslot(d, frame, field);
field_mem = upb_decode_prepareslot(frame, field);
CHK(field_mem);
CHK(upb_decode_varint(&d->ptr, frame->limit, &val));
@ -336,7 +345,7 @@ static bool upb_decode_64bitfield(upb_decstate *d, upb_decframe *frame,
void *field_mem;
uint64_t val;
field_mem = upb_decode_prepareslot(d, frame, field);
field_mem = upb_decode_prepareslot(frame, field);
CHK(field_mem);
CHK(upb_decode_64bit(&d->ptr, frame->limit, &val));
@ -360,7 +369,7 @@ static bool upb_decode_32bitfield(upb_decstate *d, upb_decframe *frame,
void *field_mem;
uint32_t val;
field_mem = upb_decode_prepareslot(d, frame, field);
field_mem = upb_decode_prepareslot(frame, field);
CHK(field_mem);
CHK(upb_decode_32bit(&d->ptr, frame->limit, &val));
@ -394,7 +403,7 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame,
const char *field_start,
const upb_msglayout_field *field,
upb_stringview val) {
upb_array *arr = upb_getorcreatearr(d, frame, field);
upb_array *arr = upb_getorcreatearr(frame, field);
#define VARINT_CASE(ctype, decode) { \
const char *ptr = val.data; \
@ -455,7 +464,7 @@ static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame,
subm = frame->m->submsgs[field->submsg_index];
UPB_ASSERT(subm);
submsg = upb_msg_new((upb_msglayout *)subm, upb_env_arena(d->env));
submsg = upb_msg_new(subm, upb_msg_arena(frame->msg));
CHK(submsg);
field_mem = upb_array_add(arr, 1);
@ -485,7 +494,7 @@ static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame,
switch ((upb_descriptortype_t)field->descriptortype) {
case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_DESCRIPTOR_TYPE_BYTES: {
void *field_mem = upb_decode_prepareslot(d, frame, field);
void *field_mem = upb_decode_prepareslot(frame, field);
CHK(field_mem);
memcpy(field_mem, &val, sizeof(val));
break;
@ -587,11 +596,9 @@ static bool upb_decode_message(upb_decstate *d, const char *limit,
return true;
}
bool upb_decode(upb_stringview buf, void *msg, const upb_msglayout *l,
upb_env *env) {
bool upb_decode(upb_stringview buf, void *msg, const upb_msglayout *l) {
upb_decstate state;
state.ptr = buf.data;
state.env = env;
return upb_decode_message(&state, buf.data + buf.size, 0, msg, l);
}

@ -9,8 +9,7 @@
UPB_BEGIN_EXTERN_C
bool upb_decode(upb_stringview buf, void *msg, const upb_msglayout *l,
upb_env *env);
bool upb_decode(upb_stringview buf, upb_msg *msg, const upb_msglayout *l);
UPB_END_EXTERN_C

@ -47,7 +47,7 @@ static uint32_t upb_zzencode_32(int32_t n) { return (n << 1) ^ (n >> 31); }
static uint64_t upb_zzencode_64(int64_t n) { return (n << 1) ^ (n >> 63); }
typedef struct {
upb_env *env;
upb_alloc *alloc;
char *buf, *ptr, *limit;
} upb_encstate;
@ -62,7 +62,7 @@ static size_t upb_roundup_pow2(size_t bytes) {
static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) {
size_t old_size = e->limit - e->buf;
size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
char *new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size);
char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size);
CHK(new_buf);
/* We want previous data at the end, realloc() put it at the beginning. */
@ -340,6 +340,15 @@ bool upb_encode_hasscalarfield(const char *msg, const upb_msglayout *m,
}
}
static size_t get_field_offset2(const upb_msglayout *m,
const upb_msglayout_field *field) {
if (field->oneof_index == UPB_NOT_IN_ONEOF) {
return field->offset;
} else {
return m->oneofs[field->oneof_index].data_offset;
}
}
bool upb_encode_message(upb_encstate *e, const char *msg,
const upb_msglayout *m, size_t *size) {
int i;
@ -351,13 +360,14 @@ bool upb_encode_message(upb_encstate *e, const char *msg,
for (i = m->field_count - 1; i >= 0; i--) {
const upb_msglayout_field *f = &m->fields[i];
size_t offset = get_field_offset2(m, f);
if (f->label == UPB_LABEL_REPEATED) {
CHK(upb_encode_array(e, msg + f->offset, m, f));
CHK(upb_encode_array(e, msg + offset, m, f));
} else {
if (upb_encode_hasscalarfield(msg, m, f)) {
if (f->oneof_index == UPB_NOT_IN_ONEOF) {
CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, !m->is_proto2));
CHK(upb_encode_scalarfield(e, msg + offset, m, f, !m->is_proto2));
} else {
const upb_msglayout_oneof *o = &m->oneofs[f->oneof_index];
CHK(upb_encode_scalarfield(e, msg + o->data_offset,
@ -371,10 +381,10 @@ bool upb_encode_message(upb_encstate *e, const char *msg,
return true;
}
char *upb_encode(const void *msg, const upb_msglayout *m, upb_env *env,
char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena,
size_t *size) {
upb_encstate e;
e.env = env;
e.alloc = upb_arena_alloc(arena);
e.buf = NULL;
e.limit = NULL;
e.ptr = NULL;

@ -9,7 +9,7 @@
UPB_BEGIN_EXTERN_C
char *upb_encode(const void *msg, const upb_msglayout *l, upb_env *env,
char *upb_encode(const void *msg, const upb_msglayout *l, upb_arena *arena,
size_t *size);
UPB_END_EXTERN_C

@ -0,0 +1,18 @@
#if UINTPTR_MAX == 0xffffffff
#define UPB_SIZE(size32, size64) size32
#else
#define UPB_SIZE(size32, size64) size64
#endif
#define UPB_FIELD_AT(msg, fieldtype, offset) \
*(fieldtype*)((const char*)(msg) + offset)
#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \
UPB_FIELD_AT(msg, int, case_offset) == case_val \
? UPB_FIELD_AT(msg, fieldtype, offset) \
: default
#define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \
UPB_FIELD_AT(msg, int, case_offset) = case_val; \
UPB_FIELD_AT(msg, fieldtype, offset) = value;

@ -0,0 +1,5 @@
#undef UPB_SIZE
#undef UPB_FIELD_AT
#undef UPB_READ_ONEOF
#undef UPB_WRITE_ONEOF
Loading…
Cancel
Save