/
compiled_method.rb
222 lines (186 loc) · 4.29 KB
/
compiled_method.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
class NativeMethod
def lines
nil
end
def exceptions
nil
end
def literals
nil
end
def line_from_ip(i)
0
end
end
class StaticScope
ivar_as_index :__ivars__ => 0, :module => 1, :parent => 2
def module
@module
end
def parent
@parent
end
end
class CompiledMethod
ivar_as_index :__ivars__ => 0, :primitive => 1, :required => 2, :serial => 3, :bytecodes => 4, :name => 5, :file => 6, :locals => 7, :literals => 8, :arguments => 9, :scope => 10, :exceptions => 11, :lines => 12, :path => 13, :cache => 14, :bonus => 15, :compiled => 16, :staticscope => 17
def __ivars__ ; @__ivars__ ; end
def primitive ; @primitive ; end
def required ; @required ; end
def serial ; @serial ; end
def bytecodes ; @bytecodes ; end
def name ; @name ; end
def file ; @file ; end
def locals ; @locals ; end
def literals ; @literals ; end
def arguments ; @arguments ; end
def scope ; @scope ; end
def exceptions; @exceptions ; end
def lines ; @lines ; end
def path ; @path ; end
def cache ; @cache ; end
def bonus ; @bonus ; end
def compiled ; @compiled ; end
def staticscope; @staticscope; end
def inspect
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} name=#{@name} file=#{@file}>"
end
def from_string(bc, lcls, req)
@bytecodes = bc
@primitive = -1
@locals = lcls
@literals = Tuple.new(0)
@required = 0
@arguments = Tuple.new(0)
@exceptions = nil
@lines = nil
@file = nil
@name = nil
@path = nil
@required = req
return self
end
def exceptions=(tup)
@exceptions = tup
end
def literals=(tup)
@literals = tup
end
def file=(val)
@file = val
end
def name=(val)
@name = val
end
# Lines consists of an array of tuples, with each tuple representing a line.
# The tuple for a line has fields for the first ip, last ip, and line number.
def lines=(val)
@lines = val
end
def path=(val)
@path = val
end
def primitive=(idx)
@primitive = idx
end
def cache=(tup)
@cache = tup
end
def serial=(ser)
@serial = ser
end
def bonus=(tup)
@bonus = tup
end
def activate(recv, mod, args, locals=nil, &prc)
sz = args.total
if prc
block = prc.block
else
block = nil
end
out = Rubinius.asm(args, block, locals, sz, mod, recv) do |a,b,l,s,m,r|
run a
push_array
run b
run l
run s
run m
push :self
run r
activate_method 0
end
return out
end
def line_from_ip(i)
@lines.each do |t|
start = t.at(0)
nd = t.at(1)
op = t.at(2)
if i >= start and i <= nd
return op
end
end
return 0
end
def first_ip_on_line(line)
@lines.each do |t|
if t.at(2) >= line
return t.at(0)
end
end
return -1
end
def bytecodes=(other)
@bytecodes = other
end
def first_line
@lines.each do |ent|
return ent[2] if ent[2] > 0
end
return -1
end
# Decodes the instruction sequence that is represented by this compileed
# method. Delegates to +InstructionSequence+ to do the instruction decoding,
# but then converts opcode literal arguments to their actual values by looking
# them up in the literals tuple.
def decode
stream = @bytecodes.decode
ip = 0
stream.map! do |inst|
instruct = Instruction.new(inst, self, ip)
ip += instruct.size
instruct
end
end
class Instruction
def initialize(inst, cm, ip)
@op = InstructionSet[inst[0]]
@args = inst[1..-1]
@args.each_index do |i|
case @op.args[i]
when :literal
@args[i] = cm.literals[@args[i]]
end
end
@ip = ip
@line = cm.line_from_ip(ip)
end
# Returns the symbol representing the opcode for this instruction
def opcode
@op.opcode
end
# Returns an array of 0 to 2 arguments, depending on the opcode
def args
@args
end
def size
@args.size + 1
end
attr_reader :ip
attr_reader :line
def to_s
str = "%04d: %-27s" % [@ip, opcode]
str << @args.map{|a| a.inspect}.join(', ')
end
end
end