fastruby 0.0.5 → 0.0.6
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/CHANGELOG +2 -0
- data/README +18 -2
- data/Rakefile +1 -1
- data/lib/fastruby/builder.rb +144 -20
- data/lib/fastruby/cache/cache.rb +86 -0
- data/lib/fastruby/custom_require.rb +3 -0
- data/lib/fastruby/exceptions.rb +10 -0
- data/lib/fastruby/fastruby_sexp.rb +25 -0
- data/lib/fastruby/getlocals.rb +2 -2
- data/lib/fastruby/object.rb +57 -268
- data/lib/fastruby/set_tree.rb +61 -0
- data/lib/fastruby/sexp_extension.rb +37 -0
- data/lib/fastruby/translator.rb +748 -287
- data/lib/fastruby.rb +12 -2
- metadata +8 -4
data/CHANGELOG
CHANGED
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Fastruby - fast execution of ruby code
|
2
2
|
|
3
|
-
Fastruby is a gem which allows to execute ruby code faster than normal (about
|
3
|
+
Fastruby is a gem which allows to execute ruby code faster than normal (about 20X of the MRI1.8)
|
4
4
|
|
5
5
|
Fastruby IS NOT a separated ruby interpreter. Then, the design is simple
|
6
6
|
|
@@ -47,6 +47,8 @@ sudo gem install fastruby
|
|
47
47
|
|
48
48
|
== Documentation
|
49
49
|
|
50
|
+
Overhead due new frame structure of reduce the speed to 20x (previously was near 100X). This refactor was necessary
|
51
|
+
to implement most of the common ruby constructions (blocks, yields, breaks, next, exceptions, etc...)
|
50
52
|
Since this first version of fastruby is in part an spike/PoC, there is no stable API to document.
|
51
53
|
So, I recommend not to develop other software on top of fastruby since its API could change in any moment.
|
52
54
|
But I will try as much as possible keep the backward compatibility in the near future
|
@@ -55,13 +57,27 @@ I will stabilize the API and document it for next releases. I promise
|
|
55
57
|
|
56
58
|
== Known Limitations & Issues
|
57
59
|
|
58
|
-
* Bootstrap is very slow since this is a Poc :P
|
59
60
|
* monkey patching does not work with fastruby methods
|
60
61
|
* calls with blocks to ruby or cruby methods are almost as slow as normal ruby (if the called method is defined by fastruby, the call it's pretty fast)
|
61
62
|
* does not support methods with variable number of arguments
|
62
63
|
|
63
64
|
== Usage
|
64
65
|
|
66
|
+
=== Environment variables
|
67
|
+
|
68
|
+
FASTRUBY_LOG define the output file of logging (default is standard output)
|
69
|
+
FASTRUBY_LOG_LEVEL define the logging level (default 3)
|
70
|
+
FASTRUBY_NO_CACHE set to 1 to disable the cache globally
|
71
|
+
|
72
|
+
=== Fastruby options
|
73
|
+
|
74
|
+
This options can be passed to fastruby when defining fastruby blocks
|
75
|
+
|
76
|
+
:no_cache set to true to disable cache (default: false)
|
77
|
+
:validate_lvar_vars enable runtime check of assignments of typed variable (default: disabled)
|
78
|
+
|
79
|
+
== Code Examples
|
80
|
+
|
65
81
|
The basic method is fastruby, fastruby takes a string with ruby code and compile it
|
66
82
|
|
67
83
|
=== Example 1: How invoke fastruby
|
data/Rakefile
CHANGED
data/lib/fastruby/builder.rb
CHANGED
@@ -18,7 +18,6 @@ you should have received a copy of the gnu general public license
|
|
18
18
|
along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
20
|
=end
|
21
|
-
require "fastruby/translator"
|
22
21
|
require "fastruby/inline_extension"
|
23
22
|
require "fastruby/method_extension"
|
24
23
|
require "fastruby/logging"
|
@@ -40,31 +39,80 @@ module FastRuby
|
|
40
39
|
|
41
40
|
context.alt_method_name = "singleton_" + method_name + rand(100000000).to_s
|
42
41
|
|
43
|
-
[context.extra_code + context.to_c_method_defs(tree), context.alt_method_name]
|
42
|
+
[context.extra_code + context.to_c_method_defs(tree), context.alt_method_name, context.init_extra]
|
44
43
|
end
|
45
44
|
|
46
45
|
class Method
|
47
46
|
attr_accessor :tree
|
48
47
|
attr_accessor :locals
|
49
48
|
attr_accessor :options
|
49
|
+
attr_accessor :snippet_hash
|
50
50
|
|
51
51
|
def initialize(method_name, owner)
|
52
52
|
@method_name = method_name
|
53
53
|
@owner = owner
|
54
54
|
end
|
55
55
|
|
56
|
-
def
|
57
|
-
|
56
|
+
def method_from_signature(signature, inference_complete)
|
57
|
+
begin
|
58
|
+
recvtype = @owner
|
59
|
+
if recvtype.respond_to? :fastruby_method and inference_complete
|
60
|
+
|
61
|
+
method_tree = nil
|
62
|
+
begin
|
63
|
+
method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
|
64
|
+
rescue NoMethodError
|
65
|
+
end
|
66
|
+
|
67
|
+
if method_tree
|
68
|
+
recvtype.build(signature, @method_name.to_sym)
|
69
|
+
else
|
70
|
+
recvtype.instance_method(@method_name.to_sym)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
recvtype.instance_method(@method_name.to_sym)
|
74
|
+
end
|
75
|
+
rescue NameError
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def convention(signature, inference_complete)
|
81
|
+
recvtype = @owner
|
82
|
+
if recvtype.respond_to? :fastruby_method and inference_complete
|
83
|
+
|
84
|
+
method_tree = nil
|
85
|
+
begin
|
86
|
+
method_tree = recvtype.instance_method(@method_name.to_sym).fastruby.tree
|
87
|
+
rescue NoMethodError, NameError
|
88
|
+
end
|
89
|
+
|
90
|
+
if method_tree
|
91
|
+
:fastruby
|
92
|
+
else
|
93
|
+
:cruby
|
94
|
+
end
|
95
|
+
else
|
96
|
+
:cruby
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def build(signature, noreturn = false)
|
101
|
+
require "fastruby/translator"
|
102
|
+
require "rubygems"
|
103
|
+
require "inline"
|
58
104
|
|
59
|
-
|
105
|
+
no_cache = false
|
106
|
+
|
107
|
+
mname = FastRuby.make_str_signature(@method_name, signature)
|
60
108
|
|
61
109
|
begin
|
62
110
|
if (@owner.instance_method(mname))
|
63
|
-
FastRuby.logger.info "NOT Building #{
|
111
|
+
FastRuby.logger.info "NOT Building #{@owner}::#{@method_name} for signature #{signature.inspect}, it's already done"
|
64
112
|
return @owner.instance_method(mname)
|
65
113
|
end
|
66
114
|
rescue NameError
|
67
|
-
FastRuby.logger.info "Building #{
|
115
|
+
FastRuby.logger.info "Building #{@owner}::#{@method_name} for signature #{signature.inspect}"
|
68
116
|
end
|
69
117
|
|
70
118
|
context = FastRuby::Context.new
|
@@ -74,7 +122,8 @@ module FastRuby
|
|
74
122
|
args_tree = tree[2]
|
75
123
|
|
76
124
|
# create random method name
|
77
|
-
context.
|
125
|
+
context.snippet_hash = snippet_hash
|
126
|
+
context.alt_method_name = "_" + @method_name.to_s + "_" + rand(10000000000).to_s
|
78
127
|
|
79
128
|
(1..signature.size).each do |i|
|
80
129
|
arg = args_tree[i]
|
@@ -82,24 +131,91 @@ module FastRuby
|
|
82
131
|
end
|
83
132
|
|
84
133
|
context.infer_self = signature[0]
|
85
|
-
|
86
134
|
c_code = context.to_c_method(tree)
|
87
135
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
136
|
+
unless options[:main]
|
137
|
+
context.define_method_at_init(@method_name, args_tree.size+1, signature)
|
138
|
+
end
|
139
|
+
|
140
|
+
so_name = nil
|
141
|
+
|
142
|
+
old_class_self = $class_self
|
143
|
+
$class_self = @owner
|
144
|
+
$last_obj_proc = nil
|
145
|
+
|
146
|
+
begin
|
147
|
+
|
148
|
+
@owner.class_eval do
|
149
|
+
inline :C do |builder|
|
150
|
+
builder.inc << context.extra_code
|
151
|
+
builder.include "<node.h>"
|
152
|
+
builder.init_extra = context.init_extra
|
153
|
+
|
154
|
+
def builder.generate_ext
|
155
|
+
ext = []
|
156
|
+
|
157
|
+
if @include_ruby_first
|
158
|
+
@inc.unshift "#include \"ruby.h\""
|
159
|
+
else
|
160
|
+
@inc.push "#include \"ruby.h\""
|
161
|
+
end
|
162
|
+
|
163
|
+
ext << @inc
|
164
|
+
ext << nil
|
165
|
+
ext << @src.join("\n\n")
|
166
|
+
ext << nil
|
167
|
+
ext << nil
|
168
|
+
ext << "#ifdef __cplusplus"
|
169
|
+
ext << "extern \"C\" {"
|
170
|
+
ext << "#endif"
|
171
|
+
ext << " void Init_#{module_name}() {"
|
172
|
+
|
173
|
+
ext << @init_extra.join("\n") unless @init_extra.empty?
|
174
|
+
|
175
|
+
ext << nil
|
176
|
+
ext << " }"
|
177
|
+
ext << "#ifdef __cplusplus"
|
178
|
+
ext << "}"
|
179
|
+
ext << "#endif"
|
180
|
+
ext << nil
|
181
|
+
|
182
|
+
ext.join "\n"
|
183
|
+
end
|
184
|
+
|
185
|
+
builder.c c_code
|
186
|
+
so_name = builder.so_name
|
187
|
+
end
|
93
188
|
end
|
189
|
+
|
190
|
+
if $last_obj_proc
|
191
|
+
unless options[:no_cache]
|
192
|
+
FastRuby.cache.register_proc(so_name, $last_obj_proc)
|
193
|
+
end
|
194
|
+
$last_obj_proc.call($class_self)
|
195
|
+
end
|
196
|
+
|
197
|
+
ensure
|
198
|
+
$class_self = old_class_self
|
199
|
+
end
|
200
|
+
|
201
|
+
unless no_cache
|
202
|
+
no_cache = context.no_cache
|
94
203
|
end
|
95
204
|
|
96
|
-
|
205
|
+
unless options[:no_cache]
|
206
|
+
FastRuby.cache.insert(snippet_hash, so_name) unless no_cache
|
207
|
+
end
|
97
208
|
|
98
|
-
|
99
|
-
|
209
|
+
if noreturn then
|
210
|
+
nil
|
211
|
+
else
|
212
|
+
ret = @owner.instance_method(mname)
|
100
213
|
|
101
|
-
|
214
|
+
ret.extend MethodExtent
|
215
|
+
ret.yield_signature = context.yield_signature
|
102
216
|
|
217
|
+
ret
|
218
|
+
end
|
103
219
|
end
|
104
220
|
|
105
221
|
module MethodExtent
|
@@ -108,8 +224,16 @@ module FastRuby
|
|
108
224
|
end
|
109
225
|
|
110
226
|
module BuilderModule
|
111
|
-
def build(signature, method_name)
|
112
|
-
fastruby_method(method_name.to_sym).build(signature)
|
227
|
+
def build(signature, method_name, noreturn = false)
|
228
|
+
fastruby_method(method_name.to_sym).build(signature, noreturn)
|
229
|
+
end
|
230
|
+
|
231
|
+
def convention(signature, method_name, inference_complete)
|
232
|
+
fastruby_method(method_name.to_sym).convention(signature, inference_complete)
|
233
|
+
end
|
234
|
+
|
235
|
+
def method_from_signature(signature, method_name, inference_complete)
|
236
|
+
fastruby_method(method_name.to_sym).method_from_signature(signature, inference_complete)
|
113
237
|
end
|
114
238
|
|
115
239
|
def fastruby_method(mname_)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the fastruby project, http://github.com/tario/fastruby
|
4
|
+
|
5
|
+
Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
fastruby is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
fastruby is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "sha1"
|
22
|
+
require "fileutils"
|
23
|
+
|
24
|
+
module FastRuby
|
25
|
+
|
26
|
+
def self.cache
|
27
|
+
@@cache = FastRuby::Cache.new(ENV['HOME']+"/.fastruby/") unless defined? @@cache
|
28
|
+
@@cache
|
29
|
+
end
|
30
|
+
|
31
|
+
class Cache
|
32
|
+
include FileUtils
|
33
|
+
|
34
|
+
def initialize(base_path)
|
35
|
+
@base_path = base_path
|
36
|
+
create_dir_if_not_exists(@base_path)
|
37
|
+
end
|
38
|
+
|
39
|
+
def hash_snippet(snippet, addition)
|
40
|
+
SHA1.hexdigest(snippet + addition)
|
41
|
+
end
|
42
|
+
|
43
|
+
def insert(hash,path)
|
44
|
+
create_hash_dir(hash)
|
45
|
+
dest = hash_dir(hash)
|
46
|
+
cp_r path, dest
|
47
|
+
end
|
48
|
+
|
49
|
+
def retrieve(hash)
|
50
|
+
create_hash_dir(hash)
|
51
|
+
dest = hash_dir(hash)
|
52
|
+
Dir[dest + "*.so"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def register_proc(obj, value)
|
56
|
+
@proc_hash = Hash.new unless @proc_hash
|
57
|
+
@proc_hash[obj] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute(obj, param)
|
61
|
+
@proc_hash = Hash.new unless @proc_hash
|
62
|
+
if @proc_hash[obj]
|
63
|
+
@proc_hash[obj].call(param)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
private
|
67
|
+
|
68
|
+
def hash_dir(hash)
|
69
|
+
@base_path + "/#{hash[0..1]}/#{hash[2..-1]}/"
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_hash_dir(hash)
|
73
|
+
create_dir_if_not_exists(@base_path + "/#{hash[0..1]}/")
|
74
|
+
create_dir_if_not_exists(@base_path + "/#{hash[0..1]}/#{hash[2..-1]}/")
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_dir_if_not_exists(dest)
|
78
|
+
begin
|
79
|
+
Dir.mkdir(dest)
|
80
|
+
rescue Errno::EEXIST
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/fastruby/exceptions.rb
CHANGED
@@ -21,4 +21,14 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
|
21
21
|
module FastRuby
|
22
22
|
class TypeMismatchAssignmentException < Exception
|
23
23
|
end
|
24
|
+
|
25
|
+
class Context
|
26
|
+
class UnwindFastrubyFrame < Exception
|
27
|
+
def initialize(ex,target_frame,return_value)
|
28
|
+
@ex = ex
|
29
|
+
@target_frame = target_frame
|
30
|
+
@return_value = return_value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
24
34
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the fastruby project, http://github.com/tario/fastruby
|
4
|
+
|
5
|
+
Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
fastruby is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
fastruby is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
module FastRuby
|
22
|
+
class FastRubySexp < Array
|
23
|
+
alias node_type first
|
24
|
+
end
|
25
|
+
end
|
data/lib/fastruby/getlocals.rb
CHANGED
@@ -18,8 +18,8 @@ you should have received a copy of the gnu general public license
|
|
18
18
|
along with fastruby. if not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
20
|
=end
|
21
|
-
require "rubygems"
|
22
21
|
require "set"
|
22
|
+
require "fastruby/fastruby_sexp"
|
23
23
|
|
24
24
|
module FastRuby
|
25
25
|
class GetLocalsProcessor
|
@@ -35,7 +35,7 @@ module FastRuby
|
|
35
35
|
@locals << tree[1]
|
36
36
|
end
|
37
37
|
|
38
|
-
tree.select{|subtree| subtree.instance_of?
|
38
|
+
tree.select{|subtree| subtree.instance_of? FastRuby::FastRubySexp}.each do |subtree|
|
39
39
|
process(subtree)
|
40
40
|
end
|
41
41
|
end
|