/
iseq.rb
117 lines (102 loc) · 3.24 KB
/
iseq.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# frozen_string_literal: true
require("bootsnap/bootsnap")
require("zlib")
module Bootsnap
module CompileCache
module ISeq
class << self
attr_reader(:cache_dir)
def cache_dir=(cache_dir)
@cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}iseq" : "#{cache_dir}-iseq"
end
end
has_ruby_bug_18250 = begin # https://bugs.ruby-lang.org/issues/18250
if defined? RubyVM::InstructionSequence
RubyVM::InstructionSequence.compile("def foo(*); ->{ super }; end; def foo(**); ->{ super }; end").to_binary
end
false
rescue TypeError
true
end
if has_ruby_bug_18250
def self.input_to_storage(_, path)
iseq = begin
RubyVM::InstructionSequence.compile_file(path)
rescue SyntaxError
return UNCOMPILABLE # syntax error
end
begin
iseq.to_binary
rescue TypeError
return UNCOMPILABLE # ruby bug #18250
end
end
else
def self.input_to_storage(_, path)
RubyVM::InstructionSequence.compile_file(path).to_binary
rescue SyntaxError
return UNCOMPILABLE # syntax error
end
end
def self.storage_to_output(binary, _args)
RubyVM::InstructionSequence.load_from_binary(binary)
rescue RuntimeError => error
if error.message == "broken binary format"
STDERR.puts("[Bootsnap::CompileCache] warning: rejecting broken binary")
nil
else
raise
end
end
def self.fetch(path, cache_dir: ISeq.cache_dir)
Bootsnap::CompileCache::Native.fetch(
cache_dir,
path.to_s,
Bootsnap::CompileCache::ISeq,
nil,
)
end
def self.precompile(path)
Bootsnap::CompileCache::Native.precompile(
cache_dir,
path.to_s,
Bootsnap::CompileCache::ISeq,
)
end
def self.input_to_output(_data, _kwargs)
nil # ruby handles this
end
module InstructionSequenceMixin
def load_iseq(path)
# Having coverage enabled prevents iseq dumping/loading.
return nil if defined?(Coverage) && Bootsnap::CompileCache::Native.coverage_running?
Bootsnap::CompileCache::ISeq.fetch(path.to_s)
rescue Errno::EACCES
Bootsnap::CompileCache.permission_error(path)
rescue RuntimeError => error
if error.message =~ /unmatched platform/
puts("unmatched platform for file #{path}")
end
raise
end
def compile_option=(hash)
super(hash)
Bootsnap::CompileCache::ISeq.compile_option_updated
end
end
def self.compile_option_updated
option = RubyVM::InstructionSequence.compile_option
crc = Zlib.crc32(option.inspect)
Bootsnap::CompileCache::Native.compile_option_crc32 = crc
end
compile_option_updated
def self.install!(cache_dir)
Bootsnap::CompileCache::ISeq.cache_dir = cache_dir
Bootsnap::CompileCache::ISeq.compile_option_updated
class << RubyVM::InstructionSequence
prepend(InstructionSequenceMixin)
end
end
end
end
end