bootsnap 1.24.3 → 1.24.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +10 -5
- data/ext/bootsnap/bootsnap.c +74 -95
- data/lib/bootsnap/cli/worker_pool.rb +2 -2
- data/lib/bootsnap/compile_cache/iseq.rb +41 -13
- data/lib/bootsnap/compile_cache/ruby_bug_22023_canary.rb +3 -6
- data/lib/bootsnap/load_path_cache/store.rb +1 -1
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64eaf08501294e6e0fd98b67a54eadfff566f5480a0722e2fb852611a28bd1f8
|
|
4
|
+
data.tar.gz: 8e28bc6d5714952cf5abd837453be6774309dd4b45559c3cd31684ef6658490f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c92cf4fc73d5241a876647a67e9ff70ee63b2816a6f048f3b9f408de8c460e1f97f00162c883bbcc62b01a90d4f753126e3c3be885aee41d042fa166aad812af
|
|
7
|
+
data.tar.gz: 3db013dee453d69e531d4c6cc1a0e763aeadce36a3d5254febb449957447bf801c06e06544a4f571b5a103e75d397b60d51d364eede8de5bfce63abd79dc0ddf
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
# 1.24.4
|
|
4
|
+
|
|
5
|
+
* Fix several compatibility issues with Ruby `4.0.4`, particularly the `should not compile with coverage` error. See #547.
|
|
6
|
+
* Fix `Bootsnap.enable_frozen_string_literal` to work even when coverage is enabled. Unfortunately only possible on Ruby `4.0.4+`.
|
|
7
|
+
On older rubies if coverage is enabled a warning will be issued and the feature won't work.
|
|
8
|
+
* Reduced cache files header size from 64 to 32 bytes, and got rid of the random padding element.
|
|
9
|
+
* Avoid leaking a private method in `Object` when testing for Parse.y bugs.
|
|
10
|
+
|
|
3
11
|
# 1.24.3
|
|
4
12
|
|
|
5
13
|
* Fix the `1.24.2` workaround to parse Ruby files with UTF-8 even when the `LANG` environment variable
|
data/README.md
CHANGED
|
@@ -237,14 +237,15 @@ This may look worse at a glance, but underlies a large performance difference.
|
|
|
237
237
|
useful. [This ruby patch](https://bugs.ruby-lang.org/issues/13378) optimizes them out when coupled
|
|
238
238
|
with bootsnap.)*
|
|
239
239
|
|
|
240
|
-
Bootsnap writes a cache file containing a
|
|
240
|
+
Bootsnap writes a cache file containing a 32 byte header followed by the cache contents. The header
|
|
241
241
|
is a cache key including several fields:
|
|
242
242
|
|
|
243
|
-
* `
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
243
|
+
* `ruby_version_digest`, a digest of:
|
|
244
|
+
* The `RUBY_DESCRIPTION` constant e.g. `"ruby 4.0.2 (2026-03-17 revision d3da9fec82) +PRISM [arm64-darwin25]"`.
|
|
245
|
+
* Bootsnap's cache version. Hardcoded in bootsnap. Essentially a schema version;
|
|
246
|
+
* The content of `RubyVM::InstructionSequence.compile_option`.
|
|
247
247
|
* `size`, the size of the source file;
|
|
248
|
+
* `digest`, a fnv1a_64 hash of the source file;
|
|
248
249
|
* `mtime`, the last-modification timestamp of the source file when it was compiled; and
|
|
249
250
|
* `data_size`, the number of bytes following the header, which we need to read it into a buffer.
|
|
250
251
|
|
|
@@ -349,6 +350,10 @@ Bootsnap::CompileCache::ISeq.compiler_selector = ->(path) do
|
|
|
349
350
|
end
|
|
350
351
|
```
|
|
351
352
|
|
|
353
|
+
*Important note*: This feature is only fully supported by Ruby `4.0.4` and newer.
|
|
354
|
+
On older rubies the feature work except if the `Coverage` module is enabled, in which case a warning will be emitted
|
|
355
|
+
and the default Ruby compiler will be used.
|
|
356
|
+
|
|
352
357
|
## Precompilation
|
|
353
358
|
|
|
354
359
|
In development environments the bootsnap compilation cache is generated on the fly when source files are loaded.
|
data/ext/bootsnap/bootsnap.c
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
#define MAX_CACHEPATH_SIZE 1000
|
|
41
41
|
#define MAX_CACHEDIR_SIZE 981
|
|
42
42
|
|
|
43
|
-
#define KEY_SIZE
|
|
43
|
+
#define KEY_SIZE 32
|
|
44
44
|
|
|
45
45
|
#define MAX_CREATE_TEMPFILE_ATTEMPT 3
|
|
46
46
|
|
|
@@ -49,34 +49,27 @@
|
|
|
49
49
|
#endif
|
|
50
50
|
|
|
51
51
|
/*
|
|
52
|
-
* An instance of this key is written as the first
|
|
52
|
+
* An instance of this key is written as the first `KEY_SIZE` bytes of each cache file.
|
|
53
53
|
* The mtime and size members track whether the file contents have changed, and
|
|
54
|
-
* the
|
|
55
|
-
* changes to the environment that could invalidate compile results without
|
|
54
|
+
* the ruby_version_digest (bootsnap_cache_version + RUBY_DESCRIPTION) and compile_option
|
|
55
|
+
* members track changes to the environment that could invalidate compile results without
|
|
56
56
|
* file contents having changed. The data_size member is not truly part of the
|
|
57
57
|
* "key". Really, this could be called a "header" with the first six members
|
|
58
58
|
* being an embedded "key" struct and an additional data_size member.
|
|
59
59
|
*
|
|
60
60
|
* The data_size indicates the remaining number of bytes in the cache file
|
|
61
61
|
* after the header (the size of the cached artifact).
|
|
62
|
-
*
|
|
63
|
-
* After data_size, the struct is padded to 64 bytes.
|
|
64
62
|
*/
|
|
65
63
|
struct bs_cache_key {
|
|
66
|
-
|
|
67
|
-
uint32_t ruby_platform;
|
|
68
|
-
uint32_t compile_option;
|
|
69
|
-
uint32_t ruby_revision;
|
|
70
|
-
uint64_t size;
|
|
64
|
+
uint64_t ruby_version_digest;
|
|
71
65
|
uint64_t mtime;
|
|
72
|
-
uint64_t data_size; //
|
|
73
66
|
uint64_t digest;
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
uint32_t size;
|
|
68
|
+
uint32_t data_size;
|
|
76
69
|
} __attribute__((packed));
|
|
77
70
|
|
|
78
71
|
/*
|
|
79
|
-
* If the struct padding isn't correct to pad the key to
|
|
72
|
+
* If the struct padding isn't correct to pad the key to `KEY_SIZE` bytes, refuse to
|
|
80
73
|
* compile.
|
|
81
74
|
*/
|
|
82
75
|
#define STATIC_ASSERT(X) STATIC_ASSERT2(X,__LINE__)
|
|
@@ -86,15 +79,15 @@ struct bs_cache_key {
|
|
|
86
79
|
STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);
|
|
87
80
|
|
|
88
81
|
/* Effectively a schema version. Bumping invalidates all previous caches */
|
|
89
|
-
static const uint32_t
|
|
90
|
-
|
|
91
|
-
/*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
82
|
+
static const uint32_t bootsnap_cache_version = 7;
|
|
83
|
+
|
|
84
|
+
/* Invalidates cache when switching ruby version, platform or ABI */
|
|
85
|
+
static uint64_t base_ruby_version_digest = 0;
|
|
86
|
+
|
|
87
|
+
// `base_ruby_version_digest` combined with RubyVM::InstructionSequence.compile_option
|
|
88
|
+
// Invalidates cache when RubyVM::InstructionSequence.compile_option changes
|
|
89
|
+
static uint64_t current_ruby_version_digest = 0;
|
|
90
|
+
|
|
98
91
|
/* Current umask */
|
|
99
92
|
static mode_t current_umask;
|
|
100
93
|
|
|
@@ -136,8 +129,7 @@ static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handle
|
|
|
136
129
|
static VALUE bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler);
|
|
137
130
|
static int open_current_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance);
|
|
138
131
|
static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance);
|
|
139
|
-
static
|
|
140
|
-
static uint32_t get_ruby_platform(void);
|
|
132
|
+
static uint64_t get_ruby_version_digest(void);
|
|
141
133
|
|
|
142
134
|
/*
|
|
143
135
|
* Helper functions to call ruby methods on handler object without crashing on
|
|
@@ -295,8 +287,7 @@ Init_bootsnap(void)
|
|
|
295
287
|
rb_cBootsnap_CompileCache_UNCOMPILABLE = rb_const_get(rb_mBootsnap_CompileCache, rb_intern("UNCOMPILABLE"));
|
|
296
288
|
rb_global_variable(&rb_cBootsnap_CompileCache_UNCOMPILABLE);
|
|
297
289
|
|
|
298
|
-
|
|
299
|
-
current_ruby_platform = get_ruby_platform();
|
|
290
|
+
base_ruby_version_digest = get_ruby_version_digest();
|
|
300
291
|
|
|
301
292
|
instrumentation_method = rb_intern("_instrument");
|
|
302
293
|
|
|
@@ -345,28 +336,10 @@ bs_revalidation_set(VALUE self, VALUE enabled)
|
|
|
345
336
|
return enabled;
|
|
346
337
|
}
|
|
347
338
|
|
|
348
|
-
/*
|
|
349
|
-
* Bootsnap's ruby code registers a hook that notifies us via this function
|
|
350
|
-
* when compile_option changes. These changes invalidate all existing caches.
|
|
351
|
-
*
|
|
352
|
-
* Note that on 32-bit platforms, a CRC32 can't be represented in a Fixnum, but
|
|
353
|
-
* can be represented by a uint.
|
|
354
|
-
*/
|
|
355
|
-
static VALUE
|
|
356
|
-
bs_compile_option_crc32_set(VALUE self, VALUE crc32_v)
|
|
357
|
-
{
|
|
358
|
-
if (!RB_TYPE_P(crc32_v, T_BIGNUM) && !RB_TYPE_P(crc32_v, T_FIXNUM)) {
|
|
359
|
-
Check_Type(crc32_v, T_FIXNUM);
|
|
360
|
-
}
|
|
361
|
-
current_compile_option_crc32 = NUM2UINT(crc32_v);
|
|
362
|
-
return Qnil;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
339
|
static uint64_t
|
|
366
|
-
fnv1a_64_iter(uint64_t h, const
|
|
340
|
+
fnv1a_64_iter(uint64_t h, const unsigned char *s, size_t len)
|
|
367
341
|
{
|
|
368
|
-
unsigned char *
|
|
369
|
-
unsigned char *str_end = (unsigned char *)RSTRING_PTR(str) + RSTRING_LEN(str);
|
|
342
|
+
const unsigned char *str_end = s + len;
|
|
370
343
|
|
|
371
344
|
while (s < str_end) {
|
|
372
345
|
h ^= (uint64_t)*s++;
|
|
@@ -377,45 +350,43 @@ fnv1a_64_iter(uint64_t h, const VALUE str)
|
|
|
377
350
|
}
|
|
378
351
|
|
|
379
352
|
static uint64_t
|
|
380
|
-
|
|
353
|
+
fnv1a_64_iter_str(uint64_t h, const VALUE str)
|
|
354
|
+
{
|
|
355
|
+
Check_Type(str, T_STRING);
|
|
356
|
+
return fnv1a_64_iter(h, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
static uint64_t
|
|
360
|
+
fnv1a_64_str(const VALUE str)
|
|
381
361
|
{
|
|
382
362
|
uint64_t h = (uint64_t)0xcbf29ce484222325ULL;
|
|
383
|
-
return
|
|
363
|
+
return fnv1a_64_iter_str(h, str);
|
|
384
364
|
}
|
|
385
365
|
|
|
386
366
|
/*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
367
|
+
* Bootsnap's ruby code registers a hook that notifies us via this function
|
|
368
|
+
* when compile_option changes. These changes invalidate all existing caches.
|
|
369
|
+
*
|
|
370
|
+
* Note that on 32-bit platforms, a CRC32 can't be represented in a Fixnum, but
|
|
371
|
+
* can be represented by a uint.
|
|
389
372
|
*/
|
|
390
|
-
static
|
|
391
|
-
|
|
373
|
+
static VALUE
|
|
374
|
+
bs_compile_option_crc32_set(VALUE self, VALUE crc32_v)
|
|
392
375
|
{
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
ruby_revision = rb_const_get(rb_cObject, rb_intern("RUBY_REVISION"));
|
|
396
|
-
if (RB_TYPE_P(ruby_revision, RUBY_T_FIXNUM)) {
|
|
397
|
-
return FIX2INT(ruby_revision);
|
|
398
|
-
} else {
|
|
399
|
-
uint64_t hash;
|
|
400
|
-
|
|
401
|
-
hash = fnv1a_64(ruby_revision);
|
|
402
|
-
return (uint32_t)(hash >> 32);
|
|
376
|
+
if (!RB_TYPE_P(crc32_v, T_BIGNUM) && !RB_TYPE_P(crc32_v, T_FIXNUM)) {
|
|
377
|
+
Check_Type(crc32_v, T_FIXNUM);
|
|
403
378
|
}
|
|
379
|
+
uint32_t crc32 = (uint32_t)NUM2UINT(crc32_v);
|
|
380
|
+
current_ruby_version_digest = fnv1a_64_iter(base_ruby_version_digest, (unsigned char *)&crc32, sizeof(crc32));
|
|
381
|
+
return Qnil;
|
|
404
382
|
}
|
|
405
383
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
* (or OS version), we need to invalidate the cache.
|
|
409
|
-
*/
|
|
410
|
-
static uint32_t
|
|
411
|
-
get_ruby_platform(void)
|
|
384
|
+
static uint64_t
|
|
385
|
+
get_ruby_version_digest(void)
|
|
412
386
|
{
|
|
413
|
-
uint64_t hash;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
ruby_platform = rb_const_get(rb_cObject, rb_intern("RUBY_PLATFORM"));
|
|
417
|
-
hash = fnv1a_64(ruby_platform);
|
|
418
|
-
return (uint32_t)(hash >> 32);
|
|
387
|
+
uint64_t hash = fnv1a_64_str(rb_const_get(rb_cObject, rb_intern("RUBY_DESCRIPTION")));
|
|
388
|
+
hash = fnv1a_64_iter(hash, (unsigned char *)&bootsnap_cache_version, sizeof(bootsnap_cache_version));
|
|
389
|
+
return hash;
|
|
419
390
|
}
|
|
420
391
|
|
|
421
392
|
/*
|
|
@@ -443,7 +414,7 @@ bs_cache_path(VALUE cachedir_v, VALUE namespace_v, VALUE path_v, char (* cache_p
|
|
|
443
414
|
const char * cachedir = RSTRING_PTR(cachedir_v);
|
|
444
415
|
const char * namespace = NIL_P(namespace_v) ? "" : RSTRING_PTR(namespace_v);
|
|
445
416
|
|
|
446
|
-
uint64_t hash =
|
|
417
|
+
uint64_t hash = fnv1a_64_str(path_v);
|
|
447
418
|
uint8_t first_byte = (hash >> (64 - 8));
|
|
448
419
|
uint64_t remainder = hash & 0x00ffffffffffffff;
|
|
449
420
|
|
|
@@ -460,10 +431,8 @@ bs_cache_path(VALUE cachedir_v, VALUE namespace_v, VALUE path_v, char (* cache_p
|
|
|
460
431
|
*/
|
|
461
432
|
static enum cache_status cache_key_equal_fast_path(struct bs_cache_key *k1,
|
|
462
433
|
struct bs_cache_key *k2) {
|
|
463
|
-
if (k1->
|
|
464
|
-
k1->
|
|
465
|
-
k1->compile_option == k2->compile_option &&
|
|
466
|
-
k1->ruby_revision == k2->ruby_revision && k1->size == k2->size) {
|
|
434
|
+
if (k1->ruby_version_digest == k2->ruby_version_digest &&
|
|
435
|
+
k1->size == k2->size) {
|
|
467
436
|
if (k1->mtime == k2->mtime) {
|
|
468
437
|
return hit;
|
|
469
438
|
}
|
|
@@ -507,10 +476,9 @@ static int update_cache_key(struct bs_cache_key *current_key, struct bs_cache_ke
|
|
|
507
476
|
*/
|
|
508
477
|
static void bs_cache_key_digest(struct bs_cache_key *key,
|
|
509
478
|
const VALUE input_data) {
|
|
510
|
-
if (key->
|
|
479
|
+
if (key->digest)
|
|
511
480
|
return;
|
|
512
|
-
key->digest =
|
|
513
|
-
key->digest_set = 1;
|
|
481
|
+
key->digest = fnv1a_64_str(input_data);
|
|
514
482
|
}
|
|
515
483
|
|
|
516
484
|
/*
|
|
@@ -587,13 +555,19 @@ open_current_file(const char * path, struct bs_cache_key * key, const char ** er
|
|
|
587
555
|
return -1;
|
|
588
556
|
}
|
|
589
557
|
|
|
590
|
-
key->
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
558
|
+
key->ruby_version_digest = current_ruby_version_digest;
|
|
559
|
+
|
|
560
|
+
// We're limited to file of 4GiB or less. Hopefully that's enough for everyone.
|
|
561
|
+
if (statbuf.st_size > (uint32_t)-1) {
|
|
562
|
+
*errno_provenance = "bs_fetch:open_current_file:file_too_big";
|
|
563
|
+
close(fd);
|
|
564
|
+
errno = EFBIG;
|
|
565
|
+
return -1;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
key->size = (uint32_t)statbuf.st_size;
|
|
569
|
+
key->mtime = (uint64_t)statbuf.st_mtime;
|
|
570
|
+
key->digest = 0;
|
|
597
571
|
|
|
598
572
|
return fd;
|
|
599
573
|
}
|
|
@@ -663,10 +637,10 @@ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errn
|
|
|
663
637
|
|
|
664
638
|
/*
|
|
665
639
|
* The cache file is laid out like:
|
|
666
|
-
* 0
|
|
667
|
-
*
|
|
640
|
+
* 0...`KEY_SIZE` : bs_cache_key
|
|
641
|
+
* `KEY_SIZE`..-1 : cached artifact
|
|
668
642
|
*
|
|
669
|
-
* This function takes a file descriptor whose position is pre-set to
|
|
643
|
+
* This function takes a file descriptor whose position is pre-set to `KEY_SIZE`, and
|
|
670
644
|
* the data_size (corresponding to the remaining number of bytes) listed in the
|
|
671
645
|
* cache header.
|
|
672
646
|
*
|
|
@@ -782,7 +756,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, cons
|
|
|
782
756
|
setmode(fd, O_BINARY);
|
|
783
757
|
#endif
|
|
784
758
|
|
|
785
|
-
|
|
759
|
+
uint64_t data_size = RSTRING_LEN(data);
|
|
760
|
+
if (data_size > (uint32_t)-1) {
|
|
761
|
+
return 0; // Don't cache.
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
key->data_size = (uint32_t)data_size;
|
|
786
765
|
nwrite = write(fd, key, KEY_SIZE);
|
|
787
766
|
if (nwrite < 0) {
|
|
788
767
|
*errno_provenance = "bs_fetch:atomic_write_cache_file:write";
|
|
@@ -62,7 +62,7 @@ module Bootsnap
|
|
|
62
62
|
# Ref: https://github.com/rails/bootsnap/issues/495
|
|
63
63
|
# The second forked process will hang on some QEMU environments
|
|
64
64
|
r, w = IO.pipe
|
|
65
|
-
pids = 2
|
|
65
|
+
pids = Array.new(2) do
|
|
66
66
|
::Process.fork do
|
|
67
67
|
exit!(true)
|
|
68
68
|
end
|
|
@@ -161,7 +161,7 @@ module Bootsnap
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def spawn
|
|
164
|
-
@workers = @size
|
|
164
|
+
@workers = Array.new(@size) { Worker.new(@jobs) }
|
|
165
165
|
@workers.each(&:spawn)
|
|
166
166
|
@dispatcher_thread = Thread.new { dispatch_loop }
|
|
167
167
|
@dispatcher_thread.abort_on_exception = true
|
|
@@ -27,7 +27,7 @@ module Bootsnap
|
|
|
27
27
|
@compile_options = compile_options
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
|
|
30
|
+
has_ruby_bug_18250 = RUBY_VERSION.start_with?("3.0.") && begin # https://bugs.ruby-lang.org/issues/18250
|
|
31
31
|
if defined? RubyVM::InstructionSequence
|
|
32
32
|
RubyVM::InstructionSequence.compile("def foo(*); ->{ super }; end; def foo(**); ->{ super }; end").to_binary
|
|
33
33
|
end
|
|
@@ -94,23 +94,44 @@ module Bootsnap
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def input_to_output(source, path, _kwargs)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
if @compile_options
|
|
98
|
+
RubyVM::InstructionSequence.compile(
|
|
99
|
+
source.force_encoding(Encoding.default_external),
|
|
100
|
+
path,
|
|
101
|
+
path,
|
|
102
|
+
nil,
|
|
103
|
+
@compile_options,
|
|
104
|
+
)
|
|
105
|
+
end
|
|
104
106
|
end
|
|
105
107
|
end
|
|
106
108
|
|
|
107
109
|
DEFAULT = Compiler.new
|
|
108
110
|
FROZEN_STRING_LITERAL = Compiler.new("-fstr", {frozen_string_literal: true}.freeze)
|
|
109
|
-
|
|
111
|
+
COVERAGE_SUPPORTED = RUBY_VERSION >= "4.0.4"
|
|
110
112
|
@default_compiler = DEFAULT
|
|
113
|
+
@coverage_support_warning_emitted = false
|
|
111
114
|
|
|
112
115
|
def self.fetch(path, cache_dir: ISeq.cache_dir)
|
|
113
116
|
compiler = compiler_selector&.call(path) || default_compiler
|
|
117
|
+
|
|
118
|
+
# Having coverage enabled prevents iseq dumping/loading.
|
|
119
|
+
if coverage_on?
|
|
120
|
+
return nil if compiler.equal?(DEFAULT)
|
|
121
|
+
|
|
122
|
+
if COVERAGE_SUPPORTED
|
|
123
|
+
return compiler.input_to_output(File.read(path.to_s), path.to_s, nil)
|
|
124
|
+
elsif !@coverage_support_warning_emitted
|
|
125
|
+
@coverage_support_warning_emitted = true
|
|
126
|
+
warn(<<~MSG)
|
|
127
|
+
Using `Bootsnap.enable_frozen_string_literal` with code coverage enabled is only supported on Ruby 4.0.4+.
|
|
128
|
+
Files loaded while coverage is on, will have mutable string literals.
|
|
129
|
+
MSG
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
return nil
|
|
133
|
+
end
|
|
134
|
+
|
|
114
135
|
Bootsnap::CompileCache::Native.fetch(
|
|
115
136
|
cache_dir,
|
|
116
137
|
compiler.namespace,
|
|
@@ -130,14 +151,21 @@ module Bootsnap
|
|
|
130
151
|
)
|
|
131
152
|
end
|
|
132
153
|
|
|
154
|
+
if RUBY_VERSION < "3.1."
|
|
155
|
+
def self.coverage_on?
|
|
156
|
+
defined?(Coverage) && Coverage.running?
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
def self.coverage_on?
|
|
160
|
+
defined?(Coverage) && Coverage.state != :idle
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
133
164
|
module InstructionSequenceMixin
|
|
134
165
|
def load_iseq(path)
|
|
135
|
-
# Having coverage enabled prevents iseq dumping/loading.
|
|
136
|
-
return nil if defined?(Coverage) && Coverage.running?
|
|
137
|
-
|
|
138
166
|
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
|
|
139
167
|
rescue RuntimeError => error
|
|
140
|
-
if error.message
|
|
168
|
+
if error.message.include?("unmatched platform")
|
|
141
169
|
puts("unmatched platform for file #{path}")
|
|
142
170
|
end
|
|
143
171
|
raise
|
|
@@ -84,7 +84,7 @@ module Bootsnap
|
|
|
84
84
|
rescue Errno::ENOENT, MessagePack::MalformedFormatError, MessagePack::UnknownExtTypeError, EOFError
|
|
85
85
|
default_data
|
|
86
86
|
rescue ArgumentError => error
|
|
87
|
-
if error.message
|
|
87
|
+
if error.message.include?("negative array size")
|
|
88
88
|
default_data
|
|
89
89
|
else
|
|
90
90
|
raise
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bootsnap
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.24.
|
|
4
|
+
version: 1.24.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Burke Libbey
|
|
@@ -81,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
83
|
requirements: []
|
|
84
|
-
rubygems_version: 4.0.
|
|
84
|
+
rubygems_version: 4.0.10
|
|
85
85
|
specification_version: 4
|
|
86
86
|
summary: Boot large ruby/rails apps faster
|
|
87
87
|
test_files: []
|