bootsnap 1.24.4 → 1.24.6
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 +9 -0
- data/ext/bootsnap/bootsnap.c +4 -1
- data/lib/bootsnap/cli.rb +1 -1
- data/lib/bootsnap/compile_cache/iseq.rb +167 -138
- data/lib/bootsnap/compile_cache/ruby_bug_22023_canary.rb +0 -6
- data/lib/bootsnap/version.rb +1 -1
- data/lib/bootsnap.rb +15 -11
- 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: c89c653bbd5db473e06179c6606268271c8c540a588cca938662f168d64f2d39
|
|
4
|
+
data.tar.gz: 449c08c79a258dea90e56646c9d62a06e1d696c065ce96c38a7f50ef2fb83f7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ea80faffec0206b9bb7b3d19c1419b2e7eefc2dc5f4eb03352862b83afa07ed293d0b15f04fc069d89dac1cd4d4636770626e90e6129ffad77f0cfcb8c3f676
|
|
7
|
+
data.tar.gz: 82dcb1a4c934a9de29a8aa935ffe2d1a7c6e23ebf36ea743c3d29a4d9a1d8bd42696cdefd37dacdd21a4102f88f0b605d1cc6faef9c15ccdc6d99eef15f4483e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Unreleased
|
|
2
2
|
|
|
3
|
+
# 1.24.6
|
|
4
|
+
|
|
5
|
+
* Fix detection of Ruby bug #22023 on some patch versions of Ruby 3.4, and properly apply the workaround.
|
|
6
|
+
|
|
7
|
+
# 1.24.5
|
|
8
|
+
|
|
9
|
+
* No longer load the config file by default when setup is done manually. This is so cli applications like homebrew
|
|
10
|
+
don't mistakenly load another app's boostnap config.
|
|
11
|
+
|
|
3
12
|
# 1.24.4
|
|
4
13
|
|
|
5
14
|
* Fix several compatibility issues with Ruby `4.0.4`, particularly the `should not compile with coverage` error. See #547.
|
data/ext/bootsnap/bootsnap.c
CHANGED
|
@@ -403,11 +403,14 @@ bs_cache_path(VALUE cachedir_v, VALUE namespace_v, VALUE path_v, char (* cache_p
|
|
|
403
403
|
|
|
404
404
|
Check_Type(cachedir_v, T_STRING);
|
|
405
405
|
Check_Type(path_v, T_STRING);
|
|
406
|
+
|
|
407
|
+
long namespace_len = 0;
|
|
406
408
|
if (!NIL_P(namespace_v)) {
|
|
407
409
|
Check_Type(namespace_v, T_STRING);
|
|
410
|
+
namespace_len = RSTRING_LEN(namespace_v);
|
|
408
411
|
}
|
|
409
412
|
|
|
410
|
-
if (RSTRING_LEN(cachedir_v) > MAX_CACHEDIR_SIZE) {
|
|
413
|
+
if (RSTRING_LEN(cachedir_v) + namespace_len > MAX_CACHEDIR_SIZE) {
|
|
411
414
|
rb_raise(rb_eArgError, "cachedir too long");
|
|
412
415
|
}
|
|
413
416
|
|
data/lib/bootsnap/cli.rb
CHANGED
|
@@ -19,180 +19,209 @@ module Bootsnap
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
if supported?
|
|
23
|
+
class Compiler
|
|
24
|
+
attr_reader :namespace
|
|
25
|
+
|
|
26
|
+
def initialize(namespace = nil, compile_options = nil)
|
|
27
|
+
@namespace = namespace
|
|
28
|
+
@options = compile_options.freeze
|
|
29
|
+
update_options
|
|
30
|
+
end
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
def update_options
|
|
33
|
+
@compile_options = if @options.nil? || @options < RubyVM::InstructionSequence.compile_option
|
|
34
|
+
nil
|
|
35
|
+
else
|
|
36
|
+
RubyVM::InstructionSequence.compile_option.merge(@options).freeze
|
|
37
|
+
end
|
|
33
38
|
end
|
|
34
|
-
false
|
|
35
|
-
rescue TypeError
|
|
36
|
-
true
|
|
37
|
-
end
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
has_ruby_bug_18250 = RUBY_VERSION.start_with?("3.0.") && begin # https://bugs.ruby-lang.org/issues/18250
|
|
41
|
+
if defined? RubyVM::InstructionSequence
|
|
42
|
+
RubyVM::InstructionSequence.compile(<<~RUBY).to_binary
|
|
43
|
+
def foo(*); ->{ super }; end; def foo(**); ->{ super }; end
|
|
44
|
+
RUBY
|
|
45
|
+
end
|
|
42
46
|
false
|
|
43
|
-
rescue
|
|
47
|
+
rescue TypeError
|
|
44
48
|
true
|
|
45
49
|
end
|
|
46
|
-
end
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
has_ruby_bug_22023 = case RUBY_VERSION
|
|
52
|
+
when /^3\.3\./
|
|
53
|
+
true
|
|
54
|
+
when /^3\.4\.(\d+)/
|
|
55
|
+
$1.to_i < 10
|
|
56
|
+
when /^4\.0\.(\d+)/
|
|
57
|
+
$1.to_i < 4
|
|
58
|
+
else
|
|
59
|
+
false
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if has_ruby_bug_22023 && RUBY_DESCRIPTION.include?("+PRISM")
|
|
63
|
+
module PatchRubyBug22023
|
|
64
|
+
def compile_file(path, options = nil)
|
|
65
|
+
compile_file_prism(path, options)
|
|
66
|
+
end
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
has_ruby_bug_22023_bis = !RubyVM::InstructionSequence.compile_file_prism(
|
|
69
|
+
File.expand_path("../ruby_bug_22023_canary.rb", __FILE__),
|
|
70
|
+
{frozen_string_literal: true},
|
|
71
|
+
).eval.frozen?
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
if has_ruby_bug_22023_bis
|
|
74
|
+
def compile_file_prism(path, options = nil)
|
|
75
|
+
compile_prism(::File.read(path, encoding: Encoding::UTF_8), path, path, nil, options)
|
|
76
|
+
end
|
|
62
77
|
end
|
|
63
78
|
end
|
|
79
|
+
RubyVM::InstructionSequence.singleton_class.prepend(PatchRubyBug22023)
|
|
64
80
|
end
|
|
65
|
-
RubyVM::InstructionSequence.singleton_class.prepend(PatchRubyBug22023)
|
|
66
|
-
end
|
|
67
81
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
if has_ruby_bug_18250
|
|
83
|
+
def input_to_storage(_, path)
|
|
84
|
+
iseq = RubyVM::InstructionSequence.compile_file(path, @compile_options)
|
|
85
|
+
iseq.to_binary
|
|
86
|
+
rescue TypeError, SyntaxError # Ruby [Bug #18250] & [Bug #22023]
|
|
87
|
+
UNCOMPILABLE
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
def input_to_storage(_, path)
|
|
91
|
+
RubyVM::InstructionSequence.compile_file(path, @compile_options).to_binary
|
|
92
|
+
rescue SyntaxError # Ruby [Bug #22023]
|
|
93
|
+
UNCOMPILABLE
|
|
94
|
+
end
|
|
80
95
|
end
|
|
81
|
-
end
|
|
82
96
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
def storage_to_output(binary, _args)
|
|
98
|
+
iseq = RubyVM::InstructionSequence.load_from_binary(binary)
|
|
99
|
+
binary.clear
|
|
100
|
+
iseq
|
|
101
|
+
rescue RuntimeError => error
|
|
102
|
+
if error.message == "broken binary format"
|
|
103
|
+
$stderr.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
|
|
104
|
+
nil
|
|
105
|
+
else
|
|
106
|
+
raise
|
|
107
|
+
end
|
|
93
108
|
end
|
|
94
|
-
end
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
def input_to_output(source, path, _kwargs)
|
|
111
|
+
if @compile_options
|
|
112
|
+
if source
|
|
113
|
+
RubyVM::InstructionSequence.compile(
|
|
114
|
+
source.force_encoding(Encoding.default_external),
|
|
115
|
+
path,
|
|
116
|
+
path,
|
|
117
|
+
nil,
|
|
118
|
+
@compile_options,
|
|
119
|
+
)
|
|
120
|
+
else
|
|
121
|
+
RubyVM::InstructionSequence.compile_file(path, @compile_options)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
105
124
|
end
|
|
106
125
|
end
|
|
107
|
-
end
|
|
108
126
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@default_compiler = DEFAULT
|
|
113
|
-
@coverage_support_warning_emitted = false
|
|
114
|
-
|
|
115
|
-
def self.fetch(path, cache_dir: ISeq.cache_dir)
|
|
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
|
|
127
|
+
DEFAULT = Compiler.new
|
|
128
|
+
FROZEN_STRING_LITERAL = Compiler.new("-fstr", {frozen_string_literal: true}.freeze)
|
|
129
|
+
COVERAGE_SUPPORTED = RUBY_VERSION >= "4.0.4"
|
|
131
130
|
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
@default_compiler = DEFAULT
|
|
132
|
+
@coverage_support_warning_emitted = false
|
|
134
133
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
compiler.namespace,
|
|
138
|
-
path.to_s,
|
|
139
|
-
compiler,
|
|
140
|
-
nil,
|
|
141
|
-
)
|
|
142
|
-
end
|
|
134
|
+
def self.fetch(path, cache_dir: ISeq.cache_dir)
|
|
135
|
+
compiler = compiler_selector&.call(path) || default_compiler
|
|
143
136
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
137
|
+
# Having coverage enabled prevents iseq dumping/loading.
|
|
138
|
+
if coverage_on?
|
|
139
|
+
return nil if compiler.equal?(DEFAULT)
|
|
140
|
+
|
|
141
|
+
if COVERAGE_SUPPORTED
|
|
142
|
+
return compiler.input_to_output(nil, path.to_s, nil)
|
|
143
|
+
elsif !@coverage_support_warning_emitted
|
|
144
|
+
@coverage_support_warning_emitted = true
|
|
145
|
+
warn(<<~MSG)
|
|
146
|
+
Using `Bootsnap.enable_frozen_string_literal` with code coverage enabled is only supported on Ruby 4.0.4+.
|
|
147
|
+
Files loaded while coverage is on, will have mutable string literals.
|
|
148
|
+
MSG
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
return nil
|
|
152
|
+
end
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
Bootsnap::CompileCache::Native.fetch(
|
|
155
|
+
cache_dir,
|
|
156
|
+
compiler.namespace,
|
|
157
|
+
path.to_s,
|
|
158
|
+
compiler,
|
|
159
|
+
nil,
|
|
160
|
+
)
|
|
157
161
|
end
|
|
158
|
-
|
|
159
|
-
def self.
|
|
160
|
-
|
|
162
|
+
|
|
163
|
+
def self.precompile(path)
|
|
164
|
+
compiler = compiler_selector&.call(path) || default_compiler
|
|
165
|
+
Bootsnap::CompileCache::Native.precompile(
|
|
166
|
+
cache_dir,
|
|
167
|
+
compiler.namespace,
|
|
168
|
+
path.to_s,
|
|
169
|
+
compiler,
|
|
170
|
+
)
|
|
161
171
|
end
|
|
162
|
-
end
|
|
163
172
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
173
|
+
if RUBY_VERSION < "3.1."
|
|
174
|
+
def self.coverage_on?
|
|
175
|
+
defined?(Coverage) && Coverage.running?
|
|
176
|
+
end
|
|
177
|
+
else
|
|
178
|
+
def self.coverage_on?
|
|
179
|
+
defined?(Coverage) && Coverage.state != :idle
|
|
170
180
|
end
|
|
171
|
-
raise
|
|
172
181
|
end
|
|
173
182
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
module InstructionSequenceMixin
|
|
184
|
+
def load_iseq(path)
|
|
185
|
+
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
|
|
186
|
+
rescue RuntimeError => error
|
|
187
|
+
if error.message.include?("unmatched platform")
|
|
188
|
+
puts("unmatched platform for file #{path}")
|
|
189
|
+
end
|
|
190
|
+
raise
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def compile_option=(hash)
|
|
194
|
+
super
|
|
195
|
+
Bootsnap::CompileCache::ISeq.compile_option_updated
|
|
196
|
+
end
|
|
177
197
|
end
|
|
178
|
-
end
|
|
179
198
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
199
|
+
def self.compile_option_updated
|
|
200
|
+
option = RubyVM::InstructionSequence.compile_option
|
|
201
|
+
crc = Zlib.crc32(option.inspect)
|
|
202
|
+
Bootsnap::CompileCache::Native.compile_option_crc32 = crc
|
|
203
|
+
FROZEN_STRING_LITERAL.update_options
|
|
204
|
+
end
|
|
205
|
+
compile_option_updated if supported?
|
|
206
|
+
|
|
207
|
+
def self.install!(cache_dir)
|
|
208
|
+
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
|
186
209
|
|
|
187
|
-
|
|
188
|
-
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
|
|
210
|
+
return unless supported?
|
|
189
211
|
|
|
190
|
-
|
|
212
|
+
Bootsnap::CompileCache::ISeq.compile_option_updated
|
|
191
213
|
|
|
192
|
-
|
|
214
|
+
class << RubyVM::InstructionSequence
|
|
215
|
+
prepend(InstructionSequenceMixin)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
else
|
|
219
|
+
def self.install!(...)
|
|
220
|
+
# noop
|
|
221
|
+
end
|
|
193
222
|
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
def self.precompile(...)
|
|
224
|
+
# noop
|
|
196
225
|
end
|
|
197
226
|
end
|
|
198
227
|
end
|
data/lib/bootsnap/version.rb
CHANGED
data/lib/bootsnap.rb
CHANGED
|
@@ -43,13 +43,6 @@ module Bootsnap
|
|
|
43
43
|
@instrumentation.call(event, path)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def load_config
|
|
47
|
-
config_path = File.expand_path(ENV["BOOTSNAP_CONFIG"] || "config/bootsnap.rb")
|
|
48
|
-
if File.exist?(config_path)
|
|
49
|
-
require(config_path)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
46
|
def setup(
|
|
54
47
|
cache_dir:,
|
|
55
48
|
development_mode: true,
|
|
@@ -59,7 +52,8 @@ module Bootsnap
|
|
|
59
52
|
revalidation: false,
|
|
60
53
|
compile_cache_iseq: true,
|
|
61
54
|
compile_cache_yaml: true,
|
|
62
|
-
compile_cache_json: (compile_cache_json_unset = true)
|
|
55
|
+
compile_cache_json: (compile_cache_json_unset = true),
|
|
56
|
+
config_path: nil
|
|
63
57
|
)
|
|
64
58
|
unless compile_cache_json_unset
|
|
65
59
|
warn("Bootsnap.setup `compile_cache_json` argument is deprecated and has no effect")
|
|
@@ -84,7 +78,16 @@ module Bootsnap
|
|
|
84
78
|
revalidation: revalidation,
|
|
85
79
|
)
|
|
86
80
|
|
|
87
|
-
load_config
|
|
81
|
+
load_config(config_path)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def load_config(config_path)
|
|
85
|
+
if config_path
|
|
86
|
+
config_path = File.expand_path(config_path)
|
|
87
|
+
if File.exist?(config_path)
|
|
88
|
+
require(config_path)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
88
91
|
end
|
|
89
92
|
|
|
90
93
|
def enable_frozen_string_literal(app_only: false)
|
|
@@ -102,8 +105,8 @@ module Bootsnap
|
|
|
102
105
|
end
|
|
103
106
|
}
|
|
104
107
|
else
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
options = RubyVM::InstructionSequence.compile_option.merge(frozen_string_literal: true)
|
|
109
|
+
RubyVM::InstructionSequence.compile_option = options
|
|
107
110
|
end
|
|
108
111
|
end
|
|
109
112
|
|
|
@@ -150,6 +153,7 @@ module Bootsnap
|
|
|
150
153
|
readonly: bool_env("BOOTSNAP_READONLY"),
|
|
151
154
|
revalidation: bool_env("BOOTSNAP_REVALIDATE"),
|
|
152
155
|
ignore_directories: ignore_directories,
|
|
156
|
+
config_path: ENV["BOOTSNAP_CONFIG"] || "config/bootsnap.rb",
|
|
153
157
|
)
|
|
154
158
|
|
|
155
159
|
if ENV["BOOTSNAP_LOG"]
|
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.6
|
|
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:
|
|
84
|
+
rubygems_version: 3.6.9
|
|
85
85
|
specification_version: 4
|
|
86
86
|
summary: Boot large ruby/rails apps faster
|
|
87
87
|
test_files: []
|