Class: Laser::Analysis::LaserProc

Inherits:
LaserObject show all
Defined in:
lib/laser/analysis/bootstrap/laser_proc.rb

Instance Attribute Summary (collapse)

Attributes inherited from LaserObject

#scope, #singleton_class

Instance Method Summary (collapse)

Methods inherited from LaserObject

#add_instance_method!, #instance_variable_defined?, #instance_variable_get, #instance_variable_set, #laser_simulate, #normal_class

Methods included from ModuleExtensions

#attr_accessor_with_default, #cattr_accessor, #cattr_accessor_with_default, #cattr_get_and_setter, #cattr_reader, #cattr_writer, #opposite_method

Constructor Details

- (LaserProc) initialize(arguments, ast_node, cfg = nil, callsite_block = nil)



7
8
9
10
11
12
13
14
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 7

def initialize(arguments, ast_node, cfg = nil, callsite_block = nil)
  @ast_node = ast_node
  @arguments = arguments
  @cfg = cfg
  @callsite_block = callsite_block
  @lexical_self = @exit_block = nil
  @annotations = Hash.new { |h, k| h[k] = [] }
end

Instance Attribute Details

- (Object) annotations

Returns the value of attribute annotations



6
7
8
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 6

def annotations
  @annotations
end

- (Object) arguments

Returns the value of attribute arguments



5
6
7
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 5

def arguments
  @arguments
end

- (Object) ast_node

Returns the value of attribute ast_node



5
6
7
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 5

def ast_node
  @ast_node
end

- (Object) cfg

Returns the value of attribute cfg



5
6
7
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 5

def cfg
  @cfg
end

- (Object) exit_block

Returns the value of attribute exit_block



5
6
7
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 5

def exit_block
  @exit_block
end

- (Object) lexical_self

Returns the value of attribute lexical_self



5
6
7
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 5

def lexical_self
  @lexical_self
end

- (Object) line_number

Returns the value of attribute line_number



6
7
8
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 6

def line_number
  @line_number
end

Instance Method Details

- (Object) annotated_raise_frequency



136
137
138
139
140
141
142
143
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 136

def annotated_raise_frequency
  if annotations['raises'].any?
    annotations['raises'].select(&:literal?).map(&:literal).each do |literal|
      return Frequency[literal] if !literal || Symbol === literal
    end
    nil
  end
end

- (Object) annotated_return



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 95

def annotated_return
  notes = annotations['returns']
  if notes.any?
    if notes.size > 1
      raise ArgumentError.new("Cannot have more than one 'returns' annotation")
    end
    return_type = notes.first
    if return_type.type?
      return_type.type
    else
      raise NotImplementedError.new('Literal annotated return types not implemented')
    end
  end
end

- (Object) annotated_yield_usage



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 110

def annotated_yield_usage
  notes = annotations['yield_usage']
  if notes.any?
    if notes.size > 1
      raise ArgumentError.new("Cannot have more than one 'yield_usage' annotation")
    end
    yield_usage = notes.first
    if yield_usage.type?
      raise ArgumentError.new('yield_usage requires a literal yield usage category')
    else
      yield_usage.literal
    end
  end
end

- (Object) call(*args, &blk)



69
70
71
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 69

def call(*args, &blk)
  
end

- (Object) compiled_cfg



31
32
33
34
35
36
37
38
39
40
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 31

def compiled_cfg
  return @cfg if @cfg
  # since this is lazily compiling, we should update cref to reflect the runtime
  # value before compiling. hackish.
  if @ast_node.scope.self_ptr != Scope::GlobalScope.self_ptr
    @ast_node.scope.lexical_target = @ast_node.scope.self_ptr.value.binding
  end
  builder = ControlFlow::GraphBuilder.new(@ast_node, @arguments, @ast_node.scope)
  @cfg = builder.build
end

- (Object) inspect Also known as: name



20
21
22
23
24
25
26
27
28
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 20

def inspect
  desc_part = "Proc:0x#{object_id.to_s(16)}@#{ast_node.file_name}"
  arg_part = "(#{arguments.map(&:name).join(', ')})"
  if ast_node.source_begin
    "#<#{desc_part}:#{ast_node.line_number}*#{arg_part}>"
  else
    "#<#{desc_part}*#{arg_part}>"
  end
end

- (Object) klass



82
83
84
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 82

def klass
  ClassRegistry['Proc']
end

- (Object) overloads



125
126
127
128
129
130
131
132
133
134
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 125

def overloads
  Hash[*(annotations['overload'].map do |overload|
    raise ArgumentError.new('overload must be a type') unless overload.type?
    proc_type = overload.type
    unless Types::GenericType === proc_type && proc_type.base_type == Types::PROC
      raise ArgumentError.new('overload must be a function type')
    end
    [proc_type.subtypes[0].element_types, proc_type]
  end.flatten(1))]
end

- (Object) raises



145
146
147
148
149
150
151
152
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 145

def raises
  if annotations['raises'].any?
    types = annotations['raises'].select(&:type?)
    if types.any?
      Types::UnionType.new(types.map { |note| note.type })
    end
  end
end

- (Object) simulate(args, block, opts = {})



42
43
44
45
46
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 42

def simulate(args, block, opts={})
  update_cfg_edges(opts) if opts[:invocation_sites]
  self_to_use = opts[:self] || @lexical_self
  cfg.simulate(args, opts.merge({self: self_to_use, block: block, start_block: start_block}))
end

- (Object) ssa_cfg



73
74
75
76
77
78
79
80
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 73

def ssa_cfg
  @ssa_cfg ||= compiled_cfg.tap do |cfg|
    cfg.perform_dead_code_discovery(true)
    Laser.debug_puts('>>> Starting SSA Transformation <<<')
    cfg.static_single_assignment_form
    Laser.debug_puts('>>> Finished SSA Transformation <<<')
  end
end

- (Object) start_block



16
17
18
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 16

def start_block
  @callsite_block && @callsite_block.block_taken_successors.first
end

- (Object) to_proc



65
66
67
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 65

def to_proc
  self
end

- (Object) update_cfg_edges(opts)



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/laser/analysis/bootstrap/laser_proc.rb', line 48

def update_cfg_edges(opts)
  opts[:invocation_sites][self].each do |callsite|
    opts[:invocation_counts][self][callsite] += 1
    callsite_succ = callsite.successors.find do |b|
      b.name == start_block.name || b.name.include?("SSA-FIX-#{start_block.name}")
    end
    if !callsite.has_flag?(callsite_succ, RGL::ControlFlowGraph::EDGE_EXECUTABLE)
      callsite.add_flag(callsite_succ, RGL::ControlFlowGraph::EDGE_EXECUTABLE)
    else
      exit_succ = exit_block.successors.find do |b|
        b.name == start_block.name || b.name.include?("SSA-FIX-#{start_block.name}")
      end
      exit_block.add_flag(exit_succ, RGL::ControlFlowGraph::EDGE_EXECUTABLE)
    end
  end
end