Class: MilkTea::BuildCache

Inherits:
Object
  • Object
show all
Defined in:
lib/milk_tea/tooling/build_cache.rb

Defined Under Namespace

Classes: CachedProgram

Constant Summary collapse

BACKEND_SOURCES =
%w[
  lib/milk_tea/core/lowering.rb
  lib/milk_tea/core/lowering/utils.rb
  lib/milk_tea/core/lowering/async/analysis.rb
  lib/milk_tea/core/lowering/async/normalization.rb
  lib/milk_tea/core/lowering/async/lowering.rb
  lib/milk_tea/core/lowering/async.rb
  lib/milk_tea/core/c_backend.rb
  lib/milk_tea/core/c_backend/statements.rb
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root:) ⇒ BuildCache

Returns a new instance of BuildCache.



55
56
57
58
# File 'lib/milk_tea/tooling/build_cache.rb', line 55

def initialize(root:)
  @root = File.expand_path(root.to_s)
  @cache_root = File.join(MilkTea.data_root.to_s, "tmp", "mtc-cache")
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



60
61
62
# File 'lib/milk_tea/tooling/build_cache.rb', line 60

def root
  @root
end

Instance Method Details

#binary_key(c_source:, cc:, compiler_flags:, link_flags:) ⇒ Object



186
187
188
189
190
191
192
193
194
# File 'lib/milk_tea/tooling/build_cache.rb', line 186

def binary_key(c_source:, cc:, compiler_flags:, link_flags:)
  hasher = Digest::SHA256.new
  hasher << c_source << "\0"
  hasher << cc << "\0"
  hasher << compiler_identity(cc) << "\0"
  compiler_flags.sort.each { |f| hasher << f << "\0" }
  link_flags.sort.each { |f| hasher << f << "\0" }
  hasher.hexdigest
end

#fetch_binary(key) ⇒ Object



74
75
76
77
78
79
# File 'lib/milk_tea/tooling/build_cache.rb', line 74

def fetch_binary(key)
  path = binary_path(key)
  return path if File.exist?(path)

  nil
end

#fetch_method_defsObject



171
172
173
174
175
176
177
178
179
# File 'lib/milk_tea/tooling/build_cache.rb', line 171

def fetch_method_defs
  path = File.join(@cache_root, "method_defs", "key.json")
  return unless File.exist?(path)

  raw = JSON.parse(File.read(path), symbolize_names: true)
  raw.fetch(:key)
rescue JSON::ParserError, KeyError
  nil
end

#fetch_module_ir(key) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
# File 'lib/milk_tea/tooling/build_cache.rb', line 145

def fetch_module_ir(key)
  path = File.join(@cache_root, "modules", key[0, 2], key, "ir.bin")
  return unless File.exist?(path)

  data = Marshal.load(File.read(path, mode: "rb"))
  return data.fetch(:ir) unless data.is_a?(Hash)

  [data.fetch(:ir), data[:synthetics] || {}]
rescue TypeError, ArgumentError
  nil
end

#fetch_module_state(key) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/milk_tea/tooling/build_cache.rb', line 118

def fetch_module_state(key)
  path = module_state_path(key)
  return unless File.exist?(path)

  raw = JSON.parse(File.read(path), symbolize_names: true)
  {
    module_name: raw.fetch(:module_name),
    source_key: raw.fetch(:source_key),
    dependencies: raw.fetch(:dependencies),
  }
rescue JSON::ParserError, KeyError
  nil
end

#fetch_program(key) ⇒ Object



62
63
64
65
66
67
68
# File 'lib/milk_tea/tooling/build_cache.rb', line 62

def fetch_program(key)
  dir = program_dir(key)
  return unless File.exist?(File.join(dir, "modules.json"))
  return unless File.exist?(File.join(dir, "source.c"))

  CachedProgram.load(dir)
end

#invalidate_all_module_irObject



181
182
183
184
# File 'lib/milk_tea/tooling/build_cache.rb', line 181

def invalidate_all_module_ir
  dir = File.join(@cache_root, "modules")
  FileUtils.rm_rf(dir) if File.exist?(dir)
end

#invalidate_module(key) ⇒ Object



132
133
134
135
# File 'lib/milk_tea/tooling/build_cache.rb', line 132

def invalidate_module(key)
  dir = File.join(@cache_root, "modules", key[0, 2], key)
  FileUtils.rm_rf(dir) if File.exist?(dir)
end

#method_defs_key(methods_hash_string) ⇒ Object



157
158
159
160
161
162
# File 'lib/milk_tea/tooling/build_cache.rb', line 157

def method_defs_key(methods_hash_string)
  hasher = Digest::SHA256.new
  hasher << backend_version << "\0"
  hasher << methods_hash_string << "\0"
  hasher.hexdigest
end

#module_key(source_path, source_content) ⇒ Object



96
97
98
99
100
101
# File 'lib/milk_tea/tooling/build_cache.rb', line 96

def module_key(source_path, source_content)
  hasher = Digest::SHA256.new
  hasher << backend_version << "\0"
  hasher << source_path << "\0" << source_content << "\0"
  hasher.hexdigest
end

#module_state_path(key) ⇒ Object



103
104
105
# File 'lib/milk_tea/tooling/build_cache.rb', line 103

def module_state_path(key)
  File.join(@cache_root, "modules", key[0, 2], key, "state.json")
end

#program_key(source_files:) ⇒ Object



87
88
89
90
91
92
93
94
# File 'lib/milk_tea/tooling/build_cache.rb', line 87

def program_key(source_files:)
  hasher = Digest::SHA256.new
  hasher << backend_version << "\0"
  source_files.sort_by { |path, _content| path }.each do |path, content|
    hasher << path << "\0" << content << "\0"
  end
  hasher.hexdigest
end

#shared_analysis_cacheObject



196
197
198
# File 'lib/milk_tea/tooling/build_cache.rb', line 196

def shared_analysis_cache
  @shared_analysis_cache ||= {}
end

#store_binary(key, binary_path) ⇒ Object



81
82
83
84
85
# File 'lib/milk_tea/tooling/build_cache.rb', line 81

def store_binary(key, binary_path)
  dest = binary_path(key)
  FileUtils.mkdir_p(File.dirname(dest))
  FileUtils.cp(binary_path, dest)
end

#store_method_defs(key) ⇒ Object



164
165
166
167
168
169
# File 'lib/milk_tea/tooling/build_cache.rb', line 164

def store_method_defs(key)
  dir = File.join(@cache_root, "method_defs")
  FileUtils.mkdir_p(dir)
  data = { key: }
  File.write(File.join(dir, "key.json"), JSON.generate(data))
end

#store_module_ir(key, ir_program, synthetics: nil) ⇒ Object



137
138
139
140
141
142
143
# File 'lib/milk_tea/tooling/build_cache.rb', line 137

def store_module_ir(key, ir_program, synthetics: nil)
  dir = File.join(@cache_root, "modules", key[0, 2], key)
  FileUtils.mkdir_p(dir)
  data = { ir: ir_program }
  data[:synthetics] = synthetics if synthetics && synthetics.values.any? { |v| v.any? }
  File.write(File.join(dir, "ir.bin"), Marshal.dump(data))
end

#store_module_state(key, module_name:, source_key:, dependencies:) ⇒ Object



107
108
109
110
111
112
113
114
115
116
# File 'lib/milk_tea/tooling/build_cache.rb', line 107

def store_module_state(key, module_name:, source_key:, dependencies:)
  dir = File.join(@cache_root, "modules", key[0, 2], key)
  FileUtils.mkdir_p(dir)
  state = {
    module_name: module_name.to_s,
    source_key: source_key,
    dependencies: dependencies,
  }
  File.write(File.join(dir, "state.json"), JSON.generate(state))
end

#store_program(key, c_source:, frontend_modules:) ⇒ Object



70
71
72
# File 'lib/milk_tea/tooling/build_cache.rb', line 70

def store_program(key, c_source:, frontend_modules:)
  CachedProgram.new(c_source:, frontend_modules:).store(program_dir(key))
end