Commit d63388ce authored by Kenton Varda's avatar Kenton Varda

Correctly handle inline fields that aren't present in the parent struct (i.e.…

Correctly handle inline fields that aren't present in the parent struct (i.e. because we're reading an older version of the struct that lacked those fields).
parent 03359f01
This diff is collapsed.
...@@ -27,10 +27,19 @@ ...@@ -27,10 +27,19 @@
#include "arena.h" #include "arena.h"
#include <string.h> #include <string.h>
#include <limits> #include <limits>
#include <stdlib.h>
namespace capnproto { namespace capnproto {
namespace internal { namespace internal {
namespace {
// This zero array is used only as a default value for inlined fields, which are limited
// to no more than 64 words.
static const AlignedData<64> ZERO = {{0}};
} // namespace
// ======================================================================================= // =======================================================================================
struct WireReference { struct WireReference {
...@@ -193,14 +202,16 @@ static_assert(REFERENCES * BITS_PER_REFERENCE / BITS_PER_BYTE / BYTES == sizeof( ...@@ -193,14 +202,16 @@ static_assert(REFERENCES * BITS_PER_REFERENCE / BITS_PER_BYTE / BYTES == sizeof(
struct WireHelpers { struct WireHelpers {
static CAPNPROTO_ALWAYS_INLINE(WordCount roundUpToWords(BitCount64 bits)) { static CAPNPROTO_ALWAYS_INLINE(WordCount roundUpToWords(BitCount64 bits)) {
static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
uint64_t bits2 = bits / BITS; return (bits + 63 * BITS) / BITS_PER_WORD;
return ((bits2 >> 6) + ((bits2 & 63) != 0)) * WORDS;
} }
static CAPNPROTO_ALWAYS_INLINE(WordCount roundUpToWords(ByteCount bytes)) { static CAPNPROTO_ALWAYS_INLINE(WordCount roundUpToWords(ByteCount bytes)) {
static_assert(sizeof(word) == 8, "This code assumes 64-bit words."); static_assert(sizeof(word) == 8, "This code assumes 64-bit words.");
uint bytes2 = bytes / BYTES; return (bytes + 7 * BYTES) / BYTES_PER_WORD;
return ((bytes2 >> 3) + ((bytes2 & 7) != 0)) * WORDS; }
static CAPNPROTO_ALWAYS_INLINE(ByteCount roundUpToBytes(BitCount bits)) {
return (bits + 7 * BITS) / BITS_PER_BYTE;
} }
static CAPNPROTO_ALWAYS_INLINE(word* allocate( static CAPNPROTO_ALWAYS_INLINE(word* allocate(
...@@ -944,6 +955,7 @@ struct WireHelpers { ...@@ -944,6 +955,7 @@ struct WireHelpers {
}; };
// ======================================================================================= // =======================================================================================
// StructBuilder
StructBuilder StructBuilder::initRoot( StructBuilder StructBuilder::initRoot(
SegmentBuilder* segment, word* location, StructSize size) { SegmentBuilder* segment, word* location, StructSize size) {
...@@ -1022,6 +1034,9 @@ StructReader StructBuilder::asReader() const { ...@@ -1022,6 +1034,9 @@ StructReader StructBuilder::asReader() const {
0xffffffff * BYTES, 0xffff * REFERENCES, std::numeric_limits<int>::max()); 0xffffffff * BYTES, 0xffff * REFERENCES, std::numeric_limits<int>::max());
} }
// =======================================================================================
// StructReader
StructReader StructReader::readRootTrusted(const word* location) { StructReader StructReader::readRootTrusted(const word* location) {
return WireHelpers::readStructReference(nullptr, reinterpret_cast<const WireReference*>(location), return WireHelpers::readStructReference(nullptr, reinterpret_cast<const WireReference*>(location),
nullptr, std::numeric_limits<int>::max()); nullptr, std::numeric_limits<int>::max());
...@@ -1049,6 +1064,24 @@ StructReader StructReader::getStructField( ...@@ -1049,6 +1064,24 @@ StructReader StructReader::getStructField(
return WireHelpers::readStructReference(segment, ref, defaultValue, nestingLimit); return WireHelpers::readStructReference(segment, ref, defaultValue, nestingLimit);
} }
StructReader StructReader::getInlineStructField(
ByteCount dataOffset, ByteCount inlineDataSize,
WireReferenceCount refIndex, WireReferenceCount inlineRefCount) const {
if (dataOffset + inlineDataSize <= dataSize &&
refIndex + inlineRefCount <= referenceCount) {
return StructReader(
segment, reinterpret_cast<const byte*>(data) + dataOffset,
// WireReference is incomplete here so we have to cast around... Bah.
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + refIndex * WORDS_PER_REFERENCE),
inlineDataSize, inlineRefCount,
nestingLimit);
} else {
// Return empty struct.
return StructReader();
}
}
ListReader StructReader::getListField( ListReader StructReader::getListField(
WireReferenceCount refIndex, FieldSize expectedElementSize, const word* defaultValue) const { WireReferenceCount refIndex, FieldSize expectedElementSize, const word* defaultValue) const {
const WireReference* ref = refIndex >= referenceCount ? nullptr : references + refIndex; const WireReference* ref = refIndex >= referenceCount ? nullptr : references + refIndex;
...@@ -1056,6 +1089,52 @@ ListReader StructReader::getListField( ...@@ -1056,6 +1089,52 @@ ListReader StructReader::getListField(
segment, ref, defaultValue, expectedElementSize, nestingLimit); segment, ref, defaultValue, expectedElementSize, nestingLimit);
} }
ListReader StructReader::getInlineDataListField(
ByteCount offset, ElementCount elementCount, FieldSize elementSize) const {
if (offset + WireHelpers::roundUpToBytes(
elementCount * bitsPerElement(elementSize)) <= dataSize) {
return ListReader(
segment, reinterpret_cast<const byte*>(data) + offset, nullptr,
elementCount, bytesPerElement(elementSize), 0 * REFERENCES / ELEMENTS,
nestingLimit);
} else {
// Return zeros.
return ListReader(elementCount);
}
}
ListReader StructReader::getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const {
if (offset + elementCount * (1 * REFERENCES / ELEMENTS) <= referenceCount) {
return ListReader(
segment, nullptr,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + offset * WORDS_PER_REFERENCE),
elementCount, 0 * BYTES / ELEMENTS, 1 * REFERENCES / ELEMENTS,
nestingLimit);
} else {
// Return nulls.
return ListReader(elementCount);
}
}
ListReader StructReader::getInlineStructListField(
ByteCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const {
if (dataOffset + elementSize.dataBytes <= dataSize &&
ptrOffset + elementSize.pointers <= referenceCount) {
return ListReader(
segment, reinterpret_cast<const byte*>(data) + dataOffset,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + ptrOffset * WORDS_PER_REFERENCE),
elementCount, elementSize.dataBytes / ELEMENTS, elementSize.pointers / ELEMENTS,
elementSize.dataBytes, elementSize.pointers, nestingLimit);
} else {
// Return empty structs.
return ListReader(elementCount);
}
}
Text::Reader StructReader::getTextField( Text::Reader StructReader::getTextField(
WireReferenceCount refIndex, const void* defaultValue, ByteCount defaultSize) const { WireReferenceCount refIndex, const void* defaultValue, ByteCount defaultSize) const {
const WireReference* ref = refIndex >= referenceCount ? nullptr : references + refIndex; const WireReference* ref = refIndex >= referenceCount ? nullptr : references + refIndex;
...@@ -1068,6 +1147,20 @@ Data::Reader StructReader::getDataField( ...@@ -1068,6 +1147,20 @@ Data::Reader StructReader::getDataField(
return WireHelpers::readDataReference(segment, ref, defaultValue, defaultSize); return WireHelpers::readDataReference(segment, ref, defaultValue, defaultSize);
} }
Data::Reader StructReader::getInlineDataField(ByteCount offset, ByteCount size) const {
// TODO(soon): Bounds check! Needs to fall back to some common zero'd region.
if (offset + size <= dataSize) {
return Data::Reader(reinterpret_cast<const char*>(reinterpret_cast<const byte*>(data) + offset),
size / BYTES);
} else {
CHECK(size < sizeof(ZERO) * BYTES);
return Data::Reader(reinterpret_cast<const char*>(ZERO.bytes), size / BYTES);
}
}
// =======================================================================================
// ListBuilder
StructBuilder ListBuilder::getStructElement(ElementCount index, StructSize elementSize) const { StructBuilder ListBuilder::getStructElement(ElementCount index, StructSize elementSize) const {
// TODO: Inline this method? // TODO: Inline this method?
ByteCount indexByte = ElementCount64(index) * stepBytes; ByteCount indexByte = ElementCount64(index) * stepBytes;
...@@ -1134,6 +1227,15 @@ ListReader ListBuilder::asReader(StructSize elementSize) const { ...@@ -1134,6 +1227,15 @@ ListReader ListBuilder::asReader(StructSize elementSize) const {
elementSize.dataBytes, elementSize.pointers, std::numeric_limits<int>::max()); elementSize.dataBytes, elementSize.pointers, std::numeric_limits<int>::max());
} }
// =======================================================================================
// ListReader
ListReader::ListReader(ElementCount elementCount)
: segment(nullptr), data(ZERO.bytes),
pointers(reinterpret_cast<const WireReference*>(data)), elementCount(elementCount),
stepBytes(0 * BYTES / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS),
structDataSize(0), structReferenceCount(0), nestingLimit(0) {}
StructReader ListReader::getStructElement(ElementCount index) const { StructReader ListReader::getStructElement(ElementCount index) const {
// TODO: Inline this method? // TODO: Inline this method?
VALIDATE_INPUT((segment == nullptr) | (nestingLimit > 0), VALIDATE_INPUT((segment == nullptr) | (nestingLimit > 0),
......
...@@ -422,9 +422,9 @@ public: ...@@ -422,9 +422,9 @@ public:
// struct reference, which in turn points at the struct value. The default value is allowed to // struct reference, which in turn points at the struct value. The default value is allowed to
// be null, in which case an empty struct is used. // be null, in which case an empty struct is used.
CAPNPROTO_ALWAYS_INLINE(StructReader getInlineStructField( StructReader getInlineStructField(
ByteCount dataOffset, ByteCount inlineDataSize, ByteCount dataOffset, ByteCount inlineDataSize,
WireReferenceCount refIndex, WireReferenceCount inlineRefCount) const); WireReferenceCount refIndex, WireReferenceCount inlineRefCount) const;
// Gets an inlined struct field, given the position and size of the data and pointer sections. // Gets an inlined struct field, given the position and size of the data and pointer sections.
ListReader getListField(WireReferenceCount refIndex, FieldSize expectedElementSize, ListReader getListField(WireReferenceCount refIndex, FieldSize expectedElementSize,
...@@ -432,17 +432,17 @@ public: ...@@ -432,17 +432,17 @@ public:
// Get the list field at the given index in the reference segment, or the default value if not // Get the list field at the given index in the reference segment, or the default value if not
// initialized. The default value is allowed to be null, in which case an empty list is used. // initialized. The default value is allowed to be null, in which case an empty list is used.
CAPNPROTO_ALWAYS_INLINE(ListReader getInlineDataListField( ListReader getInlineDataListField(
ByteCount offset, ElementCount elementCount, FieldSize elementSize) const); ByteCount offset, ElementCount elementCount, FieldSize elementSize) const;
// Get an inline list field. // Get an inline list field.
CAPNPROTO_ALWAYS_INLINE(ListReader getInlinePointerListField( ListReader getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const); WireReferenceCount offset, ElementCount elementCount) const;
// Get an inline list field. // Get an inline list field.
CAPNPROTO_ALWAYS_INLINE(ListReader getInlineStructListField( ListReader getInlineStructListField(
ByteCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount, ByteCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const); StructSize elementSize) const;
// Get an inline struct list field. // Get an inline struct list field.
Text::Reader getTextField(WireReferenceCount refIndex, Text::Reader getTextField(WireReferenceCount refIndex,
...@@ -453,8 +453,7 @@ public: ...@@ -453,8 +453,7 @@ public:
const void* defaultValue, ByteCount defaultSize) const; const void* defaultValue, ByteCount defaultSize) const;
// Gets the data field, or the given default value if not initialized. // Gets the data field, or the given default value if not initialized.
CAPNPROTO_ALWAYS_INLINE(Data::Reader getInlineDataField( Data::Reader getInlineDataField(ByteCount offset, ByteCount size) const;
ByteCount offset, ByteCount size) const);
// Gets the inline data field. // Gets the inline data field.
WireReferenceCount getReferenceCount() { return referenceCount; } WireReferenceCount getReferenceCount() { return referenceCount; }
...@@ -577,6 +576,10 @@ public: ...@@ -577,6 +576,10 @@ public:
stepBytes(0 * BYTES / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS), stepBytes(0 * BYTES / ELEMENTS), stepPointers(0 * REFERENCES / ELEMENTS),
structDataSize(0), structReferenceCount(0), nestingLimit(0) {} structDataSize(0), structReferenceCount(0), nestingLimit(0) {}
ListReader(ElementCount elementCount);
// Constructs a ListReader representing a list where all elements are zero. Intended to be used
// only for inlined lists that are out-of-bounds in the parent struct.
inline ElementCount size(); inline ElementCount size();
// The number of elements in the list. // The number of elements in the list.
...@@ -810,58 +813,6 @@ T StructReader::getDataField(ElementCount offset, typename MaskType<T>::Type mas ...@@ -810,58 +813,6 @@ T StructReader::getDataField(ElementCount offset, typename MaskType<T>::Type mas
return unmask<T>(getDataField<typename MaskType<T>::Type>(offset), mask); return unmask<T>(getDataField<typename MaskType<T>::Type>(offset), mask);
} }
inline StructReader StructReader::getInlineStructField(
ByteCount dataOffset, ByteCount inlineDataSize,
WireReferenceCount refIndex, WireReferenceCount inlineRefCount) const {
// TODO(soon): Too complicated to be inlined?
return StructReader(
segment, reinterpret_cast<const byte*>(data) + dataOffset,
// WireReference is incomplete here so we have to cast around... Bah.
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + refIndex * WORDS_PER_REFERENCE),
inlineDataSize * (dataOffset + inlineDataSize <= dataSize),
inlineRefCount * (refIndex + inlineRefCount <= referenceCount),
nestingLimit);
}
inline ListReader StructReader::getInlineDataListField(
ByteCount offset, ElementCount elementCount, FieldSize elementSize) const {
// TODO(soon): Bounds check! Needs to fall back to some common zero'd region.
return ListReader(
segment, reinterpret_cast<const byte*>(data) + offset, nullptr,
elementCount, bytesPerElement(elementSize), 0 * REFERENCES / ELEMENTS,
nestingLimit);
}
inline ListReader StructReader::getInlinePointerListField(
WireReferenceCount offset, ElementCount elementCount) const {
// TODO(soon): Bounds check! Needs to fall back to some common zero'd region.
return ListReader(
segment, nullptr,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + offset * WORDS_PER_REFERENCE),
elementCount, 0 * BYTES / ELEMENTS, 1 * REFERENCES / ELEMENTS,
nestingLimit);
}
inline ListReader StructReader::getInlineStructListField(
ByteCount dataOffset, WireReferenceCount ptrOffset, ElementCount elementCount,
StructSize elementSize) const {
// TODO(soon): Bounds check! Needs to fall back to some common zero'd region.
return ListReader(
segment, reinterpret_cast<const byte*>(data) + dataOffset,
reinterpret_cast<const WireReference*>(
reinterpret_cast<const word*>(references) + ptrOffset * WORDS_PER_REFERENCE),
elementCount, elementSize.dataBytes / ELEMENTS, elementSize.pointers / ELEMENTS,
elementSize.dataBytes, elementSize.pointers, nestingLimit);
}
inline Data::Reader StructReader::getInlineDataField(ByteCount offset, ByteCount size) const {
// TODO(soon): Bounds check! Needs to fall back to some common zero'd region.
return Data::Reader(reinterpret_cast<const char*>(reinterpret_cast<const byte*>(data) + offset),
size / BYTES);
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
inline ElementCount ListBuilder::size() { return elementCount; } inline ElementCount ListBuilder::size() { return elementCount; }
......
...@@ -1152,6 +1152,139 @@ void genericCheckInlineDefaults(Reader reader) { ...@@ -1152,6 +1152,139 @@ void genericCheckInlineDefaults(Reader reader) {
} }
} }
template <typename Builder>
void genericInitEmptyInlineLists(Builder builder) {
// Initialize all inline lists in TestInlineDefaults to "empty" values, of the same sizes that
// genericInitInlineDefaults() would create.
builder.initNormal();
{
auto lists = builder.initLists();
ASSERT_EQ(2u, lists.getVoidList().size());
ASSERT_EQ(3u, lists.getBoolList().size());
ASSERT_EQ(4u, lists.getUInt8List().size());
ASSERT_EQ(5u, lists.getUInt16List().size());
ASSERT_EQ(6u, lists.getUInt32List().size());
ASSERT_EQ(7u, lists.getUInt64List().size());
ASSERT_EQ(8u, lists.getTextList().size());
ASSERT_EQ(2u, lists.getStructList0().size());
ASSERT_EQ(3u, lists.getStructList1().size());
ASSERT_EQ(4u, lists.getStructList8().size());
ASSERT_EQ(2u, lists.getStructList16().size());
ASSERT_EQ(3u, lists.getStructList32().size());
ASSERT_EQ(4u, lists.getStructList64().size());
ASSERT_EQ(2u, lists.getStructList128().size());
ASSERT_EQ(3u, lists.getStructList192().size());
ASSERT_EQ(4u, lists.getStructList0p().size());
ASSERT_EQ(2u, lists.getStructList1p().size());
ASSERT_EQ(3u, lists.getStructList8p().size());
ASSERT_EQ(4u, lists.getStructList16p().size());
ASSERT_EQ(2u, lists.getStructList32p().size());
ASSERT_EQ(3u, lists.getStructList64p().size());
ASSERT_EQ(4u, lists.getStructList128p().size());
ASSERT_EQ(2u, lists.getStructList192p().size());
}
{
auto sl = builder.initStructLists();
sl.initList0(2);
sl.initList1(2);
sl.initList8(2);
sl.initList16(2);
sl.initList32(2);
sl.initList64(2);
sl.initListP(2);
}
{
auto ll = builder.initListLists();
{
auto l = ll.initInt32ListList(3);
l.init(0, 3);
l.init(1, 2);
l.init(2, 1);
}
{
auto l = ll.initTextListList(3);
l.init(0, 2);
l.init(1, 1);
l.init(2, 2);
}
{
auto l = ll.initStructListList(2);
l.init(0, 2);
l.init(1, 1);
}
{
auto l = ll.initInt32InlineListList(2);
EXPECT_EQ(7u, l[0].size());
EXPECT_EQ(7u, l[1].size());
}
{
auto l = ll.initTextInlineListList(3);
EXPECT_EQ(5u, l[0].size());
EXPECT_EQ(5u, l[1].size());
EXPECT_EQ(5u, l[2].size());
}
{
auto l = ll.initStructInlineListList(3);
EXPECT_EQ(3u, l[0].size());
EXPECT_EQ(3u, l[1].size());
EXPECT_EQ(3u, l[2].size());
}
ll.initInlineDataList(5);
{
auto l = ll.initInt32InlineListListList(3);
l.init(0, 3);
l.init(1, 2);
l.init(2, 1);
EXPECT_EQ(2u, l[0][0].size());
EXPECT_EQ(2u, l[0][1].size());
EXPECT_EQ(2u, l[0][2].size());
EXPECT_EQ(2u, l[1][0].size());
EXPECT_EQ(2u, l[1][1].size());
EXPECT_EQ(2u, l[2][0].size());
}
{
auto l = ll.initTextInlineListListList(2);
l.init(0, 2);
l.init(1, 1);
EXPECT_EQ(5u, l[0][0].size());
EXPECT_EQ(5u, l[0][1].size());
EXPECT_EQ(5u, l[1][0].size());
}
{
auto l = ll.initStructInlineListListList(2);
l.init(0, 2);
l.init(1, 1);
EXPECT_EQ(3u, l[0][0].size());
EXPECT_EQ(3u, l[0][1].size());
EXPECT_EQ(3u, l[1][0].size());
}
{
auto l = ll.initInlineDataListList(2);
l.init(0, 3);
l.init(1, 2);
}
}
}
} // namespace } // namespace
void initTestMessage(TestAllTypes::Builder builder) { genericInitTestMessage(builder); } void initTestMessage(TestAllTypes::Builder builder) { genericInitTestMessage(builder); }
......
...@@ -752,6 +752,13 @@ enforceFixed (Just (Located pos (requestedDataSize, requestedPointerCount))) ...@@ -752,6 +752,13 @@ enforceFixed (Just (Located pos (requestedDataSize, requestedPointerCount)))
\backwards-compatibility." \backwards-compatibility."
actualPointerCount requestedPointerCount actualPointerCount requestedPointerCount
recover () $ when (dataSectionBits actualDataSize > maxStructDataWords * 64) $
makeError pos $ printf "Struct is too big. Maximum data section size is %d bytes."
(maxStructDataWords * 8)
recover () $ when (actualPointerCount > maxStructPointers) $
makeError pos $ printf "Struct is too big. Maximum pointer section size is %d."
maxStructPointers
return (validatedRequestedDataSize, requestedPointerCount) return (validatedRequestedDataSize, requestedPointerCount)
------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------
...@@ -891,6 +898,9 @@ compileDecl scope ...@@ -891,6 +898,9 @@ compileDecl scope
DescUnion u -> Just (u, unionFieldDiscriminantMap u ! number) DescUnion u -> Just (u, unionFieldDiscriminantMap u ! number)
_ -> Nothing _ -> Nothing
typeDesc <- compileType scope typeExp typeDesc <- compileType scope typeExp
recover () $ when (fieldSizeInBits (fieldSize typeDesc) > maxInlineFieldBits) $
makeError pos $ printf "Inlined fields cannot exceed %d bytes."
(div maxInlineFieldBits 8)
defaultDesc <- case defaultValue of defaultDesc <- case defaultValue of
Just (Located defaultPos value) -> do Just (Located defaultPos value) -> do
result <- fmap Just (compileValue defaultPos typeDesc value) result <- fmap Just (compileValue defaultPos typeDesc value)
......
...@@ -39,6 +39,14 @@ import Grammar(AnnotationTarget(..)) ...@@ -39,6 +39,14 @@ import Grammar(AnnotationTarget(..))
-- ordinal is 65534. -- ordinal is 65534.
maxOrdinal = 65534 :: Integer maxOrdinal = 65534 :: Integer
-- Inline fields can be 64 words. (This limit is relied upon by implementations which may need
-- to produce some sort of default value when an inlined field is not actually present in the
-- struct.)
maxInlineFieldBits = 64 * 64 :: Integer
maxStructDataWords = 65536 :: Integer
maxStructPointers = 65536 :: Integer
type ByteString = [Word8] type ByteString = [Word8]
data Desc = DescFile FileDesc data Desc = DescFile FileDesc
...@@ -290,6 +298,11 @@ data FieldSize = SizeVoid ...@@ -290,6 +298,11 @@ data FieldSize = SizeVoid
| SizeReference | SizeReference
| SizeInlineComposite DataSectionSize Integer | SizeInlineComposite DataSectionSize Integer
fieldSizeInBits SizeVoid = 0
fieldSizeInBits (SizeData d) = dataSizeInBits d
fieldSizeInBits SizeReference = 64
fieldSizeInBits (SizeInlineComposite ds pc) = dataSectionBits ds + pc * 64
data FieldOffset = VoidOffset data FieldOffset = VoidOffset
| DataOffset DataSize Integer | DataOffset DataSize Integer
| PointerOffset Integer | PointerOffset Integer
...@@ -361,7 +374,7 @@ typeName scope (InlineStructType desc) = descQualifiedName scope (DescStruct des ...@@ -361,7 +374,7 @@ typeName scope (InlineStructType desc) = descQualifiedName scope (DescStruct des
typeName scope (InterfaceType desc) = descQualifiedName scope (DescInterface desc) typeName scope (InterfaceType desc) = descQualifiedName scope (DescInterface desc)
typeName scope (ListType t) = "List(" ++ typeName scope t ++ ")" typeName scope (ListType t) = "List(" ++ typeName scope t ++ ")"
typeName scope (InlineListType t s) = printf "InlineList(%s, %d)" (typeName scope t) s typeName scope (InlineListType t s) = printf "InlineList(%s, %d)" (typeName scope t) s
typeName scope (InlineDataType s) = printf "InlineData(%d)" s typeName _ (InlineDataType s) = printf "InlineData(%d)" s
-- Computes the qualified name for the given descriptor within the given scope. -- Computes the qualified name for the given descriptor within the given scope.
-- At present the scope is only used to determine whether the target is in the same file. If -- At present the scope is only used to determine whether the target is in the same file. If
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment