2055 lines
67 KiB
C++
2055 lines
67 KiB
C++
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "CompoundType.h"
|
|
|
|
#include "ArrayType.h"
|
|
#include "Reference.h"
|
|
#include "ScalarType.h"
|
|
#include "VectorType.h"
|
|
|
|
#include <android-base/logging.h>
|
|
#include <hidl-util/Formatter.h>
|
|
#include <iostream>
|
|
#include <set>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
namespace android {
|
|
|
|
CompoundType::CompoundType(Style style, const std::string& localName, const FQName& fullName,
|
|
const Location& location, Scope* parent)
|
|
: Scope(localName, fullName, location, parent), mStyle(style) {}
|
|
|
|
CompoundType::Style CompoundType::style() const {
|
|
return mStyle;
|
|
}
|
|
|
|
void CompoundType::addField(NamedReference<Type>* field) {
|
|
mFields.push_back(field);
|
|
}
|
|
|
|
std::vector<const NamedReference<Type>*> CompoundType::getFields() const {
|
|
return std::vector<const NamedReference<Type>*>(mFields.begin(), mFields.end());
|
|
}
|
|
|
|
std::vector<const Reference<Type>*> CompoundType::getReferences() const {
|
|
std::vector<const Reference<Type>*> ret;
|
|
ret.insert(ret.begin(), mFields.begin(), mFields.end());
|
|
return ret;
|
|
}
|
|
|
|
status_t CompoundType::validate() const {
|
|
for (const auto* field : mFields) {
|
|
const Type& type = field->type();
|
|
|
|
if ((type.isVector() && static_cast<const VectorType*>(&type)->isVectorOfBinders())) {
|
|
std::cerr << "ERROR: Struct/union cannot contain vectors of interfaces at "
|
|
<< field->location() << "\n";
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (mStyle == STYLE_UNION) {
|
|
if (type.isInterface()) {
|
|
std::cerr << "ERROR: Union cannot contain interfaces at " << field->location()
|
|
<< "\n";
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
if (type.needsEmbeddedReadWrite()) {
|
|
std::cerr << "ERROR: Union must not contain any types that need fixup at "
|
|
<< field->location() << "\n";
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION && mFields.size() < 2) {
|
|
std::cerr << "ERROR: Safe union must contain at least two types to be useful at "
|
|
<< location() << "\n";
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
status_t err = validateUniqueNames();
|
|
if (err != OK) return err;
|
|
|
|
err = validateSubTypeNames();
|
|
if (err != OK) return err;
|
|
|
|
return Scope::validate();
|
|
}
|
|
|
|
status_t CompoundType::validateUniqueNames() const {
|
|
std::unordered_set<std::string> names;
|
|
|
|
for (const auto* field : mFields) {
|
|
if (names.find(field->name()) != names.end()) {
|
|
std::cerr << "ERROR: Redefinition of field '" << field->name() << "' at "
|
|
<< field->location() << "\n";
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
names.insert(field->name());
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
void CompoundType::emitInvalidSubTypeNamesError(const std::string& subTypeName,
|
|
const Location& location) const {
|
|
std::cerr << "ERROR: Type name '" << subTypeName << "' defined at " << location
|
|
<< " conflicts with a member function of "
|
|
<< "safe_union " << definedName() << ". Consider renaming or "
|
|
<< "moving its definition outside the safe_union scope.\n";
|
|
}
|
|
|
|
status_t CompoundType::validateSubTypeNames() const {
|
|
if (mStyle != STYLE_SAFE_UNION) { return OK; }
|
|
const auto& subTypes = Scope::getSubTypes();
|
|
|
|
for (const auto& subType : subTypes) {
|
|
if (subType->definedName() == "getDiscriminator") {
|
|
emitInvalidSubTypeNamesError(subType->definedName(), subType->location());
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
bool CompoundType::isCompoundType() const {
|
|
return true;
|
|
}
|
|
|
|
bool CompoundType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
|
|
if (mStyle == STYLE_UNION) {
|
|
return false;
|
|
}
|
|
for (const auto* field : mFields) {
|
|
if (!field->get()->canCheckEquality(visited)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::string CompoundType::typeName() const {
|
|
switch (mStyle) {
|
|
case STYLE_STRUCT: {
|
|
return "struct " + definedName();
|
|
}
|
|
case STYLE_UNION: {
|
|
return "union " + definedName();
|
|
}
|
|
case STYLE_SAFE_UNION: {
|
|
return "safe_union " + definedName();
|
|
}
|
|
}
|
|
CHECK(!"Should not be here");
|
|
}
|
|
|
|
std::string CompoundType::getCppType(
|
|
StorageMode mode,
|
|
bool /* specifyNamespaces */) const {
|
|
const std::string base = fullName();
|
|
|
|
switch (mode) {
|
|
case StorageMode_Stack:
|
|
return base;
|
|
|
|
case StorageMode_Argument:
|
|
return "const " + base + "&";
|
|
|
|
case StorageMode_Result:
|
|
return base + (containsInterface()?"":"*");
|
|
}
|
|
CHECK(!"Should not be here");
|
|
}
|
|
|
|
std::string CompoundType::getJavaType(bool /* forInitializer */) const {
|
|
return fullJavaName();
|
|
}
|
|
|
|
std::string CompoundType::getVtsType() const {
|
|
switch (mStyle) {
|
|
case STYLE_STRUCT:
|
|
{
|
|
return "TYPE_STRUCT";
|
|
}
|
|
case STYLE_UNION:
|
|
{
|
|
return "TYPE_UNION";
|
|
}
|
|
case STYLE_SAFE_UNION:
|
|
{
|
|
return "TYPE_SAFE_UNION";
|
|
}
|
|
}
|
|
CHECK(!"Should not be here");
|
|
}
|
|
|
|
bool CompoundType::containsInterface() const {
|
|
for (const auto& field : mFields) {
|
|
if (field->type().isCompoundType()) {
|
|
const Type& t = field->type();
|
|
const CompoundType* ct = static_cast<const CompoundType*>(&t);
|
|
if (ct->containsInterface()) {
|
|
return true;
|
|
}
|
|
}
|
|
if (field->type().isInterface()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CompoundType::emitSafeUnionUnknownDiscriminatorError(Formatter& out, const std::string& value,
|
|
bool fatal) const {
|
|
if (fatal) {
|
|
out << "::android::hardware::details::logAlwaysFatal(";
|
|
} else {
|
|
out << "ALOGE(\"%s\", ";
|
|
}
|
|
out << "(\n";
|
|
out.indent(2, [&] {
|
|
out << "\"Unknown union discriminator (value: \" +\n"
|
|
<< "std::to_string(" << getUnionDiscriminatorType()->getCppTypeCast(value)
|
|
<< ") + \").\").c_str());\n";
|
|
});
|
|
}
|
|
|
|
void CompoundType::emitSafeUnionReaderWriterForInterfaces(
|
|
Formatter &out,
|
|
const std::string &name,
|
|
const std::string &parcelObj,
|
|
bool parcelObjIsPointer,
|
|
bool isReader,
|
|
ErrorMode mode) const {
|
|
|
|
CHECK(mStyle == STYLE_SAFE_UNION);
|
|
|
|
out.block([&] {
|
|
const auto discriminatorType = getUnionDiscriminatorType();
|
|
if (isReader) {
|
|
out << discriminatorType->getCppStackType()
|
|
<< " _hidl_d_primitive;\n";
|
|
} else {
|
|
out << "const "
|
|
<< discriminatorType->getCppStackType()
|
|
<< " _hidl_d_primitive = "
|
|
<< discriminatorType->getCppTypeCast(name + ".getDiscriminator()")
|
|
<< ";\n";
|
|
}
|
|
|
|
getUnionDiscriminatorType()->emitReaderWriter(out, "_hidl_d_primitive", parcelObj,
|
|
parcelObjIsPointer, isReader, mode);
|
|
out << "switch (("
|
|
<< fullName()
|
|
<< "::hidl_discriminator) _hidl_d_primitive) ";
|
|
|
|
out.block([&] {
|
|
for (const auto& field : mFields) {
|
|
out << "case " << fullName() << "::hidl_discriminator::" << field->name()
|
|
<< ": ";
|
|
|
|
const std::string tempFieldName = "_hidl_temp_" + field->name();
|
|
out.block([&] {
|
|
if (isReader) {
|
|
out << field->type().getCppResultType() << " " << tempFieldName
|
|
<< ";\n";
|
|
|
|
field->type().emitReaderWriter(out, tempFieldName, parcelObj,
|
|
parcelObjIsPointer, isReader, mode);
|
|
|
|
const std::string derefOperator =
|
|
field->type().resultNeedsDeref() ? "*" : "";
|
|
out << name << "." << field->name() << "(std::move(" << derefOperator
|
|
<< tempFieldName << "));\n";
|
|
} else {
|
|
const std::string fieldValue = name + "." + field->name() + "()";
|
|
out << field->type().getCppArgumentType() << " " << tempFieldName
|
|
<< " = " << fieldValue << ";\n";
|
|
|
|
field->type().emitReaderWriter(out, tempFieldName, parcelObj,
|
|
parcelObjIsPointer, isReader, mode);
|
|
}
|
|
out << "break;\n";
|
|
}).endl();
|
|
}
|
|
|
|
out << "default: ";
|
|
out.block([&] {
|
|
emitSafeUnionUnknownDiscriminatorError(out, "_hidl_d_primitive",
|
|
!isReader /*fatal*/);
|
|
if (isReader) {
|
|
out << "_hidl_err = ::android::BAD_VALUE;\n";
|
|
handleError(out, mode);
|
|
}
|
|
}).endl();
|
|
}).endl();
|
|
}).endl();
|
|
}
|
|
|
|
void CompoundType::emitReaderWriter(
|
|
Formatter &out,
|
|
const std::string &name,
|
|
const std::string &parcelObj,
|
|
bool parcelObjIsPointer,
|
|
bool isReader,
|
|
ErrorMode mode) const {
|
|
|
|
const std::string parcelObjDeref =
|
|
parcelObj + (parcelObjIsPointer ? "->" : ".");
|
|
|
|
if(containsInterface()){
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
emitSafeUnionReaderWriterForInterfaces(out, name, parcelObj,
|
|
parcelObjIsPointer,
|
|
isReader, mode);
|
|
return;
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
const std::string tempFieldName = "_hidl_temp_" + field->name();
|
|
const std::string fieldValue = name + "." + field->name();
|
|
|
|
out.block([&] {
|
|
if (isReader) {
|
|
out << field->type().getCppResultType()
|
|
<< " "
|
|
<< tempFieldName
|
|
<< ";\n";
|
|
} else {
|
|
out << field->type().getCppArgumentType()
|
|
<< " "
|
|
<< tempFieldName
|
|
<< " = "
|
|
<< fieldValue
|
|
<< ";\n";
|
|
}
|
|
|
|
field->type().emitReaderWriter(out, tempFieldName, parcelObj,
|
|
parcelObjIsPointer, isReader, mode);
|
|
if (isReader) {
|
|
const std::string derefOperator = field->type().resultNeedsDeref()
|
|
? "*" : "";
|
|
out << fieldValue
|
|
<< " = std::move("
|
|
<< derefOperator
|
|
<< tempFieldName
|
|
<< ");\n";
|
|
}
|
|
}).endl();
|
|
}
|
|
} else {
|
|
const std::string parentName = "_hidl_" + name + "_parent";
|
|
|
|
out << "size_t " << parentName << ";\n\n";
|
|
|
|
if (isReader) {
|
|
out << "_hidl_err = " << parcelObjDeref << "readBuffer("
|
|
<< "sizeof(*" << name << "), &" << parentName << ", "
|
|
<< " const_cast<const void**>(reinterpret_cast<void **>("
|
|
<< "&" << name << ")));\n";
|
|
handleError(out, mode);
|
|
} else {
|
|
out << "_hidl_err = "
|
|
<< parcelObjDeref
|
|
<< "writeBuffer(&"
|
|
<< name
|
|
<< ", sizeof("
|
|
<< name
|
|
<< "), &"
|
|
<< parentName
|
|
<< ");\n";
|
|
handleError(out, mode);
|
|
}
|
|
|
|
bool needEmbeddedReadWrite = needsEmbeddedReadWrite();
|
|
CHECK(mStyle != STYLE_UNION || !needEmbeddedReadWrite);
|
|
|
|
if (needEmbeddedReadWrite) {
|
|
emitReaderWriterEmbedded(out, 0 /* depth */, name, name, /* sanitizedName */
|
|
isReader /* nameIsPointer */, parcelObj, parcelObjIsPointer,
|
|
isReader, mode, parentName, "0 /* parentOffset */");
|
|
}
|
|
}
|
|
}
|
|
|
|
void CompoundType::emitReaderWriterEmbedded(
|
|
Formatter &out,
|
|
size_t /* depth */,
|
|
const std::string &name,
|
|
const std::string & /*sanitizedName */,
|
|
bool nameIsPointer,
|
|
const std::string &parcelObj,
|
|
bool parcelObjIsPointer,
|
|
bool isReader,
|
|
ErrorMode mode,
|
|
const std::string &parentName,
|
|
const std::string &offsetText) const {
|
|
emitReaderWriterEmbeddedForTypeName(
|
|
out,
|
|
name,
|
|
nameIsPointer,
|
|
parcelObj,
|
|
parcelObjIsPointer,
|
|
isReader,
|
|
mode,
|
|
parentName,
|
|
offsetText,
|
|
fullName(),
|
|
"" /* childName */,
|
|
"" /* namespace */);
|
|
}
|
|
|
|
void CompoundType::emitJavaReaderWriter(
|
|
Formatter &out,
|
|
const std::string &parcelObj,
|
|
const std::string &argName,
|
|
bool isReader) const {
|
|
if (isReader) {
|
|
out << "new " << fullJavaName() << "();\n";
|
|
}
|
|
|
|
out << "(" << getJavaTypeCast(argName) << ")."
|
|
<< (isReader ? "readFromParcel" : "writeToParcel") << "(" << parcelObj << ");\n";
|
|
}
|
|
|
|
void CompoundType::emitJavaFieldInitializer(
|
|
Formatter &out, const std::string &fieldName) const {
|
|
const std::string fieldDeclaration = fullJavaName() + " " + fieldName;
|
|
emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
|
|
}
|
|
|
|
void CompoundType::emitJavaFieldDefaultInitialValue(
|
|
Formatter &out, const std::string &declaredFieldName) const {
|
|
out << declaredFieldName
|
|
<< " = new "
|
|
<< fullJavaName()
|
|
<< "();\n";
|
|
}
|
|
|
|
void CompoundType::emitJavaFieldReaderWriter(
|
|
Formatter &out,
|
|
size_t /* depth */,
|
|
const std::string &parcelName,
|
|
const std::string &blobName,
|
|
const std::string &fieldName,
|
|
const std::string &offset,
|
|
bool isReader) const {
|
|
if (isReader) {
|
|
out << "("
|
|
<< getJavaTypeCast(fieldName)
|
|
<< ").readEmbeddedFromParcel("
|
|
<< parcelName
|
|
<< ", "
|
|
<< blobName
|
|
<< ", "
|
|
<< offset
|
|
<< ");\n";
|
|
|
|
return;
|
|
}
|
|
|
|
out << fieldName
|
|
<< ".writeEmbeddedToBlob("
|
|
<< blobName
|
|
<< ", "
|
|
<< offset
|
|
<< ");\n";
|
|
}
|
|
|
|
void CompoundType::emitLayoutAsserts(Formatter& out, const Layout& layout,
|
|
const std::string& layoutName) const {
|
|
out << "static_assert(sizeof("
|
|
<< fullName()
|
|
<< layoutName
|
|
<< ") == "
|
|
<< layout.size
|
|
<< ", \"wrong size\");\n";
|
|
|
|
out << "static_assert(__alignof("
|
|
<< fullName()
|
|
<< layoutName
|
|
<< ") == "
|
|
<< layout.align
|
|
<< ", \"wrong alignment\");\n";
|
|
}
|
|
|
|
void CompoundType::emitSafeUnionTypeDeclarations(Formatter& out) const {
|
|
out << "struct " << definedName() << " final {\n";
|
|
|
|
out.indent();
|
|
|
|
Scope::emitTypeDeclarations(out);
|
|
|
|
bool hasPointer = containsPointer();
|
|
CompoundLayout layout = hasPointer
|
|
? CompoundLayout()
|
|
: getCompoundAlignmentAndSize();
|
|
|
|
out << "enum class hidl_discriminator : "
|
|
<< getUnionDiscriminatorType()->getCppType(StorageMode_Stack, false)
|
|
<< " ";
|
|
|
|
out.block([&] {
|
|
for (size_t idx = 0; idx < mFields.size(); idx++) {
|
|
const auto& field = mFields.at(idx);
|
|
|
|
field->emitDocComment(out);
|
|
out << field->name()
|
|
<< " = "
|
|
<< idx
|
|
<< ", // "
|
|
<< field->type().getCppStackType(true /*specifyNamespaces*/)
|
|
<< "\n";
|
|
}
|
|
});
|
|
out << ";\n\n";
|
|
|
|
out << definedName() << "();\n" // Constructor
|
|
<< "~" << definedName() << "();\n" // Destructor
|
|
<< definedName() << "(" << definedName() << "&&);\n" // Move constructor
|
|
<< definedName() << "(const " << definedName() << "&);\n" // Copy constructor
|
|
<< definedName() << "& operator=(" << definedName() << "&&);\n" // Move assignment
|
|
<< definedName() << "& operator=(const " << definedName() << "&);\n\n"; // Copy assignment
|
|
|
|
for (const auto& field : mFields) {
|
|
// Setter (copy)
|
|
out << "void "
|
|
<< field->name()
|
|
<< "("
|
|
<< field->type().getCppArgumentType()
|
|
<< ");\n";
|
|
|
|
if (field->type().resolveToScalarType() == nullptr) {
|
|
// Setter (move)
|
|
out << "void "
|
|
<< field->name()
|
|
<< "("
|
|
<< field->type().getCppStackType()
|
|
<< "&&);\n";
|
|
}
|
|
|
|
// Getter (mutable)
|
|
out << field->type().getCppStackType()
|
|
<< "& "
|
|
<< field->name()
|
|
<< "();\n";
|
|
|
|
// Getter (immutable)
|
|
out << field->type().getCppArgumentType()
|
|
<< " "
|
|
<< field->name()
|
|
<< "() const;\n\n";
|
|
}
|
|
|
|
out << "// Utility methods\n";
|
|
out << "hidl_discriminator getDiscriminator() const;\n\n";
|
|
|
|
out << "constexpr size_t hidl_getUnionOffset() const ";
|
|
out.block([&] {
|
|
out << "return offsetof(" << fullName() << ", hidl_u);\n";
|
|
}).endl().endl();
|
|
|
|
out.unindent();
|
|
out << "private:\n";
|
|
out.indent();
|
|
|
|
out << "void hidl_destructUnion();\n\n";
|
|
|
|
out << "hidl_discriminator hidl_d";
|
|
if (!hasPointer) {
|
|
out << " __attribute__ ((aligned("
|
|
<< layout.discriminator.align << "))) ";
|
|
}
|
|
out << ";\n";
|
|
out << "union hidl_union final {\n";
|
|
out.indent();
|
|
|
|
for (const auto& field : mFields) {
|
|
size_t fieldAlign, fieldSize;
|
|
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
|
|
|
|
out << field->type().getCppStackType()
|
|
<< " "
|
|
<< field->name();
|
|
|
|
if (!hasPointer) {
|
|
out << " __attribute__ ((aligned("
|
|
<< fieldAlign
|
|
<< ")))";
|
|
}
|
|
out << ";\n";
|
|
}
|
|
|
|
out << "\n"
|
|
<< "hidl_union();\n"
|
|
<< "~hidl_union();\n";
|
|
|
|
out.unindent();
|
|
out << "} hidl_u;\n";
|
|
|
|
if (!hasPointer) {
|
|
out << "\n";
|
|
|
|
emitLayoutAsserts(out, layout.innerStruct, "::hidl_union");
|
|
emitLayoutAsserts(out, layout.discriminator, "::hidl_discriminator");
|
|
}
|
|
|
|
out.unindent();
|
|
out << "};\n\n";
|
|
|
|
if (!hasPointer) {
|
|
emitLayoutAsserts(out, layout.overall, "");
|
|
out << "\n";
|
|
}
|
|
}
|
|
|
|
void CompoundType::emitFieldHidlDefinition(Formatter& out, const NamedReference<Type>& ref) const {
|
|
if (ref.getDocComment() != nullptr) ref.getDocComment()->emit(out);
|
|
|
|
if (ref.definedInline()) {
|
|
// Same check as above, this is for sanity
|
|
CHECK(ref.get()->isCompoundType());
|
|
static_cast<const CompoundType*>(ref.get())->emitInlineHidlDefinition(out);
|
|
out << " " << ref.name() << ";\n";
|
|
} else {
|
|
out << ref.localName() << " " << ref.name() << ";\n";
|
|
}
|
|
}
|
|
|
|
void CompoundType::emitInlineHidlDefinition(Formatter& out) const {
|
|
if (getDocComment() != nullptr) getDocComment()->emit(out);
|
|
out << typeName() << " ";
|
|
|
|
std::set<FQName> namesDeclaredInScope;
|
|
for (const NamedReference<Type>* ref : mFields) {
|
|
if (ref->definedInline()) {
|
|
const Type* type = ref->get();
|
|
CHECK(type->isCompoundType()) << " only compound types can be defined inline";
|
|
namesDeclaredInScope.insert(static_cast<const CompoundType*>(type)->fqName());
|
|
}
|
|
}
|
|
|
|
std::vector<const NamedType*> preDeclaredTypes;
|
|
for (const NamedType* namedType : getSortedDefinedTypes()) {
|
|
if (namesDeclaredInScope.find(namedType->fqName()) == namesDeclaredInScope.end()) {
|
|
// have to predeclare it
|
|
preDeclaredTypes.push_back(namedType);
|
|
}
|
|
}
|
|
|
|
out << "{";
|
|
out.indent([&] {
|
|
size_t preDeclaredTypesIdx = 0;
|
|
size_t fieldIdx = 0;
|
|
while (preDeclaredTypesIdx < preDeclaredTypes.size() && fieldIdx < mFields.size()) {
|
|
out << "\n";
|
|
if (preDeclaredTypes.at(preDeclaredTypesIdx)->location() <
|
|
mFields.at(fieldIdx)->location()) {
|
|
preDeclaredTypes.at(preDeclaredTypesIdx++)->emitHidlDefinition(out);
|
|
} else {
|
|
emitFieldHidlDefinition(out, *mFields.at(fieldIdx++));
|
|
}
|
|
}
|
|
|
|
while (preDeclaredTypesIdx < preDeclaredTypes.size()) {
|
|
out << "\n";
|
|
preDeclaredTypes.at(preDeclaredTypesIdx++)->emitHidlDefinition(out);
|
|
}
|
|
|
|
while (fieldIdx < mFields.size()) {
|
|
out << "\n";
|
|
emitFieldHidlDefinition(out, *mFields.at(fieldIdx++));
|
|
}
|
|
});
|
|
out << "}";
|
|
}
|
|
|
|
void CompoundType::emitHidlDefinition(Formatter& out) const {
|
|
emitInlineHidlDefinition(out);
|
|
out << ";\n";
|
|
}
|
|
|
|
void CompoundType::emitTypeDeclarations(Formatter& out) const {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
emitSafeUnionTypeDeclarations(out);
|
|
return;
|
|
}
|
|
|
|
out << ((mStyle == STYLE_STRUCT) ? "struct" : "union") << " " << definedName() << " final {\n";
|
|
|
|
out.indent();
|
|
|
|
Scope::emitTypeDeclarations(out);
|
|
|
|
if (containsPointer()) {
|
|
for (const auto& field : mFields) {
|
|
field->emitDocComment(out);
|
|
out << field->type().getCppStackType()
|
|
<< " "
|
|
<< field->name()
|
|
<< ";\n";
|
|
}
|
|
|
|
out.unindent();
|
|
out << "};\n\n";
|
|
|
|
return;
|
|
}
|
|
|
|
for (int pass = 0; pass < 2; ++pass) {
|
|
size_t offset = 0;
|
|
for (const auto& field : mFields) {
|
|
size_t fieldAlign, fieldSize;
|
|
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
|
|
|
|
offset += Layout::getPad(offset, fieldAlign);
|
|
|
|
if (pass == 0) {
|
|
field->emitDocComment(out);
|
|
out << field->type().getCppStackType()
|
|
<< " "
|
|
<< field->name()
|
|
<< " __attribute__ ((aligned("
|
|
<< fieldAlign
|
|
<< ")));\n";
|
|
} else {
|
|
out << "static_assert(offsetof("
|
|
<< fullName()
|
|
<< ", "
|
|
<< field->name()
|
|
<< ") == "
|
|
<< offset
|
|
<< ", \"wrong offset\");\n";
|
|
}
|
|
|
|
if (mStyle == STYLE_STRUCT) {
|
|
offset += fieldSize;
|
|
}
|
|
}
|
|
|
|
if (pass == 0) {
|
|
out.unindent();
|
|
out << "};\n\n";
|
|
}
|
|
}
|
|
|
|
CompoundLayout layout = getCompoundAlignmentAndSize();
|
|
emitLayoutAsserts(out, layout.overall, "");
|
|
out << "\n";
|
|
}
|
|
|
|
void CompoundType::emitTypeForwardDeclaration(Formatter& out) const {
|
|
switch (mStyle) {
|
|
case STYLE_UNION: {
|
|
out << "union";
|
|
break;
|
|
}
|
|
case STYLE_STRUCT:
|
|
case STYLE_SAFE_UNION: {
|
|
out << "struct";
|
|
break;
|
|
}
|
|
default: {
|
|
CHECK(!"Should not be here");
|
|
}
|
|
}
|
|
out << " " << definedName() << ";\n";
|
|
}
|
|
|
|
void CompoundType::emitPackageTypeDeclarations(Formatter& out) const {
|
|
Scope::emitPackageTypeDeclarations(out);
|
|
|
|
out << "static inline std::string toString(" << getCppArgumentType() << " o);\n";
|
|
out << "static inline void PrintTo(" << getCppArgumentType() << " o, ::std::ostream*);\n";
|
|
|
|
if (canCheckEquality()) {
|
|
out << "static inline bool operator==("
|
|
<< getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
|
|
|
|
out << "static inline bool operator!=("
|
|
<< getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs);\n";
|
|
} else {
|
|
out << "// operator== and operator!= are not generated for " << definedName() << "\n";
|
|
}
|
|
|
|
out.endl();
|
|
}
|
|
|
|
void CompoundType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
|
|
Scope::emitPackageTypeHeaderDefinitions(out);
|
|
|
|
out << "static inline std::string toString(" << getCppArgumentType()
|
|
<< (mFields.empty() ? "" : " o") << ") ";
|
|
|
|
out.block([&] {
|
|
// include toString for scalar types
|
|
out << "using ::android::hardware::toString;\n"
|
|
<< "std::string os;\n";
|
|
out << "os += \"{\";\n";
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "\nswitch (o.getDiscriminator()) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
for (const NamedReference<Type>* field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case "
|
|
<< fullName()
|
|
<< "::hidl_discriminator::"
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
out << "os += \"."
|
|
<< field->name()
|
|
<< " = \";\n"
|
|
<< "os += toString(o."
|
|
<< field->name()
|
|
<< "());\n"
|
|
<< "break;\n";
|
|
}).endl();
|
|
} else {
|
|
out << "os += \"";
|
|
if (field != *(mFields.begin())) {
|
|
out << ", ";
|
|
}
|
|
out << "." << field->name() << " = \";\n";
|
|
field->type().emitDump(out, "os", "o." + field->name());
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] {
|
|
emitSafeUnionUnknownDiscriminatorError(out, "o.getDiscriminator()",
|
|
true /*fatal*/);
|
|
})
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
out << "os += \"}\"; return os;\n";
|
|
}).endl().endl();
|
|
|
|
out << "static inline void PrintTo(" << getCppArgumentType() << " o, ::std::ostream* os) ";
|
|
out.block([&] { out << "*os << toString(o);\n"; }).endl().endl();
|
|
|
|
if (canCheckEquality()) {
|
|
out << "static inline bool operator==(" << getCppArgumentType() << " "
|
|
<< (mFields.empty() ? "/* lhs */" : "lhs") << ", " << getCppArgumentType() << " "
|
|
<< (mFields.empty() ? "/* rhs */" : "rhs") << ") ";
|
|
out.block([&] {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out.sIf("lhs.getDiscriminator() != rhs.getDiscriminator()", [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
|
|
out << "switch (lhs.getDiscriminator()) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case "
|
|
<< fullName()
|
|
<< "::hidl_discriminator::"
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
out << "return (lhs."
|
|
<< field->name()
|
|
<< "() == rhs."
|
|
<< field->name()
|
|
<< "());\n";
|
|
}).endl();
|
|
} else {
|
|
out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] {
|
|
emitSafeUnionUnknownDiscriminatorError(out, "lhs.getDiscriminator()",
|
|
true /*fatal*/);
|
|
})
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
out << "return true;\n";
|
|
}).endl().endl();
|
|
|
|
out << "static inline bool operator!=("
|
|
<< getCppArgumentType() << " lhs, " << getCppArgumentType() << " rhs)";
|
|
out.block([&] {
|
|
out << "return !(lhs == rhs);\n";
|
|
}).endl().endl();
|
|
} else {
|
|
out << "// operator== and operator!= are not generated for " << definedName() << "\n\n";
|
|
}
|
|
}
|
|
|
|
void CompoundType::emitPackageHwDeclarations(Formatter& out) const {
|
|
Scope::emitPackageHwDeclarations(out);
|
|
|
|
if (needsEmbeddedReadWrite()) {
|
|
out << "::android::status_t readEmbeddedFromParcel(\n";
|
|
|
|
out.indent(2);
|
|
|
|
out << "const " << fullName() << " &obj,\n"
|
|
<< "const ::android::hardware::Parcel &parcel,\n"
|
|
<< "size_t parentHandle,\n"
|
|
<< "size_t parentOffset);\n\n";
|
|
|
|
out.unindent(2);
|
|
|
|
out << "::android::status_t writeEmbeddedToParcel(\n";
|
|
|
|
out.indent(2);
|
|
|
|
out << "const " << fullName() << " &obj,\n"
|
|
<< "::android::hardware::Parcel *parcel,\n"
|
|
<< "size_t parentHandle,\n"
|
|
<< "size_t parentOffset);\n\n";
|
|
|
|
out.unindent(2);
|
|
}
|
|
}
|
|
|
|
static void emitSafeUnionFieldConstructor(Formatter& out,
|
|
const NamedReference<Type>* field,
|
|
const std::string& initializerObjectName) {
|
|
out << "new (&hidl_u."
|
|
<< field->name()
|
|
<< ") "
|
|
<< field->type().getCppStackType()
|
|
<< "("
|
|
<< initializerObjectName
|
|
<< ");\n";
|
|
}
|
|
|
|
static void emitSafeUnionSetterDefinition(Formatter& out,
|
|
const NamedReference<Type>* field,
|
|
const std::string& parameterName,
|
|
bool usesMoveSemantics) {
|
|
out.block([&] {
|
|
out << "if (hidl_d != hidl_discriminator::"
|
|
<< field->name()
|
|
<< ") ";
|
|
|
|
const std::string argumentName = usesMoveSemantics
|
|
? ("std::move(" + parameterName + ")")
|
|
: parameterName;
|
|
out.block([&] {
|
|
out << "hidl_destructUnion();\n"
|
|
<< "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n\n";
|
|
|
|
emitSafeUnionFieldConstructor(out, field, argumentName);
|
|
out << "hidl_d = hidl_discriminator::"
|
|
<< field->name()
|
|
<< ";\n";
|
|
}).endl();
|
|
|
|
out << "else if (&(hidl_u."
|
|
<< field->name()
|
|
<< ") != &"
|
|
<< parameterName
|
|
<< ") ";
|
|
|
|
out.block([&] {
|
|
out << "hidl_u."
|
|
<< field->name()
|
|
<< " = "
|
|
<< argumentName
|
|
<< ";\n";
|
|
}).endl();
|
|
}).endl().endl();
|
|
}
|
|
|
|
static void emitSafeUnionGetterDefinition(Formatter& out, const std::string& fieldName) {
|
|
out.block([&] {
|
|
out << "if (CC_UNLIKELY(hidl_d != hidl_discriminator::"
|
|
<< fieldName
|
|
<< ")) ";
|
|
|
|
out.block([&] {
|
|
out << "LOG_ALWAYS_FATAL(\"Bad safe_union access: safe_union has discriminator %\" "
|
|
<< "PRIu64 \" but discriminator %\" PRIu64 \" was accessed.\",\n";
|
|
out.indent(2, [&] {
|
|
out << "static_cast<uint64_t>(hidl_d), "
|
|
<< "static_cast<uint64_t>(hidl_discriminator::" << fieldName << "));";
|
|
}).endl();
|
|
}).endl().endl();
|
|
|
|
out << "return hidl_u."
|
|
<< fieldName
|
|
<< ";\n";
|
|
}).endl().endl();
|
|
}
|
|
|
|
void CompoundType::emitSafeUnionAssignDefinition(Formatter& out, const std::string& parameterName,
|
|
bool usesMoveSemantics) const {
|
|
out.block([&] {
|
|
out << "if (this == &" << parameterName << ") { return *this; }\n\n";
|
|
|
|
out << "switch (" << parameterName << ".hidl_d) ";
|
|
|
|
out.block([&] {
|
|
for (const auto& field : mFields) {
|
|
const std::string parameterFieldName =
|
|
(parameterName + ".hidl_u." + field->name());
|
|
|
|
const std::string argumentName =
|
|
usesMoveSemantics ? ("std::move(" + parameterFieldName + ")")
|
|
: parameterFieldName;
|
|
|
|
out << "case hidl_discriminator::" << field->name() << ": ";
|
|
|
|
out.block([&] {
|
|
out << field->name() << "(" << argumentName << ");\n"
|
|
<< "break;\n";
|
|
}).endl();
|
|
}
|
|
|
|
out << "default: ";
|
|
out.block([&] {
|
|
emitSafeUnionUnknownDiscriminatorError(out, parameterName + ".hidl_d",
|
|
true /*fatal*/);
|
|
}).endl();
|
|
}).endl();
|
|
|
|
out << "return *this;\n";
|
|
})
|
|
.endl()
|
|
.endl();
|
|
}
|
|
|
|
void CompoundType::emitSafeUnionTypeConstructors(Formatter& out) const {
|
|
|
|
// Default constructor
|
|
out << fullName() << "::" << definedName() << "() ";
|
|
|
|
out.block([&] {
|
|
out << "static_assert(offsetof("
|
|
<< fullName()
|
|
<< ", hidl_d) == 0, \"wrong offset\");\n";
|
|
|
|
const CompoundLayout layout = getCompoundAlignmentAndSize();
|
|
|
|
if (!containsPointer()) {
|
|
out << "static_assert(offsetof(" << fullName()
|
|
<< ", hidl_u) == " << layout.innerStruct.offset << ", \"wrong offset\");\n";
|
|
}
|
|
|
|
out.endl();
|
|
|
|
out << "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n";
|
|
|
|
// union itself is zero'd when set
|
|
// padding after descriminator
|
|
size_t dpad = layout.innerStruct.offset - layout.discriminator.size;
|
|
emitPaddingZero(out, layout.discriminator.size /*offset*/, dpad /*size*/);
|
|
|
|
size_t innerStructEnd = layout.innerStruct.offset + layout.innerStruct.size;
|
|
// final padding of the struct
|
|
size_t fpad = layout.overall.size - innerStructEnd;
|
|
emitPaddingZero(out, innerStructEnd /*offset*/, fpad /*size*/);
|
|
|
|
out.endl();
|
|
|
|
CHECK(!mFields.empty());
|
|
out << "hidl_d = hidl_discriminator::" << mFields.at(0)->name() << ";\n";
|
|
emitSafeUnionFieldConstructor(out, mFields.at(0), "");
|
|
}).endl().endl();
|
|
|
|
// Destructor
|
|
out << fullName() << "::~" << definedName() << "() ";
|
|
|
|
out.block([&] {
|
|
out << "hidl_destructUnion();\n";
|
|
}).endl().endl();
|
|
|
|
// Move constructor
|
|
out << fullName() << "::" << definedName() << "(" << definedName()
|
|
<< "&& other) : " << fullName() << "() ";
|
|
out.block([&] { out << "*this = std::move(other);\n"; }).endl().endl();
|
|
|
|
// Copy constructor
|
|
out << fullName() << "::" << definedName() << "(const " << definedName()
|
|
<< "& other) : " << fullName() << "() ";
|
|
out.block([&] { out << "*this = other;\n"; }).endl().endl();
|
|
|
|
// Move assignment operator
|
|
out << fullName() << "& (" << fullName() << "::operator=)(" << definedName() << "&& other) ";
|
|
|
|
emitSafeUnionAssignDefinition(out, "other", true /* usesMoveSemantics */);
|
|
|
|
// Copy assignment operator
|
|
out << fullName() << "& (" << fullName() << "::operator=)(const " << definedName()
|
|
<< "& other) ";
|
|
|
|
emitSafeUnionAssignDefinition(out, "other", false /* usesMoveSemantics */);
|
|
}
|
|
|
|
void CompoundType::emitSafeUnionTypeDefinitions(Formatter& out) const {
|
|
emitSafeUnionTypeConstructors(out);
|
|
|
|
out << "void "
|
|
<< fullName()
|
|
<< "::hidl_destructUnion() ";
|
|
|
|
out.block([&] {
|
|
out << "switch (hidl_d) ";
|
|
out.block([&] {
|
|
for (const auto& field : mFields) {
|
|
out << "case hidl_discriminator::" << field->name() << ": ";
|
|
|
|
out.block([&] {
|
|
out << "::android::hardware::details::destructElement(&(hidl_u."
|
|
<< field->name() << "));\n"
|
|
<< "break;\n";
|
|
}).endl();
|
|
}
|
|
|
|
out << "default: ";
|
|
out.block([&] {
|
|
emitSafeUnionUnknownDiscriminatorError(out, "hidl_d", true /*fatal*/);
|
|
}).endl();
|
|
})
|
|
.endl()
|
|
.endl();
|
|
}).endl().endl();
|
|
|
|
for (const NamedReference<Type>* field : mFields) {
|
|
// Setter (copy)
|
|
out << "void "
|
|
<< fullName()
|
|
<< "::"
|
|
<< field->name()
|
|
<< "("
|
|
<< field->type().getCppArgumentType()
|
|
<< " o) ";
|
|
|
|
emitSafeUnionSetterDefinition(out, field, "o", false /* usesMoveSemantics */);
|
|
|
|
if (field->type().resolveToScalarType() == nullptr) {
|
|
// Setter (move)
|
|
out << "void "
|
|
<< fullName()
|
|
<< "::"
|
|
<< field->name()
|
|
<< "("
|
|
<< field->type().getCppStackType()
|
|
<< "&& o) ";
|
|
|
|
emitSafeUnionSetterDefinition(out, field, "o", true /* usesMoveSemantics */);
|
|
}
|
|
|
|
// Getter (mutable)
|
|
out << field->type().getCppStackType()
|
|
<< "& ("
|
|
<< fullName()
|
|
<< "::"
|
|
<< field->name()
|
|
<< ")() ";
|
|
|
|
emitSafeUnionGetterDefinition(out, field->name());
|
|
|
|
// Getter (immutable)
|
|
out << field->type().getCppArgumentType()
|
|
<< " ("
|
|
<< fullName()
|
|
<< "::"
|
|
<< field->name()
|
|
<< ")() const ";
|
|
|
|
emitSafeUnionGetterDefinition(out, field->name());
|
|
}
|
|
|
|
// Trivial constructor/destructor for internal union
|
|
out << fullName() << "::hidl_union::hidl_union() {}\n\n"
|
|
<< fullName() << "::hidl_union::~hidl_union() {}\n\n";
|
|
|
|
// Utility method
|
|
out << fullName() << "::hidl_discriminator ("
|
|
<< fullName() << "::getDiscriminator)() const ";
|
|
|
|
out.block([&] {
|
|
out << "return hidl_d;\n";
|
|
}).endl().endl();
|
|
}
|
|
|
|
void CompoundType::emitTypeDefinitions(Formatter& out, const std::string& prefix) const {
|
|
std::string space = prefix.empty() ? "" : (prefix + "::");
|
|
Scope::emitTypeDefinitions(out, space + definedName());
|
|
|
|
if (needsEmbeddedReadWrite()) {
|
|
emitStructReaderWriter(out, prefix, true /* isReader */);
|
|
emitStructReaderWriter(out, prefix, false /* isReader */);
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
emitSafeUnionTypeDefinitions(out);
|
|
}
|
|
}
|
|
|
|
static void emitJavaSafeUnionUnknownDiscriminatorError(Formatter& out, bool fatal) {
|
|
out << "throw new ";
|
|
|
|
if (fatal) {
|
|
out << "Error";
|
|
} else {
|
|
out << "IllegalStateException";
|
|
}
|
|
|
|
out << "(\"Unknown union discriminator (value: \" + hidl_d + \").\");\n";
|
|
}
|
|
|
|
void CompoundType::emitJavaTypeDeclarations(Formatter& out, bool atTopLevel) const {
|
|
out << "public final ";
|
|
|
|
if (!atTopLevel) {
|
|
out << "static ";
|
|
}
|
|
|
|
out << "class " << definedName() << " {\n";
|
|
|
|
out.indent();
|
|
|
|
Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "public " << definedName() << "() ";
|
|
out.block([&] {
|
|
CHECK(!mFields.empty());
|
|
mFields.at(0)->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
|
|
})
|
|
.endl()
|
|
.endl();
|
|
|
|
const std::string discriminatorStorageType = (
|
|
getUnionDiscriminatorType()->getJavaType(false));
|
|
|
|
out << "public static final class hidl_discriminator ";
|
|
out.block([&] {
|
|
for (size_t idx = 0; idx < mFields.size(); idx++) {
|
|
const auto& field = mFields.at(idx);
|
|
|
|
field->emitDocComment(out);
|
|
out << "public static final " << discriminatorStorageType << " " << field->name()
|
|
<< " = " << idx << "; // "
|
|
<< field->type().getJavaType(true /* forInitializer */) << "\n";
|
|
}
|
|
|
|
out << "\n"
|
|
<< "public static final String getName(" << discriminatorStorageType
|
|
<< " value) ";
|
|
|
|
out.block([&] {
|
|
out << "switch (value) ";
|
|
out.block([&] {
|
|
for (size_t idx = 0; idx < mFields.size(); idx++) {
|
|
const auto& field = mFields.at(idx);
|
|
|
|
out << "case " << idx << ": { return \"" << field->name()
|
|
<< "\"; }\n";
|
|
}
|
|
out << "default: { return \"Unknown\"; }\n";
|
|
}).endl();
|
|
})
|
|
.endl()
|
|
.endl();
|
|
|
|
out << "private hidl_discriminator() {}\n";
|
|
})
|
|
.endl()
|
|
.endl();
|
|
|
|
out << "private " << discriminatorStorageType << " hidl_d = 0;\n";
|
|
out << "private Object hidl_o = null;\n";
|
|
|
|
for (const auto& field : mFields) {
|
|
// Setter
|
|
out << "public void "
|
|
<< field->name()
|
|
<< "("
|
|
<< field->type().getJavaType(false)
|
|
<< " "
|
|
<< field->name()
|
|
<< ") ";
|
|
|
|
out.block([&] {
|
|
out << "hidl_d = hidl_discriminator."
|
|
<< field->name()
|
|
<< ";\n";
|
|
|
|
out << "hidl_o = "
|
|
<< field->name()
|
|
<< ";\n";
|
|
}).endl().endl();
|
|
|
|
// Getter
|
|
out << "public "
|
|
<< field->type().getJavaType(false)
|
|
<< " "
|
|
<< field->name()
|
|
<< "() ";
|
|
|
|
out.block([&] {
|
|
out << "if (hidl_d != hidl_discriminator."
|
|
<< field->name()
|
|
<< ") ";
|
|
|
|
out.block([&] {
|
|
out << "String className = (hidl_o != null) ? "
|
|
<< "hidl_o.getClass().getName() : \"null\";\n";
|
|
|
|
out << "throw new IllegalStateException(\n";
|
|
out.indent(2, [&] {
|
|
out << "\"Read access to inactive union components is disallowed. \" +\n"
|
|
<< "\"Discriminator value is \" + hidl_d + \" (corresponding \" +\n"
|
|
<< "\"to \" + hidl_discriminator.getName(hidl_d) + \"), and \" +\n"
|
|
<< "\"hidl_o is of type \" + className + \".\");\n";
|
|
});
|
|
}).endl();
|
|
|
|
out << "if (hidl_o != null && !"
|
|
<< field->type().getJavaTypeClass()
|
|
<< ".class.isInstance(hidl_o)) ";
|
|
|
|
out.block([&] {
|
|
out << "throw new Error(\"Union is in a corrupted state.\");\n";
|
|
}).endl();
|
|
|
|
out << "return ("
|
|
<< field->type().getJavaTypeCast("hidl_o")
|
|
<< ");\n";
|
|
}).endl().endl();
|
|
}
|
|
|
|
out << "// Utility method\n"
|
|
<< "public "
|
|
<< discriminatorStorageType
|
|
<< " getDiscriminator() { return hidl_d; }\n\n";
|
|
|
|
} else if (mStyle == STYLE_STRUCT) {
|
|
for (const auto& field : mFields) {
|
|
field->emitDocComment(out);
|
|
|
|
out << "public ";
|
|
field->type().emitJavaFieldInitializer(out, field->name());
|
|
}
|
|
|
|
out << "\n";
|
|
} else {
|
|
LOG(FATAL) << "Java output doesn't support " << mStyle;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
if (canCheckEquality()) {
|
|
out << "@Override\npublic final boolean equals(Object otherObject) ";
|
|
out.block([&] {
|
|
out.sIf("this == otherObject", [&] {
|
|
out << "return true;\n";
|
|
}).endl();
|
|
out.sIf("otherObject == null", [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
// Though class is final, we use getClass instead of instanceof to be explicit.
|
|
out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n";
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out.sIf("this.hidl_d != other.hidl_d", [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
out.sIf("!android.os.HidlSupport.deepEquals(this.hidl_o, other.hidl_o)", [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
} else {
|
|
for (const auto& field : mFields) {
|
|
std::string condition = (field->type().isScalar() || field->type().isEnum())
|
|
? "this." + field->name() + " != other." + field->name()
|
|
: ("!android.os.HidlSupport.deepEquals(this." + field->name()
|
|
+ ", other." + field->name() + ")");
|
|
out.sIf(condition, [&] {
|
|
out << "return false;\n";
|
|
}).endl();
|
|
}
|
|
}
|
|
out << "return true;\n";
|
|
}).endl().endl();
|
|
|
|
out << "@Override\npublic final int hashCode() ";
|
|
out.block([&] {
|
|
out << "return java.util.Objects.hash(\n";
|
|
out.indent(2, [&] {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "android.os.HidlSupport.deepHashCode(this.hidl_o),\n"
|
|
<< "java.util.Objects.hashCode(this.hidl_d)";
|
|
} else {
|
|
out.join(mFields.begin(), mFields.end(), ", \n", [&](const auto& field) {
|
|
out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
|
|
});
|
|
}
|
|
});
|
|
out << ");\n";
|
|
}).endl().endl();
|
|
} else {
|
|
out << "// equals() is not generated for " << definedName() << "\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
out << "@Override\npublic final String toString() ";
|
|
out.block([&] {
|
|
out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n"
|
|
<< "builder.append(\"{\");\n";
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "switch (this.hidl_d) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case hidl_discriminator."
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
out << "builder.append(\""
|
|
<< "."
|
|
<< field->name()
|
|
<< " = \");\n";
|
|
|
|
field->type().emitJavaDump(out, "builder", "this." + field->name() + "()");
|
|
out << "break;\n";
|
|
}).endl();
|
|
}
|
|
else {
|
|
out << "builder.append(\"";
|
|
if (field != *(mFields.begin())) {
|
|
out << ", ";
|
|
}
|
|
out << "." << field->name() << " = \");\n";
|
|
field->type().emitJavaDump(out, "builder", "this." + field->name());
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
|
|
out << "builder.append(\"}\");\nreturn builder.toString();\n";
|
|
}).endl().endl();
|
|
|
|
CompoundLayout layout = getCompoundAlignmentAndSize();
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
out << "public final void readFromParcel(android.os.HwParcel parcel) {\n";
|
|
out.indent();
|
|
if (containsInterface()) {
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "hidl_d = ";
|
|
getUnionDiscriminatorType()->emitJavaReaderWriter(
|
|
out, "parcel", "hidl_d", true);
|
|
|
|
out << "switch (hidl_d) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case hidl_discriminator."
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
out << "hidl_o = ";
|
|
field->type().emitJavaReaderWriter(out, "parcel", "hidl_o", true);
|
|
|
|
out << "break;\n";
|
|
}).endl();
|
|
} else {
|
|
out << field->name() << " = ";
|
|
field->type().emitJavaReaderWriter(out, "parcel", field->name(), true);
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
} else {
|
|
out << "android.os.HwBlob blob = parcel.readBuffer(";
|
|
out << layout.overall.size << " /* size */);\n";
|
|
out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
|
|
}
|
|
out.unindent();
|
|
out << "}\n\n";
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
size_t vecAlign, vecSize;
|
|
VectorType::getAlignmentAndSizeStatic(&vecAlign, &vecSize);
|
|
|
|
out << "public static final java.util.ArrayList<" << definedName()
|
|
<< "> readVectorFromParcel(android.os.HwParcel parcel) {\n";
|
|
out.indent();
|
|
|
|
out << "java.util.ArrayList<" << definedName() << "> _hidl_vec = new java.util.ArrayList();\n";
|
|
|
|
if (containsInterface()) {
|
|
out << "int size = parcel.readInt32();\n";
|
|
out << "for(int i = 0 ; i < size; i ++) {\n";
|
|
out.indent();
|
|
out << fullJavaName() << " tmp = ";
|
|
emitJavaReaderWriter(out, "parcel", "tmp", true);
|
|
out << "_hidl_vec.add(tmp);\n";
|
|
out.unindent();
|
|
out << "}\n";
|
|
} else {
|
|
out << "android.os.HwBlob _hidl_blob = parcel.readBuffer(";
|
|
out << vecSize << " /* sizeof hidl_vec<T> */);\n\n";
|
|
|
|
VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
|
|
"_hidl_blob", "_hidl_vec", "0",
|
|
true /* isReader */);
|
|
}
|
|
out << "\nreturn _hidl_vec;\n";
|
|
out.unindent();
|
|
out << "}\n\n";
|
|
////////////////////////////////////////////////////////////////////////////
|
|
if (containsInterface()) {
|
|
out << "// readEmbeddedFromParcel is not generated()\n";
|
|
} else {
|
|
out << "public final void readEmbeddedFromParcel(\n";
|
|
out.indent(2);
|
|
out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
|
|
out.unindent();
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
|
|
out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
|
|
"_hidl_offset + " + std::to_string(layout.discriminator.offset),
|
|
true /* isReader */);
|
|
|
|
out << "switch (this.hidl_d) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
size_t offset = layout.innerStruct.offset;
|
|
for (const auto& field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case hidl_discriminator."
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
field->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
|
|
field->type().emitJavaFieldReaderWriter(
|
|
out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_o",
|
|
"_hidl_offset + " + std::to_string(offset), true /* isReader */);
|
|
|
|
out << "break;\n";
|
|
}).endl();
|
|
} else {
|
|
size_t fieldAlign, fieldSize;
|
|
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
|
|
|
|
offset += Layout::getPad(offset, fieldAlign);
|
|
field->type().emitJavaFieldReaderWriter(
|
|
out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
|
|
"_hidl_offset + " + std::to_string(offset), true /* isReader */);
|
|
offset += fieldSize;
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, false /*fatal*/); })
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
out.unindent();
|
|
out << "}\n\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
out << "public final void writeToParcel(android.os.HwParcel parcel) {\n";
|
|
out.indent();
|
|
|
|
if (containsInterface()) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
getUnionDiscriminatorType()->emitJavaReaderWriter(
|
|
out, "parcel", "hidl_d", false);
|
|
|
|
out << "switch (this.hidl_d) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case hidl_discriminator."
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
field->type().emitJavaReaderWriter(out, "parcel", field->name() + "()", false);
|
|
out << "break;\n";
|
|
}).endl();
|
|
} else {
|
|
field->type().emitJavaReaderWriter(out, "parcel", field->name(), false);
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
} else {
|
|
out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob("
|
|
<< layout.overall.size
|
|
<< " /* size */);\n";
|
|
|
|
out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
|
|
<< "parcel.writeBuffer(_hidl_blob);\n";
|
|
}
|
|
out.unindent();
|
|
out << "}\n\n";
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
out << "public static final void writeVectorToParcel(\n";
|
|
out.indent(2);
|
|
out << "android.os.HwParcel parcel, java.util.ArrayList<" << definedName()
|
|
<< "> _hidl_vec) {\n";
|
|
out.unindent();
|
|
|
|
if (containsInterface()) {
|
|
out << "parcel.writeInt32(_hidl_vec.size());\n";
|
|
out << "for(" << fullJavaName() << " tmp: _hidl_vec) ";
|
|
out.block([&] {
|
|
emitJavaReaderWriter(out, "parcel", "tmp", false);
|
|
}).endl();
|
|
} else {
|
|
out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" << vecSize
|
|
<< " /* sizeof(hidl_vec<T>) */);\n";
|
|
|
|
VectorType::EmitJavaFieldReaderWriterForElementType(out, 0 /* depth */, this, "parcel",
|
|
"_hidl_blob", "_hidl_vec", "0",
|
|
false /* isReader */);
|
|
|
|
out << "\nparcel.writeBuffer(_hidl_blob);\n";
|
|
}
|
|
out.unindent();
|
|
out << "}\n\n";
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
if (containsInterface()) {
|
|
out << "// writeEmbeddedToBlob() is not generated\n";
|
|
} else {
|
|
out << "public final void writeEmbeddedToBlob(\n";
|
|
out.indent(2);
|
|
out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n";
|
|
out.unindent();
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
getUnionDiscriminatorType()->emitJavaFieldReaderWriter(
|
|
out, 0 /* depth */, "parcel", "_hidl_blob", "hidl_d",
|
|
"_hidl_offset + " + std::to_string(layout.discriminator.offset),
|
|
false /* isReader */);
|
|
|
|
out << "switch (this.hidl_d) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
size_t offset = layout.innerStruct.offset;
|
|
for (const auto& field : mFields) {
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case hidl_discriminator."
|
|
<< field->name()
|
|
<< ": ";
|
|
|
|
out.block([&] {
|
|
field->type().emitJavaFieldReaderWriter(
|
|
out, 0 /* depth */, "parcel", "_hidl_blob", field->name() + "()",
|
|
"_hidl_offset + " + std::to_string(offset), false /* isReader */);
|
|
|
|
out << "break;\n";
|
|
}).endl();
|
|
} else {
|
|
size_t fieldAlign, fieldSize;
|
|
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
|
|
|
|
offset += Layout::getPad(offset, fieldAlign);
|
|
field->type().emitJavaFieldReaderWriter(
|
|
out, 0 /* depth */, "parcel", "_hidl_blob", field->name(),
|
|
"_hidl_offset + " + std::to_string(offset), false /* isReader */);
|
|
offset += fieldSize;
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: ";
|
|
out.block([&] { emitJavaSafeUnionUnknownDiscriminatorError(out, true /*fatal*/); })
|
|
.endl();
|
|
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
|
|
out.unindent();
|
|
out << "};\n\n";
|
|
}
|
|
|
|
void CompoundType::emitStructReaderWriter(
|
|
Formatter &out, const std::string &prefix, bool isReader) const {
|
|
|
|
std::string space = prefix.empty() ? "" : (prefix + "::");
|
|
|
|
out << "::android::status_t "
|
|
<< (isReader ? "readEmbeddedFromParcel"
|
|
: "writeEmbeddedToParcel")
|
|
<< "(\n";
|
|
|
|
out.indent(2);
|
|
|
|
const std::string name = "obj";
|
|
if (isReader) {
|
|
out << "const " << space << definedName() << " &" << name << ",\n";
|
|
out << "const ::android::hardware::Parcel &parcel,\n";
|
|
} else {
|
|
out << "const " << space << definedName() << " &" << name << ",\n";
|
|
out << "::android::hardware::Parcel *parcel,\n";
|
|
}
|
|
|
|
out << "size_t parentHandle,\n"
|
|
<< "size_t parentOffset)";
|
|
|
|
out << " {\n";
|
|
|
|
out.unindent(2);
|
|
out.indent();
|
|
|
|
out << "::android::status_t _hidl_err = ::android::OK;\n\n";
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "switch (" << name << ".getDiscriminator()) {\n";
|
|
out.indent();
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
if (!field->type().needsEmbeddedReadWrite()) {
|
|
continue;
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "case " << fullName() << "::hidl_discriminator::"
|
|
<< field->name() << ": {\n";
|
|
out.indent();
|
|
}
|
|
|
|
const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
|
|
? (name + "." + field->name() + "()")
|
|
: (name + "." + field->name());
|
|
|
|
const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
|
|
? (name + ".hidl_getUnionOffset() " +
|
|
"/* safe_union: union offset into struct */")
|
|
: ("offsetof(" + fullName() + ", " + field->name() + ")");
|
|
|
|
field->type().emitReaderWriterEmbedded(
|
|
out,
|
|
0 /* depth */,
|
|
fieldName,
|
|
field->name() /* sanitizedName */,
|
|
false /* nameIsPointer */,
|
|
"parcel",
|
|
!isReader /* parcelObjIsPointer */,
|
|
isReader,
|
|
ErrorMode_Return,
|
|
"parentHandle",
|
|
"parentOffset + " + fieldOffset);
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "break;\n";
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
}
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
out << "default: { break; }\n";
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
|
|
out << "return _hidl_err;\n";
|
|
|
|
out.unindent();
|
|
out << "}\n\n";
|
|
}
|
|
|
|
bool CompoundType::needsEmbeddedReadWrite() const {
|
|
if (mStyle == STYLE_UNION) {
|
|
return false;
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
if (field->type().needsEmbeddedReadWrite()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CompoundType::resultNeedsDeref() const {
|
|
return !containsInterface() ;
|
|
}
|
|
|
|
void CompoundType::emitVtsTypeDeclarations(Formatter& out) const {
|
|
out << "name: \"" << fullName() << "\"\n";
|
|
out << "type: " << getVtsType() << "\n";
|
|
|
|
// Emit declaration for each subtype.
|
|
for (const auto &type : getSubTypes()) {
|
|
switch (mStyle) {
|
|
case STYLE_STRUCT:
|
|
{
|
|
out << "sub_struct: {\n";
|
|
break;
|
|
}
|
|
case STYLE_UNION:
|
|
{
|
|
out << "sub_union: {\n";
|
|
break;
|
|
}
|
|
case STYLE_SAFE_UNION:
|
|
{
|
|
out << "sub_safe_union: {\n";
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
CHECK(!"Should not be here");
|
|
}
|
|
}
|
|
out.indent();
|
|
type->emitVtsTypeDeclarations(out);
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
|
|
// Emit declaration for each field.
|
|
for (const auto& field : mFields) {
|
|
switch (mStyle) {
|
|
case STYLE_STRUCT:
|
|
{
|
|
out << "struct_value: {\n";
|
|
break;
|
|
}
|
|
case STYLE_UNION:
|
|
{
|
|
out << "union_value: {\n";
|
|
break;
|
|
}
|
|
case STYLE_SAFE_UNION:
|
|
{
|
|
out << "safe_union_value: {\n";
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
CHECK(!"Should not be here");
|
|
}
|
|
}
|
|
out.indent();
|
|
out << "name: \"" << field->name() << "\"\n";
|
|
field->type().emitVtsAttributeType(out);
|
|
out.unindent();
|
|
out << "}\n";
|
|
}
|
|
}
|
|
|
|
void CompoundType::emitVtsAttributeType(Formatter& out) const {
|
|
out << "type: " << getVtsType() << "\n";
|
|
out << "predefined_type: \"" << fullName() << "\"\n";
|
|
}
|
|
|
|
bool CompoundType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
|
|
if (mStyle == STYLE_UNION) {
|
|
return false;
|
|
}
|
|
|
|
for (const auto* field : mFields) {
|
|
if (!field->get()->isJavaCompatible(visited)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return Scope::deepIsJavaCompatible(visited);
|
|
}
|
|
|
|
bool CompoundType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
|
|
for (const auto* field : mFields) {
|
|
if (field->get()->containsPointer(visited)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return Scope::deepContainsPointer(visited);
|
|
}
|
|
|
|
void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
|
|
CompoundLayout layout = getCompoundAlignmentAndSize();
|
|
*align = layout.overall.align;
|
|
*size = layout.overall.size;
|
|
}
|
|
|
|
CompoundType::CompoundLayout CompoundType::getCompoundAlignmentAndSize() const {
|
|
CompoundLayout compoundLayout;
|
|
|
|
// Local aliases for convenience
|
|
Layout& overall = compoundLayout.overall;
|
|
Layout& innerStruct = compoundLayout.innerStruct;
|
|
Layout& discriminator = compoundLayout.discriminator;
|
|
|
|
if (mStyle == STYLE_SAFE_UNION) {
|
|
getUnionDiscriminatorType()->getAlignmentAndSize(
|
|
&(discriminator.align), &(discriminator.size));
|
|
|
|
innerStruct.offset = discriminator.size;
|
|
}
|
|
|
|
for (const auto& field : mFields) {
|
|
// Each field is aligned according to its alignment requirement.
|
|
// The surrounding structure's alignment is the maximum of its
|
|
// fields' aligments.
|
|
size_t fieldAlign, fieldSize;
|
|
field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
|
|
size_t lPad = Layout::getPad(innerStruct.size, fieldAlign);
|
|
|
|
innerStruct.size = (mStyle == STYLE_STRUCT)
|
|
? (innerStruct.size + lPad + fieldSize)
|
|
: std::max(innerStruct.size, fieldSize);
|
|
|
|
innerStruct.align = std::max(innerStruct.align, fieldAlign);
|
|
}
|
|
|
|
// Pad the inner structure's size
|
|
innerStruct.size += Layout::getPad(innerStruct.size,
|
|
innerStruct.align);
|
|
|
|
// Compute its final offset
|
|
innerStruct.offset += Layout::getPad(innerStruct.offset,
|
|
innerStruct.align);
|
|
|
|
// An empty struct/union still occupies a byte of space in C++.
|
|
if (innerStruct.size == 0) {
|
|
innerStruct.size = 1;
|
|
}
|
|
|
|
overall.size = innerStruct.offset + innerStruct.size;
|
|
|
|
// Pad the overall structure's size
|
|
overall.align = std::max(innerStruct.align, discriminator.align);
|
|
overall.size += Layout::getPad(overall.size, overall.align);
|
|
|
|
if (mStyle != STYLE_SAFE_UNION) {
|
|
CHECK(overall.offset == innerStruct.offset) << overall.offset << " " << innerStruct.offset;
|
|
CHECK(overall.align == innerStruct.align) << overall.align << " " << innerStruct.align;
|
|
CHECK(overall.size == innerStruct.size) << overall.size << " " << innerStruct.size;
|
|
}
|
|
|
|
return compoundLayout;
|
|
}
|
|
|
|
void CompoundType::emitPaddingZero(Formatter& out, size_t offset, size_t size) const {
|
|
if (size > 0) {
|
|
out << "::std::memset(reinterpret_cast<uint8_t*>(this) + " << offset << ", 0, " << size
|
|
<< ");\n";
|
|
} else {
|
|
out << "// no padding to zero starting at offset " << offset << "\n";
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<ScalarType> CompoundType::getUnionDiscriminatorType() const {
|
|
static const std::vector<std::pair<int, ScalarType::Kind> > scalars {
|
|
{8, ScalarType::Kind::KIND_UINT8},
|
|
{16, ScalarType::Kind::KIND_UINT16},
|
|
{32, ScalarType::Kind::KIND_UINT32},
|
|
};
|
|
|
|
size_t numFields = mFields.size();
|
|
auto kind = ScalarType::Kind::KIND_UINT64;
|
|
|
|
for (const auto& scalar : scalars) {
|
|
if (numFields <= (1ULL << scalar.first)) {
|
|
kind = scalar.second; break;
|
|
}
|
|
}
|
|
|
|
return std::unique_ptr<ScalarType>(new ScalarType(kind, nullptr));
|
|
}
|
|
|
|
size_t CompoundType::Layout::getPad(size_t offset, size_t align) {
|
|
size_t remainder = offset % align;
|
|
return (remainder > 0) ? (align - remainder) : 0;
|
|
}
|
|
|
|
} // namespace android
|
|
|