Skip to content
Browse files

Merge branch 'master' into rubinius

Conflicts:
	src/org/jruby/ext/rubinius/RubiniusLibrary.java
  • Loading branch information...
2 parents 2e809d4 + c402564 commit 947564724f86515d3318fd97a51dc9bd49b902db @headius headius committed
Showing with 1,192 additions and 327 deletions.
  1. +36 −0 bench/bench_avi_base64.rb
  2. +17 −0 bench/language/bench_case.rb
  3. +0 −80 build.xml
  4. +1 −1 default.build.properties
  5. +424 −0 lib/ruby/site_ruby/shared/rubinius/actor.rb
  6. +68 −0 lib/ruby/site_ruby/shared/rubinius/actor/filter.rb
  7. +1 −1 maven/jruby-complete/pom.xml
  8. +1 −1 maven/jruby-core/pom.xml
  9. +1 −1 maven/jruby-dist/pom.xml
  10. +3 −3 maven/jruby-rake-plugin/pom.xml
  11. +1 −1 maven/jruby-stdlib/pom.xml
  12. +1 −1 maven/jruby/pom.xml
  13. +1 −1 maven/pom.xml
  14. +1 −1 pom.xml
  15. BIN spec/regression/.JRUBY-5811_case_insensitive_loaded_features.rb.swp
  16. +56 −0 spec/regression/JRUBY-3194_autoload_thread_safety.rb
  17. +27 −0 spec/regression/JRUBY-5811_case_insensitive_loaded_features.rb
  18. +0 −2 spec/tags/1.8/ruby/core/string/scan_tags.txt
  19. +0 −1 spec/tags/1.9/ruby/core/string/gsub_tags.txt
  20. +0 −3 spec/tags/1.9/ruby/core/string/scan_tags.txt
  21. +0 −1 spec/tags/1.9/ruby/core/string/split_tags.txt
  22. +32 −2 src/org/jruby/Ruby.java
  23. +1 −1 src/org/jruby/RubyException.java
  24. +1 −1 src/org/jruby/RubyInstanceConfig.java
  25. +5 −3 src/org/jruby/RubyKernel.java
  26. +1 −1 src/org/jruby/RubyModule.java
  27. +7 −2 src/org/jruby/RubyString.java
  28. +3 −3 src/org/jruby/ast/Colon2ConstNode.java
  29. +3 −3 src/org/jruby/ast/Colon3Node.java
  30. +3 −3 src/org/jruby/ast/ConstNode.java
  31. +7 −6 src/org/jruby/ast/executable/RuntimeCache.java
  32. +1 −1 src/org/jruby/compiler/impl/BaseBodyCompiler.java
  33. +1 −2 src/org/jruby/compiler/impl/ChildScopedBodyCompiler.java
  34. +1 −2 src/org/jruby/compiler/impl/ClassBodyCompiler.java
  35. +25 −4 src/org/jruby/compiler/impl/InheritedCacheCompiler.java
  36. +46 −0 src/org/jruby/compiler/impl/InvokeDynamicCacheCompiler.java
  37. +23 −0 src/org/jruby/compiler/impl/InvokeDynamicInvocationCompiler.java
  38. +1 −2 src/org/jruby/compiler/impl/MethodBodyCompiler.java
  39. +1 −2 src/org/jruby/compiler/impl/RootScopedBodyCompiler.java
  40. +23 −6 src/org/jruby/compiler/impl/StandardASMCompiler.java
  41. +2 −3 src/org/jruby/embed/osgi/internal/OSGiBundlesSearcher.java
  42. +1 −1 src/org/jruby/embed/variable/Argv.java
  43. +1 −1 src/org/jruby/embed/variable/Constant.java
  44. +2 −1 src/org/jruby/ext/ffi/StructLayout.java
  45. +2 −1 src/org/jruby/ext/psych/PsychParser.java
  46. +4 −0 src/org/jruby/javasupport/util/RuntimeHelpers.java
  47. +4 −9 src/org/jruby/runtime/ThreadContext.java
  48. +75 −14 src/org/jruby/runtime/invokedynamic/InvokeDynamicSupport.java
  49. +114 −115 src/org/jruby/runtime/load/LoadService.java
  50. +42 −0 src/org/jruby/runtime/opto/Invalidator.java
  51. +44 −0 src/org/jruby/runtime/opto/ObjectIdentityInvalidator.java
  52. +46 −0 src/org/jruby/runtime/opto/SwitchPointInvalidator.java
  53. +7 −10 src/org/jruby/util/collections/StringArraySet.java
  54. +24 −30 src/org/jruby/util/io/SelectorPool.java
