fastruby 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|