Class: Laser::Analysis::ControlFlow::Instruction

Inherits:
BasicObject
Defined in:
lib/laser/analysis/control_flow/cfg_instruction.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(body, opts = {}) ⇒ Instruction



8
9
10
11
12
13
14
15
16
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 8

def initialize(body, opts={})
  @body = body
  @node = opts[:node]
  @block = opts[:block]
  @raise_frequency = :unknown
  @raise_type = Types::EMPTY
  @ignore_privacy = opts[:ignore_privacy]
  @true_successor = @false_successor = nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &blk) ⇒ Object



49
50
51
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 49

def method_missing(meth, *args, &blk)
  @body.send(meth, *args, &blk)
end

Instance Attribute Details

#blockObject (readonly)

Returns the value of attribute block



6
7
8
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 6

def block
  @block
end

#bodyObject (readonly)

Returns the value of attribute body



6
7
8
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 6

def body
  @body
end

#ignore_privacyObject (readonly)

Returns the value of attribute ignore_privacy



6
7
8
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 6

def ignore_privacy
  @ignore_privacy
end

#nodeObject (readonly)

Returns the value of attribute node



6
7
8
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 6

def node
  @node
end

#raise_frequencyObject

Returns the value of attribute raise_frequency



7
8
9
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 7

def raise_frequency
  @raise_frequency
end

#raise_typeObject

Returns the value of attribute raise_type



7
8
9
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 7

def raise_type
  @raise_type
end

Instance Method Details

#==(other) ⇒ Object



26
27
28
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 26

def ==(other)
  @body == other.body
end

#block_operandObject



131
132
133
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 131

def block_operand
  ::Hash === last ? last[:block] : nil
end

#calculate_branch_successorsObject



81
82
83
84
85
86
87
88
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 81

def calculate_branch_successors
  return if @true_successor
  successors = block.successors.to_a
  if successors[0].name == self[2]
  then @true_successor, @false_successor = successors[0..1]
  else @false_successor, @true_successor = successors[0..1]
  end
end

#classObject



22
23
24
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 22

def class
  Instruction
end

#deep_dup(temp_lookup, opts = {}) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 30

def deep_dup(temp_lookup, opts={})
  new_body = @body[1..-1].map do |arg|
    case arg
    when Bindings::ConstantBinding then arg
    when Bindings::Base then temp_lookup[arg]
    when ::Hash
      if arg[:block]
      then arg.merge(block: temp_lookup[arg[:block]])
      else arg
      end
    else arg.dup rescue arg
    end
  end
  
  new_body.unshift(self[0])  # self[0] always symbol
  new_opts = {node: @node, block: temp_lookup[@block], ignore_privacy: @ignore_privacy}.merge(opts)
  self.class.new(new_body, new_opts)
end

#explicit_targetsObject

Gets all bindings that are explicitly set in this instruction (no aliasing concerns)



122
123
124
125
126
127
128
129
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 122

def explicit_targets
  case self[0]
  when :assign, :call, :call_vararg, :super, :super_vararg, :lambda, :phi
    self[1] ? ::Set[self[1]] : ::Set[]
  else
    ::Set[]
  end
end

#false_successorObject



75
76
77
78
79
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 75

def false_successor
  require_branch('#false_successor')
  calculate_branch_successors
  return @false_successor
end

#method_call?Boolean



53
54
55
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 53

def method_call?
  [:call, :call_vararg, :super, :super_vararg].include?(type)
end

#operandsObject

Gets all bindings that are operands in this instruction



140
141
142
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 140

def operands
  self[operand_range].select { |x| Bindings::Base === x && x != Bootstrap::VISIBILITY_STACK }
end

#possible_methods(opts) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 105

def possible_methods(opts)
  require_method_call
  if type == :call || type == :call_vararg
    if Bindings::ConstantBinding === self[2]
      [self[2].value.singleton_class.instance_method(self[3])].compact
    elsif LaserObject === self[2].value
      [self[2].value.klass.instance_method(self[3])].compact
    else
      self[2].expr_type.matching_methods(self[3])
    end
  else
    [opts[:method].super_method]
  end
end

#possible_public_methodsObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 90

def possible_public_methods
  require_method_call
  if type == :call || type == :call_vararg
    if Bindings::ConstantBinding === self[2]
      [self[2].value.singleton_class.public_instance_method(self[3])].compact
    elsif LaserObject === self[2].value
      [self[2].value.klass.public_instance_method(self[3])].compact
    else
      self[2].expr_type.public_matching_methods(self[3])
    end
  else
    #TODO(adgar): SUPER
  end
end

#replace_block_operand(new_block) ⇒ Object



135
136
137
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 135

def replace_block_operand(new_block)
  last[:block] = new_block
end

#replace_operands(new_operands) ⇒ Object

Replaces the operands with a new list. Used by SSA renaming.



145
146
147
148
149
150
151
152
153
154
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 145

def replace_operands(new_operands)
  # splice in new operands: replace bindings with bindings.
  index = operand_range.begin
  while new_operands.any? && index < @body.size
    if Bindings::Base === self[index] && self[index] != Bootstrap::VISIBILITY_STACK 
      self[index] = new_operands.shift
    end
    index += 1
  end
end

#replace_target(original_target, new_target) ⇒ Object

Replaces a target of the instruction. Used by SSA renaming. Currently, all instructions only have at most 1 target.



158
159
160
161
162
163
164
165
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 158

def replace_target(original_target, new_target)
  if self[1] == original_target
    self[1] = new_target
  else
    raise ArgumentError.new("#{original_target.inspect} is not a "+
                            "target of #{self.inspect}")
  end
end

#require_branch(method_needed = 'the requested operation') ⇒ Object



63
64
65
66
67
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 63

def require_branch(method_needed='the requested operation')
  unless type == :branch
    raise TypeError.new("#{method_needed} is not defined on #{type} instructions.")
  end
end

#require_method_callObject



57
58
59
60
61
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 57

def require_method_call
  unless method_call?
    raise TypeError.new("#possible_methods is not defined on #{type} instructions.")
  end
end

#true_successorObject



69
70
71
72
73
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 69

def true_successor
  require_branch('#true_successor')
  calculate_branch_successors
  return @true_successor
end

#typeObject



18
19
20
# File 'lib/laser/analysis/control_flow/cfg_instruction.rb', line 18

def type
  @body[0]
end