|
|
|
// Copyright (c) 2009-2021, Google LLC
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are met:
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
|
|
// documentation and/or other materials provided with the distribution.
|
|
|
|
// * Neither the name of Google LLC nor the
|
|
|
|
// names of its contributors may be used to endorse or promote products
|
|
|
|
// derived from this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
|
|
|
|
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
#ifndef UPBC_FILE_LAYOUT_H
|
|
|
|
#define UPBC_FILE_LAYOUT_H
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "google/protobuf/descriptor.pb.h"
|
|
|
|
#include "absl/container/flat_hash_map.h"
|
|
|
|
#include "absl/strings/substitute.h"
|
|
|
|
#include "upb/mini_table/decode.h"
|
|
|
|
#include "upb/mini_table/encode_internal.hpp"
|
|
|
|
#include "upb/upb.hpp"
|
|
|
|
|
|
|
|
namespace upbc {
|
|
|
|
|
|
|
|
namespace protoc = ::google::protobuf::compiler;
|
|
|
|
namespace protobuf = ::google::protobuf;
|
|
|
|
|
|
|
|
std::vector<const protobuf::EnumDescriptor*> SortedEnums(
|
|
|
|
const protobuf::FileDescriptor* file);
|
|
|
|
|
|
|
|
// Ordering must match upb/def.c!
|
|
|
|
//
|
|
|
|
// The ordering is significant because each upb_MessageDef* will point at the
|
|
|
|
// corresponding upb_MiniTable and we just iterate through the list without
|
|
|
|
// any search or lookup.
|
|
|
|
std::vector<const protobuf::Descriptor*> SortedMessages(
|
|
|
|
const protobuf::FileDescriptor* file);
|
|
|
|
|
|
|
|
// Ordering must match upb/def.c!
|
|
|
|
//
|
|
|
|
// The ordering is significant because each upb_FieldDef* will point at the
|
|
|
|
// corresponding upb_MiniTable_Extension and we just iterate through the list
|
|
|
|
// without any search or lookup.
|
|
|
|
std::vector<const protobuf::FieldDescriptor*> SortedExtensions(
|
|
|
|
const protobuf::FileDescriptor* file);
|
|
|
|
|
|
|
|
std::vector<const protobuf::FieldDescriptor*> FieldNumberOrder(
|
|
|
|
const protobuf::Descriptor* message);
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// FilePlatformLayout
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// FilePlatformLayout builds and vends upb MiniTables for a given platform (32
|
|
|
|
// or 64 bit).
|
|
|
|
class FilePlatformLayout {
|
|
|
|
public:
|
|
|
|
FilePlatformLayout(const protobuf::FileDescriptor* fd,
|
|
|
|
upb_MiniTablePlatform platform)
|
|
|
|
: platform_(platform) {
|
|
|
|
BuildMiniTables(fd);
|
|
|
|
BuildExtensions(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieves a upb MiniTable or Extension given a protobuf descriptor. The
|
|
|
|
// descriptor must be from this layout's file.
|
|
|
|
upb_MiniTable* GetMiniTable(const protobuf::Descriptor* m) const;
|
|
|
|
upb_MiniTable_Enum* GetEnumTable(const protobuf::EnumDescriptor* d) const;
|
|
|
|
const upb_MiniTable_Extension* GetExtension(
|
|
|
|
const protobuf::FieldDescriptor* fd) const;
|
|
|
|
|
|
|
|
// Get the initializer for the given sub-message/sub-enum link.
|
|
|
|
static std::string GetSub(upb_MiniTable_Sub sub);
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Functions to build mini-tables for this file's messages and extensions.
|
|
|
|
void BuildMiniTables(const protobuf::FileDescriptor* fd);
|
|
|
|
void BuildExtensions(const protobuf::FileDescriptor* fd);
|
|
|
|
upb_MiniTable* MakeMiniTable(const protobuf::Descriptor* m);
|
|
|
|
upb_MiniTable* MakeMapMiniTable(const protobuf::Descriptor* m);
|
|
|
|
upb_MiniTable* MakeMessageSetMiniTable(const protobuf::Descriptor* m);
|
|
|
|
upb_MiniTable* MakeRegularMiniTable(const protobuf::Descriptor* m);
|
|
|
|
upb_MiniTable_Enum* MakeMiniTableEnum(const protobuf::EnumDescriptor* d);
|
|
|
|
uint64_t GetMessageModifiers(const protobuf::Descriptor* m);
|
|
|
|
uint64_t GetFieldModifiers(const protobuf::FieldDescriptor* f);
|
|
|
|
void ResolveIntraFileReferences();
|
|
|
|
|
|
|
|
// When we are generating code, tables are linked to sub-tables via name (ie.
|
|
|
|
// a string) rather than by pointer. We need to emit an initializer like
|
|
|
|
// `&foo_sub_table`. To do this, we store `const char*` strings in all the
|
|
|
|
// links that would normally be pointers:
|
|
|
|
// field -> sub-message
|
|
|
|
// field -> enum table (proto2 only)
|
|
|
|
// extension -> extendee
|
|
|
|
//
|
|
|
|
// This requires a bit of reinterpret_cast<>(), but it's confined to a few
|
|
|
|
// functions. We tag the pointer so we know which member of the union to
|
|
|
|
// initialize.
|
|
|
|
enum SubTag {
|
|
|
|
kNull = 0,
|
|
|
|
kMessage = 1,
|
|
|
|
kEnum = 2,
|
|
|
|
kMask = 3,
|
|
|
|
};
|
|
|
|
|
|
|
|
static upb_MiniTable_Sub PackSub(const char* data, SubTag tag);
|
|
|
|
static bool IsNull(upb_MiniTable_Sub sub);
|
|
|
|
void SetSubTableStrings();
|
|
|
|
upb_MiniTable_Sub PackSubForField(const protobuf::FieldDescriptor* f,
|
|
|
|
const upb_MiniTable_Field* mt_f);
|
|
|
|
const char* AllocStr(absl::string_view str);
|
|
|
|
|
|
|
|
private:
|
|
|
|
using TableMap =
|
|
|
|
absl::flat_hash_map<const protobuf::Descriptor*, upb_MiniTable*>;
|
|
|
|
using EnumMap =
|
|
|
|
absl::flat_hash_map<const protobuf::EnumDescriptor*, upb_MiniTable_Enum*>;
|
|
|
|
using ExtensionMap = absl::flat_hash_map<const protobuf::FieldDescriptor*,
|
|
|
|
upb_MiniTable_Extension>;
|
|
|
|
upb::Arena arena_;
|
|
|
|
TableMap table_map_;
|
|
|
|
EnumMap enum_map_;
|
|
|
|
ExtensionMap extension_map_;
|
|
|
|
upb_MiniTablePlatform platform_;
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// FileLayout
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// FileLayout is a pair of platform layouts: one for 32-bit and one for 64-bit.
|
|
|
|
class FileLayout {
|
|
|
|
public:
|
|
|
|
FileLayout(const protobuf::FileDescriptor* fd)
|
|
|
|
: descriptor_(fd),
|
|
|
|
layout32_(fd, kUpb_MiniTablePlatform_32Bit),
|
|
|
|
layout64_(fd, kUpb_MiniTablePlatform_64Bit) {}
|
|
|
|
|
|
|
|
const protobuf::FileDescriptor* descriptor() const { return descriptor_; }
|
|
|
|
|
|
|
|
const upb_MiniTable* GetMiniTable32(const protobuf::Descriptor* m) const {
|
|
|
|
return layout32_.GetMiniTable(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
const upb_MiniTable* GetMiniTable64(const protobuf::Descriptor* m) const {
|
|
|
|
return layout64_.GetMiniTable(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
const upb_MiniTable_Enum* GetEnumTable(
|
|
|
|
const protobuf::EnumDescriptor* d) const {
|
|
|
|
return layout64_.GetEnumTable(d);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GetFieldOffset(const protobuf::FieldDescriptor* f) const {
|
|
|
|
const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber(
|
|
|
|
GetMiniTable32(f->containing_type()), f->number());
|
|
|
|
const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber(
|
|
|
|
GetMiniTable64(f->containing_type()), f->number());
|
|
|
|
return absl::Substitute("UPB_SIZE($0, $1)", f_32->offset, f_64->offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GetOneofCaseOffset(const protobuf::OneofDescriptor* o) const {
|
|
|
|
const protobuf::FieldDescriptor* f = o->field(0);
|
|
|
|
const upb_MiniTable_Field* f_32 = upb_MiniTable_FindFieldByNumber(
|
|
|
|
GetMiniTable32(f->containing_type()), f->number());
|
|
|
|
const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber(
|
|
|
|
GetMiniTable64(f->containing_type()), f->number());
|
|
|
|
return absl::Substitute("UPB_SIZE($0, $1)", ~f_32->presence,
|
|
|
|
~f_64->presence);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GetMessageSize(const protobuf::Descriptor* d) const {
|
|
|
|
return absl::Substitute("UPB_SIZE($0, $1)", GetMiniTable32(d)->size,
|
|
|
|
GetMiniTable64(d)->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetHasbitIndex(const protobuf::FieldDescriptor* f) const {
|
|
|
|
const upb_MiniTable_Field* f_64 = upb_MiniTable_FindFieldByNumber(
|
|
|
|
GetMiniTable64(f->containing_type()), f->number());
|
|
|
|
return f_64->presence;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HasHasbit(const protobuf::FieldDescriptor* f) const {
|
|
|
|
return GetHasbitIndex(f) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const upb_MiniTable_Extension* GetExtension(
|
|
|
|
const protobuf::FieldDescriptor* f) const {
|
|
|
|
return layout64_.GetExtension(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const protobuf::FileDescriptor* descriptor_;
|
|
|
|
FilePlatformLayout layout32_;
|
|
|
|
FilePlatformLayout layout64_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace upbc
|
|
|
|
|
|
|
|
#endif // UPBC_FILE_LAYOUT_H
|