View
36 bench/bench_avi_base64.rb
@@ -0,0 +1,36 @@
+require 'stringio'
+require 'base64'
+
+def read_varint(io)
+ value = index = 0
+ begin
+ byte = io.readbyte
+ value |= (byte & 0x7f) << (7 * index)
+ index += 1
+ end while (byte & 0x80).nonzero?
+ value
+end
+
+def decode_base64_protobuf(string)
+ values = []
+ io = StringIO.new(Base64.decode64(string))
+ until io.eof?
+ bits = read_varint(io)
+ values[(bits >> 3) - 1] =
+ case bits & 0x07
+ when 0; read_varint(io)
+ when 2; io.read(read_varint(io))
+ end
+ end
+ values
+end
+
+require 'benchmark'
+(ARGV[0] || 5).to_i.times do
+ puts Benchmark.measure {
+ line = 'CKeTAxCmmfRHGK6trLv1prbkEiCglsTnBDgBMAA='
+ 100_000.times do
+ decode_base64_protobuf(line.split[-1]).join("\t")
+ end
+ }
+end
View
17 bench/language/bench_case.rb
@@ -64,6 +64,14 @@ def do_case_multi_char_symbol
case :jx; when :ax; when :bx; when :cx; when :dx; when :ex; when :fx; when :gx; when :hx; when :ix; when :jx; end
case :jx; when :ax; when :bx; when :cx; when :dx; when :ex; when :fx; when :gx; when :hx; when :ix; when :jx; end
end
+
+ def do_case_custom_object(obj)
+ case 1; when 10; when 9; when 8; when 7; when 6; when 5; when 4; when 3; when 2; when obj; end
+ case 1; when 10; when 9; when 8; when 7; when 6; when 5; when 4; when 3; when 2; when obj; end
+ case 1; when 10; when 9; when 8; when 7; when 6; when 5; when 4; when 3; when 2; when obj; end
+ case 1; when 10; when 9; when 8; when 7; when 6; when 5; when 4; when 3; when 2; when obj; end
+ case 1; when 10; when 9; when 8; when 7; when 6; when 5; when 4; when 3; when 2; when obj; end
+ end
end
def bench_case(bm)
@@ -132,6 +140,15 @@ def bench_case(bm)
a += 1
end
end
+
+ bm.report "1m x5 cases, 9 fixnum 1 custom" do
+ a = 0
+ obj = Object.new
+ while a < 1_000_000
+ bc.do_case_custom_object(obj)
+ a += 1
+ end
+ end
end
if $0 == __FILE__
View
80 build.xml
@@ -845,14 +845,6 @@
description="Runs unit tests.">
</target>
- <target name="test-indy" depends="
- copy-test-files,
- install-gems,
- run-junit-indy-short,
- test-rake-targets"
- description="Runs unit tests.">
- </target>
-
<target name="test-extended" depends="
copy-test-files,
install-gems,
@@ -893,8 +885,6 @@
<target name="run-junit-compiled"><run-junit-1.8 compile.mode="JIT" jit.threshold="0"/></target>
<target name="run-junit-compiled-short"><run-junit-1.8-short compile.mode="JIT" jit.threshold="0"/></target>
<target name="run-junit-interpreted-short"><run-junit-1.8-short/></target>
- <target name="run-junit-indy-short"><run-junit-1.8-indy-short/></target>
- <!-- temporarily disabled during compiler work -->
<target name="run-junit-compiled-1.9"><run-junit-1.9 compile.mode="JIT" jit.threshold="0"/></target>
<target name="run-junit-reflected-compiled"><run-junit-1.8 compile.mode="JIT" jit.threshold="0" reflection="true"/></target>
<target name="run-junit-reflected-compiled-1.9"><run-junit-1.9 compile.mode="JIT" jit.threshold="0" reflection="true"/></target>
@@ -920,61 +910,6 @@
<pathelement location="${test.dir}"/>
</path>
- <macrodef name="run-junit-indy">
- <attribute name="jruby.version" default="ruby1_8"/>
- <attribute name="compile.mode" default="-X+O"/>
- <attribute name="jit.threshold" default="0"/>
- <attribute name="jit.maxsize" default="1000000000"/>
- <attribute name="jit.max" default="-1"/>
- <attribute name="objectspace.enabled" default="true"/>
- <attribute name="thread.pooling" default="false"/>
- <attribute name="reflection" default="false"/>
- <element name="junit-tests"/>
- <sequential>
- <echo message="compile=@{compile.mode}, jit.threshold=@{jit.threshold}, jit.maxsize=@{jit.maxsize}, jit.max=@{jit.max}, objectspace=@{objectspace.enabled} threadpool=@{thread.pooling} reflection=@{reflection} version=@{jruby.version}"/>
- <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask" classpath="${build.lib.dir}/junit.jar"/>
-
- <junit jvm="${jruby.test.jvm}" fork="yes" forkMode="once" haltonfailure="true" dir="${basedir}" maxmemory="${jruby.test.memory}" showoutput="true" timeout="1800000">
- <classpath refid="test.class.path"/>
-
- <sysproperty key="jruby.compile.invokedynamic" value="true"/>
- <sysproperty key="java.awt.headless" value="true"/>
- <sysproperty key="jruby.home" value="${basedir}"/>
- <sysproperty key="jruby.lib" value="${lib.dir}"/>
- <sysproperty key="jruby.compile.mode" value="@{compile.mode}"/>
- <sysproperty key="jruby.jit.threshold" value="@{jit.threshold}"/>
- <sysproperty key="jruby.jit.maxsize" value="@{jit.maxsize}"/>
- <sysproperty key="jruby.jit.max" value="@{jit.max}"/>
- <sysproperty key="jruby.compat.version" value="@{jruby.version}"/>
- <sysproperty key="jruby.objectspace.enabled" value="@{objectspace.enabled}"/>
- <sysproperty key="jruby.thread.pool.enabled" value="@{thread.pooling}"/>
- <sysproperty key="jruby.reflection" value="@{reflection}"/>
- <sysproperty key="jruby.jit.logging.verbose" value="true"/>
- <sysproperty key="jruby.compile.lazyHandles" value="true"/>
-
- <!-- emma coverage tool properties -->
- <sysproperty key="emma.coverage.out.file" value="${test.results.dir}/coverage.emma" />
- <sysproperty key="emma.coverage.out.merge" value="true" />
- <sysproperty key="emma.verbosity.level" value="silent" />
-
- <syspropertyset refid="test.sysproperties"/>
-
- <!-- force client VM to improve test run times AND -->
- <!-- set a larger max permgen, since the tests load a lot of bytecode -->
- <jvmarg line="-ea ${java.opts} -client -XX:MaxPermSize=256M -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic"/>
-
- <formatter type="xml"/>
- <formatter type="brief" usefile="false" />
-
- <junit-tests/>
- </junit>
- <junitreport todir="${test.results.dir}">
- <fileset dir="${test.results.dir}" includes="TEST-*.xml"/>
- <report format="frames" todir="${html.test.results.dir}"/>
- </junitreport>
- </sequential>
- </macrodef>
-
<macrodef name="run-junit">
<attribute name="jruby.version" default="ruby1_8"/>
<attribute name="compile.mode" default="OFF"/>
@@ -1054,21 +989,6 @@
</macrodef>
<!-- runs junit tests for 1.8 functionality -->
- <macrodef name="run-junit-1.8-indy-short">
- <sequential>
- <run-junit-indy>
- <junit-tests>
- <test name="${test}" if="test"/>
- <test name="org.jruby.test.ScriptTestSuite" todir="${test.results.dir}" unless="test"/>
- <test name="org.jruby.test.JRubyTestSuite" todir="${test.results.dir}" unless="test"/>
- <test name="org.jruby.test.MRITestSuite" todir="${test.results.dir}" unless="test"/>
- <test name="org.jruby.test.MainTestSuite" todir="${test.results.dir}" unless="test"/>
- </junit-tests>
- </run-junit-indy>
- </sequential>
- </macrodef>
-
- <!-- runs junit tests for 1.8 functionality -->
<macrodef name="run-junit-1.8">
<attribute name="compile.mode" default="OFF"/>
<attribute name="jit.threshold" default="20"/>
View
2 default.build.properties
@@ -70,7 +70,7 @@ version.ruby1_9.major=1.9
version.ruby1_9=1.9.2
version.ruby1_9.patchlevel=136
version.ruby1_9.revision=27758
-version.jruby=1.6.1
+version.jruby=1.7.0.dev
mspec.revision=6563955da20f93e6dcd5a35ec5828de75c6165eb
rubyspecs.revision=3bf5857d44f9a69092862fa100a0ee1d152e6117
joda.time.version=1.6.2
View
424 lib/ruby/site_ruby/shared/rubinius/actor.rb
@@ -0,0 +1,424 @@
+# actor.rb - implementation of the actor model
+#
+# Copyright 2007-2008 MenTaLguY <mental@rydia.net>
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# thi slist of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice
+# this list of conditions and the following disclaimer in the documentatio
+# and/or other materials provided with the distribution.
+# * Neither the name of the Evan Phoenix nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+class Actor
+ class DeadActorError < RuntimeError
+ attr_reader :actor
+ attr_reader :reason
+ def initialize(actor, reason)
+ super(reason)
+ @actor = actor
+ @reason = reason
+ end
+ end
+
+ ANY = Object.new
+ def ANY.===(other)
+ true
+ end
+
+ class << self
+ alias_method :private_new, :new
+ private :private_new
+
+ @@registered_lock = Rubinius::Channel.new
+ @@registered = {}
+ @@registered_lock << nil
+
+ def current
+ Thread.current[:__current_actor__] ||= private_new
+ end
+
+ # Spawn a new Actor that will run in its own thread
+ def spawn(*args, &block)
+ raise ArgumentError, "no block given" unless block
+ spawned = Rubinius::Channel.new
+ Thread.new do
+ private_new do |actor|
+ Thread.current[:__current_actor__] = actor
+ spawned << actor
+ block.call *args
+ end
+ end
+ spawned.receive
+ end
+ alias_method :new, :spawn
+
+ # Atomically spawn an actor and link it to the current actor
+ def spawn_link(*args, &block)
+ current = self.current
+ link_complete = Rubinius::Channel.new
+ spawn do
+ begin
+ Actor.link(current)
+ ensure
+ link_complete << Actor.current
+ end
+ block.call *args
+ end
+ link_complete.receive
+ end
+
+ # Polls for exit notifications
+ def check_for_interrupt
+ current._check_for_interrupt
+ self
+ end
+
+ # Waits until a matching message is received in the current actor's
+ # mailbox, and executes the appropriate action. May be interrupted by
+ # exit notifications.
+ def receive #:yields: filter
+ filter = Filter.new
+ if block_given?
+ yield filter
+ else
+ filter.when(ANY) { |m| m }
+ end
+ current._receive(filter)
+ end
+
+ # Send a "fake" exit notification to another actor, as if the current
+ # actor had exited with +reason+
+ def send_exit(recipient, reason)
+ recipient.notify_exited(current, reason)
+ self
+ end
+
+ # Link the current Actor to another one.
+ def link(actor)
+ current = self.current
+ current.notify_link actor
+ actor.notify_link current
+ self
+ end
+
+ # Unlink the current Actor from another one
+ def unlink(actor)
+ current = self.current
+ current.notify_unlink actor
+ actor.notify_unlink current
+ self
+ end
+
+ # Actors trapping exit do not die when an error occurs in an Actor they
+ # are linked to. Instead the exit message is sent to their regular
+ # mailbox in the form [:exit, actor, reason]. This allows certain
+ # Actors to supervise sets of others and restart them in the event
+ # of an error. Setting the trap flag may be interrupted by pending
+ # exit notifications.
+ #
+ def trap_exit=(value)
+ current._trap_exit = value
+ self
+ end
+
+ # Is the Actor trapping exit?
+ def trap_exit
+ current._trap_exit
+ end
+ alias_method :trap_exit?, :trap_exit
+
+ # Lookup a locally named service
+ def lookup(name)
+ raise ArgumentError, "name must be a symbol" unless Symbol === name
+ @@registered_lock.receive
+ begin
+ @@registered[name]
+ ensure
+ @@registered_lock << nil
+ end
+ end
+ alias_method :[], :lookup
+
+ # Register an Actor locally as a named service
+ def register(name, actor)
+ raise ArgumentError, "name must be a symbol" unless Symbol === name
+ unless actor.nil? or actor.is_a?(Actor)
+ raise ArgumentError, "only actors may be registered"
+ end
+
+ @@registered_lock.receive
+ begin
+ if actor.nil?
+ @@registered.delete(name)
+ else
+ @@registered[name] = actor
+ end
+ ensure
+ @@registered_lock << nil
+ end
+ end
+ alias_method :[]=, :register
+
+ def _unregister(actor) #:nodoc:
+ @@registered_lock.receive
+ begin
+ @@registered.delete_if { |n, a| actor.equal? a }
+ ensure
+ @@registered_lock << nil
+ end
+ end
+ end
+
+ def initialize
+ @lock = Rubinius::Channel.new
+
+ @filter = nil
+ @ready = Rubinius::Channel.new
+ @action = nil
+ @message = nil
+
+ @mailbox = []
+ @interrupts = []
+ @links = []
+ @alive = true
+ @exit_reason = nil
+ @trap_exit = false
+ @thread = Thread.current
+
+ @lock << nil
+
+ if block_given?
+ watchdog { yield self }
+ else
+ Thread.new { watchdog { @thread.join } }
+ end
+ end
+
+ def send(message)
+ @lock.receive
+ begin
+ return self unless @alive
+ if @filter
+ @action = @filter.action_for(message)
+ if @action
+ @filter = nil
+ @message = message
+ @ready << nil
+ else
+ @mailbox << message
+ end
+ else
+ @mailbox << message
+ end
+ ensure
+ @lock << nil
+ end
+ self
+ end
+ alias_method :<<, :send
+
+ def _check_for_interrupt #:nodoc:
+ check_thread
+ @lock.receive
+ begin
+ raise @interrupts.shift unless @interrupts.empty?
+ ensure
+ @lock << nil
+ end
+ end
+
+ def _receive(filter) #:nodoc:
+ check_thread
+
+ action = nil
+ message = nil
+ timed_out = false
+
+ @lock.receive
+ begin
+ raise @interrupts.shift unless @interrupts.empty?
+
+ for i in 0...(@mailbox.size)
+ message = @mailbox[i]
+ action = filter.action_for(message)
+ if action
+ @mailbox.delete_at(i)
+ break
+ end
+ end
+
+ unless action
+ @filter = filter
+ @lock << nil
+ begin
+ if filter.timeout?
+ timed_out = @ready.receive_timeout(filter.timeout) == false
+ else
+ @ready.receive
+ end
+ ensure
+ @lock.receive
+ end
+
+ if !timed_out and @interrupts.empty?
+ action = @action
+ message = @message
+ else
+ @mailbox << @message if @action
+ end
+
+ @action = nil
+ @message = nil
+
+ raise @interrupts.shift unless @interrupts.empty?
+ end
+ ensure
+ @lock << nil
+ end
+
+ if timed_out
+ filter.timeout_action.call
+ else
+ action.call message
+ end
+ end
+
+ # Notify this actor that it's now linked to the given one; this is not
+ # intended to be used directly except by actor implementations. Most
+ # users will want to use Actor.link instead.
+ #
+ def notify_link(actor)
+ @lock.receive
+ alive = nil
+ exit_reason = nil
+ begin
+ alive = @alive
+ exit_reason = @exit_reason
+ @links << actor if alive and not @links.include? actor
+ ensure
+ @lock << nil
+ end
+ actor.notify_exited(self, exit_reason) unless alive
+ self
+ end
+
+ # Notify this actor that it's now unlinked from the given one; this is
+ # not intended to be used directly except by actor implementations. Most
+ # users will want to use Actor.unlink instead.
+ #
+ def notify_unlink(actor)
+ @lock.receive
+ begin
+ return self unless @alive
+ @links.delete(actor)
+ ensure
+ @lock << nil
+ end
+ self
+ end
+
+ # Notify this actor that one of the Actors it's linked to has exited;
+ # this is not intended to be used directly except by actor implementations.
+ # Most users will want to use Actor.send_exit instead.
+ #
+ def notify_exited(actor, reason)
+ to_send = nil
+ @lock.receive
+ begin
+ return self unless @alive
+ @links.delete(actor)
+ ex = DeadActorError.new(actor, reason)
+ if @trap_exit
+ to_send = ex
+ elsif reason
+ @interrupts << ex
+ if @filter
+ @filter = nil
+ @ready << nil
+ end
+ end
+ ensure
+ @lock << nil
+ end
+ send to_send if to_send
+ self
+ end
+
+ def watchdog
+ reason = nil
+ begin
+ yield
+ rescue Exception => reason
+ ensure
+ links = nil
+ Actor._unregister(self)
+ @lock.receive
+ begin
+ @alive = false
+ @mailbox = nil
+ @interrupts = nil
+ @exit_reason = reason
+ links = @links
+ @links = nil
+ ensure
+ @lock << nil
+ end
+ links.each do |actor|
+ begin
+ actor.notify_exited(self, reason)
+ rescue Exception
+ end
+ end
+ end
+ end
+ private :watchdog
+
+ def check_thread
+ unless Thread.current == @thread
+ raise ThreadError, "illegal cross-actor call"
+ end
+ end
+ private :check_thread
+
+ def _trap_exit=(value) #:nodoc:
+ check_thread
+ @lock.receive
+ begin
+ raise @interrupts.shift unless @interrupts.empty?
+ @trap_exit = !!value
+ ensure
+ @lock << nil
+ end
+ end
+
+ def _trap_exit #:nodoc:
+ check_thread
+ @lock.receive
+ begin
+ @trap_exit
+ ensure
+ @lock << nil
+ end
+ end
+end
+
+require 'actor/filter'
View
68 lib/ruby/site_ruby/shared/rubinius/actor/filter.rb
@@ -0,0 +1,68 @@
+# actor/filter.rb - actor message filters
+#
+# Copyright 2007-2008 MenTaLguY <mental@rydia.net>
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# thi slist of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice
+# this list of conditions and the following disclaimer in the documentatio
+# and/or other materials provided with the distribution.
+# * Neither the name of the Evan Phoenix nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+class Actor
+class Filter
+ attr_reader :timeout
+ attr_reader :timeout_action
+
+ def initialize
+ @pairs = []
+ @timeout = nil
+ @timeout_action = nil
+ end
+
+ def timeout?
+ not @timeout.nil?
+ end
+
+ def when(pattern, &action)
+ raise ArgumentError, "no block given" unless action
+ @pairs.push [pattern, action]
+ self
+ end
+
+ def after(seconds, &action)
+ raise ArgumentError, "no block given" unless action
+
+ seconds = seconds.to_f
+ if !@timeout or seconds < @timeout
+ @timeout = seconds
+ @timeout_action = action
+ end
+ self
+ end
+
+ def action_for(value)
+ pair = @pairs.find { |pattern, action| pattern === value }
+ pair ? pair.last : nil
+ end
+end
+end
View
2 maven/jruby-complete/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>jruby-common</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
View
2 maven/jruby-core/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>jruby-common</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
View
2 maven/jruby-dist/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>shared</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
View
6 maven/jruby-rake-plugin/pom.xml
@@ -3,14 +3,14 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>shared</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jruby.plugins</groupId>
<artifactId>jruby-rake-plugin</artifactId>
<packaging>maven-plugin</packaging>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<name>JRuby Rake Plugin</name>
<dependencies>
<dependency>
@@ -31,7 +31,7 @@
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
</dependency>
</dependencies>
View
2 maven/jruby-stdlib/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>shared</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
View
2 maven/jruby/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>jruby-common</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
View
2 maven/pom.xml
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jruby</groupId>
<artifactId>shared</artifactId>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
View
2 pom.xml
@@ -5,7 +5,7 @@
<groupId>org.jruby</groupId>
<artifactId>shared</artifactId>
<packaging>pom</packaging>
- <version>1.6.1</version>
+ <version>1.7.0.dev</version>
<name>JRuby Shared</name>
<url>http://www.jruby.org/</url>
<description>A 1.8.7 compatible Ruby interpreter written in 100% pure Java</description>
View
BIN spec/regression/.JRUBY-5811_case_insensitive_loaded_features.rb.swp
Binary file not shown.
View
56 spec/regression/JRUBY-3194_autoload_thread_safety.rb
@@ -0,0 +1,56 @@
+require 'tempfile'
+require 'thread'
+
+describe 'JRUBY-3194: threaded autoload' do
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ end
+
+ if RUBY_VERSION >= "1.9.2"
+ # TODO: RubyModule#resolveUndefConstant() removes existing Constant in 1.8 mode for CRuby compatibility.
+ it 'should not raise for threaded autoload' do
+ file = Tempfile.open(['autoload', '.rb'])
+ file.puts 'sleep 0.5'
+ file.puts 'class Object; SpecRegressionJruby3194 = 1; end'
+ file.close
+ eval <<-END
+ class Object
+ autoload :SpecRegressionJruby3194, #{file.path.dump}
+ end
+ END
+ t1 = Thread.new {
+ Object::SpecRegressionJruby3194
+ }
+ t2 = Thread.new {
+ Object::SpecRegressionJruby3194
+ }
+ t1.join.value.should == 1
+ t2.join.value.should == 1
+ class Object
+ remove_const(:SpecRegressionJruby3194)
+ end
+ end
+ end
+
+ it 'should not raise recursive autoload' do
+ file = Tempfile.open(['autoload', '.rb'])
+ file.puts 'class Object; SpecRegressionJruby3194 = 1; end'
+ file.close
+ eval <<-END
+ class Object
+ autoload :SpecRegressionJruby3194, #{file.path.dump}
+ end
+ END
+ lambda {
+ (require file.path).should == true
+ SpecRegressionJruby3194.should == 1
+ }.should_not raise_error
+ class Object
+ remove_const(:SpecRegressionJruby3194)
+ end
+ end
+end
View
27 spec/regression/JRUBY-5811_case_insensitive_loaded_features.rb
@@ -0,0 +1,27 @@
+require 'tempfile'
+
+describe 'JRUBY-5811: jruby 1.9 fails to load irb' do
+ if RUBY_VERSION >= "1.9"
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace(@loaded_features)
+ end
+
+ it 'works' do
+ @file = Tempfile.open(['dummy', '.rb'])
+ @file.close
+ if File.exist?(@file.path.upcase)
+ org_size = $".size
+ require @file.path.downcase
+ (require @file.path.upcase).should == false
+ (require @file.path.capitalize).should == false
+ $".size.should == org_size + 1
+ else
+ File.exist?(@file.path.upcase).should be_false
+ end
+ end
+ end
+end
View
2 spec/tags/1.8/ruby/core/string/scan_tags.txt
@@ -1,2 +0,0 @@
-fails(JRUBY-5665):String#scan taints the results if the String argument is tainted
-fails(JRUBY-5665):String#scan with pattern and block taints the results if the String argument is tainted
View
1 spec/tags/1.9/ruby/core/string/gsub_tags.txt
@@ -1 +0,0 @@
-fails(JRUBY-4587):String#gsub with pattern and replacement respects $KCODE when the pattern collapses
View
3 spec/tags/1.9/ruby/core/string/scan_tags.txt
@@ -1,3 +0,0 @@
-fails(JRUBY-4587):String#scan respects $KCODE when the pattern collapses to nothing
-fails(JRUBY-5665):String#scan taints the results if the String argument is tainted
-fails(JRUBY-5665):String#scan with pattern and block taints the results if the String argument is tainted
View
1 spec/tags/1.9/ruby/core/string/split_tags.txt
@@ -1 +0,0 @@
-fails(JRUBY-4587):String#split with Regexp respects $KCODE when splitting between characters
View
34 src/org/jruby/Ruby.java
@@ -130,6 +130,8 @@
import org.jruby.RubyInstanceConfig.CompileMode;
import org.jruby.ast.RootNode;
import org.jruby.ast.executable.RuntimeCache;
+import org.jruby.runtime.opto.ObjectIdentityInvalidator;
+import org.jruby.runtime.opto.Invalidator;
import org.jruby.evaluator.ASTInterpreter;
import org.jruby.exceptions.Unrescuable;
import org.jruby.internal.runtime.methods.DynamicMethod;
@@ -143,6 +145,7 @@
import org.jruby.runtime.load.BasicLibraryService;
import org.jruby.threading.DaemonThreadFactory;
import org.jruby.util.io.SelectorPool;
+import org.objectweb.asm.Opcodes;
/**
* The Ruby object represents the top-level of a JRuby "instance" in a given VM.
@@ -279,6 +282,20 @@ private Ruby(RubyInstanceConfig config) {
this.runtimeCache = new RuntimeCache();
runtimeCache.initMethodCache(ClassIndex.MAX_CLASSES * MethodIndex.MAX_METHODS);
+
+ Invalidator myConstantInvalidator;
+ if (RubyInstanceConfig.JAVA_VERSION == Opcodes.V1_7) {
+ try {
+ myConstantInvalidator = (Invalidator)Class.forName("org.jruby.runtime.opto.SwitchPointInvalidator").newInstance();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ // ignore
+ myConstantInvalidator = new ObjectIdentityInvalidator();
+ }
+ constantInvalidator = myConstantInvalidator;
+ } else {
+ constantInvalidator = new ObjectIdentityInvalidator();
+ }
}
/**
@@ -2777,6 +2794,8 @@ public void tearDown(boolean systemExit) {
getBeanManager().unregisterClassCache();
getBeanManager().unregisterMethodCache();
+ getSelectorPool().cleanup();
+
if (getJRubyClassLoader() != null) {
getJRubyClassLoader().tearDown(isDebug());
}
@@ -3666,12 +3685,22 @@ public ExecutorService getExecutor() {
return timeZoneCache;
}
+ @Deprecated
public int getConstantGeneration() {
- return constantGeneration;
+ return -1;
}
+ @Deprecated
public synchronized void incrementConstantGeneration() {
- constantGeneration++;
+ constantInvalidator.invalidate();
+ }
+
+ public Invalidator getConstantInvalidator() {
+ return constantInvalidator;
+ }
+
+ public void invalidateConstants() {
+
}
public <E extends Enum<E>> void loadConstantSet(RubyModule module, Class<E> enumClass) {
@@ -3867,6 +3896,7 @@ public void setRubinius(boolean rubinius) {
}
private volatile int constantGeneration = 1;
+ private final Invalidator constantInvalidator;
private final ThreadService threadService;
private POSIX posix;
View
2 src/org/jruby/RubyException.java
@@ -82,7 +82,7 @@ public RubyException(Ruby runtime, RubyClass rubyClass, String message) {
this.message = message == null ? runtime.getNil() : runtime.newString(message);
}
- private static ObjectAllocator EXCEPTION_ALLOCATOR = new ObjectAllocator() {
+ public static ObjectAllocator EXCEPTION_ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
RubyException instance = new RubyException(runtime, klass);
View
2 src/org/jruby/RubyInstanceConfig.java
@@ -359,7 +359,7 @@ public LoadService create(Ruby runtime) {
// stack map calculation is failing for some compilation scenarios, so
// forcing both 1.5 and 1.6 to use 1.5 bytecode for the moment.
- if (specVersion.equals("1.5") || specVersion.equals("1.6")) {
+ if (specVersion.equals("1.5")) {// || specVersion.equals("1.6")) {
JAVA_VERSION = Opcodes.V1_5;
} else if (specVersion.equals("1.6")) {
JAVA_VERSION = Opcodes.V1_6;
View
8 src/org/jruby/RubyKernel.java
@@ -204,8 +204,9 @@ public String file() {
* @see org.jruby.runtime.load.IAutoloadMethod#load(Ruby, String)
*/
public IRubyObject load(Ruby runtime, String name) {
- boolean required = loadService.require(file());
-
+ boolean required = loadService.autoloadRequire(file());
+ loadService.removeAutoLoadFor(name);
+
// File to be loaded by autoload has already been or is being loaded.
if (!required) return null;
@@ -1297,7 +1298,8 @@ public static IRubyObject warn(ThreadContext context, IRubyObject recv, IRubyObj
if (runtime.warningsEnabled()) {
IRubyObject out = runtime.getGlobalVariables().get("$stderr");
- RuntimeHelpers.invoke(context, out, "puts", message);
+ RuntimeHelpers.invoke(context, out, "write", message);
+ RuntimeHelpers.invoke(context, out, "write", runtime.getGlobalVariables().getDefaultSeparator());
}
return runtime.getNil();
}
View
2 src/org/jruby/RubyModule.java
@@ -1038,7 +1038,7 @@ protected void invalidateCacheDescendantsInner() {
}
protected void invalidateConstantCache() {
- getRuntime().incrementConstantGeneration();
+ getRuntime().getConstantInvalidator().invalidate();
}
/**
View
9 src/org/jruby/RubyString.java
@@ -4632,7 +4632,12 @@ public IRubyObject scan(ThreadContext context, IRubyObject arg, Block block) {
tuFlags = regex.flags;
} else {
pattern = getStringPattern(runtime, enc, arg);
- tuFlags = 0;
+ if (arg.isTaint()) {
+ tuFlags = RubyBasicObject.TAINTED_F;
+ }
+ else {
+ tuFlags = 0;
+ }
}
int begin = value.getBegin();
@@ -4749,7 +4754,7 @@ public IRubyObject scan19(ThreadContext context, IRubyObject arg, Block block) {
prepared = regexp.preparePattern(this);
} else {
regexp = null;
- tuFlags = 0;
+ tuFlags = arg.isTaint() ? RubyBasicObject.TAINTED_F : 0;
pattern = getStringPattern19(runtime, arg);
prepared = RubyRegexp.preparePattern(runtime, pattern, this);
}
View
6 src/org/jruby/ast/Colon2ConstNode.java
@@ -21,7 +21,7 @@
*/
public class Colon2ConstNode extends Colon2Node {
private volatile transient IRubyObject cachedValue = null;
- private volatile int generation = -1;
+ private volatile Object generation = -1;
private volatile int hash = -1;
public Colon2ConstNode(ISourcePosition position, Node leftNode, String name) {
@@ -61,12 +61,12 @@ private boolean isCached(ThreadContext context, RubyModule target, IRubyObject v
// We could probably also detect if LHS value came out of cache and avoid some of this
return
value != null &&
- generation == context.getRuntime().getConstantGeneration() &&
+ generation == context.getRuntime().getConstantInvalidator().getData() &&
hash == target.hashCode();
}
public IRubyObject reCache(ThreadContext context, RubyModule target) {
- int newGeneration = context.getRuntime().getConstantGeneration();
+ Object newGeneration = context.getRuntime().getConstantInvalidator().getData();
IRubyObject value = target.fastGetConstantFromNoConstMissing(name);
cachedValue = value;
View
6 src/org/jruby/ast/Colon3Node.java
@@ -51,7 +51,7 @@
public class Colon3Node extends Node implements INameNode {
protected String name;
private volatile transient IRubyObject cachedValue;
- private volatile int generation;
+ private volatile Object generation;
public Colon3Node(ISourcePosition position, String name) {
super(position);
@@ -130,12 +130,12 @@ public IRubyObject getValue(ThreadContext context) {
}
private boolean isCached(ThreadContext context, IRubyObject value) {
- return value != null && generation == context.getRuntime().getConstantGeneration();
+ return value != null && generation == context.getRuntime().getConstantInvalidator().getData();
}
public IRubyObject reCache(ThreadContext context, String name) {
Ruby runtime = context.getRuntime();
- int newGeneration = runtime.getConstantGeneration();
+ Object newGeneration = runtime.getConstantInvalidator().getData();
IRubyObject value = runtime.getObject().fastGetConstantFromNoConstMissing(name);
cachedValue = value;
View
6 src/org/jruby/ast/ConstNode.java
@@ -48,7 +48,7 @@
public class ConstNode extends Node implements INameNode {
private String name;
private volatile transient IRubyObject cachedValue = null;
- private int generation = -1;
+ private Object generation = -1;
public ConstNode(ISourcePosition position, String name) {
super(position);
@@ -104,11 +104,11 @@ public IRubyObject getValue(ThreadContext context) {
}
private boolean isCached(ThreadContext context, IRubyObject value) {
- return value != null && generation == context.getRuntime().getConstantGeneration();
+ return value != null && generation == context.getRuntime().getConstantInvalidator().getData();
}
public IRubyObject reCache(ThreadContext context, String name) {
- int newGeneration = context.getRuntime().getConstantGeneration();
+ Object newGeneration = context.getRuntime().getConstantInvalidator().getData();
IRubyObject value = context.getConstant(name);
cachedValue = value;
View
13 src/org/jruby/ast/executable/RuntimeCache.java
@@ -363,7 +363,7 @@ public final void initBigIntegers(int size) {
public final void initConstants(int size) {
constants = new IRubyObject[size];
constantTargetHashes = new int[size];
- constantGenerations = new int[size];
+ constantGenerations = new Object[size];
Arrays.fill(constantGenerations, -1);
Arrays.fill(constantTargetHashes, -1);
}
@@ -395,11 +395,11 @@ public IRubyObject getValue(ThreadContext context, String name, int index) {
}
private boolean isCached(ThreadContext context, IRubyObject value, int index) {
- return value != null && constantGenerations[index] == context.getRuntime().getConstantGeneration();
+ return value != null && constantGenerations[index] == context.getRuntime().getConstantInvalidator().getData();
}
public IRubyObject reCache(ThreadContext context, String name, int index) {
- int newGeneration = context.getRuntime().getConstantGeneration();
+ Object newGeneration = context.getRuntime().getConstantInvalidator().getData();
IRubyObject value = context.getConstant(name);
constants[index] = value;
if (value != null) {
@@ -420,11 +420,11 @@ public IRubyObject getValueFrom(RubyModule target, ThreadContext context, String
}
private boolean isCachedFrom(RubyModule target, ThreadContext context, IRubyObject value, int index) {
- return value != null && constantGenerations[index] == context.getRuntime().getConstantGeneration() && constantTargetHashes[index] == target.hashCode();
+ return value != null && constantGenerations[index] == context.getRuntime().getConstantInvalidator().getData() && constantTargetHashes[index] == target.hashCode();
}
public IRubyObject reCacheFrom(RubyModule target, ThreadContext context, String name, int index) {
- int newGeneration = context.getRuntime().getConstantGeneration();
+ Object newGeneration = context.getRuntime().getConstantInvalidator().getData();
IRubyObject value = target.fastGetConstantFromNoConstMissing(name);
constants[index] = value;
if (value != null) {
@@ -654,6 +654,7 @@ private CacheEntry getCacheEntry(int index) {
public VariableAccessor[] variableWriters = EMPTY_VARIABLE_ACCESSORS;
public IRubyObject[] constants = IRubyObject.NULL_ARRAY;
private static final int[] EMPTY_INTS = {};
- public int[] constantGenerations = EMPTY_INTS;
+ private static final Object[] EMPTY_OBJS = {};
+ public Object[] constantGenerations = EMPTY_OBJS;
public int[] constantTargetHashes = EMPTY_INTS;
}
View
2 src/org/jruby/compiler/impl/BaseBodyCompiler.java
@@ -774,7 +774,7 @@ public void createNewLambda(CompilerCallback closure) {
/**
* Invoke IRubyObject.isTrue
*/
- private void isTrue() {
+ public void isTrue() {
invokeIRubyObject("isTrue", sig(Boolean.TYPE));
}
View
3 src/org/jruby/compiler/impl/ChildScopedBodyCompiler.java
@@ -103,8 +103,7 @@ public void loadBlock() {
public void performReturn() {
loadThreadContext();
- invokeUtilityMethod("returnJump", sig(JumpException.ReturnJump.class, IRubyObject.class, ThreadContext.class));
- method.athrow();
+ invokeUtilityMethod("throwReturnJump", sig(IRubyObject.class, IRubyObject.class, ThreadContext.class));
}
public void issueBreakEvent(CompilerCallback value) {
View
3 src/org/jruby/compiler/impl/ClassBodyCompiler.java
@@ -27,8 +27,7 @@ public void beginMethod(CompilerCallback bodyPrep, StaticScope scope) {
public void performReturn() {
// return in a class body raises error
loadThreadContext();
- invokeUtilityMethod("returnJump", sig(JumpException.ReturnJump.class, IRubyObject.class, ThreadContext.class));
- method.athrow();
+ invokeUtilityMethod("throwReturnJump", sig(IRubyObject.class, IRubyObject.class, ThreadContext.class));
}
public boolean isSimpleRoot() {
View
29 src/org/jruby/compiler/impl/InheritedCacheCompiler.java
@@ -1,8 +1,29 @@
/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
+ ***** BEGIN LICENSE BLOCK *****
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Common Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the CPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the CPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
package org.jruby.compiler.impl;
import java.math.BigInteger;
View
46 src/org/jruby/compiler/impl/InvokeDynamicCacheCompiler.java
@@ -0,0 +1,46 @@
+/*
+ ***** BEGIN LICENSE BLOCK *****
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Common Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the CPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the CPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
+package org.jruby.compiler.impl;
+
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.runtime.invokedynamic.InvokeDynamicSupport;
+import static org.jruby.util.CodegenUtils.*;
+
+public class InvokeDynamicCacheCompiler extends InheritedCacheCompiler {
+ public InvokeDynamicCacheCompiler(StandardASMCompiler scriptCompiler) {
+ super(scriptCompiler);
+ }
+
+ public void cacheConstant(BaseBodyCompiler method, String constantName) {
+ method.loadThreadContext();
+ method.method.invokedynamic(
+ constantName,
+ sig(IRubyObject.class, ThreadContext.class),
+ InvokeDynamicSupport.getConstantHandle());
+ }
+}
View
23 src/org/jruby/compiler/impl/InvokeDynamicInvocationCompiler.java
@@ -29,6 +29,7 @@
package org.jruby.compiler.impl;
import org.jruby.compiler.ArgumentsCallback;
+import org.jruby.compiler.BodyCompiler;
import org.jruby.compiler.CompilerCallback;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallType;
@@ -127,4 +128,26 @@ public void invokeDynamic(String name, CompilerCallback receiverCallback, Argume
// adapter, tc, recv, args{0,1}, block{0,1}]
method.invokedynamic(invokeName, signature, InvokeDynamicSupport.bootstrapHandle());
}
+
+ @Override
+ public void invokeEqq(ArgumentsCallback receivers, final CompilerCallback argument) {
+ if (argument == null) {
+ super.invokeEqq(receivers, argument);
+ } else {
+ if (receivers.getArity() == 1) {
+ invokeDynamic("===", receivers, new ArgumentsCallback() {
+ public int getArity() {
+ return 1;
+ }
+
+ public void call(BodyCompiler context) {
+ argument.call(context);
+ }
+ }, CallType.FUNCTIONAL, null, false);
+ methodCompiler.isTrue();
+ } else {
+ super.invokeEqq(receivers, argument);
+ }
+ }
+ }
}
View
3 src/org/jruby/compiler/impl/MethodBodyCompiler.java
@@ -119,8 +119,7 @@ public void performReturn() {
// normal return for method body. return jump for within a begin/rescue/ensure
if (inNestedMethod) {
loadThreadContext();
- invokeUtilityMethod("returnJump", sig(JumpException.ReturnJump.class, IRubyObject.class, ThreadContext.class));
- method.athrow();
+ invokeUtilityMethod("throwReturnJump", sig(IRubyObject.class, IRubyObject.class, ThreadContext.class));
} else {
method.areturn();
}
View
3 src/org/jruby/compiler/impl/RootScopedBodyCompiler.java
@@ -116,8 +116,7 @@ public void performReturn() {
// normal return for method body. return jump for within a begin/rescue/ensure
if (inNestedMethod) {
loadThreadContext();
- invokeUtilityMethod("returnJump", sig(JumpException.ReturnJump.class, IRubyObject.class, ThreadContext.class));
- method.athrow();
+ invokeUtilityMethod("throwReturnJump", sig(IRubyObject.class, IRubyObject.class, ThreadContext.class));
} else {
method.areturn();
}
View
29 src/org/jruby/compiler/impl/StandardASMCompiler.java
@@ -177,13 +177,15 @@ public static String getClosure19Signature() {
private CacheCompiler cacheCompiler;
public static final Constructor invDynInvCompilerConstructor;
+ public static final Constructor invDynCacheCompilerConstructor;
private List<InvokerDescriptor> invokerDescriptors = new ArrayList<InvokerDescriptor>();
private List<BlockCallbackDescriptor> blockCallbackDescriptors = new ArrayList<BlockCallbackDescriptor>();
private List<BlockCallbackDescriptor> blockCallback19Descriptors = new ArrayList<BlockCallbackDescriptor>();
static {
- Constructor compilerConstructor = null;
+ Constructor invCompilerConstructor = null;
+ Constructor cacheCompilerConstructor = null;
try {
if (RubyInstanceConfig.USE_INVOKEDYNAMIC) {
// attempt to access an invokedynamic-related class
@@ -192,14 +194,16 @@ public static String getClosure19Signature() {
// if that succeeds, use invokedynamic compiler stuff
Class compiler =
Class.forName("org.jruby.compiler.impl.InvokeDynamicInvocationCompiler");
- Class support =
- Class.forName("org.jruby.runtime.invokedynamic.InvokeDynamicSupport");
- compilerConstructor = compiler.getConstructor(BaseBodyCompiler.class, SkinnyMethodAdapter.class);
+ invCompilerConstructor = compiler.getConstructor(BaseBodyCompiler.class, SkinnyMethodAdapter.class);
+ compiler =
+ Class.forName("org.jruby.compiler.impl.InvokeDynamicCacheCompiler");
+ cacheCompilerConstructor = compiler.getConstructor(StandardASMCompiler.class);
}
} catch (Exception e) {
// leave it null and fall back on our normal invocation logic
}
- invDynInvCompilerConstructor = compilerConstructor;
+ invDynInvCompilerConstructor = invCompilerConstructor;
+ invDynCacheCompilerConstructor = cacheCompilerConstructor;
}
/** Creates a new instance of StandardCompilerContext */
@@ -452,7 +456,20 @@ public void startScript(StaticScope scope) {
beginInit();
- cacheCompiler = new InheritedCacheCompiler(this);
+ if (invDynCacheCompilerConstructor != null) {
+ try {
+ cacheCompiler = (CacheCompiler)StandardASMCompiler.invDynCacheCompilerConstructor.newInstance(this);
+ } catch (InstantiationException ie) {
+ // do nothing, fall back on default compiler below
+ } catch (IllegalAccessException ie) {
+ // do nothing, fall back on default compiler below
+ } catch (InvocationTargetException ie) {
+ // do nothing, fall back on default compiler below
+ }
+ }
+ if (invDynCacheCompilerConstructor == null) {
+ cacheCompiler = new InheritedCacheCompiler(this);
+ }
// This code was originally used to provide debugging info using JSR-45
// "SMAP" format. However, it breaks using normal Java traces to
View
5 src/org/jruby/embed/osgi/internal/OSGiBundlesSearcher.java
@@ -27,7 +27,6 @@
***** END LICENSE BLOCK *****/
package org.jruby.embed.osgi.internal;
-import org.jruby.runtime.load.LoadService.AlreadyLoaded;
import org.jruby.runtime.load.LoadService.LoadSearcher;
import org.jruby.runtime.load.LoadService.SearchState;
@@ -48,8 +47,8 @@ public boolean shouldTrySearch(SearchState state) {
/* (non-Javadoc)
* @see org.jruby.runtime.load.LoadService.LoadSearcher#trySearch(org.jruby.runtime.load.LoadService.SearchState)
*/
- public void trySearch(SearchState state) throws AlreadyLoaded {
-
+ public boolean trySearch(SearchState state) {
+ return true;
}
}
View
2 src/org/jruby/embed/variable/Argv.java
@@ -132,7 +132,7 @@ public void inject() {
if (rubyModule == null) return;
rubyModule.storeConstant(name, irubyObject);
- receiver.getRuntime().incrementConstantGeneration();
+ receiver.getRuntime().getConstantInvalidator().invalidate();
fromRuby = true;
}
View
2 src/org/jruby/embed/variable/Constant.java
@@ -222,10 +222,10 @@ public void inject() {
if (rubyModule == null) return;
rubyModule.storeConstant(name, irubyObject);
- receiver.getRuntime().incrementConstantGeneration();
} else {
receiver.getMetaClass().storeConstant(name, irubyObject);
}
+ receiver.getRuntime().getConstantInvalidator().invalidate();
initialized = true;
}
View
3 src/org/jruby/ext/ffi/StructLayout.java
@@ -935,8 +935,9 @@ public IRubyObject to_ptr(ThreadContext context) {
@JRubyMethod(name = { "size" })
public IRubyObject size(ThreadContext context) {
- return context.getRuntime().newFixnum(arrayType.getNativeSize());
+ return arrayType.length(context);
}
+
/**
* Needed for Enumerable implementation
*/
View
3 src/org/jruby/ext/psych/PsychParser.java
@@ -36,6 +36,7 @@
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
+import org.jruby.RubyException;
import org.jruby.RubyKernel;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
@@ -81,7 +82,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
psychParser.defineAnnotatedMethods(PsychParser.class);
- psych.defineClassUnder("SyntaxError", runtime.getSyntaxError(), OBJECT_ALLOCATOR);
+ psych.defineClassUnder("SyntaxError", runtime.getSyntaxError(), RubyException.EXCEPTION_ALLOCATOR);
}
public PsychParser(Ruby runtime, RubyClass klass) {
View
4 src/org/jruby/javasupport/util/RuntimeHelpers.java
@@ -961,6 +961,10 @@ public static IRubyObject callZSuper(Ruby runtime, ThreadContext context, Block
return context.returnJump(result);
}
+ public static IRubyObject throwReturnJump(IRubyObject result, ThreadContext context) {
+ throw context.returnJump(result);
+ }
+
public static IRubyObject breakJumpInWhile(JumpException.BreakJump bj, ThreadContext context) {
// JRUBY-530, while case
if (bj.getTarget() == context.getFrameJumpTarget()) {
View
13 src/org/jruby/runtime/ThreadContext.java
@@ -40,9 +40,7 @@
import org.jruby.runtime.profile.IProfileData;
import java.util.ArrayList;
import org.jruby.runtime.profile.ProfileData;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.jruby.runtime.scope.ManyVarsDynamicScope;
import org.jruby.Ruby;
@@ -53,8 +51,6 @@
import org.jruby.RubyString;
import org.jruby.RubyThread;
import org.jruby.ast.executable.RuntimeCache;
-import org.jruby.compiler.JITCompiler;
-import org.jruby.evaluator.ASTInterpreter;
import org.jruby.exceptions.JumpException.ReturnJump;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.libraries.FiberLibrary.Fiber;
@@ -63,7 +59,6 @@
import org.jruby.parser.StaticScope;
import org.jruby.runtime.backtrace.TraceType.Gather;
import org.jruby.runtime.builtin.IRubyObject;
-import org.jruby.util.JavaNameMangler;
public final class ThreadContext {
public static ThreadContext newContext(Ruby runtime) {
@@ -685,13 +680,13 @@ private static void addBackTraceElement(Ruby runtime, RubyArray backtrace, RubyS
public IRubyObject createCallerBacktrace(Ruby runtime, int level) {
runtime.incrementCallerCount();
RubyStackTraceElement[] trace = gatherCallerBacktrace(level);
- RubyArray backtrace = runtime.newArray(trace.length - level);
+ RubyArray newTrace = runtime.newArray(trace.length - level);
for (int i = level; i < trace.length; i++) {
- addBackTraceElement(runtime, backtrace, trace[i]);
+ addBackTraceElement(runtime, newTrace, trace[i]);
}
- return backtrace;
+ return newTrace;
}
public RubyStackTraceElement[] gatherCallerBacktrace(int level) {
@@ -764,7 +759,7 @@ private static String createRubyBacktraceString(StackTraceElement element) {
public static String createRawBacktraceStringFromThrowable(Throwable t) {
StackTraceElement[] javaStackTrace = t.getStackTrace();
- StringBuffer buffer = new StringBuffer();
+ StringBuilder buffer = new StringBuilder();
if (javaStackTrace != null && javaStackTrace.length > 0) {
StackTraceElement element = javaStackTrace[0];
View
89 src/org/jruby/runtime/invokedynamic/InvokeDynamicSupport.java
@@ -5,7 +5,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
-import java.util.Arrays;
+import java.lang.invoke.SwitchPoint;
import java.util.Comparator;
import org.jruby.RubyBasicObject;
import org.jruby.RubyClass;
@@ -31,8 +31,9 @@
@SuppressWarnings("deprecation")
public class InvokeDynamicSupport {
- private static final int MAX_FAIL_COUNT = SafePropertyAccessor.getInt("jruby.compile.invokedynamic.maxfail", 2);
+ private static final int MAX_FAIL_COUNT = SafePropertyAccessor.getInt("jruby.invokedynamic.maxfail", 2);
private static final boolean LOG_INDY_BINDINGS = SafePropertyAccessor.getBoolean("jruby.invokedynamic.log.binding");
+ private static final boolean LOG_INDY_CONSTANTS = SafePropertyAccessor.getBoolean("jruby.invokedynamic.log.constants");
public static class JRubyCallSite extends MutableCallSite {
private final CallType callType;
@@ -50,6 +51,19 @@ public CallType callType() {
return callType;
}
}
+
+ public static class RubyConstantCallSite extends MutableCallSite {
+ private final String name;
+
+ public RubyConstantCallSite(MethodType type, String name) {
+ super(type);
+ this.name = name;
+ }
+
+ public String name() {
+ return name;
+ }
+ }
public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
JRubyCallSite site;
@@ -69,13 +83,60 @@ public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, Metho
site.setTarget(myFallback);
return site;
}
+
+ public static CallSite getConstantBootstrap(MethodHandles.Lookup lookup, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ RubyConstantCallSite site;
+
+ site = new RubyConstantCallSite(type, name);
+
+ MethodType fallbackType = type.insertParameterTypes(0, RubyConstantCallSite.class);
+ MethodHandle myFallback = MethodHandles.insertArguments(
+ lookup.findStatic(InvokeDynamicSupport.class, "constantFallback",
+ fallbackType),
+ 0,
+ site);
+ site.setTarget(myFallback);
+ return site;
+ }
+
+ public static IRubyObject constantFallback(RubyConstantCallSite site,
+ ThreadContext context) {
+ IRubyObject value = context.getConstant(site.name());
+
+ if (value != null) {
+ if (LOG_INDY_CONSTANTS) System.out.println("binding constant " + site.name() + " with invokedynamic");
+
+ MethodHandle valueHandle = MethodHandles.constant(IRubyObject.class, value);
+ valueHandle = MethodHandles.dropArguments(valueHandle, 0, ThreadContext.class);
+
+ MethodHandle fallback = MethodHandles.insertArguments(
+ findStatic(InvokeDynamicSupport.class, "constantFallback",
+ MethodType.methodType(IRubyObject.class, RubyConstantCallSite.class, ThreadContext.class)),
+ 0,
+ site);
+
+ SwitchPoint switchPoint = (SwitchPoint)context.runtime.getConstantInvalidator().getData();
+ MethodHandle gwt = switchPoint.guardWithTest(valueHandle, fallback);
+ site.setTarget(gwt);
+ } else {
+ value = context.getCurrentScope().getStaticScope().getModule()
+ .callMethod(context, "const_missing", context.getRuntime().fastNewSymbol(site.name()));
+ }
+
+ return value;
+ }
public final static MethodType BOOTSTRAP_SIGNATURE = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
public final static String BOOTSTRAP_SIGNATURE_DESC = sig(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
+ public final static String GETCONSTANT_SIGNATURE_DESC = sig(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
public static org.objectweb.asm.MethodHandle bootstrapHandle() {
return new org.objectweb.asm.MethodHandle(Opcodes.MH_INVOKESTATIC, p(InvokeDynamicSupport.class), "bootstrap", BOOTSTRAP_SIGNATURE_DESC);
}
+
+ public static org.objectweb.asm.MethodHandle getConstantHandle() {
+ return new org.objectweb.asm.MethodHandle(Opcodes.MH_INVOKESTATIC, p(InvokeDynamicSupport.class), "getConstantBootstrap", GETCONSTANT_SIGNATURE_DESC);
+ }
private static MethodHandle createGWT(String name, MethodHandle test, MethodHandle target, MethodHandle fallback, CacheEntry entry, JRubyCallSite site) {
return createGWT(name, test, target, fallback, entry, site, true);
@@ -668,7 +729,6 @@ private static MethodHandle createAttrGWT(
// if (LOG_INDY_BINDINGS) System.out.println("binding attr target: " + site.name());
MethodHandle target = creatAttrHandle(entry.method);
- System.out.println(target);
MethodHandle myTest = MethodHandles.insertArguments(test, 0, entry.token);
MethodHandle myTarget = target;
@@ -803,7 +863,8 @@ public static IRubyObject fallback(JRubyCallSite site,
return callMethodMissing(entry, site.callType(), context, self, name);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
+ if (LOG_INDY_BINDINGS) System.out.println("failing over to inline cache for '" + name + "' call");
site.setTarget(createFail(FAIL_0, site));
} else {
// if (entry.method instanceof AttrReaderMethod) {
@@ -838,7 +899,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, arg0);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_1, site));
} else {
if (site.getTarget() != null) {
@@ -857,7 +918,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_2, site));
} else {
if (site.getTarget() != null) {
@@ -876,7 +937,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1, arg2);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_3, site));
} else {
if (site.getTarget() != null) {
@@ -895,7 +956,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, args);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_N, site));
} else {
if (site.getTarget() != null) {
@@ -916,7 +977,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, block);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_0_B, site));
} else {
if (site.getTarget() != null) {
@@ -943,7 +1004,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, arg0, block);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_1_B, site));
} else {
if (site.getTarget() != null) {
@@ -970,7 +1031,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1, block);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_2_B, site));
} else {
if (site.getTarget() != null) {
@@ -997,7 +1058,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1, arg2, block);
}
- if (site.failCount++ > MAX_FAIL_COUNT) {
+ if (++site.failCount > MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_3_B, site));
} else {
if (site.getTarget() != null) {
@@ -1024,7 +1085,7 @@ public static IRubyObject fallback(JRubyCallSite site, ThreadContext context, IR
if (methodMissing(entry, site.callType(), name, caller)) {
return callMethodMissing(entry, site.callType(), context, self, name, args, block);
}
- if (site.failCount++ >= MAX_FAIL_COUNT) {
+ if (++site.failCount >= MAX_FAIL_COUNT) {
site.setTarget(createFail(FAIL_N_B, site));
} else {
if (site.getTarget() != null) {
@@ -1787,4 +1848,4 @@ private static MethodHandle findVirtual(Class target, String name, MethodType ty
// } finally {
// block.escape();
// }
-// }
+// }
View
229 src/org/jruby/runtime/load/LoadService.java
@@ -164,8 +164,6 @@
protected final Map<String, IAutoloadMethod> autoloadMap = new HashMap<String, IAutoloadMethod>();
protected final Ruby runtime;
-
- protected boolean caseInsensitiveFS = false;
public LoadService(Ruby runtime) {
this.runtime = runtime;
@@ -180,21 +178,7 @@ public void init(List additionalDirectories) {
loadPath = RubyArray.newArray(runtime);
String jrubyHome = runtime.getJRubyHome();
- if (jrubyHome != null) {
- String lowerCaseJRubyHome = jrubyHome.toLowerCase();
- String upperCaseJRubyHome = lowerCaseJRubyHome.toUpperCase();
-
- try {
- String canonNormal = new File(jrubyHome).getCanonicalPath();
- String canonLower = new File(lowerCaseJRubyHome).getCanonicalPath();
- String canonUpper = new File(upperCaseJRubyHome).getCanonicalPath();
- if (canonNormal.equals(canonLower) && canonLower.equals(canonUpper)) {
- caseInsensitiveFS = true;
- }
- } catch (Exception e) {}
- }
-
- loadedFeatures = new StringArraySet(runtime, caseInsensitiveFS);
+ loadedFeatures = new StringArraySet(runtime);
// add all startup load paths to the list first
for (Iterator iter = additionalDirectories.iterator(); iter.hasNext();) {
@@ -240,8 +224,8 @@ public void init(List additionalDirectories) {
}
}
- protected void addLoadedFeature(RubyString loadNameRubyString) {
- loadedFeatures.append(loadNameRubyString);
+ protected void addLoadedFeature(String name) {
+ loadedFeatures.append(RubyString.newString(runtime, name));
}
protected void addPath(String path) {
@@ -255,7 +239,7 @@ protected void addPath(String path) {
public void load(String file, boolean wrap) {
if(!runtime.getProfile().allowLoad(file)) {
- throw runtime.newLoadError("No such file to load -- " + file);
+ throw runtime.newLoadError("no such file to load -- " + file);
}
SearchState state = new SearchState(file);
@@ -267,7 +251,7 @@ public void load(String file, boolean wrap) {
if (library == null) {
library = findLibraryWithClassloaders(state, state.searchFile, state.suffixType);
if (library == null) {
- throw runtime.newLoadError("No such file to load -- " + file);
+ throw runtime.newLoadError("no such file to load -- " + file);
}
}
try {
@@ -278,15 +262,25 @@ public void load(String file, boolean wrap) {
}
}
- public SearchState findFileForLoad(String file) throws AlreadyLoaded {
+ public SearchState findFileForLoad(String file) {
+ if (Platform.IS_WINDOWS) {
+ file = file.replace('\\', '/');
+ }
+ // Even if we don't support .so, some stdlib require .so directly.
+ // Replace it with .jar to look for a java extension
+ // JRUBY-5033: The ExtensionSearcher will locate C exts, too, this way.
+ if (file.endsWith(".so")) {
+ file = file.replaceAll(".so$", ".jar");
+ }
+
SearchState state = new SearchState(file);
state.prepareRequireSearch(file);
for (LoadSearcher searcher : searchers) {
if (searcher.shouldTrySearch(state)) {
- searcher.trySearch(state);
- } else {
- continue;
+ if (!searcher.trySearch(state)) {
+ return null;
+ }
}
}
@@ -294,43 +288,71 @@ public SearchState findFileForLoad(String file) throws AlreadyLoaded {
}
public boolean require(String requireName) {
- ReentrantLock requireLock;
- synchronized (requireLocks) {
- requireLock = requireLocks.get(requireName);
+ return requireCommon(requireName, true) == RequireState.LOADED;
+ }
+
+ public boolean autoloadRequire(String requireName) {
+ return requireCommon(requireName, false) != RequireState.CIRCULAR;
+ }
+
+ private enum RequireState {
+ LOADED, ALREADY_LOADED, CIRCULAR
+ };
+
+ private RequireState requireCommon(String requireName, boolean circularRequireWarning) {
+ ReentrantLock requireLock = null;
+ try {
+ requireLock = acquireRequireLock(requireName);