| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| 6 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| 7 | XX XX |
| 8 | XX Unwind Info XX |
| 9 | XX XX |
| 10 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| 11 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
| 12 | */ |
| 13 | |
| 14 | #ifdef _TARGET_ARMARCH_ |
| 15 | |
| 16 | // Windows no longer imposes a maximum prolog size. However, we still have an |
| 17 | // assert here just to inform us if we increase the size of the prolog |
| 18 | // accidentally, as there is still a slight performance advantage in the |
| 19 | // OS unwinder to having as few unwind codes as possible. |
| 20 | // You can increase this "max" number if necessary. |
| 21 | |
| 22 | #if defined(_TARGET_ARM_) |
| 23 | const unsigned MAX_PROLOG_SIZE_BYTES = 40; |
| 24 | const unsigned MAX_EPILOG_SIZE_BYTES = 40; |
| 25 | #define UWC_END 0xFF // "end" unwind code |
| 26 | #define UW_MAX_FRAGMENT_SIZE_BYTES (1U << 19) |
| 27 | #define UW_MAX_CODE_WORDS_COUNT 15 // Max number that can be encoded in the "Code Words" field of the .pdata record |
| 28 | #define UW_MAX_EPILOG_START_INDEX 0xFFU // Max number that can be encoded in the "Epilog Start Index" field |
| 29 | // of the .pdata record |
| 30 | #elif defined(_TARGET_ARM64_) |
| 31 | const unsigned MAX_PROLOG_SIZE_BYTES = 100; |
| 32 | const unsigned MAX_EPILOG_SIZE_BYTES = 100; |
| 33 | #define UWC_END 0xE4 // "end" unwind code |
| 34 | #define UWC_END_C 0xE5 // "end_c" unwind code |
| 35 | #define UW_MAX_FRAGMENT_SIZE_BYTES (1U << 20) |
| 36 | #define UW_MAX_CODE_WORDS_COUNT 31 |
| 37 | #define UW_MAX_EPILOG_START_INDEX 0x3FFU |
| 38 | #endif // _TARGET_ARM64_ |
| 39 | |
| 40 | #define UW_MAX_EPILOG_COUNT 31 // Max number that can be encoded in the "Epilog count" field |
| 41 | // of the .pdata record |
| 42 | #define UW_MAX_EXTENDED_CODE_WORDS_COUNT 0xFFU // Max number that can be encoded in the "Extended Code Words" |
| 43 | // field of the .pdata record |
| 44 | #define UW_MAX_EXTENDED_EPILOG_COUNT 0xFFFFU // Max number that can be encoded in the "Extended Epilog Count" |
| 45 | // field of the .pdata record |
| 46 | #define UW_MAX_EPILOG_START_OFFSET 0x3FFFFU // Max number that can be encoded in the "Epilog Start Offset" |
| 47 | // field of the .pdata record |
| 48 | |
| 49 | // |
| 50 | // Forward declaration of class defined in emit.h |
| 51 | // |
| 52 | |
| 53 | class emitLocation; |
| 54 | |
| 55 | // |
| 56 | // Forward declarations of classes defined in this file |
| 57 | // |
| 58 | |
| 59 | class UnwindCodesBase; |
| 60 | class UnwindPrologCodes; |
| 61 | class UnwindEpilogCodes; |
| 62 | class UnwindEpilogInfo; |
| 63 | class UnwindFragmentInfo; |
| 64 | class UnwindInfo; |
| 65 | |
| 66 | // UnwindBase: A base class shared by the the unwind classes that require |
| 67 | // a Compiler* for memory allocation. |
| 68 | |
| 69 | class UnwindBase |
| 70 | { |
| 71 | protected: |
| 72 | UnwindBase(Compiler* comp) : uwiComp(comp) |
| 73 | { |
| 74 | } |
| 75 | |
| 76 | UnwindBase() |
| 77 | { |
| 78 | } |
| 79 | ~UnwindBase() |
| 80 | { |
| 81 | } |
| 82 | |
| 83 | // TODO: How do we get the ability to access uwiComp without error on Clang? |
| 84 | #if defined(DEBUG) && !defined(__GNUC__) |
| 85 | |
| 86 | template <typename T> |
| 87 | T dspPtr(T p) |
| 88 | { |
| 89 | return uwiComp->dspPtr(p); |
| 90 | } |
| 91 | |
| 92 | template <typename T> |
| 93 | T dspOffset(T o) |
| 94 | { |
| 95 | return uwiComp->dspOffset(o); |
| 96 | } |
| 97 | |
| 98 | static const char* dspBool(bool b) |
| 99 | { |
| 100 | return (b) ? "true" : "false" ; |
| 101 | } |
| 102 | |
| 103 | #endif // DEBUG |
| 104 | |
| 105 | // |
| 106 | // Data |
| 107 | // |
| 108 | |
| 109 | Compiler* uwiComp; |
| 110 | }; |
| 111 | |
| 112 | // UnwindCodesBase: A base class shared by the the classes used to represent the prolog |
| 113 | // and epilog unwind codes. |
| 114 | |
| 115 | class UnwindCodesBase |
| 116 | { |
| 117 | public: |
| 118 | // Add a single unwind code. |
| 119 | |
| 120 | virtual void AddCode(BYTE b1) = 0; |
| 121 | virtual void AddCode(BYTE b1, BYTE b2) = 0; |
| 122 | virtual void AddCode(BYTE b1, BYTE b2, BYTE b3) = 0; |
| 123 | virtual void AddCode(BYTE b1, BYTE b2, BYTE b3, BYTE b4) = 0; |
| 124 | |
| 125 | // Get access to the unwind codes |
| 126 | |
| 127 | virtual BYTE* GetCodes() = 0; |
| 128 | |
| 129 | bool IsEndCode(BYTE b) |
| 130 | { |
| 131 | #if defined(_TARGET_ARM_) |
| 132 | return b >= 0xFD; |
| 133 | #elif defined(_TARGET_ARM64_) |
| 134 | return (b == UWC_END); // TODO-ARM64-Bug?: what about the "end_c" code? |
| 135 | #endif // _TARGET_ARM64_ |
| 136 | } |
| 137 | |
| 138 | #ifdef DEBUG |
| 139 | |
| 140 | unsigned GetCodeSizeFromUnwindCodes(bool isProlog); |
| 141 | |
| 142 | #endif // DEBUG |
| 143 | }; |
| 144 | |
| 145 | // UnwindPrologCodes: represents the unwind codes for a prolog sequence. |
| 146 | // Prolog unwind codes arrive in reverse order from how they will be emitted. |
| 147 | // Store them as a stack, storing from the end of an array towards the beginning. |
| 148 | // This class is also re-used as the final location of the consolidated unwind |
| 149 | // information for a function, including unwind info header, the prolog codes, |
| 150 | // and any epilog codes. |
| 151 | |
| 152 | class UnwindPrologCodes : public UnwindBase, public UnwindCodesBase |
| 153 | { |
| 154 | // UPC_LOCAL_COUNT is the amount of memory local to this class. For ARM mscorlib.dll, the maximum size is 34. |
| 155 | // Here is a histogram of other interesting sizes: |
| 156 | // <=16 79% |
| 157 | // <=24 96% |
| 158 | // <=32 99% |
| 159 | // From this data, we choose to use 24. |
| 160 | |
| 161 | static const int UPC_LOCAL_COUNT = 24; |
| 162 | |
| 163 | public: |
| 164 | UnwindPrologCodes(Compiler* comp) |
| 165 | : UnwindBase(comp) |
| 166 | , upcMem(upcMemLocal) |
| 167 | , upcMemSize(UPC_LOCAL_COUNT) |
| 168 | , upcCodeSlot(UPC_LOCAL_COUNT) |
| 169 | , upcHeaderSlot(-1) |
| 170 | , upcEpilogSlot(-1) |
| 171 | { |
| 172 | // Assume we've got a normal end code. |
| 173 | // Push four so we can generate an array that is a multiple of 4 bytes in size with the |
| 174 | // end codes (and padding) already in place. One is the end code for the prolog codes, |
| 175 | // three are end-of-array alignment padding. |
| 176 | PushByte(UWC_END); |
| 177 | PushByte(UWC_END); |
| 178 | PushByte(UWC_END); |
| 179 | PushByte(UWC_END); |
| 180 | } |
| 181 | |
| 182 | // |
| 183 | // Implementation of UnwindCodesBase |
| 184 | // |
| 185 | |
| 186 | virtual void AddCode(BYTE b1) |
| 187 | { |
| 188 | PushByte(b1); |
| 189 | } |
| 190 | |
| 191 | virtual void AddCode(BYTE b1, BYTE b2) |
| 192 | { |
| 193 | PushByte(b2); |
| 194 | PushByte(b1); |
| 195 | } |
| 196 | |
| 197 | virtual void AddCode(BYTE b1, BYTE b2, BYTE b3) |
| 198 | { |
| 199 | PushByte(b3); |
| 200 | PushByte(b2); |
| 201 | PushByte(b1); |
| 202 | } |
| 203 | |
| 204 | virtual void AddCode(BYTE b1, BYTE b2, BYTE b3, BYTE b4) |
| 205 | { |
| 206 | PushByte(b4); |
| 207 | PushByte(b3); |
| 208 | PushByte(b2); |
| 209 | PushByte(b1); |
| 210 | } |
| 211 | |
| 212 | // Return a pointer to the first unwind code byte |
| 213 | virtual BYTE* GetCodes() |
| 214 | { |
| 215 | assert(upcCodeSlot < upcMemSize); // There better be at least one code! |
| 216 | return &upcMem[upcCodeSlot]; |
| 217 | } |
| 218 | |
| 219 | /////////////////////////////////////////////////////////////////////////// |
| 220 | |
| 221 | BYTE GetByte(int index) |
| 222 | { |
| 223 | assert(upcCodeSlot <= index && index < upcMemSize); |
| 224 | return upcMem[index]; |
| 225 | } |
| 226 | |
| 227 | // Push a single byte on the unwind code stack |
| 228 | void PushByte(BYTE b) |
| 229 | { |
| 230 | if (upcCodeSlot == 0) |
| 231 | { |
| 232 | // We've run out of space! Reallocate, and copy everything to a new array. |
| 233 | EnsureSize(upcMemSize + 1); |
| 234 | } |
| 235 | |
| 236 | --upcCodeSlot; |
| 237 | noway_assert(0 <= upcCodeSlot && upcCodeSlot < upcMemSize); |
| 238 | |
| 239 | upcMem[upcCodeSlot] = b; |
| 240 | } |
| 241 | |
| 242 | // Return the size of the unwind codes, in bytes. The size is the exact size, not an aligned size. |
| 243 | // The size includes exactly one "end" code. |
| 244 | int Size() |
| 245 | { |
| 246 | // -3 because we put 4 "end" codes at the end in the constructor, and we shouldn't count that here |
| 247 | return upcMemSize - upcCodeSlot - 3; |
| 248 | } |
| 249 | |
| 250 | void SetFinalSize(int headerBytes, int epilogBytes); |
| 251 | |
| 252 | void AddHeaderWord(DWORD d); |
| 253 | |
| 254 | void GetFinalInfo(/* OUT */ BYTE** ppUnwindBlock, /* OUT */ ULONG* pUnwindBlockSize); |
| 255 | |
| 256 | // AppendEpilog: copy the epilog bytes to the next epilog bytes slot |
| 257 | void AppendEpilog(UnwindEpilogInfo* pEpi); |
| 258 | |
| 259 | // Match the prolog codes to a set of epilog codes |
| 260 | int Match(UnwindEpilogInfo* pEpi); |
| 261 | |
| 262 | // Copy the prolog codes from another prolog |
| 263 | void CopyFrom(UnwindPrologCodes* pCopyFrom); |
| 264 | |
| 265 | UnwindPrologCodes() |
| 266 | { |
| 267 | } |
| 268 | ~UnwindPrologCodes() |
| 269 | { |
| 270 | } |
| 271 | |
| 272 | #ifdef DEBUG |
| 273 | void Dump(int indent = 0); |
| 274 | #endif // DEBUG |
| 275 | |
| 276 | private: |
| 277 | void EnsureSize(int requiredSize); |
| 278 | |
| 279 | // No copy constructor or operator= |
| 280 | UnwindPrologCodes(const UnwindPrologCodes& info); |
| 281 | UnwindPrologCodes& operator=(const UnwindPrologCodes&); |
| 282 | |
| 283 | // |
| 284 | // Data |
| 285 | // |
| 286 | |
| 287 | // To store the unwind codes, we first use a local array that should satisfy almost all cases. |
| 288 | // If there are more unwind codes, we dynamically allocate memory. |
| 289 | BYTE upcMemLocal[UPC_LOCAL_COUNT]; |
| 290 | BYTE* upcMem; |
| 291 | |
| 292 | // upcMemSize is the number of bytes in upcMem. This is equal to UPC_LOCAL_COUNT unless |
| 293 | // we've dynamically allocated memory to store the codes. |
| 294 | int upcMemSize; |
| 295 | |
| 296 | // upcCodeSlot points to the last unwind code added to the array. The array is filled in from |
| 297 | // the end, so it starts pointing one beyond the array end. |
| 298 | int upcCodeSlot; |
| 299 | |
| 300 | // upcHeaderSlot points to the last header byte prepended to the array. Headers bytes are |
| 301 | // filled in from the beginning, and only after SetFinalSize() is called. |
| 302 | int upcHeaderSlot; |
| 303 | |
| 304 | // upcEpilogSlot points to the next epilog location to fill |
| 305 | int upcEpilogSlot; |
| 306 | |
| 307 | // upcUnwindBlockSlot is only set after SetFinalSize() is called. It is the index of the first |
| 308 | // byte of the final unwind data, namely the first byte of the header. |
| 309 | int upcUnwindBlockSlot; |
| 310 | }; |
| 311 | |
| 312 | // UnwindEpilogCodes: represents the unwind codes for a single epilog sequence. |
| 313 | // Epilog unwind codes arrive in the order they will be emitted. Store them as an array, |
| 314 | // adding new ones to the end of the array. |
| 315 | |
| 316 | class UnwindEpilogCodes : public UnwindBase, public UnwindCodesBase |
| 317 | { |
| 318 | // UEC_LOCAL_COUNT is the amount of memory local to this class. For ARM mscorlib.dll, the maximum size is 6, |
| 319 | // while 89% of epilogs fit in 4. So, set it to 4 to maintain array alignment and hit most cases. |
| 320 | static const int UEC_LOCAL_COUNT = 4; |
| 321 | |
| 322 | public: |
| 323 | UnwindEpilogCodes(Compiler* comp) |
| 324 | : UnwindBase(comp) |
| 325 | , uecMem(uecMemLocal) |
| 326 | , firstByteOfLastCode(0) |
| 327 | , uecMemSize(UEC_LOCAL_COUNT) |
| 328 | , uecCodeSlot(-1) |
| 329 | , uecFinalized(false) |
| 330 | { |
| 331 | } |
| 332 | |
| 333 | // |
| 334 | // Implementation of UnwindCodesBase |
| 335 | // |
| 336 | |
| 337 | virtual void AddCode(BYTE b1) |
| 338 | { |
| 339 | AppendByte(b1); |
| 340 | |
| 341 | firstByteOfLastCode = b1; |
| 342 | } |
| 343 | |
| 344 | virtual void AddCode(BYTE b1, BYTE b2) |
| 345 | { |
| 346 | AppendByte(b1); |
| 347 | AppendByte(b2); |
| 348 | |
| 349 | firstByteOfLastCode = b1; |
| 350 | } |
| 351 | |
| 352 | virtual void AddCode(BYTE b1, BYTE b2, BYTE b3) |
| 353 | { |
| 354 | AppendByte(b1); |
| 355 | AppendByte(b2); |
| 356 | AppendByte(b3); |
| 357 | |
| 358 | firstByteOfLastCode = b1; |
| 359 | } |
| 360 | |
| 361 | virtual void AddCode(BYTE b1, BYTE b2, BYTE b3, BYTE b4) |
| 362 | { |
| 363 | AppendByte(b1); |
| 364 | AppendByte(b2); |
| 365 | AppendByte(b3); |
| 366 | AppendByte(b4); |
| 367 | |
| 368 | firstByteOfLastCode = b1; |
| 369 | } |
| 370 | |
| 371 | // Return a pointer to the first unwind code byte |
| 372 | virtual BYTE* GetCodes() |
| 373 | { |
| 374 | assert(uecFinalized); |
| 375 | |
| 376 | // Codes start at the beginning |
| 377 | return uecMem; |
| 378 | } |
| 379 | |
| 380 | /////////////////////////////////////////////////////////////////////////// |
| 381 | |
| 382 | BYTE GetByte(int index) |
| 383 | { |
| 384 | assert(0 <= index && index <= uecCodeSlot); |
| 385 | return uecMem[index]; |
| 386 | } |
| 387 | |
| 388 | // Add a single byte on the unwind code array |
| 389 | void AppendByte(BYTE b) |
| 390 | { |
| 391 | if (uecCodeSlot == uecMemSize - 1) |
| 392 | { |
| 393 | // We've run out of space! Reallocate, and copy everything to a new array. |
| 394 | EnsureSize(uecMemSize + 1); |
| 395 | } |
| 396 | |
| 397 | ++uecCodeSlot; |
| 398 | noway_assert(0 <= uecCodeSlot && uecCodeSlot < uecMemSize); |
| 399 | |
| 400 | uecMem[uecCodeSlot] = b; |
| 401 | } |
| 402 | |
| 403 | // Return the size of the unwind codes, in bytes. The size is the exact size, not an aligned size. |
| 404 | int Size() |
| 405 | { |
| 406 | if (uecFinalized) |
| 407 | { |
| 408 | // Add one because uecCodeSlot is 0-based |
| 409 | return uecCodeSlot + 1; |
| 410 | } |
| 411 | else |
| 412 | { |
| 413 | // Add one because uecCodeSlot is 0-based, and one for an "end" code that isn't stored (yet). |
| 414 | return uecCodeSlot + 2; |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | void FinalizeCodes() |
| 419 | { |
| 420 | assert(!uecFinalized); |
| 421 | noway_assert(0 <= uecCodeSlot && uecCodeSlot < uecMemSize); // There better be at least one code! |
| 422 | |
| 423 | if (!IsEndCode(firstByteOfLastCode)) // If the last code is an end code, we don't need to append one. |
| 424 | { |
| 425 | AppendByte(UWC_END); // Add a default "end" code to the end of the array of unwind codes |
| 426 | firstByteOfLastCode = UWC_END; // Update firstByteOfLastCode in case we use it later |
| 427 | } |
| 428 | |
| 429 | uecFinalized = true; // With the "end" code in place, now we're done |
| 430 | |
| 431 | #ifdef DEBUG |
| 432 | unsigned codeSize = GetCodeSizeFromUnwindCodes(false); |
| 433 | assert(codeSize <= MAX_EPILOG_SIZE_BYTES); |
| 434 | #endif // DEBUG |
| 435 | } |
| 436 | |
| 437 | UnwindEpilogCodes() |
| 438 | { |
| 439 | } |
| 440 | ~UnwindEpilogCodes() |
| 441 | { |
| 442 | } |
| 443 | |
| 444 | #ifdef DEBUG |
| 445 | void Dump(int indent = 0); |
| 446 | #endif // DEBUG |
| 447 | |
| 448 | private: |
| 449 | void EnsureSize(int requiredSize); |
| 450 | |
| 451 | // No destructor, copy constructor or operator= |
| 452 | UnwindEpilogCodes(const UnwindEpilogCodes& info); |
| 453 | UnwindEpilogCodes& operator=(const UnwindEpilogCodes&); |
| 454 | |
| 455 | // |
| 456 | // Data |
| 457 | // |
| 458 | |
| 459 | // To store the unwind codes, we first use a local array that should satisfy almost all cases. |
| 460 | // If there are more unwind codes, we dynamically allocate memory. |
| 461 | BYTE uecMemLocal[UEC_LOCAL_COUNT]; |
| 462 | BYTE* uecMem; |
| 463 | BYTE firstByteOfLastCode; |
| 464 | |
| 465 | // uecMemSize is the number of bytes/slots in uecMem. This is equal to UEC_LOCAL_COUNT unless |
| 466 | // we've dynamically allocated memory to store the codes. |
| 467 | int uecMemSize; |
| 468 | |
| 469 | // uecCodeSlot points to the last unwind code added to the array. The array is filled in from |
| 470 | // the beginning, so it starts at -1. |
| 471 | int uecCodeSlot; |
| 472 | |
| 473 | // Is the unwind information finalized? Finalized info has an end code appended. |
| 474 | bool uecFinalized; |
| 475 | }; |
| 476 | |
| 477 | // UnwindEpilogInfo: represents the unwind information for a single epilog sequence. Epilogs for a |
| 478 | // single function/funclet are in a linked list. |
| 479 | |
| 480 | class UnwindEpilogInfo : public UnwindBase |
| 481 | { |
| 482 | friend class UnwindFragmentInfo; |
| 483 | |
| 484 | static const unsigned EPI_ILLEGAL_OFFSET = 0xFFFFFFFF; |
| 485 | |
| 486 | public: |
| 487 | UnwindEpilogInfo(Compiler* comp) |
| 488 | : UnwindBase(comp) |
| 489 | , epiNext(NULL) |
| 490 | , epiEmitLocation(NULL) |
| 491 | , epiCodes(comp) |
| 492 | , epiStartOffset(EPI_ILLEGAL_OFFSET) |
| 493 | , epiMatches(false) |
| 494 | , epiStartIndex(-1) |
| 495 | { |
| 496 | } |
| 497 | |
| 498 | void CaptureEmitLocation(); |
| 499 | |
| 500 | void FinalizeOffset(); |
| 501 | |
| 502 | void FinalizeCodes() |
| 503 | { |
| 504 | epiCodes.FinalizeCodes(); |
| 505 | } |
| 506 | |
| 507 | UNATIVE_OFFSET GetStartOffset() |
| 508 | { |
| 509 | assert(epiStartOffset != EPI_ILLEGAL_OFFSET); |
| 510 | return epiStartOffset; |
| 511 | } |
| 512 | |
| 513 | int GetStartIndex() |
| 514 | { |
| 515 | assert(epiStartIndex != -1); |
| 516 | return epiStartIndex; // The final "Epilog Start Index" of this epilog's unwind codes |
| 517 | } |
| 518 | |
| 519 | void SetStartIndex(int index) |
| 520 | { |
| 521 | assert(epiStartIndex == -1); |
| 522 | epiStartIndex = (int)index; |
| 523 | } |
| 524 | |
| 525 | void SetMatches() |
| 526 | { |
| 527 | epiMatches = true; |
| 528 | } |
| 529 | |
| 530 | bool Matches() |
| 531 | { |
| 532 | return epiMatches; |
| 533 | } |
| 534 | |
| 535 | // Size of epilog unwind codes in bytes |
| 536 | int Size() |
| 537 | { |
| 538 | return epiCodes.Size(); |
| 539 | } |
| 540 | |
| 541 | // Return a pointer to the first unwind code byte |
| 542 | BYTE* GetCodes() |
| 543 | { |
| 544 | return epiCodes.GetCodes(); |
| 545 | } |
| 546 | |
| 547 | // Match the codes to a set of epilog codes |
| 548 | int Match(UnwindEpilogInfo* pEpi); |
| 549 | |
| 550 | UnwindEpilogInfo() |
| 551 | { |
| 552 | } |
| 553 | ~UnwindEpilogInfo() |
| 554 | { |
| 555 | } |
| 556 | |
| 557 | #ifdef DEBUG |
| 558 | void Dump(int indent = 0); |
| 559 | #endif // DEBUG |
| 560 | |
| 561 | private: |
| 562 | // No copy constructor or operator= |
| 563 | UnwindEpilogInfo(const UnwindEpilogInfo& info); |
| 564 | UnwindEpilogInfo& operator=(const UnwindEpilogInfo&); |
| 565 | |
| 566 | // |
| 567 | // Data |
| 568 | // |
| 569 | |
| 570 | UnwindEpilogInfo* epiNext; |
| 571 | emitLocation* epiEmitLocation; // The emitter location of the beginning of the epilog |
| 572 | UnwindEpilogCodes epiCodes; |
| 573 | UNATIVE_OFFSET epiStartOffset; // Actual offset of the epilog, in bytes, from the start of the function. Set in |
| 574 | // FinalizeOffset(). |
| 575 | bool epiMatches; // Do the epilog unwind codes match some other set of codes? If so, we don't copy these to the |
| 576 | // final set; we just point to another set. |
| 577 | int epiStartIndex; // The final "Epilog Start Index" of this epilog's unwind codes |
| 578 | }; |
| 579 | |
| 580 | // UnwindFragmentInfo: represents all the unwind information for a single fragment of a function or funclet. |
| 581 | // A fragment is a section with a code size less than the maximum unwind code size: either 512K bytes, or |
| 582 | // that specified by COMPlus_JitSplitFunctionSize. In most cases, there will be exactly one fragment. |
| 583 | |
| 584 | class UnwindFragmentInfo : public UnwindBase |
| 585 | { |
| 586 | friend class UnwindInfo; |
| 587 | |
| 588 | static const unsigned UFI_ILLEGAL_OFFSET = 0xFFFFFFFF; |
| 589 | |
| 590 | public: |
| 591 | UnwindFragmentInfo(Compiler* comp, emitLocation* emitLoc, bool hasPhantomProlog); |
| 592 | |
| 593 | void FinalizeOffset(); |
| 594 | |
| 595 | UNATIVE_OFFSET GetStartOffset() |
| 596 | { |
| 597 | assert(ufiStartOffset != UFI_ILLEGAL_OFFSET); |
| 598 | return ufiStartOffset; |
| 599 | } |
| 600 | |
| 601 | // Add an unwind code. It could be for a prolog, or for the current epilog. |
| 602 | // A single unwind code can be from 1 to 4 bytes. |
| 603 | |
| 604 | void AddCode(BYTE b1) |
| 605 | { |
| 606 | assert(ufiInitialized == UFI_INITIALIZED_PATTERN); |
| 607 | ufiCurCodes->AddCode(b1); |
| 608 | } |
| 609 | |
| 610 | void AddCode(BYTE b1, BYTE b2) |
| 611 | { |
| 612 | assert(ufiInitialized == UFI_INITIALIZED_PATTERN); |
| 613 | ufiCurCodes->AddCode(b1, b2); |
| 614 | } |
| 615 | |
| 616 | void AddCode(BYTE b1, BYTE b2, BYTE b3) |
| 617 | { |
| 618 | assert(ufiInitialized == UFI_INITIALIZED_PATTERN); |
| 619 | ufiCurCodes->AddCode(b1, b2, b3); |
| 620 | } |
| 621 | |
| 622 | void AddCode(BYTE b1, BYTE b2, BYTE b3, BYTE b4) |
| 623 | { |
| 624 | assert(ufiInitialized == UFI_INITIALIZED_PATTERN); |
| 625 | ufiCurCodes->AddCode(b1, b2, b3, b4); |
| 626 | } |
| 627 | |
| 628 | unsigned EpilogCount() |
| 629 | { |
| 630 | unsigned count = 0; |
| 631 | for (UnwindEpilogInfo* pEpi = ufiEpilogList; pEpi != NULL; pEpi = pEpi->epiNext) |
| 632 | { |
| 633 | ++count; |
| 634 | } |
| 635 | return count; |
| 636 | } |
| 637 | |
| 638 | void AddEpilog(); |
| 639 | |
| 640 | void MergeCodes(); |
| 641 | |
| 642 | void CopyPrologCodes(UnwindFragmentInfo* pCopyFrom); |
| 643 | |
| 644 | void SplitEpilogCodes(emitLocation* emitLoc, UnwindFragmentInfo* pSplitFrom); |
| 645 | |
| 646 | bool IsAtFragmentEnd(UnwindEpilogInfo* pEpi); |
| 647 | |
| 648 | // Return the full, final size of unwind block. This will be used to allocate memory for |
| 649 | // the unwind block. This is called before the code offsets are finalized. |
| 650 | // Size is in bytes. |
| 651 | ULONG Size() |
| 652 | { |
| 653 | assert(ufiSize != 0); |
| 654 | return ufiSize; |
| 655 | } |
| 656 | |
| 657 | void Finalize(UNATIVE_OFFSET functionLength); |
| 658 | |
| 659 | // GetFinalInfo: return a pointer to the final unwind info to hand to the VM, and the size of this info in bytes |
| 660 | void GetFinalInfo(/* OUT */ BYTE** ppUnwindBlock, /* OUT */ ULONG* pUnwindBlockSize) |
| 661 | { |
| 662 | ufiPrologCodes.GetFinalInfo(ppUnwindBlock, pUnwindBlockSize); |
| 663 | } |
| 664 | |
| 665 | void Reserve(BOOL isFunclet, bool isHotCode); |
| 666 | |
| 667 | void Allocate( |
| 668 | CorJitFuncKind funKind, void* pHotCode, void* pColdCode, UNATIVE_OFFSET funcEndOffset, bool isHotCode); |
| 669 | |
| 670 | UnwindFragmentInfo() |
| 671 | { |
| 672 | } |
| 673 | ~UnwindFragmentInfo() |
| 674 | { |
| 675 | } |
| 676 | |
| 677 | #ifdef DEBUG |
| 678 | void Dump(int indent = 0); |
| 679 | #endif // DEBUG |
| 680 | |
| 681 | private: |
| 682 | // No copy constructor or operator= |
| 683 | UnwindFragmentInfo(const UnwindFragmentInfo& info); |
| 684 | UnwindFragmentInfo& operator=(const UnwindFragmentInfo&); |
| 685 | |
| 686 | // |
| 687 | // Data |
| 688 | // |
| 689 | |
| 690 | UnwindFragmentInfo* ufiNext; // The next fragment |
| 691 | emitLocation* ufiEmitLoc; // Emitter location for start of fragment |
| 692 | bool ufiHasPhantomProlog; // Are the prolog codes for a phantom prolog, or a real prolog? |
| 693 | // (For a phantom prolog, this code fragment represents a fragment in |
| 694 | // the sense of the unwind info spec; something without a real prolog.) |
| 695 | UnwindPrologCodes ufiPrologCodes; // The unwind codes for the prolog |
| 696 | UnwindEpilogInfo ufiEpilogFirst; // In-line the first epilog to avoid separate memory allocation, since |
| 697 | // almost all functions will have at least one epilog. It is pointed |
| 698 | // to by ufiEpilogList when the first epilog is added. |
| 699 | UnwindEpilogInfo* ufiEpilogList; // The head of the epilog list |
| 700 | UnwindEpilogInfo* ufiEpilogLast; // The last entry in the epilog list (the last epilog added) |
| 701 | UnwindCodesBase* ufiCurCodes; // Pointer to current unwind codes, either prolog or epilog |
| 702 | |
| 703 | // Some data computed when merging the unwind codes, and used when finalizing the |
| 704 | // unwind block for emission. |
| 705 | unsigned ufiSize; // The size of the unwind data for this fragment, in bytes |
| 706 | bool ufiSetEBit; |
| 707 | bool ufiNeedExtendedCodeWordsEpilogCount; |
| 708 | unsigned ufiCodeWords; |
| 709 | unsigned ufiEpilogScopes; |
| 710 | UNATIVE_OFFSET ufiStartOffset; |
| 711 | |
| 712 | #ifdef DEBUG |
| 713 | |
| 714 | unsigned ufiNum; |
| 715 | |
| 716 | // Are we processing the prolog? The prolog must come first, followed by a (possibly empty) |
| 717 | // set of epilogs, for this function/funclet. |
| 718 | bool ufiInProlog; |
| 719 | |
| 720 | static const unsigned UFI_INITIALIZED_PATTERN = 0x0FACADE0; // Something unlikely to be the fill pattern for |
| 721 | // uninitialized memory |
| 722 | unsigned ufiInitialized; |
| 723 | |
| 724 | #endif // DEBUG |
| 725 | }; |
| 726 | |
| 727 | // UnwindInfo: represents all the unwind information for a single function or funclet |
| 728 | |
| 729 | class UnwindInfo : public UnwindBase |
| 730 | { |
| 731 | public: |
| 732 | void InitUnwindInfo(Compiler* comp, emitLocation* startLoc, emitLocation* endLoc); |
| 733 | |
| 734 | void HotColdSplitCodes(UnwindInfo* puwi); |
| 735 | |
| 736 | // The following act on all the fragments that make up the unwind info for this function or funclet. |
| 737 | |
| 738 | void Split(); |
| 739 | |
| 740 | static void EmitSplitCallback(void* context, emitLocation* emitLoc); |
| 741 | |
| 742 | void Reserve(BOOL isFunclet, bool isHotCode); |
| 743 | |
| 744 | void Allocate(CorJitFuncKind funKind, void* pHotCode, void* pColdCode, bool isHotCode); |
| 745 | |
| 746 | // The following act on the current fragment (the one pointed to by 'uwiFragmentLast'). |
| 747 | |
| 748 | // Add an unwind code. It could be for a prolog, or for the current epilog. |
| 749 | // A single unwind code can be from 1 to 4 bytes. |
| 750 | |
| 751 | void AddCode(BYTE b1) |
| 752 | { |
| 753 | assert(uwiInitialized == UWI_INITIALIZED_PATTERN); |
| 754 | assert(uwiFragmentLast != NULL); |
| 755 | INDEBUG(CheckOpsize(b1)); |
| 756 | |
| 757 | uwiFragmentLast->AddCode(b1); |
| 758 | CaptureLocation(); |
| 759 | } |
| 760 | |
| 761 | void AddCode(BYTE b1, BYTE b2) |
| 762 | { |
| 763 | assert(uwiInitialized == UWI_INITIALIZED_PATTERN); |
| 764 | assert(uwiFragmentLast != NULL); |
| 765 | INDEBUG(CheckOpsize(b1)); |
| 766 | |
| 767 | uwiFragmentLast->AddCode(b1, b2); |
| 768 | CaptureLocation(); |
| 769 | } |
| 770 | |
| 771 | void AddCode(BYTE b1, BYTE b2, BYTE b3) |
| 772 | { |
| 773 | assert(uwiInitialized == UWI_INITIALIZED_PATTERN); |
| 774 | assert(uwiFragmentLast != NULL); |
| 775 | INDEBUG(CheckOpsize(b1)); |
| 776 | |
| 777 | uwiFragmentLast->AddCode(b1, b2, b3); |
| 778 | CaptureLocation(); |
| 779 | } |
| 780 | |
| 781 | void AddCode(BYTE b1, BYTE b2, BYTE b3, BYTE b4) |
| 782 | { |
| 783 | assert(uwiInitialized == UWI_INITIALIZED_PATTERN); |
| 784 | assert(uwiFragmentLast != NULL); |
| 785 | INDEBUG(CheckOpsize(b1)); |
| 786 | |
| 787 | uwiFragmentLast->AddCode(b1, b2, b3, b4); |
| 788 | CaptureLocation(); |
| 789 | } |
| 790 | |
| 791 | void AddEpilog(); |
| 792 | |
| 793 | emitLocation* GetCurrentEmitterLocation() |
| 794 | { |
| 795 | return uwiCurLoc; |
| 796 | } |
| 797 | |
| 798 | #if defined(_TARGET_ARM_) |
| 799 | unsigned GetInstructionSize(); |
| 800 | #endif // defined(_TARGET_ARM_) |
| 801 | |
| 802 | void CaptureLocation(); |
| 803 | |
| 804 | UnwindInfo() |
| 805 | { |
| 806 | } |
| 807 | ~UnwindInfo() |
| 808 | { |
| 809 | } |
| 810 | |
| 811 | #ifdef DEBUG |
| 812 | |
| 813 | #if defined(_TARGET_ARM_) |
| 814 | // Given the first byte of the unwind code, check that its opsize matches |
| 815 | // the last instruction added in the emitter. |
| 816 | void CheckOpsize(BYTE b1); |
| 817 | #elif defined(_TARGET_ARM64_) |
| 818 | void CheckOpsize(BYTE b1) |
| 819 | { |
| 820 | } // nothing to do; all instructions are 4 bytes |
| 821 | #endif // defined(_TARGET_ARM64_) |
| 822 | |
| 823 | void Dump(bool isHotCode, int indent = 0); |
| 824 | |
| 825 | bool uwiAddingNOP; |
| 826 | |
| 827 | #endif // DEBUG |
| 828 | |
| 829 | private: |
| 830 | void AddFragment(emitLocation* emitLoc); |
| 831 | |
| 832 | // No copy constructor or operator= |
| 833 | UnwindInfo(const UnwindInfo& info); |
| 834 | UnwindInfo& operator=(const UnwindInfo&); |
| 835 | |
| 836 | // |
| 837 | // Data |
| 838 | // |
| 839 | |
| 840 | UnwindFragmentInfo uwiFragmentFirst; // The first fragment is directly here, so it doesn't need to be separately |
| 841 | // allocated. |
| 842 | UnwindFragmentInfo* uwiFragmentLast; // The last entry in the fragment list (the last fragment added) |
| 843 | emitLocation* uwiEndLoc; // End emitter location of this function/funclet (NULL == end of all code) |
| 844 | emitLocation* uwiCurLoc; // The current emitter location (updated after an unwind code is added), used for NOP |
| 845 | // padding, and asserts. |
| 846 | |
| 847 | #ifdef DEBUG |
| 848 | |
| 849 | static const unsigned UWI_INITIALIZED_PATTERN = 0x0FACADE1; // Something unlikely to be the fill pattern for |
| 850 | // uninitialized memory |
| 851 | unsigned uwiInitialized; |
| 852 | |
| 853 | #endif // DEBUG |
| 854 | }; |
| 855 | |
| 856 | #ifdef DEBUG |
| 857 | |
| 858 | // Forward declaration |
| 859 | void DumpUnwindInfo(Compiler* comp, |
| 860 | bool isHotCode, |
| 861 | UNATIVE_OFFSET startOffset, |
| 862 | UNATIVE_OFFSET endOffset, |
| 863 | const BYTE* const pHeader, |
| 864 | ULONG unwindBlockSize); |
| 865 | |
| 866 | #endif // DEBUG |
| 867 | |
| 868 | #endif // _TARGET_ARMARCH_ |
| 869 | |