bootsnap 1.7.5 → 1.11.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7dac6bb1ac2018e46d1cdac77a243cc1e2d46d8dc24deb0a9248320451549ba
4
- data.tar.gz: 9cd95e8c52993daffd79f1d21961c5754f88642250c9552881f30f26f9dcc462
3
+ metadata.gz: 1cc142349008790c310bcbc875a437996403242e579f85fb48f46eceecb383ad
4
+ data.tar.gz: fa1d21fafa8a4fa4d44ced76d597b773d3321e077dc815ccbcae3fe9dc4e661a
5
5
  SHA512:
6
- metadata.gz: e6cee7f1ed6c30d819e576fa79d1e627585996d139dd4add684fc22d4bf720ae1c0f778bb1ee23c2a7819d788c7956b9632f03b5861bb7f6e507f3562687b70e
7
- data.tar.gz: 505de0bcbfa90ab03fde256bea4dec4f5728482b61d452887da7a49c84894daff61c1aa0b16a2a114ddab142ae2a75d09f4447de80a6b33068ea0c15ec0fdd8f
6
+ metadata.gz: 81445538692ae0dc34b7309c44195fce5c864e508afe6eed4124d3d87bc1bfa07fd2ddb2c602faa2409f1537f8da63b885fd692bdc74e961febdd2a39e6e1919
7
+ data.tar.gz: 6389ce3a667c528660976665ce8184fb61d638da6cd4040e7b2d55441679574bdf691e4991294396c19a6e79bbf185ba1cdca848d5ea499a5b8e197dca143a5f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,114 @@
1
1
  # Unreleased
2
2
 
