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

- (Instruction) initialize(body, opts = {})



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

- (Object) method_missing(meth, *args, &blk)



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

- (Object) block (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

- (Object) body (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

- (Object) ignore_privacy (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

- (Object) node (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

- (Object) raise_frequency

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

- (Object) raise_type

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

- (Object) ==(other)



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

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

- (Object) block_operand



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

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

- (Object) calculate_branch_successors



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

- (Object) class



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

def class
  Instruction
end

- (Object) deep_dup(temp_lookup, opts = {})



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

- (Object) explicit_targets

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

- (Object) false_successor



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

- (Boolean) method_call?



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

- (Object) operands

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

- (Object) possible_methods(opts)



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

- (Object) possible_public_methods



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

- (Object) replace_block_operand(new_block)



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

- (Object) replace_operands(new_operands)

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

- (Object) replace_target(original_target, new_target)

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

- (Object) require_branch(method_needed = 'the requested operation')



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

- (Object) require_method_call



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

- (Object) true_successor



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

- (Object) type



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

def type
  @body[0]
end