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 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