3
+ # 1.11.1
4
+
5
+ * Fix the `can't modify frozen Hash` error on load path cache mutation. See #411.
6
+
7
+ # 1.11.0
8
+
9
+ * Drop dependency on `fileutils`.
10
+
11
+ * Better respect `Kernel#require` duck typing. While it almost never comes up in practice, `Kernel#require`
12
+ follow a fairly intricate duck-typing protocol on its argument implemented as `rb_get_path(VALUE)` in MRI.
13
+ So when applicable we bind `rb_get_path` and use it for improved compatibility. See #396 and #406.
14
+
15
+ * Get rid of the `Kernel.require_relative` decorator by resolving `$LOAD_PATH` members to their real path.
16
+ This way we handle symlinks in `$LOAD_PATH` much more efficiently. See #402 for the detailed explanation.
17
+
18
+ * Drop support for Ruby 2.3 (to allow getting rid of the `Kernel.require_relative` decorator).
19
+
20
+ # 1.10.3
21
+
22
+ * Fix Regexp and Date type support in YAML compile cache. (#400)
23
+
24
+ * Improve the YAML compile cache to support `UTF-8` symbols. (#398, #399)
25
+ [The default `MessagePack` symbol serializer assumes all symbols are ASCII](https://github.com/msgpack/msgpack-ruby/pull/211),
26
+ because of this, non-ASCII compatible symbol would be restored with `ASCII_8BIT` encoding (AKA `BINARY`).
27
+ Bootsnap now properly cache them in `UTF-8`.
28
+
29
+ Note that the above only apply for actual YAML symbols (e..g `--- :foo`).
30
+ The issue is still present for string keys parsed with `YAML.load_file(..., symbolize_names: true)`, that is a bug
31
+ in `msgpack` that will hopefully be solved soon, see: https://github.com/msgpack/msgpack-ruby/pull/246
32
+
33
+ * Entirely disable the YAML compile cache if `Encoding.default_internal` is set to an encoding not supported by `msgpack`. (#398)
34
+ `Psych` coerce strings to `Encoding.default_internal`, but `MessagePack` doesn't. So in this scenario we can't provide
35
+ YAML caching at all without returning the strings in the wrong encoding.
36
+ This never came up in practice but might as well be safe.
37
+
38
+ # 1.10.2
39
+
40
+ * Reduce the `Kernel.require` extra stack frames some more. Now bootsnap should only add one extra frame per `require` call.
41
+
42
+ * Better check `freeze` option support in JSON compile cache.
43
+ Previously `JSON.load_file(..., freeze: true)` would be cached even when the msgpack version is missing support for it.
44
+
45
+ # 1.10.1
46
+
47
+ * Fix `Kernel#autoload`'s fallback path always being executed.
48
+
49
+ * Consider `unlink` failing with `ENOENT` as a success.
50
+
51
+ # 1.10.0
52
+
53
+ * Delay requiring `FileUtils`. (#285)
54
+ `FileUtils` can be installed as a gem, so it's best to wait for bundler to have setup the load path before requiring it.
55
+
56
+ * Improve support of Psych 4. (#392)
57
+ Since `1.8.0`, `YAML.load_file` was no longer cached when Psych 4 was used. This is because `load_file` loads
58
+ in safe mode by default, so the Bootsnap cache could defeat that safety.
59
+ Now when precompiling YAML files, Bootsnap first try to parse them in safe mode, and if it can't fallback to unsafe mode,
60
+ and the cache contains a flag that records whether it was generated in safe mode or not.
61
+ `YAML.unsafe_load_file` will use safe caches just fine, but `YAML.load_file` will fallback to uncached YAML parsing
62
+ if the cache was generated using unsafe parsing.
63
+
64
+ * Minimize the Kernel.require extra stack frames. (#393)
65
+ This should reduce the noise generated by bootsnap on `LoadError`.
66
+
67
+ # 1.9.4
68
+
69
+ * Ignore absolute paths in the loaded feature index. (#385)
70
+ This fixes a compatibility issue with Zeitwerk when Zeitwerk is loaded before bootsnap. It also should
71
+ reduce the memory usage and improve load performance of Zeitwerk managed files.
72
+
73
+ * Automatically invalidate the load path cache whenever the Ruby version change. (#387)
74
+ This is to avoid issues in case the same installation path is re-used for subsequent ruby patch releases.
75
+
76
+ # 1.9.3
77
+
78
+ * Only disable the compile cache for source files impacted by [Ruby 3.0.3 [Bug 18250]](https://bugs.ruby-lang.org/issues/18250).
79
+ This should keep the performance loss to a minimum.
80
+
81
+ # 1.9.2
82
+
83
+ * Disable compile cache if [Ruby 3.0.3's ISeq cache bug](https://bugs.ruby-lang.org/issues/18250) is detected.
84
+ AKA `iseq.rb:13 to_binary: wrong argument type false (expected Symbol)`
85
+ * Fix `Kernel.load` behavior: before `load 'a'` would load `a.rb` (and other tried extensions) and wouldn't load `a` unless `development_mode: true`, now only `a` would be loaded and files with extensions wouldn't be.
86
+
87
+ # 1.9.1
88
+
89
+ * Removed a forgotten debug statement in JSON precompilation.
90
+
91
+ # 1.9.0
92
+
93
+ * Added a compilation cache for `JSON.load_file`. (#370)
94
+
95
+ # 1.8.1
96
+
97
+ * Fixed support for older Psych. (#369)
98
+
99
+ # 1.8.0
100
+
101
+ * Improve support for Psych 4. (#368)
102
+
103
+ # 1.7.7
104
+
105
+ * Fix `require_relative` in evaled code on latest ruby 3.1.0-dev. (#366)
106
+
107
+ # 1.7.6
108
+
109
+ * Fix reliance on `set` to be required.
110
+ * Fix `Encoding::UndefinedConversionError` error for Rails applications when precompiling cache. (#364)
111
+
3
112
  # 1.7.5
4
113
 
5
114
  * Handle a regression of Ruby 2.7.3 causing Bootsnap to call the deprecated `untaint` method. (#360)
@@ -7,8 +116,8 @@
7
116
 
8
117
  # 1.7.4
9
118
 
10
- * Stop raising errors when encoutering various file system errors. The cache is now best effort,
11
- if somehow it can't be saved, bootsnapp will gracefully fallback to the original operation (e.g. `Kernel.require`).
119
+ * Stop raising errors when encountering various file system errors. The cache is now best effort,
120
+ if somehow it can't be saved, bootsnap will gracefully fallback to the original operation (e.g. `Kernel.require`).
12
121
  (#353, #177, #262)
13
122
 
14
123
  # 1.7.3
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2017 Shopify, Inc.
3
+ Copyright (c) 2017-present Shopify, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -41,7 +41,7 @@ getting progressively slower, this is almost certainly the cause.**
41
41
  It's technically possible to simply specify `gem 'bootsnap', require: 'bootsnap/setup'`, but it's
42
42
  important to load Bootsnap as early as possible to get maximum performance improvement.
43
43
 
44
- You can see how this require works [here](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/setup.rb).
44
+ You can see how this require works [here](https://github.com/Shopify/bootsnap/blob/main/lib/bootsnap/setup.rb).
45
45
 
46
46
  If you are not using Rails, or if you are but want more control over things, add this to your
47
47
  application setup immediately after `require 'bundler/setup'` (i.e. as early as possible: the sooner
@@ -161,7 +161,7 @@ The only directories considered "stable" are things under the Ruby install prefi
161
161
  "volatile".
162
162
 
163
163
  In addition to the [`Bootsnap::LoadPathCache::Cache`
164
- source](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/load_path_cache/cache.rb),
164
+ source](https://github.com/Shopify/bootsnap/blob/main/lib/bootsnap/load_path_cache/cache.rb),
165
165
  this diagram may help clarify how entry resolution works:
166
166
 
167
167
  ![How path searching works](https://cloud.githubusercontent.com/assets/3074765/25388270/670b5652-299b-11e7-87fb-975647f68981.png)
data/exe/bootsnap CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'bootsnap/cli'
4
+ require "bootsnap/cli"
5
5
  exit Bootsnap::CLI.new(ARGV).run
@@ -75,7 +75,7 @@ struct bs_cache_key {
75
75
  STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);
76
76
 
77
77
  /* Effectively a schema version. Bumping invalidates all previous caches */
78
- static const uint32_t current_version = 3;
78
+ static const uint32_t current_version = 4;
79
79
 
80
80
  /* hash of e.g. "x86_64-darwin17", invalidating when ruby is recompiled on a
81
81
  * new OS ABI, etc. */
@@ -91,8 +91,7 @@ static mode_t current_umask;
91
91
  static VALUE rb_mBootsnap;
92
92
  static VALUE rb_mBootsnap_CompileCache;
93
93
  static VALUE rb_mBootsnap_CompileCache_Native;
94
- static VALUE rb_eBootsnap_CompileCache_Uncompilable;
95
- static ID uncompilable;
94
+ static VALUE rb_cBootsnap_CompileCache_UNCOMPILABLE;
96
95
  static ID instrumentation_method;
97
96
  static VALUE sym_miss;
98
97
  static VALUE sym_stale;
@@ -120,10 +119,8 @@ static uint32_t get_ruby_platform(void);
120
119
  * exception.
121
120
  */
122
121
  static int bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data);
123
- static VALUE prot_storage_to_output(VALUE arg);
124
122
  static VALUE prot_input_to_output(VALUE arg);
125
123
  static void bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag);
126
- static VALUE prot_input_to_storage(VALUE arg);
127
124
  static int bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data);
128
125
  struct s2o_data;
129
126
  struct i2o_data;
@@ -138,6 +135,12 @@ bs_rb_coverage_running(VALUE self)
138
135
  return RTEST(cov) ? Qtrue : Qfalse;
139
136
  }
140
137
 
138
+ static VALUE
139
+ bs_rb_get_path(VALUE self, VALUE fname)
140
+ {
141
+ return rb_get_path(fname);
142
+ }
143
+
141
144
  /*
142
145
  * Ruby C extensions are initialized by calling Init_<extname>.
143
146
  *
@@ -149,14 +152,17 @@ void
149
152
  Init_bootsnap(void)
150
153
  {
151
154
  rb_mBootsnap = rb_define_module("Bootsnap");
155
+
156
+ rb_define_singleton_method(rb_mBootsnap, "rb_get_path", bs_rb_get_path, 1);
157
+
152
158
  rb_mBootsnap_CompileCache = rb_define_module_under(rb_mBootsnap, "CompileCache");
153
159
  rb_mBootsnap_CompileCache_Native = rb_define_module_under(rb_mBootsnap_CompileCache, "Native");
154
- rb_eBootsnap_CompileCache_Uncompilable = rb_define_class_under(rb_mBootsnap_CompileCache, "Uncompilable", rb_eStandardError);
160
+ rb_cBootsnap_CompileCache_UNCOMPILABLE = rb_const_get(rb_mBootsnap_CompileCache, rb_intern("UNCOMPILABLE"));
161
+ rb_global_variable(&rb_cBootsnap_CompileCache_UNCOMPILABLE);
155
162
 
156
163
  current_ruby_revision = get_ruby_revision();
157
164
  current_ruby_platform = get_ruby_platform();
158
165
 
159
- uncompilable = rb_intern("__bootsnap_uncompilable__");
160
166
  instrumentation_method = rb_intern("_instrument");
161
167
 
162
168
  sym_miss = ID2SYM(rb_intern("miss"));
@@ -426,6 +432,7 @@ open_current_file(char * path, struct bs_cache_key * key, const char ** errno_pr
426
432
  #define ERROR_WITH_ERRNO -1
427
433
  #define CACHE_MISS -2
428
434
  #define CACHE_STALE -3
435
+ #define CACHE_UNCOMPILABLE -4
429
436
 
430
437
  /*
431
438
  * Read the cache key from the given fd, which must have position 0 (e.g.
@@ -507,14 +514,14 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
507
514
  if (data_size > 100000000000) {
508
515
  *errno_provenance = "bs_fetch:fetch_cached_data:datasize";
509
516
  errno = EINVAL; /* because wtf? */
510
- ret = -1;
517
+ ret = ERROR_WITH_ERRNO;
511
518
  goto done;
512
519
  }
513
520
  data = ALLOC_N(char, data_size);
514
521
  nread = read(fd, data, data_size);
515
522
  if (nread < 0) {
516
523
  *errno_provenance = "bs_fetch:fetch_cached_data:read";
517
- ret = -1;
524
+ ret = ERROR_WITH_ERRNO;
518
525
  goto done;
519
526
  }
520
527
  if (nread != data_size) {
@@ -525,6 +532,10 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE *
525
532
  storage_data = rb_str_new(data, data_size);
526
533
 
527
534
  *exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
535
+ if (*output_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
536
+ ret = CACHE_UNCOMPILABLE;
537
+ goto done;
538
+ }
528
539
  ret = 0;
529
540
  done:
530
541
  if (data != NULL) xfree(data);
@@ -737,7 +748,15 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
737
748
  &output_data, &exception_tag, &errno_provenance
738
749
  );
739
750
  if (exception_tag != 0) goto raise;
740
- else if (res == CACHE_MISS || res == CACHE_STALE) valid_cache = 0;
751
+ else if (res == CACHE_UNCOMPILABLE) {
752
+ /* If fetch_cached_data returned `Uncompilable` we fallback to `input_to_output`
753
+ This happens if we have say, an unsafe YAML cache, but try to load it in safe mode */
754
+ if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
755
+ input_data = rb_str_new(contents, current_key.size);
756
+ bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
757
+ if (exception_tag != 0) goto raise;
758
+ goto succeed;
759
+ } else if (res == CACHE_MISS || res == CACHE_STALE) valid_cache = 0;
741
760
  else if (res == ERROR_WITH_ERRNO) goto fail_errno;
742
761
  else if (!NIL_P(output_data)) goto succeed; /* fast-path, goal */
743
762
  }
@@ -754,7 +773,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
754
773
  if (exception_tag != 0) goto raise;
755
774
  /* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
756
775
  * to cache anything; just return input_to_output(input_data) */
757
- if (storage_data == uncompilable) {
776
+ if (storage_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
758
777
  bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
759
778
  if (exception_tag != 0) goto raise;
760
779
  goto succeed;
@@ -772,12 +791,20 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args
772
791
  exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
773
792
  if (exception_tag != 0) goto raise;
774
793
 
775
- /* If output_data is nil, delete the cache entry and generate the output
776
- * using input_to_output */
777
- if (NIL_P(output_data)) {
794
+ if (output_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
795
+ /* If storage_to_output returned `Uncompilable` we fallback to `input_to_output` */
796
+ bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
797
+ if (exception_tag != 0) goto raise;
798
+ } else if (NIL_P(output_data)) {
799
+ /* If output_data is nil, delete the cache entry and generate the output
800
+ * using input_to_output */
778
801
  if (unlink(cache_path) < 0) {
779
- errno_provenance = "bs_fetch:unlink";
780
- goto fail_errno;
802
+ /* If the cache was already deleted, it might be that another process did it before us.
803
+ * No point raising an error */
804
+ if (errno != ENOENT) {
805
+ errno_provenance = "bs_fetch:unlink";
806
+ goto fail_errno;
807
+ }
781
808
  }
782
809
  bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
783
810
  if (exception_tag != 0) goto raise;
@@ -856,7 +883,7 @@ bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
856
883
 
857
884
  /* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
858
885
  * to cache anything; just return false */
859
- if (storage_data == uncompilable) {
886
+ if (storage_data == rb_cBootsnap_CompileCache_UNCOMPILABLE) {
860
887
  goto fail;
861
888
  }
862
889
  /* If storage_data isn't a string, we can't cache it */
@@ -919,7 +946,7 @@ struct i2s_data {
919
946
  };
920
947
 
921
948
  static VALUE
922
- prot_storage_to_output(VALUE arg)
949
+ try_storage_to_output(VALUE arg)
923
950
  {
924
951
  struct s2o_data * data = (struct s2o_data *)arg;
925
952
  return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
@@ -934,7 +961,7 @@ bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * outp
934
961
  .args = args,
935
962
  .storage_data = storage_data,
936
963
  };
937
- *output_data = rb_protect(prot_storage_to_output, (VALUE)&s2o_data, &state);
964
+ *output_data = rb_protect(try_storage_to_output, (VALUE)&s2o_data, &state);
938
965
  return state;
939
966
  }
940
967
 
@@ -963,22 +990,6 @@ try_input_to_storage(VALUE arg)
963
990
  return rb_funcall(data->handler, rb_intern("input_to_storage"), 2, data->input_data, data->pathval);
964
991
  }
965
992
 
966
- static VALUE
967
- rescue_input_to_storage(VALUE arg, VALUE e)
968
- {
969
- return uncompilable;
970
- }
971
-
972
- static VALUE
973
- prot_input_to_storage(VALUE arg)
974
- {
975
- struct i2s_data * data = (struct i2s_data *)arg;
976
- return rb_rescue2(
977
- try_input_to_storage, (VALUE)data,
978
- rescue_input_to_storage, Qnil,
979
- rb_eBootsnap_CompileCache_Uncompilable, 0);
980
- }
981
-
982
993
  static int
983
994
  bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
984
995
  {
@@ -988,6 +999,6 @@ bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval,
988
999
  .input_data = input_data,
989
1000
  .pathval = pathval,
990
1001
  };
991
- *storage_data = rb_protect(prot_input_to_storage, (VALUE)&i2s_data, &state);
1002
+ *storage_data = rb_protect(try_input_to_storage, (VALUE)&i2s_data, &state);
992
1003
  return state;
993
1004
  }
@@ -1,21 +1,23 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require("mkmf")
3
4
 
4
- if RUBY_ENGINE == 'ruby'
5
- $CFLAGS << ' -O3 '
6
- $CFLAGS << ' -std=c99'
5
+ if RUBY_ENGINE == "ruby"
6
+ $CFLAGS << " -O3 "
7
+ $CFLAGS << " -std=c99"
7
8
 
8
9
  # ruby.h has some -Wpedantic fails in some cases
9
10
  # (e.g. https://github.com/Shopify/bootsnap/issues/15)
10
- unless ['0', '', nil].include?(ENV['BOOTSNAP_PEDANTIC'])
11
- $CFLAGS << ' -Wall'
12
- $CFLAGS << ' -Werror'
13
- $CFLAGS << ' -Wextra'
14
- $CFLAGS << ' -Wpedantic'
11
+ unless ["0", "", nil].include?(ENV["BOOTSNAP_PEDANTIC"])
12
+ $CFLAGS << " -Wall"
13
+ $CFLAGS << " -Werror"
14
+ $CFLAGS << " -Wextra"
15
+ $CFLAGS << " -Wpedantic"
15
16
 
16
- $CFLAGS << ' -Wno-unused-parameter' # VALUE self has to be there but we don't care what it is.
17
- $CFLAGS << ' -Wno-keyword-macro' # hiding return
18
- $CFLAGS << ' -Wno-gcc-compat' # ruby.h 2.6.0 on macos 10.14, dunno
17
+ $CFLAGS << " -Wno-unused-parameter" # VALUE self has to be there but we don't care what it is.
18
+ $CFLAGS << " -Wno-keyword-macro" # hiding return
19
+ $CFLAGS << " -Wno-gcc-compat" # ruby.h 2.6.0 on macos 10.14, dunno
20
+ $CFLAGS << " -Wno-compound-token-split-by-macro"
19
21
  end
20
22
 
21
23
  create_makefile("bootsnap/bootsnap")
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Bootsnap
3
4
  extend(self)
4
5
 
@@ -37,7 +37,11 @@ module Bootsnap
37
37
 
38
38
  def initialize(jobs)
39
39
  @jobs = jobs
40
- @pipe_out, @to_io = IO.pipe
40
+ @pipe_out, @to_io = IO.pipe(binmode: true)
41
+ # Set the writer encoding to binary since IO.pipe only sets it for the reader.
42
+ # https://github.com/rails/rails/issues/16514#issuecomment-52313290
43
+ @to_io.set_encoding(Encoding::BINARY)
44
+
41
45
  @pid = nil
42
46
  end
43
47
 
@@ -59,6 +63,7 @@ module Bootsnap
59
63
  loop do
60
64
  job, *args = Marshal.load(@pipe_out)
61
65
  return if job == :exit
66
+
62
67
  @jobs.fetch(job).call(*args)
63
68
  end
64
69
  rescue IOError