ruby-llvm/ruby-llvm

View on GitHub
lib/llvm/core/bitcode.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require 'llvm/core/bitcode_ffi'

module LLVM
  class Module
    # Parse a module from a memory buffer
    # @param [String, LLVM::MemoryBuffer] path_or_memory_buffer
    # @return [LLVM::Module]
    def self.parse_bitcode(path_or_memory_buffer)
      memory_buffer = case path_or_memory_buffer
      when MemoryBuffer then path_or_memory_buffer
      else MemoryBuffer.from_file(path_or_memory_buffer)
      end
      FFI::MemoryPointer.new(:pointer) do |mod_ref|
        FFI::MemoryPointer.new(:pointer) do |msg_ref|
          status = C.parse_bitcode(memory_buffer, mod_ref, msg_ref)
          raise msg_ref.get_pointer(0).get_string(0) if status != 0
          return from_ptr(mod_ref.get_pointer(0))
        end
      end
    end

    # Write bitcode to the given path, IO object or file descriptor
    # @param [String, IO, Integer] path_or_io Pathname, IO object or file descriptor
    # @return [true, false] Success
    def write_bitcode(path_or_io)
      status = if path_or_io.respond_to?(:path)
        C.write_bitcode_to_file(self, path_or_io.path)
      elsif path_or_io.respond_to?(:fileno)
        C.write_bitcode_to_fd(self, path_or_io.fileno, 0, 1)
      elsif path_or_io.kind_of?(Integer)
        C.write_bitcode_to_fd(self, path_or_io, 0, 1)
      else
        C.write_bitcode_to_file(self, path_or_io.to_str)
      end
      status == 0
    end

    def self.parse_ir(path_or_memory_buffer, context = Context.global)
      memory_buffer = case path_or_memory_buffer
      when MemoryBuffer then path_or_memory_buffer
      else MemoryBuffer.from_file(path_or_memory_buffer)
      end
      FFI::MemoryPointer.new(:pointer) do |mod_ref|
        FFI::MemoryPointer.new(:pointer) do |msg_ref|
          status = C.parse_ir_in_context(context, memory_buffer, mod_ref, msg_ref)
          raise msg_ref.get_pointer(0).get_string(0) if status
          return from_ptr(mod_ref.get_pointer(0))
        end
      end
    end

    def write_ir!(filename)
      FFI::MemoryPointer.new(:pointer) do |msg_ref|
        status = C.print_module_to_file(self, filename, msg_ref)
        raise msg_ref.get_pointer(0).get_string(0) if status != 0
      end
      self
    end
  end

  # @private
  class MemoryBuffer
    private_class_method :new

    # @private
    def initialize(ptr)
      @ptr = ptr
    end

    # @private
    def to_ptr
      @ptr
    end

    # Read the contents of a file into a memory buffer
    # @param [String] path
    # @return [LLVM::MemoryBuffer]
    def self.from_file(path)
      FFI::MemoryPointer.new(:pointer) do |buf_ref|
        FFI::MemoryPointer.new(:pointer) do |msg_ref|
          status = C.create_memory_buffer_with_contents_of_file(path.to_str, buf_ref, msg_ref)
          raise msg_ref.get_pointer(0).get_string(0) if status != 0
          return new(buf_ref.get_pointer(0))
        end
      end
    end

    # Read STDIN into a memory buffer
    # @return [LLVM::MemoryBuffer]
    def self.from_stdin
      FFI::Buffer.new(:pointer) do |buf_ref|
        FFI::Buffer.new(:pointer) do |msg_ref|
          status = C.create_memory_buffer_with_stdin(buf_ref, msg_ref)
          raise msg_ref.get_pointer(0).get_string(0) if status != 0
          return new(buf_ref.get_pointer(0))
        end
      end
    end

    def dispose
      return if @ptr.nil?
      C.dispose_memory_buffer(@ptr)
      @ptr = nil
    end
  end
end