Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 //===- NaClBitcodeMungeWriter.cpp - Write munged bitcode --------*- C++ -*-===// | |
| 2 // | |
| 3 // The LLVM Compiler Infrastructure | |
| 4 // | |
| 5 // This file is distributed under the University of Illinois Open Source | |
| 6 // License. See LICENSE.TXT for details. | |
| 7 // | |
| 8 //===----------------------------------------------------------------------===// | |
| 9 // | |
| 10 // Implements method NaClMungedBitcode.write(), which writes out a munged | |
| 11 // list of bitcode records using a bitstream writer. | |
| 12 | |
| 13 #include "llvm/Bitcode/NaCl/NaClBitcodeMungeUtils.h" | |
| 14 | |
| 15 #include "llvm/Bitcode/NaCl/NaClBitstreamWriter.h" | |
| 16 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" | |
| 17 | |
| 18 using namespace llvm; | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // For debugging. When true, shows each PNaCl record that is | |
| 23 // emitted to the bitcode file. | |
| 24 static bool DebugEmitRecord = false; | |
| 25 | |
| 26 // State of bitcode writing. | |
| 27 struct WriteState { | |
| 28 // The block ID associated with the block being written. | |
| 29 int WriteBlockID = -1; | |
| 30 // The SetBID for the blockinfo block. | |
| 31 int SetBID = -1; | |
| 32 // The stack of maximum abbreviation indices allowed by block enter record. | |
| 33 SmallVector<uint64_t, 3> AbbrevIndexLimitStack; | |
| 34 // The set of write flags to use. | |
| 35 const NaClMungedBitcode::WriteFlags &Flags; | |
| 36 // The results of the attempted write. | |
| 37 NaClMungedBitcode::WriteResults Results; | |
| 38 | |
| 39 WriteState(const NaClMungedBitcode::WriteFlags &Flags) : Flags(Flags) {} | |
| 40 | |
| 41 // Returns stream to print error message to. | |
| 42 raw_ostream &Error() { | |
| 43 Results.HasErrors = true; | |
| 44 return errs() << "Error (Block " << WriteBlockID << "): "; | |
| 45 } | |
| 46 | |
| 47 // Returns stream to print error message to, assuming that | |
| 48 // the error message can be repaired if Flags.TryToRecover is true. | |
| 49 raw_ostream &RecoverableError() { | |
| 50 if (Flags.TryToRecover) | |
| 51 Results.HasRepairs = true; | |
| 52 return Error(); | |
| 53 } | |
| 54 | |
| 55 // Converts the abbreviation record to the corresponding abbreviation. | |
| 56 // Returns nullptr if unable to build abbreviation. | |
| 57 NaClBitCodeAbbrev *buildAbbrev(const NaClBitcodeAbbrevRecord &Record); | |
| 58 | |
| 59 // Emits the given record to the bitcode file. Returns true if | |
| 60 // successful. | |
| 61 bool emitRecord(NaClBitstreamWriter &Writer, | |
| 62 const NaClBitcodeAbbrevRecord &Record); | |
| 63 | |
| 64 // Adds any missing end blocks to written bitcode. | |
| 65 void writeMissingEndBlocks(NaClBitstreamWriter &Writer) { | |
| 66 while (!AbbrevIndexLimitStack.empty()) { | |
| 67 Writer.ExitBlock(); | |
| 68 AbbrevIndexLimitStack.pop_back(); | |
| 69 } | |
| 70 } | |
| 71 }; | |
| 72 | |
| 73 bool WriteState::emitRecord(NaClBitstreamWriter &Writer, | |
| 74 const NaClBitcodeAbbrevRecord &Record) { | |
| 75 size_t NumValues = Record.Values.size(); | |
| 76 if (DebugEmitRecord) { | |
| 77 errs() << "Emit " << Record.Abbrev << ": <" << Record.Code; | |
| 78 for (size_t i = 0; i < NumValues; ++i) { | |
| 79 errs() << ", " << Record.Values[i]; | |
| 80 } | |
| 81 errs() << ">\n"; | |
| 82 } | |
| 83 | |
| 84 switch (Record.Code) { | |
| 85 case naclbitc::BLK_CODE_ENTER: { | |
| 86 unsigned NumBits = naclbitc::DEFAULT_MAX_ABBREV; | |
|
jvoung (off chromium)
2015/05/06 22:08:09
Should this also be NaClBitsNeededForValue( naclbi
Karl
2015/05/07 20:09:18
Good catch. Fixing!
| |
| 87 WriteBlockID = -1; | |
| 88 if (Record.Abbrev != naclbitc::ENTER_SUBBLOCK) { | |
| 89 RecoverableError() | |
| 90 << "Uses illegal abbreviation index in enter block record: " | |
| 91 << Record << "\n"; | |
| 92 if (!Flags.TryToRecover) | |
| 93 return false; | |
| 94 } | |
| 95 if (NumValues == 2) { | |
| 96 WriteBlockID = Record.Values[0]; | |
| 97 NumBits = Record.Values[1]; | |
| 98 if (NumBits > 32 || NumBits < 2) { | |
| 99 RecoverableError() | |
| 100 << "Bit size " << NumBits << " for record should be " | |
| 101 << (NumBits > 32 ? "<= 32" : ">= 2") << ": " << Record << "\n"; | |
| 102 if (!Flags.TryToRecover) | |
| 103 return false; | |
| 104 NumBits = 32; | |
| 105 } | |
| 106 } else { | |
| 107 Error() << "Values for enter record should be of size 2, but found " | |
| 108 << NumValues << ": " << Record << "\n"; | |
| 109 return false; | |
| 110 } | |
| 111 uint64_t MaxAbbrev = (static_cast<uint64_t>(1) << NumBits) - 1; | |
| 112 AbbrevIndexLimitStack.push_back(MaxAbbrev); | |
| 113 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { | |
| 114 unsigned DefaultMaxBits = | |
| 115 NaClBitsNeededForValue(naclbitc::DEFAULT_MAX_ABBREV); | |
| 116 if (NumBits != DefaultMaxBits) { | |
| 117 RecoverableError() | |
| 118 << "Numbits entry for abbreviations record not " | |
| 119 << DefaultMaxBits << " but found " << NumBits << | |
| 120 ": " << Record << "\n"; | |
| 121 if (!Flags.TryToRecover) | |
| 122 return false; | |
| 123 } | |
| 124 Writer.EnterBlockInfoBlock(); | |
| 125 } else { | |
| 126 NaClBitcodeSelectorAbbrev CurCodeLen(MaxAbbrev); | |
| 127 Writer.EnterSubblock(WriteBlockID, CurCodeLen); | |
| 128 } | |
| 129 break; | |
| 130 } | |
| 131 case naclbitc::BLK_CODE_EXIT: | |
| 132 if (Record.Abbrev != naclbitc::END_BLOCK) { | |
| 133 RecoverableError() | |
| 134 << "Uses illegal abbreviation index in exit block record: " | |
| 135 << Record << "\n"; | |
| 136 if (!Flags.TryToRecover) | |
| 137 return false; | |
| 138 } | |
| 139 if (NumValues != 0) { | |
| 140 RecoverableError() << "Exit block should not have values: " | |
| 141 << Record << "\n"; | |
| 142 if (!Flags.TryToRecover) | |
| 143 return false; | |
| 144 } | |
| 145 if (!AbbrevIndexLimitStack.empty()) | |
| 146 AbbrevIndexLimitStack.pop_back(); | |
| 147 Writer.ExitBlock(); | |
| 148 break; | |
| 149 case naclbitc::BLK_CODE_DEFINE_ABBREV: { | |
| 150 if (Record.Abbrev != naclbitc::DEFINE_ABBREV) { | |
| 151 RecoverableError() | |
| 152 << "Uses illegal abbreviation index in define abbreviation record: " | |
| 153 << Record << "\n"; | |
| 154 if (!Flags.TryToRecover) | |
| 155 return false; | |
| 156 } | |
| 157 NaClBitCodeAbbrev *Abbrev = buildAbbrev(Record); | |
| 158 if (Abbrev == NULL) | |
| 159 return Flags.TryToRecover; | |
| 160 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID) { | |
| 161 Writer.EmitBlockInfoAbbrev(SetBID, Abbrev); | |
| 162 } else { | |
| 163 Writer.EmitAbbrev(Abbrev); | |
| 164 } | |
| 165 break; | |
| 166 } | |
| 167 case naclbitc::BLK_CODE_HEADER: | |
| 168 // Note: There is no abbreviation index here. Ignore. | |
| 169 for (uint64_t Value : Record.Values) | |
| 170 Writer.Emit(Value, 8); | |
| 171 break; | |
| 172 default: | |
| 173 bool UsesDefaultAbbrev = Record.Abbrev == naclbitc::UNABBREV_RECORD; | |
| 174 if (!UsesDefaultAbbrev | |
| 175 && !Writer.isUserRecordAbbreviation(Record.Abbrev)) { | |
| 176 uint64_t BlockAbbrevIndexLimit = 0; | |
| 177 if (!AbbrevIndexLimitStack.empty()) | |
| 178 BlockAbbrevIndexLimit = AbbrevIndexLimitStack.back(); | |
| 179 // Can't generate abbreviation ID because not enough bits | |
| 180 // specified in block ID. | |
| 181 raw_ostream &ErrStrm = RecoverableError(); | |
| 182 ErrStrm << "Uses illegal abbreviation index"; | |
| 183 if (Record.Abbrev > BlockAbbrevIndexLimit) | |
|
jvoung (off chromium)
2015/05/06 22:08:09
When does this > check fail? If for some reason th
Karl
2015/05/07 20:09:18
Decided to simplify this code and be more generic.
| |
| 184 ErrStrm << ". Must not exceed " << BlockAbbrevIndexLimit; | |
| 185 ErrStrm << ": " << Record << "\n"; | |
| 186 if (!Flags.TryToRecover && !Flags.SaveBadAbbrevIndices) | |
|
jvoung (off chromium)
2015/05/06 22:08:09
So this code is saying that SaveBadAbbrevIndices w
Karl
2015/05/07 20:09:18
Hopefully the code is now clearer since I simplifi
jvoung (off chromium)
2015/05/07 21:33:56
Thanks -- I like the new version more.
| |
| 187 return false; | |
| 188 if (Flags.SaveBadAbbrevIndices) { | |
| 189 // Note: If this point is reached, the abbreviation is bad and | |
| 190 // RecoverOnBadAbbrevID is true. Generate bad abbreviation index | |
|
jvoung (off chromium)
2015/05/06 22:08:09
there is no RecoverOnBadAbbrevID anymore
You also
Karl
2015/05/07 20:09:18
Again, I simplified this code so that we don't nee
| |
| 191 // so that the bitcode reader can be tested. | |
| 192 Writer.EmitCode(Record.Abbrev); | |
| 193 // Note: We need to close blocks or the bitcode Writer will terminate | |
| 194 // due to assertions. | |
| 195 writeMissingEndBlocks(Writer); | |
| 196 Results.SavedBadAbbrevIndices = true; | |
|
jvoung (off chromium)
2015/05/06 22:08:09
Perhaps "Save..." should be "Write..." ?
In some
Karl
2015/05/07 20:09:18
Hopefully I have clarified that the Save Case (now
| |
| 197 return false; | |
| 198 } | |
| 199 UsesDefaultAbbrev = true; | |
| 200 } | |
| 201 if (WriteBlockID == naclbitc::BLOCKINFO_BLOCK_ID | |
| 202 && Record.Code == naclbitc::BLOCKINFO_CODE_SETBID) { | |
| 203 // Note: SetBID records are handled by Writer->EmitBlockInfoAbbrev, | |
| 204 // based on the SetBID value. Don't bother to generate SetBID record here. | |
| 205 // Rather just set SetBID and let call to Writer->EmitBlockInfoAbbrev | |
| 206 // generate the SetBID record. | |
| 207 if (NumValues != 1) { | |
| 208 Error() << "SetBID record expects 1 value but found " | |
| 209 << NumValues << ": " << Record << "\n"; | |
| 210 return false; | |
| 211 } | |
| 212 SetBID = Record.Values[0]; | |
| 213 return true; | |
| 214 } | |
| 215 if (UsesDefaultAbbrev) | |
| 216 Writer.EmitRecord(Record.Code, Record.Values); | |
| 217 else | |
| 218 Writer.EmitRecord(Record.Code, Record.Values, Record.Abbrev); | |
| 219 } | |
| 220 return true; | |
| 221 } | |
| 222 | |
| 223 static NaClBitCodeAbbrev *deleteAbbrev(NaClBitCodeAbbrev *Abbrev) { | |
| 224 Abbrev->dropRef(); | |
| 225 return nullptr; | |
| 226 } | |
| 227 | |
| 228 NaClBitCodeAbbrev *WriteState::buildAbbrev( | |
| 229 const NaClBitcodeAbbrevRecord &Record) { | |
| 230 // Note: Recover by removing abbreviation. | |
| 231 NaClBitCodeAbbrev *Abbrev = new NaClBitCodeAbbrev(); | |
| 232 size_t Index = 0; | |
| 233 size_t NumValues = Record.Values.size(); | |
| 234 if (NumValues == 0) { | |
| 235 RecoverableError() << "Empty abbreviation record not allowed: " | |
| 236 << Record << "\n"; | |
| 237 return deleteAbbrev(Abbrev); | |
| 238 } | |
| 239 size_t NumAbbreviations = Record.Values[Index++]; | |
| 240 if (NumAbbreviations == 0) { | |
| 241 RecoverableError() << "Abbreviation must contain at least one operator: " | |
| 242 << Record << "\n"; | |
| 243 return deleteAbbrev(Abbrev); | |
| 244 } | |
| 245 for (size_t Count = 0; Count < NumAbbreviations; ++Count) { | |
| 246 if (Index >= NumValues) { | |
| 247 RecoverableError() | |
| 248 << "Malformed abbreviation found. Expects " << NumAbbreviations | |
| 249 << " operands but ound " << Count << ": " << Record << "\n"; | |
| 250 return deleteAbbrev(Abbrev); | |
| 251 } | |
| 252 switch (Record.Values[Index++]) { | |
| 253 case 1: | |
| 254 if (Index >= NumValues) { | |
| 255 RecoverableError() << "Malformed literal abbreviation: " | |
| 256 << Record << "\n"; | |
| 257 return deleteAbbrev(Abbrev); | |
| 258 } | |
| 259 Abbrev->Add(NaClBitCodeAbbrevOp(Record.Values[Index++])); | |
| 260 break; | |
| 261 case 0: { | |
| 262 if (Index >= NumValues) { | |
| 263 RecoverableError() << "Malformed abbreviation found: " | |
| 264 << Record << "\n"; | |
| 265 return deleteAbbrev(Abbrev); | |
| 266 } | |
| 267 unsigned Kind = Record.Values[Index++]; | |
| 268 switch (Kind) { | |
| 269 case NaClBitCodeAbbrevOp::Fixed: | |
| 270 if (Index >= NumValues) { | |
| 271 RecoverableError() << "Malformed fixed abbreviation found: " | |
| 272 << Record << "\n"; | |
| 273 return deleteAbbrev(Abbrev); | |
| 274 } | |
| 275 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, | |
| 276 Record.Values[Index++])); | |
| 277 break; | |
| 278 case NaClBitCodeAbbrevOp::VBR: | |
| 279 if (Index >= NumValues) { | |
| 280 RecoverableError() << "Malformed vbr abbreviation found: " | |
| 281 << Record << "\n"; | |
| 282 return deleteAbbrev(Abbrev); | |
| 283 } | |
| 284 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, | |
| 285 Record.Values[Index++])); | |
| 286 break; | |
| 287 case NaClBitCodeAbbrevOp::Array: | |
| 288 if (Index >= NumValues) { | |
| 289 RecoverableError() << "Malformed array abbreviation found: " | |
| 290 << Record << "\n"; | |
| 291 return deleteAbbrev(Abbrev); | |
| 292 } | |
| 293 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Array)); | |
| 294 break; | |
| 295 case NaClBitCodeAbbrevOp::Char6: | |
| 296 Abbrev->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Char6)); | |
| 297 break; | |
| 298 default: | |
| 299 RecoverableError() << "Unknown abbreviation kind " << Kind | |
| 300 << ": " << Record << "\n"; | |
| 301 return deleteAbbrev(Abbrev); | |
| 302 } | |
| 303 break; | |
| 304 } | |
| 305 default: | |
| 306 RecoverableError() << "Error: Bad literal flag " << Record.Values[Index] | |
| 307 << ": " << Record << "\n"; | |
| 308 return deleteAbbrev(Abbrev); | |
| 309 } | |
| 310 } | |
| 311 return Abbrev; | |
| 312 } | |
| 313 | |
| 314 } // end of anonymous namespace. | |
| 315 | |
| 316 NaClMungedBitcode::WriteResults NaClMungedBitcode::writeMaybeRepair( | |
| 317 SmallVectorImpl<char> &Buffer, bool AddHeader, | |
| 318 const WriteFlags &Flags) const { | |
| 319 NaClBitstreamWriter Writer(Buffer); | |
| 320 WriteState State(Flags); | |
| 321 if (AddHeader) { | |
| 322 NaClWriteHeader(Writer, true); | |
| 323 } | |
| 324 for (const NaClBitcodeAbbrevRecord &Record : *this) { | |
| 325 if (!State.emitRecord(Writer, Record)) | |
| 326 break; | |
| 327 } | |
| 328 if (!State.AbbrevIndexLimitStack.empty()) { | |
| 329 State.RecoverableError() | |
| 330 << "Bitcode missing " << State.AbbrevIndexLimitStack.size() | |
| 331 << " close blocks.\n"; | |
| 332 if (Flags.TryToRecover) | |
| 333 State.writeMissingEndBlocks(Writer); | |
| 334 } | |
| 335 return State.Results; | |
| 336 } | |
| OLD | NEW |