rubinius/rubinius

View on GitHub
build/scripts/create_codedb_cache.rb

Summary

Maintainability
A
0 mins
Test Coverage
# This is a temporary script to compile a new CodeDB cache from an existing
# bootstrap cache. It's pretty messy. Hopefully, it will be short-lived.

require "rubinius/code/toolset"

Rubinius::ToolSets.create :build do
  require "rubinius/code/melbourne"
  require "rubinius/code/processor"
  require "rubinius/code/compiler"
  require "rubinius/code/ast"
end

require File.expand_path("../config/config.rb", __dir__)

class CodeDBCompiler
  def self.compile(file, line=1, transforms=[:default, :kernel, :experimental])
    compiler = Rubinius::ToolSets::Build::Compiler.new :file, :compiled_code

    parser = compiler.parser
    parser.root Rubinius::ToolSets::Build::AST::Script

    if transforms.kind_of? Array
      transforms.each { |t| parser.enable_category t }
    else
      parser.enable_category transforms
    end

    parser.input file, line

    generator = compiler.generator
    generator.processor Rubinius::ToolSets::Build::Generator

    compiler.run
  end

  def self.marshal(code)
    marshaler = Rubinius::ToolSets::Build::CompiledFile::Marshal.new
    marshaler.marshal code
  end
end

class CodeDBWriter
  MAGIC = "!RBIX\n"
  VERSION = "   1\n"
  SIGNATURE_HASH = 0
  SIZE_FORMAT = "%15d\n"

  def initialize(path)
    @path = path
    @init_files = []
    @source_files = []
    @init = ""
    @index = ""
    @contents = ""
    @data = ""
  end

  def add_init(source)
    @init_files << source
  end

  def add_source(source)
    @source_files << source
  end

  def add_code(name, id, code)
    @contents << "#{name.size} #{name} 0 0 #{id} 0\n"

    cache = [[id, code]]

    while x = cache.shift
      id, cc = x

      cc.literals.each_with_index do |value, index|
        if value.kind_of? Rubinius::CompiledCode
          cc.literals[index] = i = value.code_id
          cache.unshift [i, value]
        end
      end

      marshaled = CodeDBCompiler.marshal cc

      @index << "#{id} #{@data.size} #{marshaled.size}\n"

      @data << marshaled
    end
  end

  def compile_file(file)
    puts "RBC #{file}"

    code = CodeDBCompiler.compile file

    return file, code.code_id, code
  end

  def compile
    @init_files.each do |file|
      name, id, code = compile_file file

      add_code name, id, code

      @init << "#{id}\n"
    end

    @source_files.each do |file|
      add_code(*compile_file(file))
    end
  end

  def write
    File.open @path, "wb" do |f|
      f.write MAGIC
      f.write VERSION
      f.write "%64d\n" % SIGNATURE_HASH
      f.write SIZE_FORMAT % @init.size
      f.write SIZE_FORMAT % @data.size
      f.write SIZE_FORMAT % @data.size
      f.write SIZE_FORMAT % @index.size
      f.write SIZE_FORMAT % @contents.size
      f.write @init
      f.write @data
      f.write @index
      f.write @contents
    end
  end
end

path = ARGV.shift
puts "Building CodeDB cache: #{path}"

db_writer = CodeDBWriter.new path

Dir.chdir "#{Rubinius::BUILD_CONFIG[:builddir]}#{Rubinius::BUILD_CONFIG[:codedbdir]}/source" do
  File.foreach "#{Rubinius::BUILD_CONFIG[:sourcedir]}/core/load_order.txt" do |name|
    db_writer.add_init "core/#{name.chomp}"
  end

  Dir["**/*.rb"].each do |name|
    next if name.start_with? "core/"

    db_writer.add_source name
  end

  db_writer.compile
end

db_writer.write