bootsnap 1.4.5-java → 1.5.0-java

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +15 -2
  4. data/exe/bootsnap +5 -0
  5. data/ext/bootsnap/bootsnap.c +91 -64
  6. data/ext/bootsnap/extconf.rb +1 -0
  7. data/lib/bootsnap.rb +2 -0
  8. data/lib/bootsnap/bundler.rb +1 -0
  9. data/lib/bootsnap/cli.rb +136 -0
  10. data/lib/bootsnap/compile_cache.rb +3 -2
  11. data/lib/bootsnap/compile_cache/iseq.rb +15 -8
  12. data/lib/bootsnap/compile_cache/yaml.rb +67 -38
  13. data/lib/bootsnap/explicit_require.rb +1 -0
  14. data/lib/bootsnap/load_path_cache.rb +1 -1
  15. data/lib/bootsnap/load_path_cache/cache.rb +8 -8
  16. data/lib/bootsnap/load_path_cache/change_observer.rb +2 -1
  17. data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +1 -0
  18. data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +18 -5
  19. data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
  20. data/lib/bootsnap/load_path_cache/loaded_features_index.rb +33 -10
  21. data/lib/bootsnap/load_path_cache/path.rb +3 -2
  22. data/lib/bootsnap/load_path_cache/path_scanner.rb +39 -26
  23. data/lib/bootsnap/load_path_cache/realpath_cache.rb +5 -5
  24. data/lib/bootsnap/load_path_cache/store.rb +6 -5
  25. data/lib/bootsnap/setup.rb +1 -0
  26. data/lib/bootsnap/version.rb +2 -1
  27. metadata +14 -28
  28. data/.github/CODEOWNERS +0 -2
  29. data/.github/probots.yml +0 -2
  30. data/.gitignore +0 -17
  31. data/.rubocop.yml +0 -20
  32. data/.travis.yml +0 -21
  33. data/CODE_OF_CONDUCT.md +0 -74
  34. data/CONTRIBUTING.md +0 -21
  35. data/Gemfile +0 -8
  36. data/README.jp.md +0 -231
  37. data/Rakefile +0 -12
  38. data/bin/ci +0 -10
  39. data/bin/console +0 -14
  40. data/bin/setup +0 -8
  41. data/bin/test-minimal-support +0 -7
  42. data/bin/testunit +0 -8
  43. data/bootsnap.gemspec +0 -45
  44. data/dev.yml +0 -10
  45. data/shipit.rubygems.yml +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b500e88c916d4f157bc2bcb5d412fec363fa12efc3e9554c983934c89a08a43
4
- data.tar.gz: d4fc038bb787798938b56ddcf98c348f0c5a93da350e3e588eb6bfd55203bbc8
3
+ metadata.gz: a6981435a732015b8043d7ffc3a63c0603b6f1de300db2610becafc93c25b91e
4
+ data.tar.gz: d977b2ee4969224edd10530a4cb4332bcaea0298f8f147e4e3aaf846cbc584ab
5
5
  SHA512:
