cast_off 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +578 -0
- data/README.en +256 -0
- data/bin/CastOff +145 -0
- data/cast_off.gemspec +25 -0
- data/ext/cast_off/cast_off.c.rb +1386 -0
- data/ext/cast_off/cast_off.h +24 -0
- data/ext/cast_off/depend +70 -0
- data/ext/cast_off/extconf.rb +19 -0
- data/ext/cast_off/generated_c_include/inline_api.h +507 -0
- data/ext/cast_off/generated_c_include/iter_api.h +595 -0
- data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
- data/ext/cast_off/generated_c_include/vm_api.h +751 -0
- data/ext/cast_off/ruby_source/atomic.h +56 -0
- data/ext/cast_off/ruby_source/constant.h +34 -0
- data/ext/cast_off/ruby_source/debug.h +41 -0
- data/ext/cast_off/ruby_source/eval_intern.h +234 -0
- data/ext/cast_off/ruby_source/gc.h +98 -0
- data/ext/cast_off/ruby_source/id.h +175 -0
- data/ext/cast_off/ruby_source/insns.inc +179 -0
- data/ext/cast_off/ruby_source/insns_info.inc +695 -0
- data/ext/cast_off/ruby_source/internal.h +227 -0
- data/ext/cast_off/ruby_source/iseq.h +125 -0
- data/ext/cast_off/ruby_source/manual_update.h +135 -0
- data/ext/cast_off/ruby_source/method.h +105 -0
- data/ext/cast_off/ruby_source/node.h +503 -0
- data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
- data/ext/cast_off/ruby_source/thread_win32.h +40 -0
- data/ext/cast_off/ruby_source/vm_core.h +756 -0
- data/ext/cast_off/ruby_source/vm_exec.h +184 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
- data/ext/cast_off/ruby_source/vm_opts.h +51 -0
- data/lib/cast_off.rb +15 -0
- data/lib/cast_off/compile.rb +629 -0
- data/lib/cast_off/compile/basicblock.rb +144 -0
- data/lib/cast_off/compile/cfg.rb +391 -0
- data/lib/cast_off/compile/code_manager.rb +284 -0
- data/lib/cast_off/compile/configuration.rb +2368 -0
- data/lib/cast_off/compile/dependency.rb +240 -0
- data/lib/cast_off/compile/information.rb +775 -0
- data/lib/cast_off/compile/instruction.rb +446 -0
- data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
- data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
- data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
- data/lib/cast_off/compile/ir/operand.rb +934 -0
- data/lib/cast_off/compile/ir/param_ir.rb +98 -0
- data/lib/cast_off/compile/ir/return_ir.rb +92 -0
- data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
- data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
- data/lib/cast_off/compile/iseq.rb +454 -0
- data/lib/cast_off/compile/method_information.rb +1384 -0
- data/lib/cast_off/compile/namespace/namespace.rb +556 -0
- data/lib/cast_off/compile/namespace/uuid.rb +323 -0
- data/lib/cast_off/compile/stack.rb +65 -0
- data/lib/cast_off/compile/translator.rb +1562 -0
- data/lib/cast_off/suggestion.rb +98 -0
- data/lib/cast_off/util.rb +58 -0
- metadata +107 -0
data/README.en
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
* About CastOff
|
2
|
+
CastOff is a performance improvement tool for Ruby1.9.3.
|
3
|
+
In other words, CastOff is a compiler for Ruby1.9.3.
|
4
|
+
CastOff compiles Ruby method (method written in Ruby) into C extension (method written in C)
|
5
|
+
by using given information such as class information of variables.
|
6
|
+
CastOff can reduce Ruby virtual machine overhead, so by use of CastOff,
|
7
|
+
the performance of compilation target method can improve.
|
8
|
+
|
9
|
+
This README document introduce basic functionality of CastOff.
|
10
|
+
If you have any questions, comments, or suggestions please send email to shiba@rvm.jp,
|
11
|
+
or use http://github.com/soba1104/CastOff/issues.
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
* License
|
16
|
+
Same as the license of Ruby1.9.3 runtime.
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
* Installation
|
21
|
+
$gem build cast_off.gemspec
|
22
|
+
$gem install cast_off-0.2.0.gem --local
|
23
|
+
|
24
|
+
Currently, CastOff supports Ruby1.9.3 only.
|
25
|
+
So, if you attempt to use CastOff, please install CastOff under Ruby1.9.3 runtime.
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
* Attention
|
30
|
+
|
31
|
+
** Incompatibility
|
32
|
+
-Continuation
|
33
|
+
CastOff causes problem about capture of continuation (callcc).
|
34
|
+
So, you should not use CastOff to your program which uses Continuation.
|
35
|
+
|
36
|
+
-Constant redefinition
|
37
|
+
<<<Sorry, not yet documented.>>>
|
38
|
+
|
39
|
+
-Built-in functions related with Method and Proc
|
40
|
+
CastOff compiles Ruby method and proc into C extension.
|
41
|
+
So, built-in functions related with Method and Proc (such as Method#arity, Proc#arity)
|
42
|
+
return different values.
|
43
|
+
|
44
|
+
# example
|
45
|
+
class Foo
|
46
|
+
def foo(a, b = :b, *c); end
|
47
|
+
end
|
48
|
+
f = Foo.new
|
49
|
+
puts (f.method(:foo).arity) # => -2
|
50
|
+
CastOff.compile(Foo, :foo)
|
51
|
+
puts (f.method(:foo).arity) # => -1
|
52
|
+
|
53
|
+
|
54
|
+
** Startup time
|
55
|
+
<<<Sorry, not yet documented.>>>
|
56
|
+
|
57
|
+
|
58
|
+
** Compilation time
|
59
|
+
<<<Sorry, not yet documented.>>>
|
60
|
+
|
61
|
+
|
62
|
+
** Load of compiled method
|
63
|
+
CastOff needs definition of compilation target method to load compiled method.
|
64
|
+
If compilation target method is not defined, CastOff cannot load compiled method.
|
65
|
+
|
66
|
+
When you use CastOff from command line, CastOff hooks class definition statement
|
67
|
+
to check method definition. And load compiled method if compilation target method is defined.
|
68
|
+
So, if you want to compile method outer class definition statement (such as following bar method),
|
69
|
+
you need call CastOff.autoload or CastOff.load after method definition explicitly.
|
70
|
+
|
71
|
+
-----------------------------------------------------
|
72
|
+
class Foo # Compiled Foo#foo is loaded after class definition of Foo
|
73
|
+
def foo
|
74
|
+
...
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def bar() # There are no class definition after definition of bar,
|
79
|
+
# so Compiled bar method is not loaded.
|
80
|
+
...
|
81
|
+
end
|
82
|
+
# If you want to load compiled bar method,
|
83
|
+
# you should call CastOff.autoload or CastOff.load after definition of bar method.
|
84
|
+
|
85
|
+
...
|
86
|
+
-----------------------------------------------------
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
* Usage
|
91
|
+
|
92
|
+
** Use CastOff from command line
|
93
|
+
By use of command line tool CastOff, you can improve performance of your Ruby program easily.
|
94
|
+
If you want to improve performance of your Ruby program, you should execute following command repeatedly.
|
95
|
+
|
96
|
+
-----------------------------------------------------
|
97
|
+
$CastOff PathOfTargetProgram ArgumentsOfTargetProgram
|
98
|
+
-----------------------------------------------------
|
99
|
+
|
100
|
+
For example, when you want to improve performance of Ruby program "foo.rb"
|
101
|
+
(in this example, "foo.rb" recieves one argument "bar" or "baz"), you should execute following commands.
|
102
|
+
|
103
|
+
-----------------------------------------------------
|
104
|
+
$CastOff foo.rb bar
|
105
|
+
$CastOff foo.rb baz
|
106
|
+
-----------------------------------------------------
|
107
|
+
|
108
|
+
When you execute these commands, CastOff does followings to compile foo.rb and related libraries.
|
109
|
+
|
110
|
+
1: Executes "foo.rb" with argument "bar" to get profile information.
|
111
|
+
2: Compiles "foo.rb" and related libraries.
|
112
|
+
3: Executes "foo.rb" with argument "baz" to get and update profile information.
|
113
|
+
4: Compiles "foo.rb" and related libraries.
|
114
|
+
|
115
|
+
When CastOff finishes compilation, CastOff outputs some codes.
|
116
|
+
You can load compiled methods by pasting these codes.
|
117
|
+
In above example, CastOff outputs following codes.
|
118
|
+
|
119
|
+
-----------------------------------------------------
|
120
|
+
require 'cast_off'
|
121
|
+
CastOff.program_name = "foo.rb"
|
122
|
+
CastOff.skip_configuration_check(true)
|
123
|
+
CastOff.deoptimize(false)
|
124
|
+
CastOff.use_default_configuration()
|
125
|
+
CastOff.autoload()
|
126
|
+
-----------------------------------------------------
|
127
|
+
|
128
|
+
"CastOff.autoload" uses trace api provided from Ruby runtime.
|
129
|
+
But this api slows down Ruby program execution significantly.
|
130
|
+
If you want to avoid this overhead, call "CastOff.autoload" after all method definitions.
|
131
|
+
CastOff uses trace api to check method definition,
|
132
|
+
so if you call "CastOff.autoload" after all method definitions, CastOff can cancel tracing immediately.
|
133
|
+
|
134
|
+
|
135
|
+
*** Command line arguments
|
136
|
+
|
137
|
+
CastOff [options] PathOfTargetProgram ArgumentsOfTargetProgram
|
138
|
+
|
139
|
+
|
140
|
+
*** Command line options
|
141
|
+
--verbose
|
142
|
+
Show compilation progress and internal information.
|
143
|
+
|
144
|
+
--deoptimize
|
145
|
+
Enable deoptimization.
|
146
|
+
(Currently, CastOff does not support deoptimization of methods which use block.)
|
147
|
+
|
148
|
+
--clear
|
149
|
+
Clear profile information and delete compiled methods.
|
150
|
+
If you want to clear profile information and compiled methods of target name "foo",
|
151
|
+
you should execute following command.
|
152
|
+
$CastOff --clear --name=foo
|
153
|
+
|
154
|
+
--threshold=COUNT
|
155
|
+
Compile method which is executed more than COUNT.
|
156
|
+
Default value is 100.
|
157
|
+
|
158
|
+
--name=NAME
|
159
|
+
Name compiled methods NAME.
|
160
|
+
This name is used for search of compiled methods.
|
161
|
+
If you don't use this option, CastOff uses File.basename([programfile]) as name.
|
162
|
+
|
163
|
+
-h, --help
|
164
|
+
Show help.
|
165
|
+
|
166
|
+
--version
|
167
|
+
Show version number of CastOff.
|
168
|
+
|
169
|
+
--step-1
|
170
|
+
Execute first step of compilation.
|
171
|
+
On this step, CastOff decides compilation target methods.
|
172
|
+
|
173
|
+
--step-2
|
174
|
+
Execute second step of compilation.
|
175
|
+
On this step, CastOff collects profile information and compiles methods.
|
176
|
+
|
177
|
+
--run
|
178
|
+
Execute target program with compiled methods.
|
179
|
+
|
180
|
+
|
181
|
+
|
182
|
+
** Use CastOff from script
|
183
|
+
<<<Sorry, not yet documented. >>>
|
184
|
+
|
185
|
+
|
186
|
+
*** Specify class information to CastOff
|
187
|
+
You can specify class information to CastOff by followings.
|
188
|
+
|
189
|
+
-Specify class of variables:
|
190
|
+
--local variables, arguments
|
191
|
+
:local_variable_name => class_name
|
192
|
+
:local_variable_name => [class_name1, class_name2, ...]
|
193
|
+
[:local_variable_name1, :local_variable_name2, ...] => class_name
|
194
|
+
[:local_variable_name1, :local_variable_name2, ...] => [class_name1, class_name2, ...]
|
195
|
+
|
196
|
+
--instance variables
|
197
|
+
:@instance_variable_name => class_name
|
198
|
+
:@instance_variable_name => [class_name1, class_name2, ...]
|
199
|
+
[:@instance_variable_name1, :@instance_variable_name2, ...] => class_name
|
200
|
+
[:@instance_variable_name1, :@instance_variable_name2, ...] => [class_name1, class_name2, ...]
|
201
|
+
|
202
|
+
--class variables
|
203
|
+
:@@class_variable_name => class_name
|
204
|
+
:@@class_variable_name => [class_name1, class_name2, ...]
|
205
|
+
[:@@class_variable_name1, :@@class_variable_name2, ...] => class_name
|
206
|
+
[:@@class_variable_name1, :@@class_variable_name2, ...] => [class_name1, class_name2, ...]
|
207
|
+
|
208
|
+
--global variables
|
209
|
+
:$global_variable_name => class_name
|
210
|
+
:$global_variable_name => [class_name1, class_name2, ...]
|
211
|
+
[:$global_variable_name1, :$global_variable_name2, ...] => class_name
|
212
|
+
[:$global_variable_name1, :$global_variable_name2, ...] => [class_name1, class_name2, ...]
|
213
|
+
|
214
|
+
-Specify class of method return values:
|
215
|
+
class_name => {:method_name1 => class_of_return_value, :method_name2 => [class_of_return_value1, class_of_return_value2, ...], ...}
|
216
|
+
|
217
|
+
-Specify class of constants:
|
218
|
+
<<<Sorry, not yet documented. >>>
|
219
|
+
|
220
|
+
|
221
|
+
*** Compilation
|
222
|
+
You can compile Ruby method into C extension by followings.
|
223
|
+
|
224
|
+
-Compile instance method
|
225
|
+
--API
|
226
|
+
CastOff.compile(target(Class or Module), method_name(Symbol))
|
227
|
+
CastOff.compile(target(Class or Module), method_name(Symbol), class_information(Hash))
|
228
|
+
CastOff.compile(target(Class or Module), method_name(Symbol), binding(Binding))
|
229
|
+
CastOff.compile(target(Class or Module), method_name(Symbol), binding(Binding), class_information(Hash))
|
230
|
+
--Notes
|
231
|
+
This API compiles Ruby instance method into C extension and loads compiled method.
|
232
|
+
You should specify method_name(second argument) by Symbol class.
|
233
|
+
CastOff uses binding(third argument) to resolve Ruby constants.
|
234
|
+
|
235
|
+
-Compile singleton method
|
236
|
+
--API
|
237
|
+
CastOff.compile_singleton_method(target(Any Object), method_name(Symbol))
|
238
|
+
CastOff.compile_singleton_method(target(Any Object), method_name(Symbol), class_information(Hash))
|
239
|
+
CastOff.compile_singleton_method(target(Any Object), method_name(Symbol), binding(Binding))
|
240
|
+
CastOff.compile_singleton_method(target(Any Object), method_name(Symbol), binding(Binding), class_information(Hash))
|
241
|
+
--Notes
|
242
|
+
This API compiles Ruby singleton method into C extension and loads compiled method.
|
243
|
+
You should not use CastOff.compile when compile singleton method.
|
244
|
+
You should specify method_name(second argument) by Symbol class.
|
245
|
+
CastOff uses binding(third argument) to resolve Ruby constants.
|
246
|
+
|
247
|
+
-Compile Ruby code and execute
|
248
|
+
--API
|
249
|
+
CastOff.execute(class_information(Hash)) { target code }
|
250
|
+
--Notes
|
251
|
+
This API compiles passed block and executes.
|
252
|
+
|
253
|
+
|
254
|
+
*** Compile options
|
255
|
+
<<<Sorry, not yet documented. >>>
|
256
|
+
|
data/bin/CastOff
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require 'cast_off'
|
6
|
+
|
7
|
+
this = File.expand_path(__FILE__)
|
8
|
+
step = nil
|
9
|
+
verbose = false
|
10
|
+
clear = false
|
11
|
+
deoptimize = false
|
12
|
+
threshold = 100
|
13
|
+
name = nil
|
14
|
+
|
15
|
+
opt = OptionParser.new(<<-EOS, 32, ' ')
|
16
|
+
CastOff is a performance improvement tool for Ruby1.9.3.
|
17
|
+
|
18
|
+
Usage:
|
19
|
+
CastOff [options] [programfile] [arguments]
|
20
|
+
EOS
|
21
|
+
opt.separator("\n Options:")
|
22
|
+
opt.on('--verbose', <<-EOS.strip) {|v| verbose = true }
|
23
|
+
Show compilation progress and internal information.
|
24
|
+
EOS
|
25
|
+
opt.on('--deoptimize', <<-EOS.strip) {|v| deoptimize = true }
|
26
|
+
Enable deoptimization.
|
27
|
+
EOS
|
28
|
+
opt.on('--threshold=COUNT', <<-EOS.strip, Integer) {|v| threshold = v }
|
29
|
+
Compile method which is executed more than COUNT.
|
30
|
+
Default value is 100.
|
31
|
+
EOS
|
32
|
+
opt.on('--name=NAME', <<-EOS.strip, String) {|v| name = v }
|
33
|
+
Name compiled methods NAME.
|
34
|
+
This name is used for search of compiled methods.
|
35
|
+
If you don't use this option, CastOff uses File.basename([programfile]) as name.
|
36
|
+
EOS
|
37
|
+
opt.on('--clear', <<-EOS.strip) {|v| clear = true }
|
38
|
+
Clear profile information and delete compiled methods.
|
39
|
+
If you want to clear profile information and compiled methods of target name "foo",
|
40
|
+
you should execute following command.
|
41
|
+
$CastOff --clear --name=foo
|
42
|
+
EOS
|
43
|
+
opt.on('--run', <<-EOS.strip) {|v| step = 'run' }
|
44
|
+
Execute [programfile] with compiled methods.
|
45
|
+
EOS
|
46
|
+
opt.on('--step-1', <<-EOS.strip) {|v| step = '1' }
|
47
|
+
First step of compilation.
|
48
|
+
On this step, CastOff decides compilation target methods.
|
49
|
+
EOS
|
50
|
+
opt.on('--step-2', <<-EOS.strip) {|v| step = '2' }
|
51
|
+
Second step of compilation.
|
52
|
+
On this step, CastOff collects profile information and compiles methods.
|
53
|
+
EOS
|
54
|
+
opt.on_tail('-h', "--help", "Show this help.") do
|
55
|
+
puts opt
|
56
|
+
exit
|
57
|
+
end
|
58
|
+
opt.on_tail("--version", "Show version number.") do
|
59
|
+
puts Gem.loaded_specs['cast_off'].version.to_s
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
opt.order!(ARGV)
|
64
|
+
|
65
|
+
args = ARGV.join(" ")
|
66
|
+
script = ARGV.shift || ''
|
67
|
+
name = File.basename(script) unless name
|
68
|
+
|
69
|
+
if clear
|
70
|
+
if name.empty?
|
71
|
+
STDERR.puts(<<-EOS)
|
72
|
+
Invalid arguments. You should pass target name to CastOff.
|
73
|
+
If you want to clear profile information and compiled methods of target name "foo",
|
74
|
+
you should execute following command.
|
75
|
+
$CastOff --clear --name=foo
|
76
|
+
EOS
|
77
|
+
exit(1)
|
78
|
+
end
|
79
|
+
CastOff.program_name = name
|
80
|
+
CastOff.clear()
|
81
|
+
exit(0)
|
82
|
+
end
|
83
|
+
|
84
|
+
unless File.exist?(script)
|
85
|
+
if script.empty?
|
86
|
+
STDERR.puts("Invalid arguments. You should pass [programname] to CastOff.")
|
87
|
+
else
|
88
|
+
STDERR.puts("#{script} is not exist.")
|
89
|
+
end
|
90
|
+
exit(1)
|
91
|
+
end
|
92
|
+
|
93
|
+
configuration = <<-EOS
|
94
|
+
CastOff.program_name = #{name.inspect}
|
95
|
+
CastOff.skip_configuration_check(true)
|
96
|
+
CastOff.deoptimize(#{deoptimize})
|
97
|
+
CastOff.use_default_configuration()
|
98
|
+
EOS
|
99
|
+
eval(configuration, binding)
|
100
|
+
CastOff.compilation_threshold = threshold
|
101
|
+
CastOff.program_name = name
|
102
|
+
CastOff.verbose(verbose)
|
103
|
+
|
104
|
+
case step
|
105
|
+
when nil
|
106
|
+
STDERR.puts("-------------------------------- compilation start, threshold = #{threshold}, name = #{name}: #{args} --------------------------------")
|
107
|
+
2.times{|i| system("#{this} --step-#{i + 1} --threshold=#{threshold} --name=#{name} #{deoptimize ? '--deoptimize' : ''} #{verbose ? '--verbose' : ''} #{args}")}
|
108
|
+
when '1'
|
109
|
+
STDERR.puts("-------------------------------- step 1 --------------------------------")
|
110
|
+
CastOff.development(true)
|
111
|
+
CastOff.use_base_configuration(false)
|
112
|
+
CastOff.autocompile()
|
113
|
+
when '2'
|
114
|
+
STDERR.puts("-------------------------------- step 2 --------------------------------")
|
115
|
+
CastOff.development(true)
|
116
|
+
CastOff.use_base_configuration(false)
|
117
|
+
CastOff.autoload()
|
118
|
+
#fin = Object.new
|
119
|
+
#ObjectSpace.define_finalizer(fin){
|
120
|
+
at_exit{
|
121
|
+
CastOff.development(false)
|
122
|
+
CastOff.use_base_configuration(true)
|
123
|
+
# step 3
|
124
|
+
CastOff.load(true)
|
125
|
+
msg = <<-EOS
|
126
|
+
|
127
|
+
----------------------------------------------------------------------------------------
|
128
|
+
Compilation finished successfully.
|
129
|
+
Please add following lines to #{script}.
|
130
|
+
|
131
|
+
require 'cast_off'
|
132
|
+
#{configuration.chomp}
|
133
|
+
CastOff.autoload()
|
134
|
+
----------------------------------------------------------------------------------------
|
135
|
+
EOS
|
136
|
+
STDERR.puts(msg)
|
137
|
+
}
|
138
|
+
when 'run'
|
139
|
+
CastOff.autoload()
|
140
|
+
else
|
141
|
+
raise("should not be reached")
|
142
|
+
end
|
143
|
+
|
144
|
+
load script if step
|
145
|
+
|
data/cast_off.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "cast_off"
|
3
|
+
spec.version = "0.2.0"
|
4
|
+
spec.platform = Gem::Platform::RUBY
|
5
|
+
spec.summary = "performance improvement tool for Ruby1.9.3"
|
6
|
+
spec.description = <<-EOS
|
7
|
+
CastOff is performance improvement tool for Ruby1.9.3
|
8
|
+
EOS
|
9
|
+
spec.files = Dir['{lib/**/*,ext/**/*}'] + %w[
|
10
|
+
cast_off.gemspec
|
11
|
+
]
|
12
|
+
spec.bindir = 'bin'
|
13
|
+
spec.executables << 'CastOff'
|
14
|
+
spec.require_path = 'lib'
|
15
|
+
spec.extensions = 'ext/cast_off/extconf.rb'
|
16
|
+
spec.has_rdoc = false
|
17
|
+
spec.extra_rdoc_files = ['README', 'README.en']
|
18
|
+
#spec.test_files = Dir['test/*']
|
19
|
+
spec.author = 'Satoshi Shiba'
|
20
|
+
spec.email = 'shiba@rvm.jp'
|
21
|
+
spec.homepage = 'http://github.com/soba1104/CastOff'
|
22
|
+
#spec.rubyforge_project = 'cast_off'
|
23
|
+
spec.required_ruby_version = '> 1.9.2'
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,1386 @@
|
|
1
|
+
#if 1
|
2
|
+
#define __END__ /* void */
|
3
|
+
#else
|
4
|
+
ruby_srcdir = ARGV[0];
|
5
|
+
generated_c_include = ARGV[1];
|
6
|
+
srcdir = File.dirname(__FILE__)
|
7
|
+
require("erb");
|
8
|
+
require('rbconfig');
|
9
|
+
DATA.rewind();
|
10
|
+
|
11
|
+
ERB.new(DATA.read(), 0, "%-").run();
|
12
|
+
#endif
|
13
|
+
__END__
|
14
|
+
|
15
|
+
#include <cast_off.h>
|
16
|
+
|
17
|
+
VALUE rb_eCastOffCompileError;
|
18
|
+
VALUE rb_eCastOffExecutionError;
|
19
|
+
VALUE rb_eCastOffLoadError;
|
20
|
+
VALUE rb_eCastOffUnsupportedError;
|
21
|
+
VALUE rb_mCastOff;
|
22
|
+
VALUE rb_mCastOffCompiler;
|
23
|
+
VALUE rb_mCastOffCompilerInstruction;
|
24
|
+
VALUE rb_cCastOffConfiguration;
|
25
|
+
VALUE rb_cCastOffDependency;
|
26
|
+
VALUE rb_cCastOffInsnInfo;
|
27
|
+
VALUE rb_cCastOffSingletonClass;
|
28
|
+
VALUE rb_cCastOffClassWrapper;
|
29
|
+
VALUE rb_cCastOffMethodWrapper;
|
30
|
+
VALUE rb_cCastOffModuleWrapper;
|
31
|
+
|
32
|
+
static VALUE
|
33
|
+
gen_headers(void)
|
34
|
+
{
|
35
|
+
% files = %w[
|
36
|
+
% debug.h
|
37
|
+
% eval_intern.h
|
38
|
+
% gc.h
|
39
|
+
% id.h
|
40
|
+
% iseq.h
|
41
|
+
% method.h
|
42
|
+
% node.h
|
43
|
+
% thread_pthread.h
|
44
|
+
% thread_win32.h
|
45
|
+
% vm_core.h
|
46
|
+
% vm_exec.h
|
47
|
+
% vm_insnhelper.h
|
48
|
+
% vm_insnhelper.c
|
49
|
+
% vm_opts.h
|
50
|
+
% insns_info.inc
|
51
|
+
% insns.inc
|
52
|
+
% atomic.h
|
53
|
+
% internal.h
|
54
|
+
% manual_update.h
|
55
|
+
% ].map{|f| [ruby_srcdir, f ]} + %w[
|
56
|
+
% iter_api.h
|
57
|
+
% vm_api.h
|
58
|
+
% inline_api.h
|
59
|
+
% unbox_api.h
|
60
|
+
% ].map{|f| [generated_c_include, f]}
|
61
|
+
% case RUBY_VERSION
|
62
|
+
% when "1.9.2"
|
63
|
+
% # nothing to do
|
64
|
+
% when "1.9.3", "1.9.4"
|
65
|
+
% files << [ruby_srcdir, "constant.h"]
|
66
|
+
% else
|
67
|
+
% raise("unsupported ruby version #{RUBY_VERSION}")
|
68
|
+
% end
|
69
|
+
%data = Marshal.dump files.inject({}){|r, i|
|
70
|
+
% dir, file = i
|
71
|
+
% r[file] = File.read("#{srcdir}/#{dir}/#{file}")
|
72
|
+
% r
|
73
|
+
%}
|
74
|
+
|
75
|
+
rb_encoding* binary = rb_ascii8bit_encoding();
|
76
|
+
VALUE str = rb_enc_str_new(NULL, 0, binary);
|
77
|
+
% max = 0
|
78
|
+
%data.each_byte.each_slice(1024).each_with_index {|b, index|
|
79
|
+
char data_<%= index %>[] = {
|
80
|
+
% size = 0
|
81
|
+
% b.each_slice(16).each {|bytes|
|
82
|
+
% size += bytes.size
|
83
|
+
<%= bytes.map {|i| "%#04x" % i }.join(", ") %>,
|
84
|
+
% }
|
85
|
+
};
|
86
|
+
VALUE str_<%= index %> = rb_enc_str_new(data_<%= index %>, <%= size %>, binary);
|
87
|
+
% max += 1
|
88
|
+
%}
|
89
|
+
%max.times do |i|
|
90
|
+
rb_str_concat(str, str_<%= i %>);
|
91
|
+
%end
|
92
|
+
return rb_marshal_load(str);
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE
|
96
|
+
cast_off_get_child_iseq(VALUE self, VALUE iseqval, VALUE pcval)
|
97
|
+
{
|
98
|
+
long pc;
|
99
|
+
rb_iseq_t *parent_iseq, *child_iseq;
|
100
|
+
VALUE insn, ret;
|
101
|
+
|
102
|
+
if (rb_class_of(iseqval) != rb_cISeq || !FIXNUM_P(pcval)) {
|
103
|
+
rb_bug("should not be reached (0)");
|
104
|
+
}
|
105
|
+
|
106
|
+
parent_iseq = DATA_PTR(iseqval);
|
107
|
+
pc = FIX2LONG(pcval);
|
108
|
+
insn = parent_iseq->iseq[pc];
|
109
|
+
|
110
|
+
if (insn != BIN(send)) {
|
111
|
+
rb_bug("should not be reached (1), pc = %ld", pc);
|
112
|
+
}
|
113
|
+
|
114
|
+
child_iseq = (rb_iseq_t*)parent_iseq->iseq[pc + 3];
|
115
|
+
ret = child_iseq->self;
|
116
|
+
|
117
|
+
if (rb_class_of(ret) == rb_cISeq) {
|
118
|
+
return ret;
|
119
|
+
} else {
|
120
|
+
rb_bug("should not be reached (2)");
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
static struct st_table *insn_table;
|
125
|
+
static VALUE *insn_syms;
|
126
|
+
|
127
|
+
static void
|
128
|
+
init_insn_table(void)
|
129
|
+
{
|
130
|
+
int i;
|
131
|
+
|
132
|
+
if (!insn_syms) {
|
133
|
+
insn_table = st_init_numtable();
|
134
|
+
insn_syms = malloc(sizeof(VALUE) * VM_INSTRUCTION_SIZE);
|
135
|
+
for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
|
136
|
+
insn_syms[i] = ID2SYM(rb_intern(insn_name(i)));
|
137
|
+
st_insert(insn_table, insn_syms[i], i);
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
static VALUE
|
143
|
+
cast_off_instruction_popnum(VALUE self, VALUE insns)
|
144
|
+
{
|
145
|
+
VALUE *opes;
|
146
|
+
VALUE insnsym;
|
147
|
+
VALUE insn;
|
148
|
+
int pop;
|
149
|
+
|
150
|
+
if (TYPE(insns) != T_ARRAY) {
|
151
|
+
rb_funcall(self, rb_intern("bug"), 1, rb_str_new2("instruction_stack_usage: invalid argument"));
|
152
|
+
/* no return */
|
153
|
+
}
|
154
|
+
insnsym = RARRAY_PTR(insns)[0];
|
155
|
+
if (!st_lookup(insn_table, insnsym, &insn)) {
|
156
|
+
rb_raise(rb_eArgError, "unsupported instruction");
|
157
|
+
/* no return */
|
158
|
+
}
|
159
|
+
|
160
|
+
opes = RARRAY_PTR(insns) + 1;
|
161
|
+
pop = insn_ret_num(insn) - insn_stack_increase(0, insn, opes);
|
162
|
+
|
163
|
+
return INT2FIX(pop);
|
164
|
+
}
|
165
|
+
|
166
|
+
static VALUE
|
167
|
+
cast_off_instruction_pushnum(VALUE self, VALUE insns)
|
168
|
+
{
|
169
|
+
VALUE *opes;
|
170
|
+
VALUE insnsym;
|
171
|
+
VALUE insn;
|
172
|
+
|
173
|
+
if (TYPE(insns) != T_ARRAY) {
|
174
|
+
rb_funcall(self, rb_intern("bug"), 1, rb_str_new2("instruction_stack_usage: invalid argument"));
|
175
|
+
/* no return */
|
176
|
+
}
|
177
|
+
insnsym = RARRAY_PTR(insns)[0];
|
178
|
+
if (!st_lookup(insn_table, insnsym, &insn)) {
|
179
|
+
rb_raise(rb_eArgError, "unsupported instruction");
|
180
|
+
/* no return */
|
181
|
+
}
|
182
|
+
|
183
|
+
opes = RARRAY_PTR(insns) + 1;
|
184
|
+
return INT2FIX(insn_ret_num(insn));
|
185
|
+
}
|
186
|
+
|
187
|
+
static VALUE
|
188
|
+
cast_off_instruction_stack_usage(VALUE self, VALUE insns)
|
189
|
+
{
|
190
|
+
VALUE *opes;
|
191
|
+
VALUE insnsym;
|
192
|
+
VALUE insn;
|
193
|
+
|
194
|
+
if (TYPE(insns) != T_ARRAY) {
|
195
|
+
rb_funcall(self, rb_intern("bug"), 1, rb_str_new2("instruction_stack_usage: invalid argument"));
|
196
|
+
/* no return */
|
197
|
+
}
|
198
|
+
insnsym = RARRAY_PTR(insns)[0];
|
199
|
+
if (!st_lookup(insn_table, insnsym, &insn)) {
|
200
|
+
rb_raise(rb_eArgError, "unsupported instruction");
|
201
|
+
/* no return */
|
202
|
+
}
|
203
|
+
|
204
|
+
opes = RARRAY_PTR(insns) + 1;
|
205
|
+
return INT2FIX(insn_stack_increase(0, insn, opes));
|
206
|
+
}
|
207
|
+
|
208
|
+
static VALUE
|
209
|
+
cast_off_instruction_class_information_in_ic(VALUE self, VALUE iseqval)
|
210
|
+
{
|
211
|
+
VALUE pc = rb_ivar_get(self, rb_intern("@pc"));
|
212
|
+
VALUE klass = Qnil;
|
213
|
+
VALUE *insn;
|
214
|
+
rb_iseq_t *iseq;
|
215
|
+
IC ic = NULL;
|
216
|
+
|
217
|
+
if (rb_class_of(pc) != rb_cFixnum || rb_class_of(iseqval) != rb_cISeq) {
|
218
|
+
rb_bug("cast_off_instruction_class_information_in_ic: should not be reached (0)");
|
219
|
+
}
|
220
|
+
|
221
|
+
if (FIX2INT(pc) < 0) {
|
222
|
+
return Qnil;
|
223
|
+
}
|
224
|
+
|
225
|
+
iseq = DATA_PTR(iseqval);
|
226
|
+
insn = &iseq->iseq[FIX2INT(pc)];
|
227
|
+
|
228
|
+
switch(insn[0]) {
|
229
|
+
case(BIN(send)):
|
230
|
+
ic = (IC)insn[5];
|
231
|
+
break;
|
232
|
+
case(BIN(opt_plus)):
|
233
|
+
case(BIN(opt_minus)):
|
234
|
+
case(BIN(opt_mult)):
|
235
|
+
case(BIN(opt_div)):
|
236
|
+
case(BIN(opt_mod)):
|
237
|
+
case(BIN(opt_eq)):
|
238
|
+
case(BIN(opt_lt)):
|
239
|
+
case(BIN(opt_le)):
|
240
|
+
case(BIN(opt_gt)):
|
241
|
+
case(BIN(opt_ge)):
|
242
|
+
case(BIN(opt_ltlt)):
|
243
|
+
case(BIN(opt_aref)):
|
244
|
+
case(BIN(opt_aset)):
|
245
|
+
case(BIN(opt_length)):
|
246
|
+
case(BIN(opt_size)):
|
247
|
+
case(BIN(opt_succ)):
|
248
|
+
case(BIN(opt_not)):
|
249
|
+
ic = (IC)insn[1];
|
250
|
+
break;
|
251
|
+
}
|
252
|
+
|
253
|
+
if (!ic) {
|
254
|
+
return Qnil;
|
255
|
+
}
|
256
|
+
|
257
|
+
klass = ic->ic_class;
|
258
|
+
|
259
|
+
if (!klass || klass == Qnil) {
|
260
|
+
return Qnil;
|
261
|
+
}
|
262
|
+
|
263
|
+
if (rb_obj_class(klass) != rb_cClass) {
|
264
|
+
/* FIXME 普通のオブジェクトが来ることがある。何でだろう。要調査 */
|
265
|
+
/* rb_bug("cast_off_instruction_class_information_in_ic: should not be reached (1)"); */
|
266
|
+
return Qnil;
|
267
|
+
}
|
268
|
+
|
269
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
270
|
+
VALUE obj = rb_iv_get(klass, "__attached__");
|
271
|
+
VALUE __klass = rb_obj_class(obj);
|
272
|
+
if (__klass != rb_cClass && __klass != rb_cModule) {
|
273
|
+
return Qnil;
|
274
|
+
}
|
275
|
+
return rb_funcall(rb_cCastOffClassWrapper, rb_intern("new"), 2, obj, Qfalse);
|
276
|
+
} else {
|
277
|
+
return rb_funcall(rb_cCastOffClassWrapper, rb_intern("new"), 2, klass, Qtrue);
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
static VALUE cast_off_override_target(VALUE self, VALUE km, VALUE msym)
|
282
|
+
{
|
283
|
+
ID mid;
|
284
|
+
rb_method_entry_t *me;
|
285
|
+
int class;
|
286
|
+
VALUE c = rb_obj_class(km);
|
287
|
+
VALUE target;
|
288
|
+
|
289
|
+
if (c == rb_cClass) {
|
290
|
+
class = 1;
|
291
|
+
} else if (c == rb_cModule) {
|
292
|
+
class = 0;
|
293
|
+
} else {
|
294
|
+
rb_bug("cast_off_override_target: should not be reached(0)");
|
295
|
+
}
|
296
|
+
|
297
|
+
if (rb_class_of(msym) != rb_cSymbol) {
|
298
|
+
rb_bug("cast_off_override_target: should not be reached(1)");
|
299
|
+
}
|
300
|
+
|
301
|
+
mid = SYM2ID(msym);
|
302
|
+
me = search_method(km, mid);
|
303
|
+
|
304
|
+
if (!me) {
|
305
|
+
VALUE name;
|
306
|
+
|
307
|
+
if (class) {
|
308
|
+
name = rb_class_path(km);
|
309
|
+
} else {
|
310
|
+
name = rb_mod_name(km);
|
311
|
+
}
|
312
|
+
rb_raise(rb_eCastOffCompileError, "method not found (%s#%s)", RSTRING_PTR(name), rb_id2name(mid));
|
313
|
+
}
|
314
|
+
|
315
|
+
target = me->klass;
|
316
|
+
|
317
|
+
if (FL_TEST(target, FL_SINGLETON)) {
|
318
|
+
rb_bug("cast_off_override_target: should not be reached(2)");
|
319
|
+
}
|
320
|
+
|
321
|
+
if (rb_obj_class(target) != rb_cClass && rb_obj_class(target) != rb_cModule) {
|
322
|
+
rb_bug("cast_off_override_target: should not be reached(3)");
|
323
|
+
}
|
324
|
+
|
325
|
+
return target;
|
326
|
+
}
|
327
|
+
|
328
|
+
static VALUE cast_off_get_iseq(VALUE self, VALUE obj, VALUE mid, VALUE singleton_p)
|
329
|
+
{
|
330
|
+
rb_iseq_t *iseq;
|
331
|
+
rb_method_entry_t *me;
|
332
|
+
rb_method_definition_t *def;
|
333
|
+
VALUE km;
|
334
|
+
int class;
|
335
|
+
char *msg = NULL;
|
336
|
+
VALUE name;
|
337
|
+
|
338
|
+
if (singleton_p == Qtrue) {
|
339
|
+
class = 1;
|
340
|
+
km = rb_class_of(obj);
|
341
|
+
} else if (singleton_p == Qfalse) {
|
342
|
+
VALUE c = rb_obj_class(obj);
|
343
|
+
if (c == rb_cClass) {
|
344
|
+
class = 1;
|
345
|
+
} else if (c == rb_cModule) {
|
346
|
+
class = 0;
|
347
|
+
} else {
|
348
|
+
rb_bug("cast_off_get_iseq: should not be reached(0)");
|
349
|
+
}
|
350
|
+
km = obj;
|
351
|
+
} else {
|
352
|
+
rb_bug("cast_off_get_iseq: should not be reached(1)");
|
353
|
+
}
|
354
|
+
|
355
|
+
me = search_method(km, SYM2ID(mid));
|
356
|
+
if (!me) {
|
357
|
+
if (class) {
|
358
|
+
name = rb_class_path(km);
|
359
|
+
} else {
|
360
|
+
name = rb_mod_name(km);
|
361
|
+
}
|
362
|
+
rb_raise(rb_eCastOffCompileError, "method not found (%s#%s)", RSTRING_PTR(name), rb_id2name(SYM2ID(mid)));
|
363
|
+
}
|
364
|
+
|
365
|
+
def = me->def;
|
366
|
+
switch (def->type) {
|
367
|
+
case VM_METHOD_TYPE_ISEQ:
|
368
|
+
return def->body.iseq->self;
|
369
|
+
case VM_METHOD_TYPE_CFUNC:
|
370
|
+
msg = "CastOff cannot compile C method";
|
371
|
+
break;
|
372
|
+
case VM_METHOD_TYPE_ATTRSET:
|
373
|
+
msg = "CastOff cannot compile attr_writer";
|
374
|
+
break;
|
375
|
+
case VM_METHOD_TYPE_IVAR:
|
376
|
+
msg = "CastOff cannot compile attr_reader";
|
377
|
+
break;
|
378
|
+
case VM_METHOD_TYPE_BMETHOD:
|
379
|
+
msg = "Currently, CastOff cannot compile method defined by define_method";
|
380
|
+
break;
|
381
|
+
case VM_METHOD_TYPE_ZSUPER:
|
382
|
+
msg = "Unsupported method type zsuper";
|
383
|
+
break;
|
384
|
+
case VM_METHOD_TYPE_UNDEF:
|
385
|
+
msg = "Unsupported method type undef";
|
386
|
+
break;
|
387
|
+
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
388
|
+
msg = "Unsupported method type notimplemented";
|
389
|
+
break;
|
390
|
+
case VM_METHOD_TYPE_OPTIMIZED:
|
391
|
+
msg = "Unsupported method type optimized";
|
392
|
+
break;
|
393
|
+
case VM_METHOD_TYPE_MISSING:
|
394
|
+
msg = "Unsupported method type missing";
|
395
|
+
break;
|
396
|
+
default:
|
397
|
+
msg = NULL;
|
398
|
+
}
|
399
|
+
|
400
|
+
if (!msg) {
|
401
|
+
rb_bug("cast_off_get_iseq: should not be reached(2)");
|
402
|
+
}
|
403
|
+
|
404
|
+
if (class) {
|
405
|
+
name = rb_class_path(km);
|
406
|
+
} else {
|
407
|
+
name = rb_mod_name(km);
|
408
|
+
}
|
409
|
+
rb_raise(rb_eCastOffUnsupportedError, "%s (%s#%s)", msg, RSTRING_PTR(name), rb_id2name(SYM2ID(mid)));
|
410
|
+
}
|
411
|
+
|
412
|
+
static VALUE cast_off_get_iseq_from_block(VALUE self, VALUE block)
|
413
|
+
{
|
414
|
+
rb_iseq_t *iseq;
|
415
|
+
rb_proc_t *proc;
|
416
|
+
|
417
|
+
if (rb_obj_class(block) != rb_cProc) {
|
418
|
+
rb_raise(rb_eCastOffCompileError, "Invalid argument");
|
419
|
+
}
|
420
|
+
|
421
|
+
GetProcPtr(block, proc);
|
422
|
+
iseq = proc->block.iseq;
|
423
|
+
|
424
|
+
if (!iseq) {
|
425
|
+
rb_raise(rb_eCastOffCompileError, "invalid block given");
|
426
|
+
}
|
427
|
+
|
428
|
+
return iseq->self;
|
429
|
+
}
|
430
|
+
|
431
|
+
static VALUE cast_off_get_caller(VALUE self)
|
432
|
+
{
|
433
|
+
VALUE thval = rb_thread_current();
|
434
|
+
rb_thread_t *th;
|
435
|
+
rb_control_frame_t *cfp;
|
436
|
+
|
437
|
+
th = DATA_PTR(thval);
|
438
|
+
cfp = th->cfp;
|
439
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
440
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
441
|
+
|
442
|
+
return cfp->self;
|
443
|
+
}
|
444
|
+
|
445
|
+
RUBY_EXTERN void* dln_load(const char *file);
|
446
|
+
static VALUE cast_off_load_compiled_file(VALUE self, VALUE file)
|
447
|
+
{
|
448
|
+
if (rb_obj_class(file) != rb_cString) {
|
449
|
+
rb_funcall(self, rb_intern("bug"), 1, rb_str_new2("load_compiled_file: invalid argument"));
|
450
|
+
}
|
451
|
+
dln_load(RSTRING_PTR(file));
|
452
|
+
|
453
|
+
return Qnil;
|
454
|
+
}
|
455
|
+
|
456
|
+
typedef struct class_wrapper_struct {
|
457
|
+
VALUE klass;
|
458
|
+
VALUE obj;
|
459
|
+
int wrap;
|
460
|
+
} class_wrapper_t;
|
461
|
+
|
462
|
+
static void cast_off_class_wrapper_mark(void *ptr)
|
463
|
+
{
|
464
|
+
class_wrapper_t *wrapper = ptr;
|
465
|
+
if (!wrapper) return;
|
466
|
+
rb_gc_mark(wrapper->klass);
|
467
|
+
rb_gc_mark(wrapper->obj);
|
468
|
+
}
|
469
|
+
|
470
|
+
static void cast_off_class_wrapper_free(void *wrapper)
|
471
|
+
{
|
472
|
+
if (wrapper) xfree(wrapper);
|
473
|
+
}
|
474
|
+
|
475
|
+
static size_t cast_off_class_wrapper_memsize(const void *wrapper)
|
476
|
+
{
|
477
|
+
return wrapper ? sizeof(class_wrapper_t) : 0;
|
478
|
+
}
|
479
|
+
|
480
|
+
static const rb_data_type_t cast_off_class_wrapper_data_type = {
|
481
|
+
"cast_off_class_wrapper",
|
482
|
+
{cast_off_class_wrapper_mark, cast_off_class_wrapper_free, cast_off_class_wrapper_memsize},
|
483
|
+
};
|
484
|
+
|
485
|
+
static VALUE cast_off_allocate_class_wrapper(VALUE klass)
|
486
|
+
{
|
487
|
+
VALUE obj;
|
488
|
+
class_wrapper_t *wrapper;
|
489
|
+
|
490
|
+
obj = TypedData_Make_Struct(klass, class_wrapper_t, &cast_off_class_wrapper_data_type, wrapper);
|
491
|
+
wrapper->klass = Qnil;
|
492
|
+
wrapper->obj = Qnil;
|
493
|
+
|
494
|
+
return obj;
|
495
|
+
}
|
496
|
+
|
497
|
+
static VALUE cast_off_initialize_class_wrapper(VALUE self, VALUE obj, VALUE is_wrap)
|
498
|
+
{
|
499
|
+
int wrap;
|
500
|
+
class_wrapper_t *wrapper = DATA_PTR(self);
|
501
|
+
|
502
|
+
switch(is_wrap) {
|
503
|
+
case Qtrue:
|
504
|
+
wrap = 1;
|
505
|
+
break;
|
506
|
+
case Qfalse:
|
507
|
+
wrap = 0;
|
508
|
+
break;
|
509
|
+
default:
|
510
|
+
rb_bug("ClassWrapper#initialize: should not be reached");
|
511
|
+
}
|
512
|
+
|
513
|
+
if (wrap) {
|
514
|
+
wrapper->klass = obj;
|
515
|
+
} else {
|
516
|
+
wrapper->klass = rb_class_of(obj);
|
517
|
+
wrapper->obj = obj;
|
518
|
+
}
|
519
|
+
wrapper->wrap = wrap;
|
520
|
+
|
521
|
+
return self;
|
522
|
+
}
|
523
|
+
|
524
|
+
static VALUE cast_off_class_wrapper_eq(VALUE self, VALUE obj)
|
525
|
+
{
|
526
|
+
if (rb_class_of(obj) == rb_cCastOffClassWrapper) {
|
527
|
+
class_wrapper_t *wrapper0 = DATA_PTR(self);
|
528
|
+
class_wrapper_t *wrapper1 = DATA_PTR(obj);
|
529
|
+
if (wrapper0->klass == wrapper1->klass) {
|
530
|
+
return Qtrue;
|
531
|
+
} else {
|
532
|
+
return Qfalse;
|
533
|
+
}
|
534
|
+
} else {
|
535
|
+
if (rb_class_of(obj) == rb_cCastOffModuleWrapper) {
|
536
|
+
return Qfalse;
|
537
|
+
}
|
538
|
+
rb_bug("ClassWrapper#eq: should not be reached");
|
539
|
+
}
|
540
|
+
}
|
541
|
+
|
542
|
+
static class_wrapper_t *cast_off_class_wrapper_get_wrapper(VALUE self)
|
543
|
+
{
|
544
|
+
class_wrapper_t *wrapper;
|
545
|
+
VALUE klass;
|
546
|
+
|
547
|
+
if (rb_class_of(self) != rb_cCastOffClassWrapper) {
|
548
|
+
rb_bug("should not be reached");
|
549
|
+
}
|
550
|
+
|
551
|
+
wrapper = DATA_PTR(self);
|
552
|
+
klass = wrapper->klass;
|
553
|
+
if (klass == Qnil) {
|
554
|
+
rb_bug("should not be reached");
|
555
|
+
}
|
556
|
+
|
557
|
+
return wrapper;
|
558
|
+
}
|
559
|
+
|
560
|
+
static VALUE cast_off_class_wrapper_get_class(VALUE self)
|
561
|
+
{
|
562
|
+
class_wrapper_t *wrapper;
|
563
|
+
VALUE klass;
|
564
|
+
|
565
|
+
if (rb_class_of(self) != rb_cCastOffClassWrapper) {
|
566
|
+
rb_bug("should not be reached");
|
567
|
+
}
|
568
|
+
|
569
|
+
wrapper = DATA_PTR(self);
|
570
|
+
klass = wrapper->klass;
|
571
|
+
if (klass == Qnil) {
|
572
|
+
rb_bug("should not be reached");
|
573
|
+
}
|
574
|
+
|
575
|
+
return klass;
|
576
|
+
}
|
577
|
+
|
578
|
+
static VALUE cast_off_class_wrapper_hash(VALUE self)
|
579
|
+
{
|
580
|
+
VALUE klass = cast_off_class_wrapper_get_class(self);
|
581
|
+
return rb_funcall(klass, rb_intern("hash"), 0);
|
582
|
+
}
|
583
|
+
|
584
|
+
static VALUE cast_off_class_wrapper_singleton_p(VALUE self)
|
585
|
+
{
|
586
|
+
class_wrapper_t *wrapper = cast_off_class_wrapper_get_wrapper(self);
|
587
|
+
VALUE klass = wrapper->klass;
|
588
|
+
VALUE obj = wrapper->obj;
|
589
|
+
|
590
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
591
|
+
VALUE __klass = rb_obj_class(obj);
|
592
|
+
if (__klass == rb_cClass) {
|
593
|
+
return Qtrue;
|
594
|
+
} else if (__klass == rb_cModule) {
|
595
|
+
return Qtrue;
|
596
|
+
} else {
|
597
|
+
rb_raise(rb_eCastOffCompileError, "CastOff can't handle singleton object without Class and Module");
|
598
|
+
}
|
599
|
+
} else {
|
600
|
+
return Qfalse;
|
601
|
+
}
|
602
|
+
}
|
603
|
+
|
604
|
+
static VALUE cast_off_class_wrapper_to_s(VALUE self)
|
605
|
+
{
|
606
|
+
class_wrapper_t *wrapper = cast_off_class_wrapper_get_wrapper(self);
|
607
|
+
VALUE klass = wrapper->klass;
|
608
|
+
VALUE obj = wrapper->obj;
|
609
|
+
|
610
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
611
|
+
VALUE __klass = rb_obj_class(obj);
|
612
|
+
if (__klass == rb_cClass) {
|
613
|
+
return rb_class_path(obj);
|
614
|
+
} else if (__klass == rb_cModule) {
|
615
|
+
return rb_mod_name(obj);
|
616
|
+
} else {
|
617
|
+
rb_raise(rb_eCastOffCompileError, "CastOff can't handle singleton object without Class and Module");
|
618
|
+
}
|
619
|
+
} else {
|
620
|
+
return rb_class_path(klass);
|
621
|
+
}
|
622
|
+
}
|
623
|
+
|
624
|
+
static VALUE cast_off_class_wrapper_marshal_dump(VALUE self)
|
625
|
+
{
|
626
|
+
class_wrapper_t *wrapper = cast_off_class_wrapper_get_wrapper(self);
|
627
|
+
VALUE ary = rb_ary_new();
|
628
|
+
|
629
|
+
if (wrapper->wrap) {
|
630
|
+
rb_ary_push(ary, rb_class_path(wrapper->klass));
|
631
|
+
rb_ary_push(ary, Qtrue);
|
632
|
+
} else {
|
633
|
+
rb_ary_push(ary, wrapper->obj);
|
634
|
+
rb_ary_push(ary, Qfalse);
|
635
|
+
}
|
636
|
+
|
637
|
+
return ary;
|
638
|
+
}
|
639
|
+
|
640
|
+
static VALUE cast_off_class_wrapper_marshal_load(VALUE self, VALUE ary)
|
641
|
+
{
|
642
|
+
VALUE obj = rb_ary_shift(ary);
|
643
|
+
VALUE is_wrap = rb_ary_shift(ary);
|
644
|
+
|
645
|
+
if (is_wrap == Qtrue) {
|
646
|
+
obj = rb_path_to_class(obj);
|
647
|
+
}
|
648
|
+
|
649
|
+
return cast_off_initialize_class_wrapper(self, obj, is_wrap);
|
650
|
+
}
|
651
|
+
|
652
|
+
static VALUE cast_off_class_wrapper_get_cfunc_argc(VALUE self, VALUE mid)
|
653
|
+
{
|
654
|
+
VALUE klass = cast_off_class_wrapper_get_class(self);
|
655
|
+
rb_method_entry_t *me = search_method(klass, SYM2ID(mid));
|
656
|
+
rb_method_definition_t *def;
|
657
|
+
|
658
|
+
if (!me) {
|
659
|
+
return Qfalse;
|
660
|
+
}
|
661
|
+
def = me->def;
|
662
|
+
switch (def->type) {
|
663
|
+
case VM_METHOD_TYPE_CFUNC:
|
664
|
+
return INT2FIX(def->body.cfunc.argc);
|
665
|
+
default:
|
666
|
+
/* nothing to do */
|
667
|
+
return Qfalse;
|
668
|
+
}
|
669
|
+
}
|
670
|
+
|
671
|
+
static VALUE cast_off_class_wrapper_get_method_type(VALUE self, VALUE mid)
|
672
|
+
{
|
673
|
+
VALUE klass = cast_off_class_wrapper_get_class(self);
|
674
|
+
rb_method_entry_t *me = search_method(klass, SYM2ID(mid));
|
675
|
+
rb_method_definition_t *def;
|
676
|
+
|
677
|
+
if (!me) {
|
678
|
+
return Qfalse;
|
679
|
+
}
|
680
|
+
def = me->def;
|
681
|
+
switch (def->type) {
|
682
|
+
case VM_METHOD_TYPE_CFUNC:
|
683
|
+
return ID2SYM(rb_intern("cfunc"));
|
684
|
+
case VM_METHOD_TYPE_ATTRSET:
|
685
|
+
return ID2SYM(rb_intern("attrset"));
|
686
|
+
case VM_METHOD_TYPE_IVAR:
|
687
|
+
return ID2SYM(rb_intern("ivar"));
|
688
|
+
default:
|
689
|
+
/* nothing to do */
|
690
|
+
return Qfalse;
|
691
|
+
}
|
692
|
+
}
|
693
|
+
|
694
|
+
static VALUE cast_off_class_wrapper_get_attr_id(VALUE self, VALUE mid)
|
695
|
+
{
|
696
|
+
VALUE klass = cast_off_class_wrapper_get_class(self);
|
697
|
+
rb_method_entry_t *me = search_method(klass, SYM2ID(mid));
|
698
|
+
rb_method_definition_t *def;
|
699
|
+
|
700
|
+
if (!me) {
|
701
|
+
return Qfalse;
|
702
|
+
}
|
703
|
+
def = me->def;
|
704
|
+
switch (def->type) {
|
705
|
+
case VM_METHOD_TYPE_IVAR:
|
706
|
+
case VM_METHOD_TYPE_ATTRSET:
|
707
|
+
return ID2SYM(me->def->body.attr.id);
|
708
|
+
default:
|
709
|
+
/* nothing to do */
|
710
|
+
return Qfalse;
|
711
|
+
}
|
712
|
+
}
|
713
|
+
|
714
|
+
static VALUE cast_off_class_wrapper_instance_method_exist_p(VALUE self, VALUE mid)
|
715
|
+
{
|
716
|
+
VALUE klass = cast_off_class_wrapper_get_class(self);
|
717
|
+
rb_method_entry_t *me = search_method(klass, SYM2ID(mid));
|
718
|
+
|
719
|
+
if (me) {
|
720
|
+
return Qtrue;
|
721
|
+
} else {
|
722
|
+
return Qfalse;
|
723
|
+
}
|
724
|
+
}
|
725
|
+
|
726
|
+
static VALUE cast_off_class_wrapper_contain_class(VALUE self)
|
727
|
+
{
|
728
|
+
class_wrapper_t *wrapper = cast_off_class_wrapper_get_wrapper(self);
|
729
|
+
VALUE klass = wrapper->klass;
|
730
|
+
|
731
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
732
|
+
rb_bug("should not be reached");
|
733
|
+
} else {
|
734
|
+
return klass;
|
735
|
+
}
|
736
|
+
}
|
737
|
+
|
738
|
+
static VALUE cast_off_class_wrapper_contain_object(VALUE self)
|
739
|
+
{
|
740
|
+
class_wrapper_t *wrapper = cast_off_class_wrapper_get_wrapper(self);
|
741
|
+
VALUE klass = wrapper->klass;
|
742
|
+
|
743
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
744
|
+
return wrapper->obj;
|
745
|
+
} else {
|
746
|
+
rb_bug("should not be reached");
|
747
|
+
}
|
748
|
+
}
|
749
|
+
|
750
|
+
#define define_type_checker(klass) \
|
751
|
+
static VALUE cast_off_class_wrapper_##klass##_p(VALUE self) \
|
752
|
+
{ \
|
753
|
+
VALUE klass = cast_off_class_wrapper_get_class(self); \
|
754
|
+
if (klass == rb_c##klass) { \
|
755
|
+
return Qtrue; \
|
756
|
+
} else { \
|
757
|
+
return Qfalse; \
|
758
|
+
} \
|
759
|
+
}
|
760
|
+
|
761
|
+
define_type_checker(String)
|
762
|
+
define_type_checker(Array)
|
763
|
+
define_type_checker(Fixnum)
|
764
|
+
define_type_checker(Float)
|
765
|
+
|
766
|
+
typedef struct module_wrapper_struct {
|
767
|
+
VALUE module;
|
768
|
+
} module_wrapper_t;
|
769
|
+
|
770
|
+
static void cast_off_module_wrapper_mark(void *ptr)
|
771
|
+
{
|
772
|
+
module_wrapper_t *wrapper = ptr;
|
773
|
+
if (!wrapper) return;
|
774
|
+
rb_gc_mark(wrapper->module);
|
775
|
+
}
|
776
|
+
|
777
|
+
static void cast_off_module_wrapper_free(void *wrapper)
|
778
|
+
{
|
779
|
+
if (wrapper) xfree(wrapper);
|
780
|
+
}
|
781
|
+
|
782
|
+
static size_t cast_off_module_wrapper_memsize(const void *wrapper)
|
783
|
+
{
|
784
|
+
return wrapper ? sizeof(module_wrapper_t) : 0;
|
785
|
+
}
|
786
|
+
|
787
|
+
static const rb_data_type_t cast_off_module_wrapper_data_type = {
|
788
|
+
"cast_off_module_wrapper",
|
789
|
+
{cast_off_module_wrapper_mark, cast_off_module_wrapper_free, cast_off_module_wrapper_memsize},
|
790
|
+
};
|
791
|
+
|
792
|
+
static VALUE cast_off_allocate_module_wrapper(VALUE klass)
|
793
|
+
{
|
794
|
+
VALUE obj;
|
795
|
+
module_wrapper_t *wrapper;
|
796
|
+
|
797
|
+
obj = TypedData_Make_Struct(klass, module_wrapper_t, &cast_off_module_wrapper_data_type, wrapper);
|
798
|
+
wrapper->module = Qnil;
|
799
|
+
|
800
|
+
return obj;
|
801
|
+
}
|
802
|
+
|
803
|
+
static VALUE cast_off_initialize_module_wrapper(VALUE self, VALUE module)
|
804
|
+
{
|
805
|
+
module_wrapper_t *wrapper = DATA_PTR(self);
|
806
|
+
|
807
|
+
if (rb_obj_class(module) != rb_cModule) {
|
808
|
+
rb_bug("should not be reached");
|
809
|
+
}
|
810
|
+
|
811
|
+
wrapper->module = module;
|
812
|
+
|
813
|
+
return self;
|
814
|
+
}
|
815
|
+
|
816
|
+
static VALUE cast_off_module_wrapper_get_module(VALUE self)
|
817
|
+
{
|
818
|
+
module_wrapper_t *wrapper;
|
819
|
+
VALUE module;
|
820
|
+
|
821
|
+
if (rb_class_of(self) != rb_cCastOffModuleWrapper) {
|
822
|
+
rb_bug("cast_off_module_wrapper_get_module: should not be reached(0)");
|
823
|
+
}
|
824
|
+
|
825
|
+
wrapper = DATA_PTR(self);
|
826
|
+
module = wrapper->module;
|
827
|
+
if (module == Qnil) {
|
828
|
+
rb_bug("cast_off_module_wrapper_get_module: should not be reached(1)");
|
829
|
+
}
|
830
|
+
|
831
|
+
return module;
|
832
|
+
}
|
833
|
+
|
834
|
+
static VALUE cast_off_module_wrapper_marshal_dump(VALUE self)
|
835
|
+
{
|
836
|
+
VALUE module = cast_off_module_wrapper_get_module(self);
|
837
|
+
VALUE name = rb_mod_name(module);
|
838
|
+
|
839
|
+
/* TODO error handling */
|
840
|
+
return name;
|
841
|
+
}
|
842
|
+
|
843
|
+
static VALUE cast_off_module_wrapper_marshal_load(VALUE self, VALUE name)
|
844
|
+
{
|
845
|
+
VALUE module = rb_path_to_class(name);
|
846
|
+
|
847
|
+
if (rb_obj_class(module) != rb_cModule) {
|
848
|
+
rb_raise(rb_eCastOffCompileError, "failed to load module");
|
849
|
+
}
|
850
|
+
|
851
|
+
return cast_off_initialize_module_wrapper(self, module);
|
852
|
+
}
|
853
|
+
|
854
|
+
static VALUE cast_off_module_wrapper_hash(VALUE self)
|
855
|
+
{
|
856
|
+
VALUE module = cast_off_module_wrapper_get_module(self);
|
857
|
+
return rb_funcall(module, rb_intern("hash"), 0);
|
858
|
+
}
|
859
|
+
|
860
|
+
static VALUE cast_off_module_wrapper_eq(VALUE self, VALUE obj)
|
861
|
+
{
|
862
|
+
if (rb_class_of(obj) == rb_cCastOffModuleWrapper) {
|
863
|
+
VALUE m0 = cast_off_module_wrapper_get_module(self);
|
864
|
+
VALUE m1 = cast_off_module_wrapper_get_module(obj);
|
865
|
+
|
866
|
+
return (m0 == m1) ? Qtrue : Qfalse;
|
867
|
+
} else {
|
868
|
+
if (rb_class_of(obj) == rb_cCastOffClassWrapper) {
|
869
|
+
return Qfalse;
|
870
|
+
}
|
871
|
+
rb_bug("ModuleWrapper#eq: should not be reached");
|
872
|
+
}
|
873
|
+
}
|
874
|
+
|
875
|
+
static VALUE cast_off_module_wrapper_to_s(VALUE self)
|
876
|
+
{
|
877
|
+
VALUE module = cast_off_module_wrapper_get_module(self);
|
878
|
+
return rb_mod_name(module);
|
879
|
+
}
|
880
|
+
|
881
|
+
static VALUE cast_off_module_wrapper_contain_module(VALUE self)
|
882
|
+
{
|
883
|
+
return cast_off_module_wrapper_get_module(self);
|
884
|
+
}
|
885
|
+
|
886
|
+
typedef struct method_wrapper_struct {
|
887
|
+
VALUE class_or_module;
|
888
|
+
VALUE class_or_module_wrapper;
|
889
|
+
ID mid;
|
890
|
+
} method_wrapper_t;
|
891
|
+
|
892
|
+
static void cast_off_method_wrapper_mark(void *ptr)
|
893
|
+
{
|
894
|
+
method_wrapper_t *wrapper = ptr;
|
895
|
+
if (!wrapper) return;
|
896
|
+
rb_gc_mark(wrapper->class_or_module);
|
897
|
+
rb_gc_mark(wrapper->class_or_module_wrapper);
|
898
|
+
|
899
|
+
return;
|
900
|
+
}
|
901
|
+
|
902
|
+
static void cast_off_method_wrapper_free(void *wrapper)
|
903
|
+
{
|
904
|
+
if (wrapper) xfree(wrapper);
|
905
|
+
}
|
906
|
+
|
907
|
+
static size_t cast_off_method_wrapper_memsize(const void *wrapper)
|
908
|
+
{
|
909
|
+
return wrapper ? sizeof(method_wrapper_t) : 0;
|
910
|
+
}
|
911
|
+
|
912
|
+
static const rb_data_type_t cast_off_method_wrapper_data_type = {
|
913
|
+
"cast_off_method_wrapper",
|
914
|
+
{cast_off_method_wrapper_mark, cast_off_method_wrapper_free, cast_off_method_wrapper_memsize},
|
915
|
+
};
|
916
|
+
|
917
|
+
static VALUE cast_off_allocate_method_wrapper(VALUE klass)
|
918
|
+
{
|
919
|
+
VALUE obj;
|
920
|
+
method_wrapper_t *wrapper;
|
921
|
+
|
922
|
+
obj = TypedData_Make_Struct(klass, method_wrapper_t, &cast_off_method_wrapper_data_type, wrapper);
|
923
|
+
wrapper->class_or_module = Qnil;
|
924
|
+
wrapper->mid = 0;
|
925
|
+
|
926
|
+
return obj;
|
927
|
+
}
|
928
|
+
|
929
|
+
static VALUE cast_off_initialize_method_wrapper(VALUE self, VALUE cm, VALUE mid_sym)
|
930
|
+
{
|
931
|
+
method_wrapper_t *wrapper = DATA_PTR(self);
|
932
|
+
VALUE klass, class_or_module;
|
933
|
+
ID mid;
|
934
|
+
rb_method_entry_t *me;
|
935
|
+
|
936
|
+
if (rb_class_of(mid_sym) != rb_cSymbol) {
|
937
|
+
rb_bug("cast_off_initialize_method_wrapper: should not be reached(0)");
|
938
|
+
}
|
939
|
+
klass = rb_class_of(cm);
|
940
|
+
if (klass == rb_cCastOffClassWrapper) {
|
941
|
+
class_or_module = cast_off_class_wrapper_get_class(cm);
|
942
|
+
} else if (klass == rb_cCastOffModuleWrapper) {
|
943
|
+
class_or_module = cast_off_module_wrapper_get_module(cm);
|
944
|
+
} else {
|
945
|
+
rb_bug("cast_off_initialize_method_wrapper: should not be reached(1)");
|
946
|
+
}
|
947
|
+
|
948
|
+
mid = SYM2ID(mid_sym);
|
949
|
+
me = search_method(class_or_module, mid);
|
950
|
+
if (!me) {
|
951
|
+
/* FIXME consider method missing */
|
952
|
+
VALUE path = rb_class_path(class_or_module);
|
953
|
+
rb_raise(rb_eCastOffCompileError, "No such method (%s#%s)", RSTRING_PTR(path), rb_id2name(mid));
|
954
|
+
}
|
955
|
+
wrapper->class_or_module = class_or_module;
|
956
|
+
wrapper->class_or_module_wrapper = cm;
|
957
|
+
wrapper->mid = mid;
|
958
|
+
|
959
|
+
return self;
|
960
|
+
}
|
961
|
+
|
962
|
+
static VALUE cast_off_method_wrapper_eq(VALUE self, VALUE obj)
|
963
|
+
{
|
964
|
+
rb_method_entry_t *me0, *me1;
|
965
|
+
if (rb_class_of(obj) == rb_cCastOffMethodWrapper) {
|
966
|
+
method_wrapper_t *wrapper0 = DATA_PTR(self);
|
967
|
+
method_wrapper_t *wrapper1 = DATA_PTR(obj);
|
968
|
+
me0 = search_method(wrapper0->class_or_module, wrapper0->mid);
|
969
|
+
me1 = search_method(wrapper1->class_or_module, wrapper1->mid);
|
970
|
+
if (!me0 || !me1) {
|
971
|
+
rb_raise(rb_eCastOffCompileError, "Failed to find method definition");
|
972
|
+
}
|
973
|
+
if (rb_method_entry_eq(me0, me1)) {
|
974
|
+
return Qtrue;
|
975
|
+
} else {
|
976
|
+
return Qfalse;
|
977
|
+
}
|
978
|
+
} else {
|
979
|
+
rb_bug("should not be reached");
|
980
|
+
}
|
981
|
+
}
|
982
|
+
|
983
|
+
static VALUE cast_off_method_wrapper_hash(VALUE self)
|
984
|
+
{
|
985
|
+
/* always collision between MethodWrapper instance */
|
986
|
+
return INT2FIX(0);
|
987
|
+
}
|
988
|
+
|
989
|
+
static VALUE cast_off_method_wrapper_marshal_dump(VALUE self)
|
990
|
+
{
|
991
|
+
method_wrapper_t *wrapper = DATA_PTR(self);
|
992
|
+
VALUE ary = rb_ary_new();
|
993
|
+
|
994
|
+
rb_ary_push(ary, wrapper->class_or_module_wrapper);
|
995
|
+
rb_ary_push(ary, ID2SYM(wrapper->mid));
|
996
|
+
|
997
|
+
return ary;
|
998
|
+
}
|
999
|
+
|
1000
|
+
static VALUE cast_off_method_wrapper_marshal_load(VALUE self, VALUE ary)
|
1001
|
+
{
|
1002
|
+
VALUE cm = rb_ary_shift(ary);
|
1003
|
+
VALUE mid = rb_ary_shift(ary);
|
1004
|
+
VALUE k = rb_class_of(cm);
|
1005
|
+
|
1006
|
+
if (k != rb_cCastOffClassWrapper && k != rb_cCastOffModuleWrapper) {
|
1007
|
+
VALUE nam = rb_class_path(k);
|
1008
|
+
rb_bug("cast_off_method_wrapper_marshal_load: should not be reached(0)");
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
if(TYPE(mid) != T_SYMBOL) {
|
1012
|
+
rb_bug("cast_off_method_wrapper_marshal_load: should not be reached(1)");
|
1013
|
+
}
|
1014
|
+
|
1015
|
+
return cast_off_initialize_method_wrapper(self, cm, mid);
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
static VALUE cast_off_destroy_last_finish(VALUE self)
|
1019
|
+
{
|
1020
|
+
VALUE thval = rb_thread_current();
|
1021
|
+
rb_thread_t *th = DATA_PTR(thval);
|
1022
|
+
rb_control_frame_t *cfp = th->cfp;
|
1023
|
+
VALUE *leave_ptr = NULL;
|
1024
|
+
unsigned long idx;
|
1025
|
+
|
1026
|
+
while(VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_METHOD) {
|
1027
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1028
|
+
}
|
1029
|
+
/* cfp = CastOff::Compiler.vm_exec frame */
|
1030
|
+
idx = 0;
|
1031
|
+
while(idx < cfp->iseq->iseq_size) {
|
1032
|
+
if (cfp->iseq->iseq[idx] == BIN(leave)) {
|
1033
|
+
leave_ptr = cfp->iseq->iseq_encoded + idx;
|
1034
|
+
break;
|
1035
|
+
} else {
|
1036
|
+
idx++;
|
1037
|
+
}
|
1038
|
+
}
|
1039
|
+
if (!leave_ptr) rb_bug("should not be reached (0)");
|
1040
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1041
|
+
if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) {
|
1042
|
+
rb_bug("should not be reached (1)");
|
1043
|
+
}
|
1044
|
+
cfp->pc = leave_ptr;
|
1045
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1046
|
+
/* cfp = deoptimization target frame */
|
1047
|
+
cfp->sp--;
|
1048
|
+
return cfp->sp[0];
|
1049
|
+
}
|
1050
|
+
|
1051
|
+
static VALUE cast_off_should_not_be_reached(VALUE self)
|
1052
|
+
{
|
1053
|
+
rb_bug("should not be reached");
|
1054
|
+
}
|
1055
|
+
|
1056
|
+
static void cast_off_class_definition_end_handler(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
|
1057
|
+
{
|
1058
|
+
/* self = target class */
|
1059
|
+
/* id = klass = 0 */
|
1060
|
+
|
1061
|
+
static VALUE args = Qnil;
|
1062
|
+
|
1063
|
+
if (args == Qnil) {
|
1064
|
+
args = rb_ary_new();
|
1065
|
+
rb_gc_register_mark_object(args);
|
1066
|
+
}
|
1067
|
+
|
1068
|
+
rb_proc_call(proc, args);
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
static VALUE cast_off_hook_class_definition_end(VALUE self, VALUE proc)
|
1072
|
+
{
|
1073
|
+
static int hook = 0;
|
1074
|
+
|
1075
|
+
if (proc == Qnil) {
|
1076
|
+
if (!hook) {
|
1077
|
+
return Qfalse;
|
1078
|
+
}
|
1079
|
+
hook = 0;
|
1080
|
+
rb_remove_event_hook(&cast_off_class_definition_end_handler);
|
1081
|
+
return Qtrue;
|
1082
|
+
}
|
1083
|
+
|
1084
|
+
if (hook) {
|
1085
|
+
return Qfalse;
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
if (rb_class_of(proc) != rb_cProc) {
|
1089
|
+
rb_bug("cast_off_hook_class_definition_end: should not be reached(0)");
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
rb_add_event_hook(&cast_off_class_definition_end_handler, RUBY_EVENT_END, proc);
|
1093
|
+
hook = 1;
|
1094
|
+
|
1095
|
+
return Qtrue;
|
1096
|
+
}
|
1097
|
+
|
1098
|
+
#define IN_HEAP_P(th, ptr) \
|
1099
|
+
(!((th)->stack < (ptr) && (ptr) < ((th)->stack + (th)->stack_size)))
|
1100
|
+
|
1101
|
+
static VALUE caller_info(rb_thread_t *th)
|
1102
|
+
{
|
1103
|
+
rb_control_frame_t *cfp;
|
1104
|
+
VALUE *lfp = NULL;
|
1105
|
+
VALUE recv, name;
|
1106
|
+
VALUE klass;
|
1107
|
+
ID mid;
|
1108
|
+
rb_method_entry_t *me;
|
1109
|
+
|
1110
|
+
cfp = th->cfp; /* this method frame */
|
1111
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1112
|
+
while (1) {
|
1113
|
+
if ((VALUE *) cfp >= th->stack + th->stack_size) {
|
1114
|
+
if (lfp && IN_HEAP_P(th, lfp)) {
|
1115
|
+
return Qnil;
|
1116
|
+
}
|
1117
|
+
rb_bug("caller_info: should not be reached (0) %p", cfp->lfp);
|
1118
|
+
}
|
1119
|
+
if (lfp && cfp->dfp != lfp) {
|
1120
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1121
|
+
continue;
|
1122
|
+
}
|
1123
|
+
lfp = NULL;
|
1124
|
+
switch(VM_FRAME_TYPE(cfp)) {
|
1125
|
+
case VM_FRAME_MAGIC_METHOD:
|
1126
|
+
recv = cfp->self;
|
1127
|
+
name = cfp->iseq->name;
|
1128
|
+
klass = rb_class_of(recv);
|
1129
|
+
mid = rb_intern(RSTRING_PTR(name));
|
1130
|
+
me = search_method(klass, mid);
|
1131
|
+
if (!me) {
|
1132
|
+
rb_bug("caller_info: should not be reached (1)");
|
1133
|
+
}
|
1134
|
+
klass = me->klass;
|
1135
|
+
return rb_ary_new3(2, klass, ID2SYM(mid));
|
1136
|
+
case VM_FRAME_MAGIC_BLOCK:
|
1137
|
+
case VM_FRAME_MAGIC_PROC:
|
1138
|
+
case VM_FRAME_MAGIC_LAMBDA:
|
1139
|
+
lfp = cfp->lfp;
|
1140
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1141
|
+
continue;
|
1142
|
+
case VM_FRAME_MAGIC_FINISH:
|
1143
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1144
|
+
continue;
|
1145
|
+
case VM_FRAME_MAGIC_CLASS:
|
1146
|
+
case VM_FRAME_MAGIC_TOP:
|
1147
|
+
case VM_FRAME_MAGIC_CFUNC:
|
1148
|
+
case VM_FRAME_MAGIC_IFUNC:
|
1149
|
+
case VM_FRAME_MAGIC_EVAL:
|
1150
|
+
return Qnil;
|
1151
|
+
default:
|
1152
|
+
rb_bug("caller_info: should not be reached (2)");
|
1153
|
+
}
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
static void cast_off_method_invocation_handler(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
|
1158
|
+
{
|
1159
|
+
VALUE thval = rb_thread_current();
|
1160
|
+
rb_thread_t *th = DATA_PTR(thval);
|
1161
|
+
const char *srcfile = rb_sourcefile();
|
1162
|
+
VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
|
1163
|
+
VALUE argv[6];
|
1164
|
+
int line = rb_sourceline();
|
1165
|
+
static VALUE ev = 0;
|
1166
|
+
|
1167
|
+
if (!ev) {
|
1168
|
+
ev = rb_str_new2("call");
|
1169
|
+
rb_gc_register_mark_object(ev);
|
1170
|
+
}
|
1171
|
+
|
1172
|
+
if (klass == 0) {
|
1173
|
+
rb_frame_method_id_and_class(&id, &klass);
|
1174
|
+
}
|
1175
|
+
|
1176
|
+
if (id == ID_ALLOCATOR) {
|
1177
|
+
return;
|
1178
|
+
}
|
1179
|
+
|
1180
|
+
if (klass) {
|
1181
|
+
if (TYPE(klass) == T_ICLASS) {
|
1182
|
+
klass = RBASIC(klass)->klass;
|
1183
|
+
} else if (FL_TEST(klass, FL_SINGLETON)) {
|
1184
|
+
klass = rb_iv_get(klass, "__attached__");
|
1185
|
+
}
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
argv[0] = ev;
|
1189
|
+
argv[1] = filename;
|
1190
|
+
argv[2] = INT2FIX(line);
|
1191
|
+
argv[3] = id ? ID2SYM(id) : Qnil;
|
1192
|
+
argv[4] = (self && srcfile) ? rb_binding_new() : Qnil;
|
1193
|
+
argv[5] = klass ? klass : Qnil;
|
1194
|
+
argv[6] = caller_info(th);
|
1195
|
+
|
1196
|
+
return rb_proc_call_with_block(proc, 7, argv, Qnil);
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
static VALUE cast_off_hook_method_invocation(VALUE self, VALUE proc)
|
1200
|
+
{
|
1201
|
+
static int hook = 0;
|
1202
|
+
|
1203
|
+
if (proc == Qnil) {
|
1204
|
+
if (!hook) {
|
1205
|
+
return Qfalse;
|
1206
|
+
}
|
1207
|
+
hook = 0;
|
1208
|
+
rb_remove_event_hook(&cast_off_method_invocation_handler);
|
1209
|
+
return Qtrue;
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
if (hook) {
|
1213
|
+
return Qfalse;
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
if (rb_class_of(proc) != rb_cProc) {
|
1217
|
+
rb_bug("cast_off_hook_method_invocation: should not be reached(0)");
|
1218
|
+
}
|
1219
|
+
|
1220
|
+
rb_add_event_hook(&cast_off_method_invocation_handler, RUBY_EVENT_CALL, proc);
|
1221
|
+
hook = 1;
|
1222
|
+
|
1223
|
+
return Qtrue;
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
static ID id_method_added, id_singleton_method_added, id_initialize_copy, id_clone;
|
1227
|
+
VALUE cast_off_ignore_overridden_p(VALUE dummy, VALUE target, VALUE midsym)
|
1228
|
+
{
|
1229
|
+
VALUE thval = rb_thread_current();
|
1230
|
+
rb_thread_t *th = DATA_PTR(thval);
|
1231
|
+
rb_control_frame_t *cfp;
|
1232
|
+
ID mid;
|
1233
|
+
|
1234
|
+
cfp = th->cfp; /* this method frame */
|
1235
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); /* method_added or singleton_method_added frame */
|
1236
|
+
if (!cfp->me) {
|
1237
|
+
rb_bug("cast_off_ignore_overridden_p: should not be reached(0)");
|
1238
|
+
}
|
1239
|
+
mid = cfp->me->called_id;
|
1240
|
+
if (mid != id_method_added && mid != id_singleton_method_added) {
|
1241
|
+
rb_bug("cast_off_ignore_overridden_p: should not be reached(1)");
|
1242
|
+
}
|
1243
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1244
|
+
if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) {
|
1245
|
+
return Qfalse;
|
1246
|
+
}
|
1247
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
|
1248
|
+
if (VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_CFUNC || !cfp->me) {
|
1249
|
+
return Qfalse;
|
1250
|
+
}
|
1251
|
+
mid = cfp->me->called_id;
|
1252
|
+
if (mid != id_initialize_copy && mid != id_clone) {
|
1253
|
+
return Qfalse;
|
1254
|
+
}
|
1255
|
+
/* ignore when initialize_copy and clone */
|
1256
|
+
return Qtrue;
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
VALUE cast_off_singleton_method_added_p(VALUE dummy)
|
1260
|
+
{
|
1261
|
+
VALUE thval = rb_thread_current();
|
1262
|
+
rb_thread_t *th = DATA_PTR(thval);
|
1263
|
+
rb_control_frame_t *cfp;
|
1264
|
+
ID mid;
|
1265
|
+
|
1266
|
+
cfp = th->cfp; /* this method frame */
|
1267
|
+
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); /* method_added or singleton_method_added frame */
|
1268
|
+
if (!cfp->me) {
|
1269
|
+
rb_bug("cast_off_singleton_method_added_p: should not be reached(0)");
|
1270
|
+
}
|
1271
|
+
mid = cfp->me->called_id;
|
1272
|
+
if (mid == id_method_added) {
|
1273
|
+
return Qfalse;
|
1274
|
+
}
|
1275
|
+
if (mid == id_singleton_method_added) {
|
1276
|
+
return Qtrue;
|
1277
|
+
}
|
1278
|
+
rb_bug("cast_off_singleton_method_added_p: should not be reached(1)");
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
/* for deoptimization */
|
1282
|
+
rb_iseq_t *cast_off_Fixnum_times_iseq;
|
1283
|
+
rb_iseq_t *cast_off_Array_each_iseq;
|
1284
|
+
rb_iseq_t *cast_off_Array_map_iseq;
|
1285
|
+
rb_iseq_t *cast_off_Array_map_bang_iseq;
|
1286
|
+
|
1287
|
+
void Init_cast_off(void)
|
1288
|
+
{
|
1289
|
+
rb_mCastOff = rb_define_module("CastOff");
|
1290
|
+
rb_mCastOffCompiler = rb_define_module_under(rb_mCastOff, "Compiler");
|
1291
|
+
rb_mCastOffCompilerInstruction = rb_define_module_under(rb_mCastOffCompiler, "Instruction");
|
1292
|
+
rb_cCastOffConfiguration = rb_define_class_under(rb_mCastOffCompiler, "Configuration", rb_cObject);
|
1293
|
+
rb_cCastOffDependency = rb_define_class_under(rb_mCastOffCompiler, "Dependency", rb_cObject);
|
1294
|
+
rb_cCastOffInsnInfo = rb_define_class_under(rb_mCastOffCompilerInstruction, "InsnInfo", rb_cObject);
|
1295
|
+
rb_cCastOffClassWrapper = rb_define_class_under(rb_mCastOffCompiler, "ClassWrapper", rb_cObject);
|
1296
|
+
rb_cCastOffModuleWrapper = rb_define_class_under(rb_mCastOffCompiler, "ModuleWrapper", rb_cObject);
|
1297
|
+
rb_cCastOffMethodWrapper = rb_define_class_under(rb_mCastOffCompiler, "MethodWrapper", rb_cObject);
|
1298
|
+
rb_cCastOffSingletonClass = rb_define_class_under(rb_mCastOffCompiler, "SingletonClass", rb_cObject);
|
1299
|
+
|
1300
|
+
rb_eCastOffCompileError = rb_define_class_under(rb_mCastOff, "CompileError", rb_eStandardError);
|
1301
|
+
rb_eCastOffExecutionError = rb_define_class_under(rb_mCastOff, "ExecutionError", rb_eStandardError);
|
1302
|
+
rb_eCastOffLoadError = rb_define_class_under(rb_mCastOff, "LoadError", rb_eStandardError);
|
1303
|
+
rb_eCastOffUnsupportedError = rb_define_class_under(rb_mCastOff, "UnsupportedError", rb_eStandardError);
|
1304
|
+
rb_define_method(rb_mCastOffCompiler, "override_target", cast_off_override_target, 2);
|
1305
|
+
rb_define_method(rb_mCastOffCompiler, "get_iseq", cast_off_get_iseq, 3);
|
1306
|
+
rb_define_method(rb_mCastOffCompiler, "get_iseq_from_block", cast_off_get_iseq_from_block, 1);
|
1307
|
+
rb_define_method(rb_mCastOffCompiler, "load_compiled_file", cast_off_load_compiled_file, 1);
|
1308
|
+
rb_define_method(rb_mCastOffCompiler, "get_caller", cast_off_get_caller, 0);
|
1309
|
+
rb_define_method(rb_mCastOffCompiler, "hook_method_invocation", cast_off_hook_method_invocation, 1);
|
1310
|
+
rb_define_method(rb_mCastOffCompiler, "hook_class_definition_end", cast_off_hook_class_definition_end, 1);
|
1311
|
+
rb_define_method(rb_mCastOffCompilerInstruction, "get_child_iseq", cast_off_get_child_iseq, 2);
|
1312
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "ROBJECT_EMBED_LEN_MAX", LONG2FIX(ROBJECT_EMBED_LEN_MAX));
|
1313
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_RETURN", LONG2FIX(TAG_RETURN));
|
1314
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_BREAK", LONG2FIX(TAG_BREAK));
|
1315
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_NEXT", LONG2FIX(TAG_NEXT));
|
1316
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_RETRY", LONG2FIX(TAG_RETRY));
|
1317
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_REDO", LONG2FIX(TAG_REDO));
|
1318
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_RAISE", LONG2FIX(TAG_RAISE));
|
1319
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_THROW", LONG2FIX(TAG_THROW));
|
1320
|
+
rb_define_const(rb_mCastOffCompilerInstruction, "THROW_TAG_FATAL", LONG2FIX(TAG_FATAL));
|
1321
|
+
rb_define_method(rb_cCastOffInsnInfo, "instruction_pushnum", cast_off_instruction_pushnum, 1);
|
1322
|
+
rb_define_method(rb_cCastOffInsnInfo, "instruction_popnum", cast_off_instruction_popnum, 1);
|
1323
|
+
rb_define_method(rb_cCastOffInsnInfo, "instruction_stack_usage", cast_off_instruction_stack_usage, 1);
|
1324
|
+
rb_define_method(rb_cCastOffInsnInfo, "class_information_in_ic", cast_off_instruction_class_information_in_ic, 1);
|
1325
|
+
|
1326
|
+
rb_define_alloc_func(rb_cCastOffClassWrapper, cast_off_allocate_class_wrapper);
|
1327
|
+
rb_define_method(rb_cCastOffClassWrapper, "initialize", cast_off_initialize_class_wrapper, 2);
|
1328
|
+
rb_define_method(rb_cCastOffClassWrapper, "===", cast_off_class_wrapper_eq, 1);
|
1329
|
+
rb_define_method(rb_cCastOffClassWrapper, "==", cast_off_class_wrapper_eq, 1);
|
1330
|
+
rb_define_method(rb_cCastOffClassWrapper, "eql?", cast_off_class_wrapper_eq, 1);
|
1331
|
+
rb_define_method(rb_cCastOffClassWrapper, "hash", cast_off_class_wrapper_hash, 0);
|
1332
|
+
rb_define_method(rb_cCastOffClassWrapper, "to_s", cast_off_class_wrapper_to_s, 0);
|
1333
|
+
rb_define_method(rb_cCastOffClassWrapper, "marshal_dump", cast_off_class_wrapper_marshal_dump, 0);
|
1334
|
+
rb_define_method(rb_cCastOffClassWrapper, "marshal_load", cast_off_class_wrapper_marshal_load, 1);
|
1335
|
+
rb_define_method(rb_cCastOffClassWrapper, "singleton?", cast_off_class_wrapper_singleton_p, 0);
|
1336
|
+
rb_define_method(rb_cCastOffClassWrapper, "get_cfunc_argc", cast_off_class_wrapper_get_cfunc_argc, 1);
|
1337
|
+
rb_define_method(rb_cCastOffClassWrapper, "get_method_type", cast_off_class_wrapper_get_method_type, 1);
|
1338
|
+
rb_define_method(rb_cCastOffClassWrapper, "get_attr_id", cast_off_class_wrapper_get_attr_id, 1);
|
1339
|
+
rb_define_method(rb_cCastOffClassWrapper, "instance_method_exist?", cast_off_class_wrapper_instance_method_exist_p, 1);
|
1340
|
+
rb_define_method(rb_cCastOffClassWrapper, "contain_class", cast_off_class_wrapper_contain_class, 0);
|
1341
|
+
rb_define_method(rb_cCastOffClassWrapper, "contain_object", cast_off_class_wrapper_contain_object, 0);
|
1342
|
+
//#define register_type_checker(klass) rb_define_method(rb_cCastOffClassWrapper, "##klass##?", cast_off_class_wrapper_##klass##_p, 0)
|
1343
|
+
//register_type_checker(String);
|
1344
|
+
//register_type_checker(Array);
|
1345
|
+
//register_type_checker(Fixnum);
|
1346
|
+
rb_define_method(rb_cCastOffClassWrapper, "String?", cast_off_class_wrapper_String_p, 0);
|
1347
|
+
rb_define_method(rb_cCastOffClassWrapper, "Array?", cast_off_class_wrapper_Array_p, 0);
|
1348
|
+
rb_define_method(rb_cCastOffClassWrapper, "Fixnum?", cast_off_class_wrapper_Fixnum_p, 0);
|
1349
|
+
rb_define_method(rb_cCastOffClassWrapper, "Float?", cast_off_class_wrapper_Float_p, 0);
|
1350
|
+
|
1351
|
+
rb_define_alloc_func(rb_cCastOffModuleWrapper, cast_off_allocate_module_wrapper);
|
1352
|
+
rb_define_method(rb_cCastOffModuleWrapper, "initialize", cast_off_initialize_module_wrapper, 1);
|
1353
|
+
rb_define_method(rb_cCastOffModuleWrapper, "===", cast_off_module_wrapper_eq, 1);
|
1354
|
+
rb_define_method(rb_cCastOffModuleWrapper, "==", cast_off_module_wrapper_eq, 1);
|
1355
|
+
rb_define_method(rb_cCastOffModuleWrapper, "eql?", cast_off_module_wrapper_eq, 1);
|
1356
|
+
rb_define_method(rb_cCastOffModuleWrapper, "hash", cast_off_module_wrapper_hash, 0);
|
1357
|
+
rb_define_method(rb_cCastOffModuleWrapper, "contain_module", cast_off_module_wrapper_contain_module, 0);
|
1358
|
+
rb_define_method(rb_cCastOffModuleWrapper, "to_s", cast_off_module_wrapper_to_s, 0);
|
1359
|
+
rb_define_method(rb_cCastOffModuleWrapper, "marshal_dump", cast_off_module_wrapper_marshal_dump, 0);
|
1360
|
+
rb_define_method(rb_cCastOffModuleWrapper, "marshal_load", cast_off_module_wrapper_marshal_load, 1);
|
1361
|
+
|
1362
|
+
rb_define_alloc_func(rb_cCastOffMethodWrapper, cast_off_allocate_method_wrapper);
|
1363
|
+
rb_define_method(rb_cCastOffMethodWrapper, "initialize", cast_off_initialize_method_wrapper, 2);
|
1364
|
+
rb_define_method(rb_cCastOffMethodWrapper, "===", cast_off_method_wrapper_eq, 1);
|
1365
|
+
rb_define_method(rb_cCastOffMethodWrapper, "==", cast_off_method_wrapper_eq, 1);
|
1366
|
+
rb_define_method(rb_cCastOffMethodWrapper, "eql?", cast_off_method_wrapper_eq, 1);
|
1367
|
+
rb_define_method(rb_cCastOffMethodWrapper, "hash", cast_off_method_wrapper_hash, 0);
|
1368
|
+
rb_define_method(rb_cCastOffMethodWrapper, "marshal_dump", cast_off_method_wrapper_marshal_dump, 0);
|
1369
|
+
rb_define_method(rb_cCastOffMethodWrapper, "marshal_load", cast_off_method_wrapper_marshal_load, 1);
|
1370
|
+
|
1371
|
+
rb_define_const(rb_mCastOffCompiler, "Headers", gen_headers());
|
1372
|
+
rb_define_const(rb_mCastOffCompiler, "DEOPTIMIZATION_ISEQ_TABLE", rb_hash_new());
|
1373
|
+
|
1374
|
+
id_method_added = rb_intern("method_added");
|
1375
|
+
id_singleton_method_added = rb_intern("singleton_method_added");
|
1376
|
+
id_initialize_copy = rb_intern("initialize_copy");
|
1377
|
+
id_clone = rb_intern("clone");
|
1378
|
+
rb_define_singleton_method(rb_cCastOffDependency, "ignore_overridden?", cast_off_ignore_overridden_p, 2);
|
1379
|
+
rb_define_singleton_method(rb_cCastOffDependency, "singleton_method_added?", cast_off_singleton_method_added_p, 0);
|
1380
|
+
|
1381
|
+
rb_define_singleton_method(rb_mCastOffCompiler, "destroy_last_finish", cast_off_destroy_last_finish, 0);
|
1382
|
+
rb_funcall(rb_mCastOffCompiler, rb_intern("module_eval"), 1, rb_str_new2("def self.vm_exec(); destroy_last_finish() end"));
|
1383
|
+
|
1384
|
+
init_insn_table();
|
1385
|
+
}
|
1386
|
+
|