Index: lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
diff --git a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
index b536fe3c848a4d81241cb4b7f6e39c49313451de..6ad7ac6536ba755d570ee4a04438c4e9f457c3ec 100644 |
--- a/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
+++ b/lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeWriter.cpp |
@@ -16,6 +16,8 @@ |
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
#include "llvm/Support/raw_ostream.h" |
+#include <set> |
+ |
using namespace llvm; |
namespace { |
@@ -24,16 +26,26 @@ namespace { |
// bitcode. |
static bool DebugEmit = false; |
+// Maximum bits that can be printed out using method |
+// NaClBitstreamWriter::Emit(). |
jvoung (off chromium)
2015/05/20 22:40:09
Seems like this should be part of NaClBitstreamWri
Karl
2015/05/21 18:22:07
I agree. I originally put it there, but I didn't l
|
+static const unsigned MaxEmitFixedBits = 32; |
+ |
// Description of current block scope |
struct BlockScope { |
BlockScope(unsigned CurBlockID, size_t AbbrevIndexLimit) |
- : CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit) {} |
+ : CurBlockID(CurBlockID), AbbrevIndexLimit(AbbrevIndexLimit), |
+ OmittedAbbreviations(false) {} |
unsigned CurBlockID; |
// Defines the maximum value for abbreviation indices in block. |
size_t AbbrevIndexLimit; |
+ // Defines if an abbreviation definition was omitted (i.e. not |
+ // written) from this block. Used to turn off writing further |
+ // abbreviation definitions for this block. |
+ bool OmittedAbbreviations; |
void print(raw_ostream &Out) const { |
Out << "BlockScope(ID=" << CurBlockID << ", AbbrevIndexLimit=" |
- << AbbrevIndexLimit << ")"; |
+ << AbbrevIndexLimit << "OmittedAbbreviations = " |
jvoung (off chromium)
2015/05/20 22:40:10
= spacing consistency
previous ones just did X=Y
Karl
2015/05/21 18:22:08
Done.
|
+ << OmittedAbbreviations << ")"; |
} |
}; |
@@ -56,6 +68,9 @@ struct WriteState { |
NaClMungedBitcode::WriteResults Results; |
// The minimum number of bits allowed to be specified in a block. |
const unsigned BlockMinBits; |
+ // The set of block IDs for which abbreviation definitions have been |
+ // omitted in the blockinfo block. |
+ std::set<unsigned> BlocksWithOmittedAbbrevs; |
jvoung (off chromium)
2015/05/20 22:40:10
Would DenseSet be better?
I suppose there are onl
Karl
2015/05/21 18:22:07
I did not expect the set to get much larger than 8
|
WriteState(const NaClMungedBitcode::WriteFlags &Flags) |
: Flags(Flags), |
@@ -90,6 +105,24 @@ struct WriteState { |
return ScopeStack.back().AbbrevIndexLimit; |
} |
+ // Returns whether any abbreviation definitions were not written to |
+ // the bitcode buffer. |
+ bool curBlockHasOmittedAbbreviations() const { |
+ assert(!ScopeStack.empty()); |
+ return ScopeStack.back().OmittedAbbreviations |
+ || BlocksWithOmittedAbbrevs.count(getCurWriteBlockID()); |
+ } |
+ |
+ // Marks that an abbreviation definition is being omitted (i.e. not |
+ // written) for the current block. |
+ void markCurrentBlockWithOmittedAbbreviations() { |
+ assert(!ScopeStack.empty()); |
+ ScopeStack.back().OmittedAbbreviations = true; |
+ if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) |
+ BlocksWithOmittedAbbrevs.insert(SetBID); |
+ return; |
jvoung (off chromium)
2015/05/20 22:40:10
The return doesn't seem to do much so may be bette
Karl
2015/05/21 18:22:08
Hmm. I guess this is a leftover of an earlier vers
|
+ } |
+ |
// Converts the abbreviation record to the corresponding abbreviation. |
// Returns nullptr if unable to build abbreviation. |
NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); |
@@ -97,7 +130,8 @@ struct WriteState { |
// Emits the given record to the bitcode file. Returns true if |
// successful. |
bool LLVM_ATTRIBUTE_UNUSED_RESULT |
- emitRecord(NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record); |
+ emitRecord(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record); |
// Enter the given block |
bool LLVM_ATTRIBUTE_UNUSED_RESULT |
@@ -118,6 +152,22 @@ struct WriteState { |
return true; |
} |
+ void WriteRecord(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record, |
+ bool UsesDefaultAbbrev) { |
+ if (UsesDefaultAbbrev) |
+ Writer.EmitRecord(Record.Code, Record.Values); |
+ else |
+ Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); |
+ |
+ } |
+ |
+ // Returns true if the abbreviation index defines an anbbreviation |
jvoung (off chromium)
2015/05/20 22:40:09
anbbreviation -> ?
Karl
2015/05/21 18:22:07
Fixed.
|
+ // that can be applied to the record. |
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT |
+ canApplyAbbreviation(NaClBitstreamWriter &Writer, |
+ const NaClBitcodeAbbrevRecord &Record); |
+ |
// Completes the write. |
NaClMungedBitcode::WriteResults &finish(NaClBitstreamWriter &Writer, |
bool RecoverSilently); |
@@ -185,6 +235,58 @@ bool WriteState::enterBlock(NaClBitstreamWriter &Writer, uint64_t WriteBlockID, |
return true; |
} |
+bool WriteState::canApplyAbbreviation( |
+ NaClBitstreamWriter &Writer, const NaClBitcodeAbbrevRecord &Record) { |
Karl
2015/05/20 20:32:04
Added following two lines to make sure that the bl
jvoung (off chromium)
2015/05/20 22:40:09
Does the Writer.getAbbreviation(...); if (Abbrev =
Karl
2015/05/21 18:22:07
This check helps. I didn't see the case until the
|
+ if (Record.Abbrev > getCurAbbrevIndexLimit()) |
+ return false; |
+ |
+ const NaClBitCodeAbbrev *Abbrev = Writer.getAbbreviation(Record.Abbrev); |
+ if (Abbrev == nullptr) |
+ return false; |
+ |
+ // Merge record code into values and then match abbreviation. |
+ NaClBitcodeValues Values(Record); |
+ size_t ValueIndex = 0; |
+ size_t ValuesSize = Values.size(); |
+ size_t AbbrevIndex = 0; |
+ size_t AbbrevSize = Abbrev->getNumOperandInfos(); |
+ bool FoundArray = false; |
+ while (ValueIndex < ValuesSize && AbbrevIndex < AbbrevSize) { |
+ const NaClBitCodeAbbrevOp *Op = &Abbrev->getOperandInfo(AbbrevIndex++); |
+ uint64_t Value = Values[ValueIndex++]; |
+ if (Op->getEncoding() == NaClBitCodeAbbrevOp::Array) { |
+ if (AbbrevIndex + 1 != AbbrevSize) |
+ return false; |
+ Op = &Abbrev->getOperandInfo(AbbrevIndex); |
+ --AbbrevIndex; // i.e. don't advance to next abbreviation op. |
+ FoundArray = true; |
+ } |
+ switch (Op->getEncoding()) { |
+ case NaClBitCodeAbbrevOp::Literal: |
+ if (Value != Op->getValue()) |
+ return false; |
+ continue; |
+ case NaClBitCodeAbbrevOp::Fixed: |
+ if (Value >= (static_cast<uint64_t>(1) < MaxEmitFixedBits) |
jvoung (off chromium)
2015/05/20 22:40:10
I assume this should actually be a shift and not (
Karl
2015/05/21 18:22:07
Yes. Fixing.
|
+ || NaClBitsNeededForValue(Value) > Op->getValue()) |
+ return false; |
+ continue; |
+ case NaClBitCodeAbbrevOp::VBR: |
+ if (Op->getValue() < 2) |
+ return false; |
+ continue; |
+ case NaClBitCodeAbbrevOp::Array: |
+ // This should not happen |
jvoung (off chromium)
2015/05/20 22:40:10
llvm_unreachable(...);
Karl
2015/05/21 18:22:08
Done.
|
+ return false; |
+ case NaClBitCodeAbbrevOp::Char6: |
+ if (!Op->isChar6(Value)) |
+ return false; |
+ continue; |
+ } |
+ } |
+ return ValueIndex == ValuesSize && (FoundArray || AbbrevIndex == AbbrevSize); |
+} |
+ |
NaClMungedBitcode::WriteResults &WriteState::finish( |
NaClBitstreamWriter &Writer, bool RecoverSilently) { |
// Be sure blocks are balanced. |
@@ -275,19 +377,29 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
RecoverableError() |
<< "Uses illegal abbreviation index in define abbreviation record: " |
<< Record << "\n"; |
+ markCurrentBlockWithOmittedAbbreviations(); |
if (!Flags.getTryToRecover()) |
jvoung (off chromium)
2015/05/20 22:40:10
Might be simpler to just return now like the other
Karl
2015/05/21 18:22:07
I agree that the check for omitted abbreviations s
|
return false; |
} |
+ if (curBlockHasOmittedAbbreviations()) { |
+ // If reached, a previous abbreviation for the block was omitted. Can't |
+ // generate more abbreviations without having to fix abbreviation indices. |
+ RecoverableError() << "Ignoring abbreviation: " << Record << "\n"; |
+ return Flags.getTryToRecover(); |
+ } |
if (getCurWriteBlockID() != naclbitc::BLOCKINFO_BLOCK_ID |
&& Writer.getMaxCurAbbrevIndex() >= getCurAbbrevIndexLimit()) { |
RecoverableError() << "Exceeds abbreviation index limit of " |
<< getCurAbbrevIndexLimit() << ": " << Record << "\n"; |
// Recover by not writing. |
+ markCurrentBlockWithOmittedAbbreviations(); |
return Flags.getTryToRecover(); |
} |
NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); |
- if (Abbrev == NULL) |
+ if (Abbrev == nullptr) { |
+ markCurrentBlockWithOmittedAbbreviations(); |
return Flags.getTryToRecover(); |
+ } |
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID) { |
Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); |
} else { |
@@ -314,9 +426,15 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
} |
UsesDefaultAbbrev = true; |
} |
- if (!UsesDefaultAbbrev |
- && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { |
- // Illegal abbreviation index found. |
+ if (!UsesDefaultAbbrev && !canApplyAbbreviation(Writer, Record)) { |
+ // Can't apply abbreviation, figure out why. |
+ if (Writer.getAbbreviation(Record.Abbrev) != nullptr) { |
+ RecoverableError() << "Abbreviation doesn't apply to record: " |
jvoung (off chromium)
2015/05/20 22:40:09
So here the abbreviation exists, but doesn't apply
Karl
2015/05/21 18:22:07
Yes.
|
+ << Record << "\n"; |
+ UsesDefaultAbbrev = true; |
+ WriteRecord(Writer, Record, UsesDefaultAbbrev); |
jvoung (off chromium)
2015/05/20 22:40:09
This and the one below might be the first case whe
Karl
2015/05/21 18:22:08
Done.
|
+ return Flags.getTryToRecover(); |
+ } |
if (Flags.getWriteBadAbbrevIndex()) { |
jvoung (off chromium)
2015/05/20 22:40:10
Maybe add a comment here. This CL adds the "figure
Karl
2015/05/21 18:22:08
Removed the first comment, and added a comment to
|
Error() << "Uses illegal abbreviation index: " << Record << "\n"; |
// Generate bad abbreviation index so that the bitcode reader |
@@ -329,9 +447,9 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
} |
RecoverableError() << "Uses illegal abbreviation index: " |
<< Record << "\n"; |
- if (!Flags.getTryToRecover()) |
- return false; |
UsesDefaultAbbrev = true; |
+ WriteRecord(Writer, Record, UsesDefaultAbbrev); |
+ return Flags.getTryToRecover(); |
} |
if (getCurWriteBlockID() == naclbitc::BLOCKINFO_BLOCK_ID |
&& Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { |
@@ -347,10 +465,8 @@ bool WriteState::emitRecord(NaClBitstreamWriter &Writer, |
SetBID = Record.Values[0]; |
return true; |
} |
- if (UsesDefaultAbbrev) |
- Writer.EmitRecord(Record.Code, Record.Values); |
- else |
- Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); |
+ WriteRecord(Writer, Record, UsesDefaultAbbrev); |
+ break; |
} |
return true; |
} |
@@ -381,7 +497,7 @@ NaClBitCodeAbbrev *WriteState::buildAbbrev( |
if (Index >= NumValues) { |
RecoverableError() |
<< "Malformed abbreviation found. Expects " << NumAbbreviations |
- << " operands but ound " << Count << ": " << Record << "\n"; |
+ << " operands but found " << Count << ": " << Record << "\n"; |
return deleteAbbrev(Abbrev); |
} |
switch (Record.Values[Index++]) { |
@@ -438,8 +554,8 @@ NaClBitCodeAbbrev *WriteState::buildAbbrev( |
break; |
} |
default: |
- RecoverableError() << "Error: Bad literal flag " << Record.Values[Index] |
- << ": " << Record << "\n"; |
+ RecoverableError() << "Error: Bad abbreviation operand encoding " |
+ << Record.Values[Index-1] << ": " << Record << "\n"; |
return deleteAbbrev(Abbrev); |
} |
} |