|
18 | 18 | #include "MetadataCache.h"
|
19 | 19 | #include "Private.h"
|
20 | 20 | #include "swift/ABI/Metadata.h"
|
| 21 | +#include "swift/ABI/MetadataValues.h" |
21 | 22 | #include "swift/ABI/TargetLayout.h"
|
22 | 23 | #include "swift/Runtime/EnvironmentVariables.h"
|
23 | 24 | #include "swift/Runtime/Metadata.h"
|
@@ -391,6 +392,141 @@ static bool equalVWTs(const ValueWitnessTable *a, const ValueWitnessTable *b) {
|
391 | 392 | return false;
|
392 | 393 | }
|
393 | 394 |
|
| 395 | +bool swift::compareGenericMetadata(const Metadata *original, |
| 396 | + const Metadata *newMetadata) { |
| 397 | + if (original == newMetadata) |
| 398 | + return true; |
| 399 | + |
| 400 | + bool equal = true; |
| 401 | + |
| 402 | + if (original->getKind() != newMetadata->getKind()) { |
| 403 | + validationLog(true, "Kinds do not match"); |
| 404 | + equal = false; |
| 405 | + } else { |
| 406 | + auto originalDescriptor = original->getTypeContextDescriptor(); |
| 407 | + auto newDescriptor = newMetadata->getTypeContextDescriptor(); |
| 408 | + |
| 409 | + if (originalDescriptor != newDescriptor) { |
| 410 | + validationLog(true, "Descriptors do not match"); |
| 411 | + equal = false; |
| 412 | + } else if (!originalDescriptor->isGeneric()) { |
| 413 | + validationLog(true, |
| 414 | + "Descriptor is not generic and pointers are not identical"); |
| 415 | + equal = false; |
| 416 | + } else { |
| 417 | + auto origVWT = asFullMetadata(original)->ValueWitnesses; |
| 418 | + auto newVWT = asFullMetadata(newMetadata)->ValueWitnesses; |
| 419 | + |
| 420 | + if (!equalVWTs(origVWT, newVWT)) { |
| 421 | + validationLog(true, "VWTs do not match"); |
| 422 | + equal = false; |
| 423 | + } |
| 424 | + |
| 425 | + size_t originalSize = 0; |
| 426 | + size_t newSize = 0; |
| 427 | + |
| 428 | + // Find the range of the generic arguments. They can't be compared with |
| 429 | + // bytewise equality. |
| 430 | + auto &genericContextHeader = |
| 431 | + originalDescriptor->getGenericContextHeader(); |
| 432 | + auto *genericArgumentsPtr = |
| 433 | + originalDescriptor->getGenericArguments(original); |
| 434 | + uintptr_t genericArgumentsStart = |
| 435 | + (uintptr_t)genericArgumentsPtr - (uintptr_t)original; |
| 436 | + uintptr_t genericArgumentsEnd = |
| 437 | + genericArgumentsStart + |
| 438 | + genericContextHeader.NumKeyArguments * sizeof(void *); |
| 439 | + if (original->getKind() == MetadataKind::Class) { |
| 440 | + originalSize = |
| 441 | + reinterpret_cast<const ClassMetadata *>(original)->getSizeInWords(); |
| 442 | + newSize = reinterpret_cast<const ClassMetadata *>(newMetadata) |
| 443 | + ->getSizeInWords(); |
| 444 | + } else { |
| 445 | + // Sizes are at least equal to genericArgumentsEnd. |
| 446 | + originalSize = newSize = genericArgumentsEnd; |
| 447 | + |
| 448 | + if (original->getKind() == MetadataKind::Struct) { |
| 449 | + // If they're structs, try the trailing flags or field offsets. |
| 450 | + auto getSize = [](const Metadata *metadata, size_t previous) { |
| 451 | + auto *structMetadata = |
| 452 | + reinterpret_cast<const StructMetadata *>(metadata); |
| 453 | + |
| 454 | + const void *end; |
| 455 | + if (auto *flags = structMetadata->getTrailingFlags()) |
| 456 | + end = &flags[1]; |
| 457 | + else if (auto *fieldOffsets = structMetadata->getFieldOffsets()) |
| 458 | + end = &fieldOffsets[structMetadata->getDescription()->NumFields]; |
| 459 | + else |
| 460 | + return previous; |
| 461 | + |
| 462 | + return (uintptr_t)end - (uintptr_t)metadata; |
| 463 | + }; |
| 464 | + |
| 465 | + originalSize = getSize(original, originalSize); |
| 466 | + newSize = getSize(newMetadata, newSize); |
| 467 | + } else if (original->getKind() == MetadataKind::Enum) { |
| 468 | + // If they're enums, try the trailing flags. |
| 469 | + auto getSize = [](const Metadata *metadata, size_t previous) { |
| 470 | + auto *enumMetadata = |
| 471 | + reinterpret_cast<const EnumMetadata *>(metadata); |
| 472 | + |
| 473 | + if (auto *flags = enumMetadata->getTrailingFlags()) |
| 474 | + return (uintptr_t)&flags[1] - (uintptr_t)metadata; |
| 475 | + return previous; |
| 476 | + }; |
| 477 | + |
| 478 | + originalSize = getSize(original, originalSize); |
| 479 | + newSize = getSize(newMetadata, newSize); |
| 480 | + } |
| 481 | + } |
| 482 | + |
| 483 | + if (originalSize != newSize) { |
| 484 | + validationLog(true, "Sizes do not match"); |
| 485 | + equal = false; |
| 486 | + } |
| 487 | + |
| 488 | + if (memcmp(original, newMetadata, genericArgumentsStart)) { |
| 489 | + validationLog( |
| 490 | + true, |
| 491 | + "Metadatas do not match in the part before generic arguments"); |
| 492 | + equal = false; |
| 493 | + } |
| 494 | + |
| 495 | + for (unsigned i = 0; i < genericContextHeader.NumKeyArguments; i++) { |
| 496 | + auto *originalArg = |
| 497 | + originalDescriptor->getGenericArguments(original)[i]; |
| 498 | + auto *newArg = newDescriptor->getGenericArguments(newMetadata)[i]; |
| 499 | + if (compareGenericMetadata(originalArg, newArg)) |
| 500 | + continue; |
| 501 | + validationLog(true, "Generic argument %u does not match", i); |
| 502 | + equal = false; |
| 503 | + } |
| 504 | + |
| 505 | + if (genericArgumentsEnd < originalSize) { |
| 506 | + if (memcmp((const char *)original + genericArgumentsEnd, |
| 507 | + (const char *)newMetadata + genericArgumentsEnd, |
| 508 | + originalSize - genericArgumentsEnd)) { |
| 509 | + validationLog( |
| 510 | + true, |
| 511 | + "Metadatas do not match in the part after generic arguments"); |
| 512 | + } |
| 513 | + } |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + if (!equal) { |
| 518 | + validationLog(true, "Error: original and new metadata do not match!"); |
| 519 | + validationLog(true, "Original metadata:"); |
| 520 | + if (auto *error = dumpMetadata(original).getError()) |
| 521 | + validationLog(true, "error dumping original metadata: %s", error->cStr()); |
| 522 | + validationLog(true, "New metadata builder:"); |
| 523 | + if (auto *error = dumpMetadata(newMetadata).getError()) |
| 524 | + validationLog(true, "error dumping new metadata: %s", error->cStr()); |
| 525 | + } |
| 526 | + |
| 527 | + return equal; |
| 528 | +} |
| 529 | + |
394 | 530 | void swift::validateExternalGenericMetadataBuilder(
|
395 | 531 | const Metadata *original, const TypeContextDescriptor *description,
|
396 | 532 | const void * const *arguments) {
|
@@ -422,32 +558,8 @@ void swift::validateExternalGenericMetadataBuilder(
|
422 | 558 | if (!success)
|
423 | 559 | return;
|
424 | 560 |
|
425 |
| - auto origVWT = asFullMetadata(original)->ValueWitnesses; |
426 |
| - auto newVWT = asFullMetadata(newMetadata)->ValueWitnesses; |
427 |
| - |
428 |
| - bool equal = true; |
429 |
| - if (!equalVWTs(origVWT, newVWT)) { |
430 |
| - validationLog(true, "VWTs do not match"); |
431 |
| - equal = false; |
432 |
| - } |
433 |
| - size_t totalSize = sizeof(ValueMetadata) + *extraDataSize.getValue(); |
434 |
| - if (memcmp(original, newMetadata, totalSize)) { |
435 |
| - validationLog(true, "Metadatas do not match"); |
436 |
| - equal = false; |
437 |
| - } |
438 |
| - |
439 |
| - if (!equal) { |
440 |
| - validationLog(true, |
441 |
| - "Error! Mismatch between new/old metadata builders!"); |
442 |
| - validationLog(true, "Original metadata:"); |
443 |
| - if (auto *error = dumpMetadata(original).getError()) |
444 |
| - validationLog(true, "error dumping original metadata: %s", |
445 |
| - error->cStr()); |
446 |
| - validationLog(true, "New metadata builder:"); |
447 |
| - if (auto *error = dumpMetadata(newMetadata).getError()) |
448 |
| - validationLog(true, "error dumping new metadata: %s", error->cStr()); |
| 561 | + if (!compareGenericMetadata(original, newMetadata)) |
449 | 562 | swift::fatalError(0, "Fatal error: mismatched metadata.\n");
|
450 |
| - } |
451 | 563 |
|
452 | 564 | auto typeName = swift_getTypeName(original, false);
|
453 | 565 | validationLog(false, "Validated generic metadata builder on %.*s",
|
|
0 commit comments