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 CHANGED
@@ -1,3 +1,5 @@
1
+ 0.0.6 Implemented cache of native libraries to speedup init, see README for more info
2
+
1
3
  0.0.5 Support for case..when..end
2
4
 
3
5
  Fixes on wrapping/translation of fastruby frames through ruby calls
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 100X of the MRI1.8)
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
@@ -7,7 +7,7 @@ require "rspec/core/rake_task"
7
7
 
8
8
  spec = Gem::Specification.new do |s|
9
9
  s.name = 'fastruby'
10
- s.version = '0.0.5'
10
+ s.version = '0.0.6'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
@@ -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 build(signature)
57
- mname = "_" + @method_name.to_s + signature.map(&:internal_value).map(&:to_s).join
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
- FastRuby.logger.info mname.to_s
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 #{self}::#{@method_name} for signature #{signature.inspect}, it's already done"
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 #{self}::#{@method_name} for signature #{signature.inspect}"
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.alt_method_name = mname
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
- @owner.class_eval do
89
- inline :C do |builder|
90
- builder.inc << context.extra_code
91
- builder.include "<node.h>"
92
- builder.c c_code
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
- ret = @owner.instance_method(mname)
205
+ unless options[:no_cache]
206
+ FastRuby.cache.insert(snippet_hash, so_name) unless no_cache
207
+ end
97
208
 
98
- ret.extend MethodExtent
99
- ret.yield_signature = context.yield_signature
209
+ if noreturn then
210
+ nil
211
+ else
212
+ ret = @owner.instance_method(mname)
100
213
 
101
- ret
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
@@ -19,6 +19,9 @@ along with fastruby. if not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
  =end
21
21
  module Kernel
22
+
23
+ alias original_require require
24
+
22
25
  def fastruby_require(path)
23
26
  if path =~ /\.so$/
24
27
  require(path)
@@ -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
@@ -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? Sexp}.each do |subtree|
38
+ tree.select{|subtree| subtree.instance_of? FastRuby::FastRubySexp}.each do |subtree|
39
39
  process(subtree)
40
40
  end
41
41
  end