1 # depends on: module.rb
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
15 # Main entrace point to the Rubinius compiler. Handles loading and compiling
22 DefaultCompiler = "compiler"
24 def self.register_compiler(obj)
26 $stderr.puts "[Registered #{obj} as system compiler]"
31 def self.find_compiler
34 loading_rbc_directly do
35 require "#{DefaultCompiler}/init"
38 STDERR.puts "Unable to load default compiler: #{e.message}"
39 puts e.awesome_backtrace.show
43 if @compiler == :loading
44 raise "Attempted to load DefaultCompiler, but no compiler was registered"
51 return @compiler if @compiler and @compiler != :loading
55 def self.version_number
56 # Until the compiler is loaded, load any versions. This
57 # lets us bootstrap the compiler into the system no matter
58 # what version it is. This is important because we don't want
59 # to keep the compiler from loading at all because it might have
60 # older versioned files.
61 return @compiler.version_number if @compiler and @compiler != :loading
65 def self.compile_file(path, flags=nil)
66 compiler.compile_file(path, flags)
69 def self.compile_string(string, context=nil, filename="(eval)", line=1)
70 compiler.compile_string(string, context, filename, line)
73 def self.execute(string)
74 eval(string, TOPLEVEL_BINDING)
77 # Sets a flag so that the next script to be loaded gets a breakpoint set at
78 # the first instruction
79 def self.debug_script!
83 # By calling require in the block passed to this, require will
84 # load rbc if they exist without checking mtime's and such.
85 @load_rbc_directly = false
87 def self.loading_rbc_directly
89 @load_rbc_directly = true
92 @load_rbc_directly = false
96 # Called when we encounter a break keyword that we do not support
97 # TODO - This leaves a moderately lame stack trace entry
98 def self.__unexpected_break__
99 raise LocalJumpError, "unexpected break"
102 # Internally used by #load and #require. Determines whether to
103 # load the file directly or by prefixing it with the paths in
104 # $LOAD_PATH and then attempts to locate and load the file.
105 def self.unified_load(path, rb, rbc, ext, requiring = nil, options = {:recompile => false})
106 # forces the compiler to be loaded. We need this to get
107 # the proper version_number calculation.
109 self.compiler unless @compiler
112 if path =~ %r{\A(?:(\.\.?)|(~))?/}
115 rbc.slice! '~/' if rbc
116 ext.slice! '~/' if ext
117 res = Compile.single_load "#{ENV['HOME']}/", rb, rbc, ext, requiring, options
120 res = Compile.single_load '', rb, rbc, ext, requiring, options
123 return res unless res.nil? # false is valid
127 $LOAD_PATH.each do |dir|
128 if rbc and dir.suffix? '.rba' and File.file? dir and !options[:recompile]
130 _, _, _, _, _, data = Ar.new(dir).extract rbc
135 unmarshal_object data, 0
137 data = Ar.new(dir).extract rbc
138 unmarshal_object data, version_number
142 return false if requiring and $LOADED_FEATURES.include? rb
145 cm.hints = { :source => :rba }
146 cm.as_script do |script|
150 $LOADED_FEATURES << rb if requiring
152 # Add script CM to CompiledMethod.scripts
153 CompiledMethod.scripts[rb] = cm
160 res = Compile.single_load "#{dir}/", rb, rbc, ext, requiring, options
161 return res unless res.nil? # false is valid
165 raise LoadError, "no such file to load -- #{path}"
168 def self.compile_feature(rb, requiring, &block)
169 $LOADED_FEATURES << rb if requiring
172 rescue Exception => e
173 $LOADED_FEATURES.delete(rb) if requiring
178 # Internally used by #unified_load. This attempts to load the
179 # designated file from a single prefix path.
180 def self.single_load(dir, rb, rbc, ext, requiring, options)
181 # Force compiler loading, required for version calculation
182 self.compiler unless @compiler
185 return false if requiring and $LOADED_FEATURES.include? rb
187 rb_path = "#{dir}#{rb}"
189 if File.file? rb_path
190 rbc_path = "#{dir}#{rbc}"
194 # Try to load rbc directly if requested
195 if @load_rbc_directly and File.file?(rbc_path)
196 compile_feature(rb, requiring) do
197 cm = CompiledMethod.load_from_file(rbc_path, version_number)
198 raise LoadError, "Invalid .rbc: #{rbc_path}" unless cm
201 # Prefer compiled whenever possible
202 elsif !File.file?(rbc_path) or File.mtime(rb_path) > File.mtime(rbc_path) or options[:recompile]
204 if !File.file?(rbc_path)
205 STDERR.puts "[Compiling #{rb_path}: Missing compiled version]"
207 STDERR.puts "[Compiling #{rb_path}: Newer source file]"
211 compile_feature(rb, requiring) do
212 cm = Compile.compile_file(rb_path)
213 raise LoadError, "Unable to compile: #{rb_path}" unless cm
216 # Store it for the future
217 Marshal.dump_to_file cm, rbc_path, version_number
219 compile_feature(rb, requiring) do
220 cm = CompiledMethod.load_from_file(rbc_path, version_number)
221 # cm is nil if the file is out of date, version wise.
224 STDERR.puts "[Recompling #{rb_path}, old version]"
227 compile_feature(rb, requiring) do
228 cm = Compile.compile_file(rb_path)
229 raise LoadError, "Unable to compile: #{rb_path}" unless cm
232 Marshal.dump_to_file cm, rbc_path, version_number
237 # Add script CM to CompiledMethod.scripts
238 CompiledMethod.scripts[rb] = cm
242 cm.hints = { :source => :rb }
243 # Set a breakpoint on the script CompiledMethod if flag is set
245 Debugger.instance.set_breakpoint cm, 0
246 @debug_script = false
248 cm.as_script do |script|
249 script.path = rb_path
251 rescue Exception => e
252 $LOADED_FEATURES.delete(rb) if requiring
262 return false if requiring and $LOADED_FEATURES.include?(rb)
264 rbc_path = "#{dir}#{rbc}"
266 if File.file? rbc_path and !options[:recompile]
267 compile_feature(rb, requiring) do
268 cm = CompiledMethod.load_from_file(rbc_path, version_number)
269 raise LoadError, "Invalid .rbc: #{rbc_path}" unless cm
274 cm.hints = { :source => :rbc }
275 cm.as_script do |script|
276 script.path = rb_path
278 rescue Exception => e
279 $LOADED_FEATURES.delete(rb) if requiring
288 return false if requiring and $LOADED_FEATURES.include? ext
290 ext_path = "#{dir}#{ext}"
291 ext_name = File.basename ext, ".#{Rubinius::LIBSUFFIX}"
293 if File.file? ext_path
294 case Rubinius::VM.load_library(ext_path, ext_name)
296 $LOADED_FEATURES << ext if requiring
298 when 0 # Absent or invalid
300 when 1 # Valid library, but no entry point
301 raise LoadError, "Invalid extension at '#{ext_path}'. " \
302 "Did you define Init_#{ext_name}?"
310 def self.load_from_extension(path)
311 path = StringValue(path)
312 # Remap all library extensions behind the scenes, just like MRI
313 path.gsub!(/\.(so|bundle|dll|dylib)$/, ".#{Rubinius::LIBSUFFIX}")
314 if path.suffix? '.rbc'
315 rb, rbc, ext = nil, path, nil
316 elsif path.suffix? '.rb'
317 rb, rbc, ext = path, "#{path}c", nil
318 elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
319 rb, rbc, ext = nil, nil, path
321 dir, name = File.split(path)
322 name = ".#{name}" unless name[0] == ?.
323 rb, rbc, ext = path, "#{dir}/#{name}.compiled.rbc", nil
326 Compile.single_load '', rb, rbc, ext, false, {}
329 def self.unmarshal_object(data, version)
330 Ruby.primitive :unmarshal_object
336 def compile(path, out=nil, flags=nil)
337 out = "#{path}c" unless out
338 cm = Compile.compile_file(path, flags)
339 raise LoadError, "Unable to compile '#{path}'" unless cm
340 Marshal.dump_to_file cm, out, Compile.version_number
343 module_function :compile
346 # Loads the given file as executable code and returns true. If
347 # the file cannot be found, cannot be compiled or some other
348 # error occurs, LoadError is raised with an explanation.
350 # Unlike #require, the file extension if any must be present but
351 # is not restricted to .rb, .rbc or .<platform shared lib ext>.
352 # Any other extensions (or no extension) are assumed to be plain
353 # Ruby files. The only exceptions to this rule are:
355 # 1. if given a .rb or no/any-extensioned file and there is a
356 # compiled version of the same file that is not older than
357 # the source file (based on File.mtime), the compiled one
358 # is loaded directly to avoid the compilation overhead.
359 # 2. if a .rb file is given but it does not exist, the system
360 # will try to load the corresponding .rbc instead (to allow
361 # distributing just .rbc files.)
363 # If the path given starts with ./, ../, ~/ or /, it is treated
364 # as a "qualified" file and will be loaded directly (after path
365 # expansion) instead of matching against $LOAD_PATH. The relative
368 # If the filename is plain (unqualified) then it is sequentially
369 # prefixed with each path in $LOAD_PATH ($:) to locate the file,
370 # using the first one that exists. If none of the resulting paths
371 # exist, LoadError is raised. Unqualified names may contain path
372 # elements so directories are valid targets and can be used with
375 # A few extra options are supported. If the second parameter is
376 # true, then the module is wrapped inside an anonymous module for
377 # loading to avoid polluting the namespace. This is actually a
378 # shorthand for passing in :wrap => true-ish in the second arg
379 # which may be an option Hash.
381 # If :recompile in option Hash is true-ish then the file in
382 # question is recompiled each time. If the source file is not
383 # present when recompiling is requested, a LoadError is raised.
385 # TODO: Support non-UNIX paths.
387 # TODO: The anonymous module wrapping is not implemented at all.
389 def load(path, opts = {:wrap => false, :recompile => false})
390 path = StringValue(path)
391 # Remap all library extensions behind the scenes, just like MRI
392 path.gsub!(/\.(so|bundle|dll|dylib)$/, ".#{Rubinius::LIBSUFFIX}")
394 opts = {:wrap => !!opts, :recompile => false} unless Hash === opts
396 if path.suffix? '.rbc'
397 rb, rbc, ext = nil, path, nil
398 elsif path.suffix? '.rb'
399 rb, rbc, ext = path, "#{path}c", nil
400 elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
401 rb, rbc, ext = nil, nil, path
403 dir, name = File.split(path)
404 name = ".#{name}" unless name[0] == ?.
405 rb, rbc, ext = path, "#{dir}/#{name}.compiled.rbc", nil
408 Compile.unified_load path, rb, rbc, ext, nil, opts
410 module_function :load
413 # Attempt to load the given file, returning true if successful.
414 # If the file has already been successfully loaded and exists
415 # in $LOADED_FEATURES, it will not be re-evaluated and false
416 # is returned instead. If the filename cannot be resolved,
417 # a LoadError is raised.
419 # The file can have one of the following extensions:
421 # [.rb] Plain Ruby source file.
422 # [.rbc] Compiled Ruby source file.
423 # [.o, .so, .dylib, .dll] Shared library (platform-specific.)
424 # [<none>] Filename without extension.
426 # (.rba files should be loaded using CodeArchive.load_everything.)
428 # If the file does not have an extension, #require attempts to
429 # match it using .rb, .rbc and .<shared extension> as extensions,
430 # in that order, instead. If foo.rb does not exist but foo.rbc
431 # does, the latter will be loaded even if called with foo.rb.
433 # If the path given starts with ./, ../, ~/ or /, it is treated
434 # as a "qualified" file and will be loaded directly (after path
435 # expansion) instead of matching against $LOAD_PATH. The relative
438 # If the filename is plain (unqualified) then it is sequentially
439 # prefixed with each path in $LOAD_PATH ($:) to locate the file,
440 # using the first one that exists. If none of the resulting paths
441 # exist, LoadError is raised. Unqualified names may contain path
442 # elements so directories are valid targets and can be used with
445 # TODO: Support non-UNIX paths.
447 # TODO: See if we can safely use 1.9 rules with $LOADED_FEATURES,
448 # i.e. expand paths into it. This should be possible if it
449 # is completely transparent to the user in all normal cases.
451 # Each successfully loaded file is added to $LOADED_FEATURES
452 # ($"), using the original unexpanded filename (with the
453 # exception that the file extension is added.)
456 path = StringValue(path)
457 rb, rbc, ext = __split_path__ path
459 Compile.unified_load path, rb, rbc, ext, true
461 module_function :require
463 def __split_path__(path)
464 # Remap all library extensions behind the scenes, just like MRI
465 path.gsub!(/\.(so|bundle|dll|dylib)$/, ".#{Rubinius::LIBSUFFIX}")
467 if path.suffix? '.rbc'
468 rb, rbc, ext = nil, path, nil
469 elsif path.suffix? '.rb'
470 rb, rbc, ext = path, "#{path}c", nil
471 elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
472 rb, rbc, ext = nil, nil, path
474 rb, rbc, ext = "#{path}.rb", "#{path}.rbc", "#{path}.#{Rubinius::LIBSUFFIX}"
478 private :__split_path__