6
- metadata.gz: f4fa5023df7724fd9f1b076b644f5537b5b35ddd6efd1a04a3a87e0f2808b2c123f99cdd7f3772f566237aa0edcb2d9bb07236b6175e2097f044b0d25a690c32
7
- data.tar.gz: cad79a047f47abb66944b7809e613f57b0312674b1289722d2b7ad365c7d83d708a078d7cbacbe5b5ab4a452f15fb89a605612ddfe843a6913cb2b06b098e645
6
+ metadata.gz: d544e765dcc1ccd998ffd0c65ee8aeda19e0a8a37cc37a0fbcb9917384283d27902acb81c079ec7c6b3cb1fe2ffb4fa752b1b668ae34bfdfc0b695cf943159bb
7
+ data.tar.gz: 7036e0b6c86ada90a48fe5d384b029c2c2f383e3231d3bcab43cc6bb765ef49cce4dc785120bac88c293aae2f24f4e23ba6d15ba9eb5ffa953eb0f8843e5e588
@@ -1,3 +1,35 @@
1
+ # 1.5.0
2
+
3
+ * Add a command line to statically precompile the ISeq cache. (#326)
4
+
5
+ # 1.4.9
6
+
7
+ * [Windows support](https://github.com/Shopify/bootsnap/pull/319)
8
+ * [Fix potential crash](https://github.com/Shopify/bootsnap/pull/322)
9
+
10
+ # 1.4.8
11
+
12
+ * [Prevent FallbackScan from polluting exception cause](https://github.com/Shopify/bootsnap/pull/314)
13
+
14
+ # 1.4.7
15
+
16
+ * Various performance enhancements
17
+ * Fix race condition in heavy concurrent load scenarios that would cause bootsnap to raise
18
+
19
+ # 1.4.6
20
+
21
+ * Fix bug that was erroneously considering that files containing `.` in the names were being
22
+ required if a different file with the same name was already being required
23
+
24
+ Example:
25
+
26
+ require 'foo'
27
+ require 'foo.en'
28
+
29
+ Before bootsnap was considering `foo.en` to be the same file as `foo`
30
+
31
+ * Use glibc as part of the ruby_platform cache key
32
+
1
33
  # 1.4.5
2
34
 
3
35
  * MRI 2.7 support
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Bootsnap [![Build Status](https://travis-ci.org/Shopify/bootsnap.svg?branch=master)](https://travis-ci.org/Shopify/bootsnap)
1
+ # Bootsnap [![Actions Status](https://github.com/Shopify/bootsnap/workflows/ci/badge.svg)](https://github.com/Shopify/bootsnap/actions)
2
2
 
3
3
  Bootsnap is a library that plugs into Ruby, with optional support for `ActiveSupport` and `YAML`,
4
4
  to optimize and cache expensive computations. See [How Does This Work](#how-does-this-work).
@@ -214,7 +214,7 @@ Bootsnap writes a cache file containing a 64 byte header followed by the cache c
214
214
  is a cache key including several fields:
215
215
 
216
216
  * `version`, hardcoded in bootsnap. Essentially a schema version;
217
- * `os_version`, A hash of the current kernel version (on macOS, BSD) or glibc version (on Linux);
217
+ * `ruby_platform`, A hash of `RUBY_PLATFORM` (e.g. x86_64-linux-gnu) variable and glibc version (on Linux) or OS version (`uname -v` on BSD, macOS)
218
218
  * `compile_option`, which changes with `RubyVM::InstructionSequence.compile_option` does;
219
219
  * `ruby_revision`, the version of Ruby this was compiled with;
220
220
  * `size`, the size of the source file;
@@ -294,6 +294,19 @@ open /c/nope.bundle -> -1
294
294
  # (nothing!)
295
295
  ```
296
296
 
297
+ ## Precompilation
298
+
299
+ In development environments the bootsnap compilation cache is generated on the fly when source files are loaded.
300
+ But in production environments, such as docker images, you might need to precompile the cache.
301
+
302
+ To do so you can use the `bootsnap precompile` command.
303
+
304
+ Example:
305
+
306
+ ```bash
307
+ $ bundle exec bootsnap precompile --gemfile app/ lib/
308
+ ```
309
+
297
310
  ## When not to use Bootsnap
298
311
 
299
312
  *Alternative engines*: Bootsnap is pretty reliant on MRI features, and parts are disabled entirely on alternative ruby
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bootsnap/cli'
5
+ exit Bootsnap::CLI.new(ARGV).run
@@ -21,6 +21,9 @@
21
21
  #ifndef _WIN32
22
22
  #include <sys/utsname.h>
23
23
  #endif
24
+ #ifdef __GLIBC__
25
+ #include <gnu/libc-version.h>
26
+ #endif
24
27
 
25
28
  /* 1000 is an arbitrary limit; FNV64 plus some slashes brings the cap down to
26
29
  * 981 for the cache dir */
@@ -29,6 +32,8 @@
29
32
 
30
33
  #define KEY_SIZE 64
31
34
 
35
+ #define MAX_CREATE_TEMPFILE_ATTEMPT 3
36
+
32
37
  /*
33
38
  * An instance of this key is written as the first 64 bytes of each cache file.
34
39
  * The mtime and size members track whether the file contents have changed, and
@@ -86,16 +91,16 @@ static ID uncompilable;
86
91
 
87
92
  /* Functions exposed as module functions on Bootsnap::CompileCache::Native */
88
93
  static VALUE bs_compile_option_crc32_set(VALUE self, VALUE crc32_v);
89
- static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
94
+ static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args);
90
95
 
91
96
  /* Helpers */
92
97
  static uint64_t fnv1a_64(const char *str);
93
- static void bs_cache_path(const char * cachedir, const char * path, char ** cache_path);
98
+ static void bs_cache_path(const char * cachedir, const char * path, const char * extra, char (* cache_path)[MAX_CACHEPATH_SIZE]);
94
99
  static int bs_read_key(int fd, struct bs_cache_key * key);
95
100
  static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
96
- static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler);
97
- static int open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance);
98
- static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance);
101
+ static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args);
102
+ static int open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance);
103
+ 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);
99
104
  static uint32_t get_ruby_revision(void);
100
105
  static uint32_t get_ruby_platform(void);
101
106
 
@@ -103,12 +108,12 @@ static uint32_t get_ruby_platform(void);
103
108
  * Helper functions to call ruby methods on handler object without crashing on
104
109
  * exception.
105
110
  */
106
- static int bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data);
111
+ static int bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data);
107
112
  static VALUE prot_storage_to_output(VALUE arg);
108
113
  static VALUE prot_input_to_output(VALUE arg);
109
- static void bs_input_to_output(VALUE handler, VALUE input_data, VALUE * output_data, int * exception_tag);
114
+ static void bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag);
110
115
  static VALUE prot_input_to_storage(VALUE arg);
111
- static int bs_input_to_storage(VALUE handler, VALUE input_data, VALUE pathval, VALUE * storage_data);
116
+ static int bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data);
112
117
  struct s2o_data;
113
118
  struct i2o_data;
114
119
  struct i2s_data;
@@ -143,7 +148,7 @@ Init_bootsnap(void)
143
148
  uncompilable = rb_intern("__bootsnap_uncompilable__");
144
149
 
145
150
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "coverage_running?", bs_rb_coverage_running, 0);
146
- rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 3);
151
+ rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 4);
147
152
  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "compile_option_crc32=", bs_compile_option_crc32_set, 1);
148
153
 
149
154
  current_umask = umask(0777);
@@ -236,6 +241,9 @@ get_ruby_platform(void)
236
241
 
237
242
  #ifdef _WIN32
238
243
  return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
244
+ #elif defined(__GLIBC__)
245
+ hash = fnv1a_64_iter(hash, gnu_get_libc_version());
246
+ return (uint32_t)(hash >> 32);
239
247
  #else
240
248
  struct utsname utsname;
241
249
 
@@ -256,9 +264,12 @@ get_ruby_platform(void)
256
264
  * The path will look something like: <cachedir>/12/34567890abcdef
257
265
  */
258
266
  static void
259
- bs_cache_path(const char * cachedir, const char * path, char ** cache_path)
267
+ bs_cache_path(const char * cachedir, const char * path, const char * extra, char (* cache_path)[MAX_CACHEPATH_SIZE])
260
268
  {
261
269
  uint64_t hash = fnv1a_64(path);
270
+ if (extra) {
271
+ hash ^= fnv1a_64(extra);
272
+ }
262
273
 
263
274
  uint8_t first_byte = (hash >> (64 - 8));
264
275
  uint64_t remainder = hash & 0x00ffffffffffffff;
@@ -293,7 +304,7 @@ cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2)
293
304
  * conversions on the ruby VALUE arguments before passing them along.
294
305
  */
295
306
  static VALUE
296
- bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
307
+ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args)
297
308
  {
298
309
  FilePathValue(path_v);
299
310
 
@@ -307,13 +318,16 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
307
318
  char * cachedir = RSTRING_PTR(cachedir_v);
308
319
  char * path = RSTRING_PTR(path_v);
309
320
  char cache_path[MAX_CACHEPATH_SIZE];
310
-
311
- { /* generate cache path to cache_path */
312
- char * tmp = (char *)&cache_path;
313
- bs_cache_path(cachedir, path, &tmp);
321
+ char * extra = NULL;
322
+ if (!NIL_P(args)) {
323
+ VALUE args_serial = rb_marshal_dump(args, Qnil);
324
+ extra = RSTRING_PTR(args_serial);
314
325
  }
315
326
 
316
- return bs_fetch(path, path_v, cache_path, handler);
327
+ /* generate cache path to cache_path */
328
+ bs_cache_path(cachedir, path, extra, &cache_path);
329
+
330
+ return bs_fetch(path, path_v, cache_path, handler, args);
317
331
  }
318
332
 
319
333
  /*
@@ -321,14 +335,14 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
321
335
  * was loaded.
322
336
  */
323
337
  static int
324
- open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance)
338
+ open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance)
325
339
  {
326
340
  struct stat statbuf;
327
341
  int fd;
328
342
 
329
343
  fd = open(path, O_RDONLY);
330
344
  if (fd < 0) {
331
- *errno_provenance = (char *)"bs_fetch:open_current_file:open";
345
+ *errno_provenance = "bs_fetch:open_current_file:open";
332
346
  return fd;
333
347
  }
334
348
  #ifdef _WIN32
@@ -336,7 +350,7 @@ open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenan
336
350
  #endif
337
351
 
338
352
  if (fstat(fd, &statbuf) < 0) {
339
- *errno_provenance = (char *)"bs_fetch:open_current_file:fstat";
353
+ *errno_provenance = "bs_fetch:open_current_file:fstat";
340
354
  close(fd);
341
355
  return -1;
342
356
  }
@@ -382,13 +396,13 @@ bs_read_key(int fd, struct bs_cache_key * key)
382
396
  * - ERROR_WITH_ERRNO (-1, errno is set)
383
397
  */
384
398
  static int
385
- open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_provenance)
399
+ open_cache_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance)
386
400
  {
387
401
  int fd, res;
388
402
 
389
403
  fd = open(path, O_RDONLY);
390
404
  if (fd < 0) {
391
- *errno_provenance = (char *)"bs_fetch:open_cache_file:open";
405
+ *errno_provenance = "bs_fetch:open_cache_file:open";
392
406
  if (errno == ENOENT) return CACHE_MISSING_OR_INVALID;
393
407
  return ERROR_WITH_ERRNO;
394
408
  }
@@ -398,7 +412,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov
398
412
 
399
413
  res = bs_read_key(fd, key);
400
414
  if (res < 0) {
401
- *errno_provenance = (char *)"bs_fetch:open_cache_file:read";
415
+ *errno_provenance = "bs_fetch:open_cache_file:read";
402
416
  close(fd);
403
417
  return res;
404
418
  }
@@ -422,7 +436,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov
422
436
  * or exception, will be the final data returnable to the user.
423
437
  */
424
438
  static int
425
- fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance)
439
+ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance)
426
440
  {
427
441
  char * data = NULL;
428
442
  ssize_t nread;
@@ -431,7 +445,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
431
445
  VALUE storage_data;
432
446
 
433
447
  if (data_size > 100000000000) {
434
- *errno_provenance = (char *)"bs_fetch:fetch_cached_data:datasize";
448
+ *errno_provenance = "bs_fetch:fetch_cached_data:datasize";
435
449
  errno = EINVAL; /* because wtf? */
436
450
  ret = -1;
437
451
  goto done;
@@ -439,7 +453,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
439
453
  data = ALLOC_N(char, data_size);
440
454
  nread = read(fd, data, data_size);
441
455
  if (nread < 0) {
442
- *errno_provenance = (char *)"bs_fetch:fetch_cached_data:read";
456
+ *errno_provenance = "bs_fetch:fetch_cached_data:read";
443
457
  ret = -1;
444
458
  goto done;
445
459
  }
@@ -448,9 +462,9 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data,
448
462
  goto done;
449
463
  }
450
464
 
451
- storage_data = rb_str_new_static(data, data_size);
465
+ storage_data = rb_str_new(data, data_size);
452
466
 
453
- *exception_tag = bs_storage_to_output(handler, storage_data, output_data);
467
+ *exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
454
468
  ret = 0;
455
469
  done:
456
470
  if (data != NULL) xfree(data);
@@ -491,29 +505,36 @@ mkpath(char * file_path, mode_t mode)
491
505
  * path.
492
506
  */
493
507
  static int
494
- atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
508
+ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, const char ** errno_provenance)
495
509
  {
496
510
  char template[MAX_CACHEPATH_SIZE + 20];
497
511
  char * tmp_path;
498
- int fd, ret;
512
+ int fd, ret, attempt;
499
513
  ssize_t nwrite;
500
514
 
501
- tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
502
- strcat(tmp_path, ".tmp.XXXXXX");
515
+ for (attempt = 0; attempt < MAX_CREATE_TEMPFILE_ATTEMPT; ++attempt) {
516
+ tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
517
+ strcat(tmp_path, ".tmp.XXXXXX");
503
518
 
504
- // mkstemp modifies the template to be the actual created path
505
- fd = mkstemp(tmp_path);
506
- if (fd < 0) {
507
- if (mkpath(tmp_path, 0775) < 0) {
508
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:mkpath";
509
- return -1;
510
- }
511
- fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
512
- if (fd < 0) {
513
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:open";
519
+ // mkstemp modifies the template to be the actual created path
520
+ fd = mkstemp(tmp_path);
521
+ if (fd > 0) break;
522
+
523
+ if (attempt == 0 && mkpath(tmp_path, 0775) < 0) {
524
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:mkpath";
514
525
  return -1;
515
526
  }
516
527
  }
528
+ if (fd < 0) {
529
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:mkstemp";
530
+ return -1;
531
+ }
532
+
533
+ if (chmod(tmp_path, 0644) < 0) {
534
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
535
+ return -1;
536
+ }
537
+
517
538
  #ifdef _WIN32
518
539
  setmode(fd, O_BINARY);
519
540
  #endif
@@ -521,11 +542,11 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
521
542
  key->data_size = RSTRING_LEN(data);
522
543
  nwrite = write(fd, key, KEY_SIZE);
523
544
  if (nwrite < 0) {
524
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:write";
545
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:write";
525
546
  return -1;
526
547
  }
527
548
  if (nwrite != KEY_SIZE) {
528
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:keysize";
549
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:keysize";
529
550
  errno = EIO; /* Lies but whatever */
530
551
  return -1;
531
552
  }
@@ -533,7 +554,7 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
533
554
  nwrite = write(fd, RSTRING_PTR(data), RSTRING_LEN(data));
534
555
  if (nwrite < 0) return -1;
535
556
  if (nwrite != RSTRING_LEN(data)) {
536
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:writelength";
557
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:writelength";
537
558
  errno = EIO; /* Lies but whatever */
538
559
  return -1;
539
560
  }
@@ -541,12 +562,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
541
562
  close(fd);
542
563
  ret = rename(tmp_path, path);
543
564
  if (ret < 0) {
544
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:rename";
565
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:rename";
545
566
  return -1;
546
567
  }
547
568
  ret = chmod(path, 0664 & ~current_umask);
548
569
  if (ret < 0) {
549
- *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:chmod";
570
+ *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
550
571
  }
551
572
  return ret;
552
573
  }
@@ -555,13 +576,13 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char
555
576
  /* Read contents from an fd, whose contents are asserted to be +size+ bytes
556
577
  * long, into a buffer */
557
578
  static ssize_t
558
- bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance)
579
+ bs_read_contents(int fd, size_t size, char ** contents, const char ** errno_provenance)
559
580
  {
560
581
  ssize_t nread;
561
582
  *contents = ALLOC_N(char, size);
562
583
  nread = read(fd, *contents, size);
563
584
  if (nread < 0) {
564
- *errno_provenance = (char *)"bs_fetch:bs_read_contents:read";
585
+ *errno_provenance = "bs_fetch:bs_read_contents:read";
565
586
  }
566
587
  return nread;
567
588
  }
@@ -611,13 +632,13 @@ bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance
611
632
  * - Return storage_to_output(storage_data)
612
633
  */
613
634
  static VALUE
614
- bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
635
+ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args)
615
636
  {
616
637
  struct bs_cache_key cached_key, current_key;
617
638
  char * contents = NULL;
618
639
  int cache_fd = -1, current_fd = -1;
619
640
  int res, valid_cache = 0, exception_tag = 0;
620
- char * errno_provenance = NULL;
641
+ const char * errno_provenance = NULL;
621
642
 
622
643
  VALUE input_data; /* data read from source file, e.g. YAML or ruby source */
623
644
  VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
@@ -644,7 +665,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
644
665
  if (valid_cache) {
645
666
  /* Fetch the cache data and return it if we're able to load it successfully */
646
667
  res = fetch_cached_data(
647
- cache_fd, (ssize_t)cached_key.data_size, handler,
668
+ cache_fd, (ssize_t)cached_key.data_size, handler, args,
648
669
  &output_data, &exception_tag, &errno_provenance
649
670
  );
650
671
  if (exception_tag != 0) goto raise;
@@ -658,15 +679,15 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
658
679
 
659
680
  /* Read the contents of the source file into a buffer */
660
681
  if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
661
- input_data = rb_str_new_static(contents, current_key.size);
682
+ input_data = rb_str_new(contents, current_key.size);
662
683
 
663
684
  /* Try to compile the input_data using input_to_storage(input_data) */
664
- exception_tag = bs_input_to_storage(handler, input_data, path_v, &storage_data);
685
+ exception_tag = bs_input_to_storage(handler, args, input_data, path_v, &storage_data);
665
686
  if (exception_tag != 0) goto raise;
666
687
  /* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
667
688
  * to cache anything; just return input_to_output(input_data) */
668
689
  if (storage_data == uncompilable) {
669
- bs_input_to_output(handler, input_data, &output_data, &exception_tag);
690
+ bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
670
691
  if (exception_tag != 0) goto raise;
671
692
  goto succeed;
672
693
  }
@@ -678,17 +699,17 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
678
699
  if (res < 0) goto fail_errno;
679
700
 
680
701
  /* Having written the cache, now convert storage_data to output_data */
681
- exception_tag = bs_storage_to_output(handler, storage_data, &output_data);
702
+ exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
682
703
  if (exception_tag != 0) goto raise;
683
704
 
684
705
  /* If output_data is nil, delete the cache entry and generate the output
685
706
  * using input_to_output */
686
707
  if (NIL_P(output_data)) {
687
708
  if (unlink(cache_path) < 0) {
688
- errno_provenance = (char *)"bs_fetch:unlink";
709
+ errno_provenance = "bs_fetch:unlink";
689
710
  goto fail_errno;
690
711
  }
691
- bs_input_to_output(handler, input_data, &output_data, &exception_tag);
712
+ bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
692
713
  if (exception_tag != 0) goto raise;
693
714
  }
694
715
 
@@ -738,16 +759,19 @@ invalid_type_storage_data:
738
759
 
739
760
  struct s2o_data {
740
761
  VALUE handler;
762
+ VALUE args;
741
763
  VALUE storage_data;
742
764
  };
743
765
 
744
766
  struct i2o_data {
745
767
  VALUE handler;
768
+ VALUE args;
746
769
  VALUE input_data;
747
770
  };
748
771
 
749
772
  struct i2s_data {
750
773
  VALUE handler;
774
+ VALUE args;
751
775
  VALUE input_data;
752
776
  VALUE pathval;
753
777
  };
@@ -756,15 +780,16 @@ static VALUE
756
780
  prot_storage_to_output(VALUE arg)
757
781
  {
758
782
  struct s2o_data * data = (struct s2o_data *)arg;
759
- return rb_funcall(data->handler, rb_intern("storage_to_output"), 1, data->storage_data);
783
+ return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
760
784
  }
761
785
 
762
786
  static int
763
- bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data)
787
+ bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data)
764
788
  {
765
789
  int state;
766
790
  struct s2o_data s2o_data = {
767
791
  .handler = handler,
792
+ .args = args,
768
793
  .storage_data = storage_data,
769
794
  };
770
795
  *output_data = rb_protect(prot_storage_to_output, (VALUE)&s2o_data, &state);
@@ -772,10 +797,11 @@ bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data)
772
797
  }
773
798
 
774
799
  static void
775
- bs_input_to_output(VALUE handler, VALUE input_data, VALUE * output_data, int * exception_tag)
800
+ bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag)
776
801
  {
777
802
  struct i2o_data i2o_data = {
778
803
  .handler = handler,
804
+ .args = args,
779
805
  .input_data = input_data,
780
806
  };
781
807
  *output_data = rb_protect(prot_input_to_output, (VALUE)&i2o_data, exception_tag);
@@ -785,18 +811,18 @@ static VALUE
785
811
  prot_input_to_output(VALUE arg)
786
812
  {
787
813
  struct i2o_data * data = (struct i2o_data *)arg;
788
- return rb_funcall(data->handler, rb_intern("input_to_output"), 1, data->input_data);
814
+ return rb_funcall(data->handler, rb_intern("input_to_output"), 2, data->input_data, data->args);
789
815
  }
790
816
 
791
817
  static VALUE
792
818
  try_input_to_storage(VALUE arg)
793
819
  {
794
820
  struct i2s_data * data = (struct i2s_data *)arg;
795
- return rb_funcall(data->handler, rb_intern("input_to_storage"), 2, data->input_data, data->pathval);
821
+ return rb_funcall(data->handler, rb_intern("input_to_storage"), 3, data->input_data, data->pathval, data->args);
796
822
  }
797
823
 
798
824
  static VALUE
799
- rescue_input_to_storage(VALUE arg)
825
+ rescue_input_to_storage(VALUE arg, VALUE e)
800
826
  {
801
827
  return uncompilable;
802
828
  }
@@ -812,11 +838,12 @@ prot_input_to_storage(VALUE arg)
812
838
  }
813
839
 
814
840
  static int
815
- bs_input_to_storage(VALUE handler, VALUE input_data, VALUE pathval, VALUE * storage_data)
841
+ bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
816
842
  {
817
843
  int state;
818
844
  struct i2s_data i2s_data = {
819
845
  .handler = handler,
846
+ .args = args,
820
847
  .input_data = input_data,
821
848
  .pathval = pathval,
822
849
  };