summaryrefslogtreecommitdiff
path: root/upbc
diff options
context:
space:
mode:
Diffstat (limited to 'upbc')
-rw-r--r--upbc/generator.cc193
-rw-r--r--upbc/message_layout.cc20
-rw-r--r--upbc/message_layout.h5
3 files changed, 187 insertions, 31 deletions
diff --git a/upbc/generator.cc b/upbc/generator.cc
index 0f7d14d..d8ec831 100644
--- a/upbc/generator.cc
+++ b/upbc/generator.cc
@@ -8,6 +8,7 @@
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/descriptor.h"
+#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "upbc/generator.h"
@@ -32,6 +33,14 @@ static std::string SourceFilename(std::string proto_filename) {
return StripExtension(proto_filename) + ".upb.c";
}
+static std::string DefHeaderFilename(std::string proto_filename) {
+ return StripExtension(proto_filename) + ".upbdefs.h";
+}
+
+static std::string DefSourceFilename(std::string proto_filename) {
+ return StripExtension(proto_filename) + ".upbdefs.c";
+}
+
class Output {
public:
Output(protobuf::io::ZeroCopyOutputStream* stream) : stream_(stream) {}
@@ -165,6 +174,10 @@ std::string ToCIdent(absl::string_view str) {
return absl::StrReplaceAll(str, {{".", "_"}, {"/", "_"}});
}
+std::string DefInitSymbol(const protobuf::FileDescriptor *file) {
+ return ToCIdent(file->name()) + "_upbdefinit";
+}
+
std::string ToPreproc(absl::string_view str) {
return absl::AsciiStrToUpper(ToCIdent(str));
}
@@ -180,10 +193,6 @@ std::string GetSizeInit(const MessageLayout::Size& size) {
std::string CTypeInternal(const protobuf::FieldDescriptor* field,
bool is_const) {
std::string maybe_const = is_const ? "const " : "";
- if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED) {
- return maybe_const + "upb_array*";
- }
-
switch (field->cpp_type()) {
case protobuf::FieldDescriptor::CPPTYPE_MESSAGE: {
std::string maybe_struct =
@@ -326,32 +335,74 @@ void GenerateMessageInHeader(const protobuf::Descriptor* message, Output& output
}
for (auto field : FieldNumberOrder(message)) {
- output("UPB_INLINE $0 $1_$2(const $1 *msg) {", CTypeConst(field), msgname,
- field->name());
- if (field->containing_oneof()) {
- output(" return UPB_READ_ONEOF(msg, $0, $1, $2, $3, $4); }\n",
- CTypeConst(field), GetSizeInit(layout.GetFieldOffset(field)),
- GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())),
- field->number(), FieldDefault(field));
+
+ if (layout.HasHasbit(field)) {
+ output(
+ "UPB_INLINE bool $0_has_$1(const $0 *msg) { "
+ "return _upb_has_field(msg, $2); }\n",
+ msgname, field->name(), layout.GetHasbitIndex(field));
+ } else if (field->containing_oneof()) {
+ output(
+ "UPB_INLINE bool $0_has_$1(const $0 *msg) { "
+ "return _upb_has_oneof_field(msg, $2, $3); }\n",
+ msgname, field->name(),
+ GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())),
+ field->number());
+ }
+
+ if (field->is_repeated()) {
+ output(
+ "UPB_INLINE $0 const* $1_$2(const $1 *msg, size_t *len) { "
+ "return ($0 const*)_upb_array_accessor(msg, $3, len); }\n",
+ CTypeConst(field), msgname, field->name(),
+ GetSizeInit(layout.GetFieldOffset(field)));
+ } else if (field->containing_oneof()) {
+ output(
+ "UPB_INLINE $0 $1_$2(const $1 *msg) { "
+ "return UPB_READ_ONEOF(msg, $0, $3, $4, $5, $6); }\n",
+ CTypeConst(field), msgname, field->name(),
+ GetSizeInit(layout.GetFieldOffset(field)),
+ GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())),
+ field->number(), FieldDefault(field));
} else {
- output(" return UPB_FIELD_AT(msg, $0, $1); }\n", CTypeConst(field),
- GetSizeInit(layout.GetFieldOffset(field)));
+ output(
+ "UPB_INLINE $0 $1_$2(const $1 *msg) { "
+ "return UPB_FIELD_AT(msg, $0, $3); }\n",
+ CTypeConst(field), msgname, field->name(),
+ GetSizeInit(layout.GetFieldOffset(field)));
}
}
output("\n");
for (auto field : FieldNumberOrder(message)) {
- output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) { ", msgname,
- field->name(), CType(field));
- if (field->containing_oneof()) {
- output("UPB_WRITE_ONEOF(msg, $0, $1, value, $2, $3); }\n", CType(field),
- GetSizeInit(layout.GetFieldOffset(field)),
- GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())),
- field->number());
+ if (field->is_repeated()) {
+ output(
+ "UPB_INLINE $0* $1_$2_mutable($1 *msg, size_t *len) { "
+ "return ($0*)_upb_array_mutable_accessor(msg, $3, len); }\n",
+ CType(field), msgname, field->name(),
+ GetSizeInit(layout.GetFieldOffset(field)));
+ output(
+ "UPB_INLINE $0* $1_$2_resize($1 *msg, size_t len, "
+ "upb_arena *arena) { "
+ "return ($0*)_upb_array_resize_accessor(msg, $3, len, $4, $5, arena); "
+ "}\n",
+ CType(field), msgname, field->name(),
+ GetSizeInit(layout.GetFieldOffset(field)),
+ GetSizeInit(MessageLayout::SizeOfUnwrapped(field).size),
+ "(upb_fieldtype_t)0" /* TODO */);
} else {
- output("UPB_FIELD_AT(msg, $0, $1) = value; }\n", CType(field),
- GetSizeInit(layout.GetFieldOffset(field)));
+ output("UPB_INLINE void $0_set_$1($0 *msg, $2 value) { ", msgname,
+ field->name(), CType(field));
+ if (field->containing_oneof()) {
+ output("UPB_WRITE_ONEOF(msg, $0, $1, value, $2, $3); }\n", CType(field),
+ GetSizeInit(layout.GetFieldOffset(field)),
+ GetSizeInit(layout.GetOneofCaseOffset(field->containing_oneof())),
+ field->number());
+ } else {
+ output("UPB_FIELD_AT(msg, $0, $1) = value; }\n", CType(field),
+ GetSizeInit(layout.GetFieldOffset(field)));
+ }
}
}
@@ -363,6 +414,7 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) {
output(
"#ifndef $0_UPB_H_\n"
"#define $0_UPB_H_\n\n"
+ "#include \"upb/generated_util.h\"\n\n"
"#include \"upb/msg.h\"\n\n"
"#include \"upb/decode.h\"\n"
"#include \"upb/encode.h\"\n"
@@ -482,7 +534,7 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) {
}
if (MessageLayout::HasHasbit(field)) {
- presence = absl::StrCat(layout.GetHasbitIndex(field) + 1);
+ presence = absl::StrCat(layout.GetHasbitIndex(field));
} else if (field->containing_oneof()) {
MessageLayout::Size case_offset =
layout.GetOneofCaseOffset(field->containing_oneof());
@@ -519,6 +571,95 @@ void WriteSource(const protobuf::FileDescriptor* file, Output& output) {
output("\n");
}
+void GenerateMessageDefAccessor(const protobuf::Descriptor* d, Output& output) {
+ output("UPB_INLINE const upb_msgdef *$0_getmsgdef(upb_symtab *s) {\n",
+ ToCIdent(d->full_name()));
+ output(" _upb_symtab_loaddefinit(s, &$0);\n", DefInitSymbol(d->file()));
+ output(" return upb_symtab_lookupmsg(s, \"$0\");\n", d->full_name());
+ output("}\n");
+ output("\n");
+
+ for (int i = 0; i < d->nested_type_count(); i++) {
+ GenerateMessageDefAccessor(d->nested_type(i), output);
+ }
+}
+
+void WriteDefHeader(const protobuf::FileDescriptor* file, Output& output) {
+ EmitFileWarning(file, output);
+
+ output("#include \"upb/def.h\"\n");
+ output("\n");
+
+ output("extern upb_def_init $0;\n", DefInitSymbol(file));
+ output("\n");
+
+ for (int i = 0; i < file->message_type_count(); i++) {
+ GenerateMessageDefAccessor(file->message_type(i), output);
+ }
+}
+
+// Escape C++ trigraphs by escaping question marks to \?
+std::string EscapeTrigraphs(absl::string_view to_escape) {
+ return absl::StrReplaceAll(to_escape, {{"?", "\\?"}});
+}
+
+void WriteDefSource(const protobuf::FileDescriptor* file, Output& output) {
+ EmitFileWarning(file, output);
+
+ output("#include \"upb/def.h\"\n");
+ output("\n");
+
+ for (int i = 0; i < file->dependency_count(); i++) {
+ output("extern upb_def_init $0;\n", DefInitSymbol(file->dependency(i)));
+ }
+
+ protobuf::FileDescriptorProto file_proto;
+ file->CopyTo(&file_proto);
+ std::string file_data;
+ file_proto.SerializeToString(&file_data);
+
+ output("static const char descriptor[$0] =\n", file_data.size());
+
+ {
+ if (file_data.size() > 65535) {
+ // Workaround for MSVC: "Error C1091: compiler limit: string exceeds
+ // 65535 bytes in length". Declare a static array of chars rather than
+ // use a string literal. Only write 25 bytes per line.
+ static const size_t kBytesPerLine = 25;
+ output("{ ");
+ for (size_t i = 0; i < file_data.size();) {
+ for (size_t j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
+ output("'$0', ", absl::CEscape(file_data.substr(i, 1)));
+ }
+ output("\n");
+ }
+ output("'\\0' }"); // null-terminate
+ } else {
+ // Only write 40 bytes per line.
+ static const size_t kBytesPerLine = 40;
+ for (size_t i = 0; i < file_data.size(); i += kBytesPerLine) {
+ output(
+ "\"$0\"\n",
+ EscapeTrigraphs(absl::CEscape(file_data.substr(i, kBytesPerLine))));
+ }
+ }
+ output(";\n");
+ }
+
+ output("static upb_def_init *deps[$0] = {\n", file->dependency_count() + 1);
+ for (int i = 0; i < file->dependency_count(); i++) {
+ output(" $0,\n", DefInitSymbol(file->dependency(i)));
+ }
+ output(" NULL\n");
+ output("};\n");
+
+ output("upb_def_init $0 = {\n", DefInitSymbol(file));
+ output(" deps,\n");
+ output(" \"$0\",\n", file->name());
+ output(" UPB_STRINGVIEW_INIT(descriptor, $0)\n", file_data.size());
+ output("};\n");
+}
+
bool Generator::Generate(const protobuf::FileDescriptor* file,
const std::string& parameter,
protoc::GeneratorContext* context,
@@ -529,6 +670,12 @@ bool Generator::Generate(const protobuf::FileDescriptor* file,
Output c_output(context->Open(SourceFilename(file->name())));
WriteSource(file, c_output);
+ Output h_def_output(context->Open(DefHeaderFilename(file->name())));
+ WriteDefHeader(file, h_def_output);
+
+ Output c_def_output(context->Open(DefSourceFilename(file->name())));
+ WriteDefSource(file, c_def_output);
+
return true;
}
diff --git a/upbc/message_layout.cc b/upbc/message_layout.cc
index b6614f0..f0a6872 100644
--- a/upbc/message_layout.cc
+++ b/upbc/message_layout.cc
@@ -30,16 +30,20 @@ bool MessageLayout::HasHasbit(const protobuf::FieldDescriptor* field) {
MessageLayout::SizeAndAlign MessageLayout::SizeOf(
const protobuf::FieldDescriptor* field) {
- if (field->label() == protobuf::FieldDescriptor::LABEL_REPEATED ||
- field->cpp_type() == protobuf::FieldDescriptor::CPPTYPE_MESSAGE) {
- return {{4, 8}, {4, 8}};
+ if (field->is_repeated()) {
+ return {{4, 8}, {4, 8}}; // Pointer to array object.
+ } else {
+ return SizeOfUnwrapped(field);
}
+}
+MessageLayout::SizeAndAlign MessageLayout::SizeOfUnwrapped(
+ const protobuf::FieldDescriptor* field) {
switch (field->cpp_type()) {
+ case protobuf::FieldDescriptor::CPPTYPE_MESSAGE:
+ return {{4, 8}, {4, 8}}; // Pointer to message.
case protobuf::FieldDescriptor::CPPTYPE_STRING:
- // upb_stringview
- // return {{8, 16}, {4, 8}};
- return {{8, 16}, {8, 16}};
+ return {{8, 16}, {4, 8}}; // upb_stringview
case protobuf::FieldDescriptor::CPPTYPE_BOOL:
return {{1, 1}, {1, 1}};
case protobuf::FieldDescriptor::CPPTYPE_FLOAT:
@@ -126,7 +130,9 @@ void MessageLayout::PlaceNonOneofFields(
int hasbit_count = 0;
for (auto field : field_order) {
if (HasHasbit(field)) {
- hasbit_indexes_[field] = hasbit_count++;
+ // We don't use hasbit 0, so that 0 can indicate "no presence" in the
+ // table. This wastes one hasbit, but we don't worry about it for now.
+ hasbit_indexes_[field] = ++hasbit_count;
}
}
diff --git a/upbc/message_layout.h b/upbc/message_layout.h
index bdcc336..a4cb289 100644
--- a/upbc/message_layout.h
+++ b/upbc/message_layout.h
@@ -60,6 +60,8 @@ class MessageLayout {
Size message_size() const { return size_; }
static bool HasHasbit(const google::protobuf::FieldDescriptor* field);
+ static SizeAndAlign SizeOfUnwrapped(
+ const google::protobuf::FieldDescriptor* field);
private:
void ComputeLayout(const google::protobuf::Descriptor* descriptor);
@@ -87,7 +89,8 @@ class MessageLayout {
}
static SizeAndAlign SizeOf(const google::protobuf::FieldDescriptor* field);
- static int64_t FieldLayoutRank(const google::protobuf::FieldDescriptor* field);
+ static int64_t FieldLayoutRank(
+ const google::protobuf::FieldDescriptor* field);
std::unordered_map<const google::protobuf::FieldDescriptor*, Size>
field_offsets_;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback