1. class CompUnit::PrecompilationId {
  2. has $.id;
  3. my $cache-lock = Lock.new;
  4. my %cache;
  5. method new(Str:D $id) {
  6. $cache-lock.protect: {
  7. %cache{$id} //= 2 < $id.chars < 64 && $id ~~ /^<[A..Za..z0..9._-]>+$/
  8. ?? self.bless(:$id)
  9. !! die "Invalid precompilation id: $id"
  10. }
  11. }
  12. method new-from-string(Str:D $id) {
  13. $cache-lock.protect: {
  14. %cache{$id} //= self.bless(:id(nqp::sha1($id)))
  15. }
  16. }
  17. method new-without-check(Str:D $id) {
  18. $cache-lock.protect: {
  19. %cache{$id} //= self.bless(:id($id))
  20. }
  21. }
  22. method Str() { $!id }
  23. method IO() { $!id.IO }
  24. method substr(|c) { $!id.substr(|c) }
  25. }
  26. role CompUnit::PrecompilationDependency {
  27. method id(--> CompUnit::PrecompilationId:D) { ... }
  28. method src(--> Str:D) { ... }
  29. method spec(--> CompUnit::DependencySpecification:D) { ... }
  30. method checksum(--> Str:D) { ... }
  31. method Str() {
  32. "$.id $.src $.spec"
  33. }
  34. method serialize(--> Str:D) { ... }
  35. method deserialize(Str, --> CompUnit::PrecompilationDependency:D) { ... }
  36. }
  37. role CompUnit::PrecompilationUnit {
  38. method id(--> CompUnit::PrecompilationId:D) { ... }
  39. method path(--> IO::Path:D) { ... }
  40. method modified(--> Instant:D) { ... }
  41. method dependencies(--> Array[CompUnit::PrecompilationDependency]) { ... }
  42. method bytecode(--> Buf:D) { ... }
  43. method checksum(--> Str:D) { ... }
  44. method source-checksum(--> Str:D) { ... }
  45. method bytecode-handle(--> IO::Handle:D) { ... }
  46. method close(--> Nil) { ... }
  47. method is-up-to-date(CompUnit::PrecompilationDependency $dependency, Bool :$check-source --> Bool) {
  48. my $RMD = $*RAKUDO_MODULE_DEBUG;
  49. if $check-source { # a repo changed, so maybe it's a change in our source file
  50. my $source-checksum = $.source-checksum;
  51. my $srcIO = CompUnit::RepositoryRegistry.file-for-spec($dependency.src) // $dependency.src.IO;
  52. unless $srcIO {
  53. return False unless $srcIO.e;
  54. }
  55. my $current-source-checksum := nqp::sha1($srcIO.slurp(:enc<iso-8859-1>));
  56. $RMD(
  57. "$.path\nspec: $dependency.spec()\nsource: $srcIO\n"
  58. ~ "source-checksum: $source-checksum\ncurrent-source-checksum: $current-source-checksum"
  59. ) if $RMD;
  60. return False if $source-checksum ne $current-source-checksum;
  61. }
  62. $RMD("dependency checksum $dependency.checksum() unit: $.checksum()") if $RMD;
  63. $.checksum eq $dependency.checksum
  64. }
  65. }
  66. class CompUnit::PrecompilationDependency::File does CompUnit::PrecompilationDependency {
  67. has CompUnit::PrecompilationId $.id;
  68. has Str $.src;
  69. has Str $.checksum is rw;
  70. has Str $!serialized-spec;
  71. has CompUnit::DependencySpecification $.spec;
  72. method source-name() {
  73. "$.src ($.spec.short-name())"
  74. }
  75. method deserialize(str $str) {
  76. my $parts := nqp::split("\0", $str);
  77. nqp::p6bindattrinvres(
  78. self.new(
  79. :id(CompUnit::PrecompilationId.new-without-check(nqp::atpos($parts, 0))),
  80. :src(nqp::atpos($parts, 1)),
  81. :checksum(nqp::atpos($parts, 2))
  82. ),
  83. CompUnit::PrecompilationDependency::File,
  84. '$!serialized-spec',
  85. nqp::atpos($parts, 3),
  86. );
  87. }
  88. method spec(--> CompUnit::DependencySpecification:D) {
  89. $!spec //= $!serialized-spec
  90. ?? do {
  91. use MONKEY-SEE-NO-EVAL;
  92. EVAL $!serialized-spec;
  93. }
  94. !! Nil;
  95. }
  96. method serialize(--> Str:D) {
  97. "$.id\0$.src\0$.checksum\0{$!serialized-spec ?? $!serialized-spec !! $!spec.perl}"
  98. }
  99. method Str() {
  100. "$.id $.src $.checksum {$!serialized-spec ?? $!serialized-spec !! $!spec.perl}"
  101. }
  102. }