Temporary tag for this failure. Updated CI spec coming.
[rbx.git] / kernel / core / compile.rb
blobbabfb8a453dc6641e8f811ada5bc4b2db57c312c
1 # depends on: module.rb
3 module Rubinius
5   ##
6   # This const controls what the lowest version of compiled methods we can
7   # allow is. This allows us to cut off compability at some point, or just
8   # increment when major changes are made to the compiler.
10   CompiledMethodVersion = 6
12 end
15 # A module for selecting which Rubinius compiler to use.
17 module Compile
19   @compiler = nil
21   DefaultCompiler = "compiler"
23   def self.register_compiler(obj)
24     if $DEBUG
25       $stderr.puts "[Registered #{obj} as system compiler]"
26     end
27     @compiler = obj
28   end
30   def self.find_compiler
31     @compiler = :loading
32     begin
33       loading_rbc_directly do
34         require "#{DefaultCompiler}/init"
35       end
36     rescue Exception => e
37       STDERR.puts "Unable to load default compiler: #{e.message}"
38       puts e.awesome_backtrace.show
39       raise e
40     end
42     if @compiler == :loading
43       raise "Attempted to load DefaultCompiler, but no compiler was registered"
44     end
46     return @compiler
47   end
49   def self.compiler
50     return @compiler if @compiler and @compiler != :loading
51     return find_compiler
52   end
54   def self.version_number
55     # Until the compiler is loaded, load any versions. This
56     # lets us bootstrap the compiler into the system no matter
57     # what version it is. This is important because we don't want
58     # to keep the compiler from loading at all because it might have
59     # older versioned files.
60     return @compiler.version_number if @compiler and @compiler != :loading
61     return 0
62   end
64   def self.compile_file(path, flags=nil)
65     compiler.compile_file(path, flags)
66   end
68   def self.compile_string(string, flags=nil, filename="(eval)", line=1)
69     compiler.compile_string(string, flags, filename, line)
70   end
72   def self.execute(string)
73     eval(string, TOPLEVEL_BINDING)
74   end
76   # Sets a flag so that the next script to be loaded gets a breakpoint set at
77   # the first instruction
78   def self.debug_script!
79     @debug_script = true
80   end
82   # By calling require in the block passed to this, require will
83   # load rbc if they exist without checking mtime's and such.
84   @load_rbc_directly = false
86   def self.loading_rbc_directly
87     begin
88       @load_rbc_directly = true
89       yield
90     ensure
91       @load_rbc_directly = false
92     end
93   end
95   # Called when we encounter a break keyword that we do not support
96   # TODO - This leaves a moderately lame stack trace entry
97   def self.__unexpected_break__
98     raise LocalJumpError, "unexpected break"
99   end
101   # Internally used by #load and #require. Determines whether to
102   # load the file directly or by prefixing it with the paths in
103   # $LOAD_PATH and then attempts to locate and load the file.
104   def self.unified_load(path, rb, rbc, ext, requiring = nil, options = {:recompile => false})
105     # forces the compiler to be loaded. We need this to get
106     # the proper version_number calculation.
107     #
108     self.compiler unless @compiler
110     # ./ ../ ~/ /
111     if path =~ %r{\A(?:(\.\.?)|(~))?/}
112       if $2    # ~ 
113         rb.slice! '~/' if rb
114         rbc.slice! '~/' if rbc
115         ext.slice! '~/' if ext
116         res = Compile.single_load "#{ENV['HOME']}/", rb, rbc, ext, requiring, options
118       else
119         res = Compile.single_load '', rb, rbc, ext, requiring, options
120       end
122       return res unless res.nil?      # false is valid
124     # Unqualified
125     else
126       $LOAD_PATH.each do |dir|
127         if rbc and dir.suffix? '.rba' and File.file? dir and !options[:recompile]
128           begin
129             _, _, _, _, _, data = Ar.new(dir).extract rbc
130           rescue Ar::Error
131           end
133           cm = if data then
134                  unmarshal_object data, 0
135                else
136                  data = Ar.new(dir).extract rbc
137                  unmarshal_object data, version_number
138                end
140           if cm
141             return false if requiring and $LOADED_FEATURES.include? rb
143             cm.compile
144             cm.hints = { :source => :rba }
145             cm.as_script do |script|
146               script.path = rb
147             end
149             $LOADED_FEATURES << rb if requiring
151             # Add script CM to CompiledMethod.scripts
152             CompiledMethod.scripts[rb] = cm
154             return true
155           end
156           # Fall through
157         end
159         res = Compile.single_load "#{dir}/", rb, rbc, ext, requiring, options
160         return res unless res.nil?      # false is valid
161       end
162     end
164     raise LoadError, "no such file to load -- #{path}"
165   end
167   def self.compile_feature(rb, requiring, &block)
168     $LOADED_FEATURES << rb if requiring
169     begin
170       yield
171     rescue Exception => e
172       $LOADED_FEATURES.delete(rb) if requiring
173       raise e
174     end
175   end
177   # Internally used by #unified_load. This attempts to load the
178   # designated file from a single prefix path.
179   def self.single_load(dir, rb, rbc, ext, requiring, options)
180     # Force compiler loading, required for version calculation
181     self.compiler unless @compiler
183     if rb
184       return false if requiring and $LOADED_FEATURES.include? rb
186       rb_path = "#{dir}#{rb}"
188       if File.file? rb_path
189         rbc_path = "#{dir}#{rbc}"
190         
191         cm = nil
193         # Try to load rbc directly if requested
194         if @load_rbc_directly and File.file?(rbc_path)
195           compile_feature(rb, requiring) do
196             cm = CompiledMethod.load_from_file(rbc_path, version_number)
197             raise LoadError, "Invalid .rbc: #{rbc_path}" unless cm
198           end
200         # Prefer compiled whenever possible
201         elsif !File.file?(rbc_path) or File.mtime(rb_path) > File.mtime(rbc_path) or options[:recompile]
202           if $DEBUG_LOADING
203             if !File.file?(rbc_path)
204               STDERR.puts "[Compiling #{rb_path}: Missing compiled version]"
205             else
206               STDERR.puts "[Compiling #{rb_path}: Newer source file]"
207             end
208           end
210           compile_feature(rb, requiring) do
211             cm = Compile.compile_file(rb_path)
212             raise LoadError, "Unable to compile: #{rb_path}" unless cm
213           end
215           # Store it for the future
216           Marshal.dump_to_file cm, rbc_path, version_number
217         else
218           compile_feature(rb, requiring) do
219             cm = CompiledMethod.load_from_file(rbc_path, version_number)
220             # cm is nil if the file is out of date, version wise.
221             unless cm
222               if $DEBUG_LOADING
223                 STDERR.puts "[Recompling #{rb_path}, old version]"
224               end
226               compile_feature(rb, requiring) do
227                 cm = Compile.compile_file(rb_path)
228                 raise LoadError, "Unable to compile: #{rb_path}" unless cm
229               end
231               Marshal.dump_to_file cm, rbc_path, version_number
232             end
233           end
234         end
236         # Add script CM to CompiledMethod.scripts
237         CompiledMethod.scripts[rb] = cm
239         begin
240           cm.compile
241           cm.hints = { :source => :rb }
242           # Set a breakpoint on the script CompiledMethod if flag is set
243           if @debug_script
244             Debugger.instance.set_breakpoint cm, 0
245             @debug_script = false
246           end
247           cm.as_script do |script|
248             script.path = rb_path
249           end
250         rescue Exception => e
251           $LOADED_FEATURES.delete(rb) if requiring
252           raise e
253         end
255         return true
256       end
257     end
259     if rbc
260       rb = rbc.chomp 'c'
261       return false if requiring and $LOADED_FEATURES.include?(rb)
263       rbc_path = "#{dir}#{rbc}"
265       if File.file? rbc_path and !options[:recompile]
266         compile_feature(rb, requiring) do
267           cm = CompiledMethod.load_from_file(rbc_path, version_number)
268           raise LoadError, "Invalid .rbc: #{rbc_path}" unless cm
269         end
271         begin
272           cm.compile
273           cm.hints = { :source => :rbc }
274           cm.as_script do |script|
275             script.path = rb_path
276           end
277         rescue Exception => e
278           $LOADED_FEATURES.delete(rb) if requiring
279           raise e
280         end
282         return true
283       end
284     end
286     if ext
287       return false if requiring and $LOADED_FEATURES.include? ext
288       
289       ext_path = "#{dir}#{ext}"
290       ext_name = File.basename ext, ".#{Rubinius::LIBSUFFIX}"
292       if File.file? ext_path
293         case Rubinius::VM.load_library(ext_path, ext_name)
294         when true
295           $LOADED_FEATURES << ext if requiring
296           return true
297         when 0 # Absent or invalid
298           return nil
299         when 1 # Valid library, but no entry point
300           raise LoadError, "Invalid extension at '#{ext_path}'. " \
301                            "Did you define Init_#{ext_name}?"
302         end
303       end
304     end
306     nil
307   end
309   def self.load_from_extension(path)
310     path = StringValue(path)
312     if path.suffix? '.rbc'
313       rb, rbc, ext = nil, path, nil
314     elsif path.suffix? '.rb'
315       rb, rbc, ext = path, "#{path}c", nil
316     elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
317       rb, rbc, ext = nil, nil, path
318     else
319       dir, name = File.split(path)
320       name = ".#{name}" unless name[0] == ?.
321       rb, rbc, ext = path, "#{dir}/#{name}.compiled.rbc", nil
322     end
324     Compile.single_load '', rb, rbc, ext, false, {}
325   end
327   def self.unmarshal_object(data, version)
328     Ruby.primitive :unmarshal_object
329   end
331 end       # Compile
333 module Kernel
334   def compile(path, out=nil, flags=nil)
335     out = "#{path}c" unless out
336     cm = Compile.compile_file(path, flags)
337     raise LoadError, "Unable to compile '#{path}'" unless cm
338     Marshal.dump_to_file cm, out, Compile.version_number
339     return out
340   end
341   module_function :compile
343   
344   # Loads the given file as executable code and returns true. If
345   # the file cannot be found, cannot be compiled or some other
346   # error occurs, LoadError is raised with an explanation.
347   #
348   # Unlike #require, the file extension if any must be present but
349   # is not restricted to .rb, .rbc or .<platform shared lib ext>.
350   # Any other extensions (or no extension) are assumed to be plain
351   # Ruby files. The only exceptions to this rule are:
352   #
353   # 1.  if given a .rb or no/any-extensioned file and there is a
354   #     compiled version of the same file that is not older than
355   #     the source file (based on File.mtime), the compiled one
356   #     is loaded directly to avoid the compilation overhead.
357   # 2.  if a .rb file is given but it does not exist, the system
358   #     will try to load the corresponding .rbc instead (to allow
359   #     distributing just .rbc files.)
360   #
361   # If the path given starts with ./, ../, ~/ or /, it is treated
362   # as a "qualified" file and will be loaded directly (after path
363   # expansion) instead of matching against $LOAD_PATH. The relative
364   # paths use Dir.pwd.
365   #
366   # If the filename is plain (unqualified) then it is sequentially
367   # prefixed with each path in $LOAD_PATH ($:) to locate the file,
368   # using the first one that exists. If none of the resulting paths
369   # exist, LoadError is raised. Unqualified names may contain path
370   # elements so directories are valid targets and can be used with
371   # $LOAD_PATH.
372   #
373   # A few extra options are supported. If the second parameter is
374   # true, then the module is wrapped inside an anonymous module for
375   # loading to avoid polluting the namespace. This is actually a
376   # shorthand for passing in :wrap => true-ish in the second arg
377   # which may be an option Hash.
378   #
379   # If :recompile in option Hash is true-ish then the file in
380   # question is recompiled each time. If the source file is not
381   # present when recompiling is requested, a LoadError is raised.
382   #
383   # TODO: Support non-UNIX paths.
384   #
385   # TODO: The anonymous module wrapping is not implemented at all.
386   #
387   def load(path, opts = {:wrap => false, :recompile => false})
388     path = StringValue(path)
389     
390     opts = {:wrap => !!opts, :recompile => false} unless Hash === opts
392     if path.suffix? '.rbc'
393       rb, rbc, ext = nil, path, nil
394     elsif path.suffix? '.rb'
395       rb, rbc, ext = path, "#{path}c", nil
396     elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
397       rb, rbc, ext = nil, nil, path
398     else
399       dir, name = File.split(path)
400       name = ".#{name}" unless name[0] == ?.
401       rb, rbc, ext = path, "#{dir}/#{name}.compiled.rbc", nil
402     end
404     Compile.unified_load path, rb, rbc, ext, nil, opts
405   end
406   module_function :load
408   
409   # Attempt to load the given file, returning true if successful.
410   # If the file has already been successfully loaded and exists
411   # in $LOADED_FEATURES, it will not be re-evaluated and false
412   # is returned instead. If the filename cannot be resolved,
413   # a LoadError is raised.
414   #
415   # The file can have one of the following extensions:
416   #
417   # [.rb]                   Plain Ruby source file.
418   # [.rbc]                  Compiled Ruby source file.
419   # [.o, .so, .dylib, .dll] Shared library (platform-specific.)
420   # [<none>]                Filename without extension.
421   #
422   # (.rba files should be loaded using CodeArchive.load_everything.)
423   #
424   # If the file does not have an extension, #require attempts to
425   # match it using .rb, .rbc and .<shared extension> as extensions,
426   # in that order, instead. If foo.rb does not exist but foo.rbc
427   # does, the latter will be loaded even if called with foo.rb.
428   #
429   # If the path given starts with ./, ../, ~/ or /, it is treated
430   # as a "qualified" file and will be loaded directly (after path
431   # expansion) instead of matching against $LOAD_PATH. The relative
432   # paths use Dir.pwd.
433   #
434   # If the filename is plain (unqualified) then it is sequentially
435   # prefixed with each path in $LOAD_PATH ($:) to locate the file,
436   # using the first one that exists. If none of the resulting paths
437   # exist, LoadError is raised. Unqualified names may contain path
438   # elements so directories are valid targets and can be used with
439   # $LOAD_PATH.
440   #
441   # TODO: Support non-UNIX paths.
442   #
443   # TODO: See if we can safely use 1.9 rules with $LOADED_FEATURES,
444   #       i.e. expand paths into it. This should be possible if it
445   #       is completely transparent to the user in all normal cases.
446   #
447   # Each successfully loaded file is added to $LOADED_FEATURES
448   # ($"), using the original unexpanded filename (with the
449   # exception that the file extension is added.)
450   #
451   def require(path)
452     path = StringValue(path)
453     rb, rbc, ext = __split_path__ path
454     Autoload.remove(rb)
455     Compile.unified_load path, rb, rbc, ext, true
456   end
457   module_function :require
459   def __split_path__(path)
460     if path.suffix? '.rbc'
461       rb, rbc, ext = nil, path, nil
462     elsif path.suffix? '.rb'
463       rb, rbc, ext = path, "#{path}c", nil
464     elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
465       rb, rbc, ext = nil, nil, path
466     else
467       rb, rbc, ext = "#{path}.rb", "#{path}.rbc", "#{path}.#{Rubinius::LIBSUFFIX}"
468     end
469     return rb,rbc,ext
470   end
471   private :__split_path__