class Ikra::TypeInference::ObjectTracer

The object tracer determines a set of objects that are relevant for the execution of a parallel section (grouped by class). Only instances of classes that have {Ikra::Entity} included are such relevant objects.

Public Class Methods

new(command) click to toggle source
# File lib/types/inference/object_tracer.rb, line 12
def initialize(command)
    # Hash map: Class -> Set[Object]
    @roots = RootsFinder.process(command)
    @num_traced_objects = 0

    @objects = Hash.new
    @objects.default_proc = Proc.new do |hash, key|
        hash[key] = Hash.new
    end

    @top_object_id = Hash.new
    @top_object_id.default = -1
end

Public Instance Methods

convert_base_array(base_array, need_union_type) click to toggle source

Returns an array of IDs for the base array or the base array itself if all values are primitive. TODO: This should be done in the environment builder, but I want to avoid copying over arrays…

# File lib/types/inference/object_tracer.rb, line 105
def convert_base_array(base_array, need_union_type)
    if base_array.first.class.to_ikra_type.is_primitive? && !need_union_type
        base_array
    else
        if !need_union_type
            base_array.map do |obj|
                @objects[obj.class][obj]
            end
        else
            mem_block = FFI::MemoryPointer.new(Translator::EnvironmentBuilder::UnionTypeStruct, base_array.size)
            array = base_array.size.times.collect do |index|
                Translator::EnvironmentBuilder::UnionTypeStruct.new(mem_block + index * Translator::EnvironmentBuilder::UnionTypeStruct.size)
            end

            base_array.each_with_index do |obj, index|
                obj_type = obj.class.to_ikra_type
                array[index][:class_id] = obj_type.class_id

                if obj_type.is_primitive?
                    # TODO: what if the primitive value is not an integer?
                    array[index][:object_id] = obj
                else
                    array[index][:object_id] = @objects[obj.class][obj]
                end
            end

            mem_block
        end
    end
end
register_soa_arrays(environment_builder) click to toggle source

Generates arrays for the Structure of Arrays (SoA) object layout

# File lib/types/inference/object_tracer.rb, line 65
def register_soa_arrays(environment_builder)
    # arrays: class x inst var name -> Array
    arrays = Hash.new
    arrays.default_proc = proc do |hash, cls|
        inner_hash = Hash.new
        inner_hash.default_proc = proc do |inner, inst_var|
            inner[inst_var] = Array.new(@top_object_id[cls] + 1)
        end
        hash[cls] = inner_hash
    end

    @objects.each do |cls, objs|
        cls.to_ikra_type.accessed_inst_vars.each do |inst_var|
            objs.each do |obj, id|
                inst_var_value = obj.instance_variable_get(inst_var)

                if inst_var_value.class.to_ikra_type.is_primitive?
                    # Use object value directly
                    arrays[cls][inst_var][id] = inst_var_value
                else
                    if !inst_var_value.class.include?(Entity)
                        Log.warn("Attempting to transfer an object of class #{inst_var_value.class} that is not an Ikra::Entity. Could be a false positive. Skipping.")
                    else
                        # Use object ID
                        arrays[cls][inst_var][id] = @objects[inst_var_value.class][inst_var_value]
                    end
                end
            end
        end
    end
    
    arrays.each do |cls, inner_hash|
        inner_hash.each do |inst_var, array|
            environment_builder.add_soa_array(cls.to_ikra_type.inst_var_array_name(inst_var), array)
        end
    end
end
trace_all() click to toggle source
# File lib/types/inference/object_tracer.rb, line 26
def trace_all
    @worklist = Set.new(@roots)

    while @worklist.size > 0
        current_obj = @worklist.first
        @worklist.delete(current_obj)

        trace_object(current_obj)
    end

    Log.info("Traced #{@num_traced_objects} objects with #{@objects.size} distinct types")

    @objects
end
trace_object(object) click to toggle source
# File lib/types/inference/object_tracer.rb, line 41
def trace_object(object)
    if not object.class.to_ikra_type.is_primitive?
        if not @objects[object.class].has_key?(object)
            # object was not traced yet
            @objects[object.class][object] = (@top_object_id[object.class] += 1)
            @num_traced_objects += 1

            object.instance_variables.each do |inst_var_name|
                value = object.instance_variable_get(inst_var_name)
                value_type = value.ikra_type

                # Gather type information
                object.ikra_type.inst_vars_types[inst_var_name].add(value_type)

                if value.class.include?(Entity)
                    # Keep tracing this object
                    @worklist.add(value)
                end
            end
        end
    end
end