Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f82f1367a4d5
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 79f088969287
Choose a head ref
  • 3 commits
  • 5 files changed
  • 1 contributor

Commits on Feb 27, 2015

  1. Contract of ClassValue states it should only calculate once.

    This appears to help avoid issues with multiple or partially-
    initialized proxies as in #2014.
    headius committed Feb 27, 2015
    Copy the full SHA
    44895a5 View commit details
  2. Copy the full SHA
    6631b88 View commit details
  3. Cleanup, reduce duplication, refactor methods for proxy creation.

    * Java.getProxyClass is the one true way to get the Ruby proxy
      class for a Java class.
    * Unified more of class vs interface proxy logic.
    * Both #1621 and #2014 appear to be working with this commit.
    headius committed Feb 27, 2015
    Copy the full SHA
    79f0889 View commit details
64 changes: 31 additions & 33 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -398,25 +398,7 @@ public static RubyModule getInterfaceModule(final Ruby runtime, final JavaClass
}

public static RubyModule getInterfaceModule(final Ruby runtime, final Class javaClass) {
if ( ! javaClass.isInterface() ) {
throw runtime.newArgumentError(javaClass.toString() + " is not an interface");
}

RubyModule proxyModule = runtime.getJavaSupport().getUnfinishedProxyClassCache().get(javaClass).get();

if (proxyModule != null) return proxyModule;

proxyModule = (RubyModule) runtime.getJavaSupport().getJavaInterfaceTemplate().dup();
// include any interfaces we extend
final Class<?>[] extended = javaClass.getInterfaces();
for ( int i = extended.length; --i >= 0; ) {
RubyModule extModule = getInterfaceModule(runtime, extended[i]);
proxyModule.includeModule(extModule);
}
Initializer.setupProxyModule(runtime, javaClass, proxyModule);
addToJavaPackageModule(proxyModule);

return proxyModule;
return Java.getProxyClass(runtime, javaClass);
}

public static RubyModule get_interface_module(final Ruby runtime, IRubyObject javaClassObject) {
@@ -457,19 +439,42 @@ public static RubyModule getProxyClass(Ruby runtime, JavaClass javaClass) {
}

public static RubyModule getProxyClass(final Ruby runtime, final Class<?> clazz) {
RubyModule unfinished = runtime.getJavaSupport().getUnfinishedProxyClassCache().get(clazz).get();
if (unfinished != null) return unfinished;
return runtime.getJavaSupport().getProxyClassFromCache(clazz);
}

// Only used by proxy ClassValue calculator in JavaSupport
static RubyModule createProxyClassForClass(final Ruby runtime, final Class<?> clazz) {
final JavaSupport javaSupport = runtime.getJavaSupport();

if ( clazz.isInterface() ) return Java.getInterfaceModule(runtime, clazz);
if (clazz.isInterface()) return generateInterfaceProxy(runtime, clazz);

return generateClassProxy(runtime, clazz, javaSupport);
}

private static RubyModule generateInterfaceProxy(final Ruby runtime, final Class javaClass) {
if (!javaClass.isInterface()) {
throw runtime.newArgumentError(javaClass.toString() + " is not an interface");
}

RubyModule proxyClass = runtime.getJavaSupport().getUnfinishedProxyClassCache().get(clazz).get();
RubyModule proxyModule = (RubyModule) runtime.getJavaSupport().getJavaInterfaceTemplate().dup();

// include any interfaces we extend
final Class<?>[] extended = javaClass.getInterfaces();
for ( int i = extended.length; --i >= 0; ) {
RubyModule extModule = getInterfaceModule(runtime, extended[i]);
proxyModule.includeModule(extModule);
}
Initializer.setupProxyModule(runtime, javaClass, proxyModule);
addToJavaPackageModule(proxyModule);

if (proxyClass != null) return proxyClass;
return proxyModule;
}

if ( clazz.isArray() ) {
private static RubyModule generateClassProxy(Ruby runtime, Class<?> clazz, JavaSupport javaSupport) {
RubyModule proxyClass;
if (clazz.isArray()) {
proxyClass = createProxyClass(runtime, javaSupport.getArrayProxyClass(), clazz, true);

// FIXME: Organizationally this might be nicer in a specialized class
@@ -493,9 +498,9 @@ else if ( clazz == Object.class ) {
// java.lang.Object is added at root of java proxy classes
proxyClass = createProxyClass(runtime, javaSupport.getConcreteProxyClass(), clazz, true);
if (NEW_STYLE_EXTENSION) {
proxyClass.getMetaClass().defineAnnotatedMethods(Java.NewStyleExtensionInherited.class);
proxyClass.getMetaClass().defineAnnotatedMethods(NewStyleExtensionInherited.class);
} else {
proxyClass.getMetaClass().defineAnnotatedMethods(Java.OldStyleExtensionInherited.class);
proxyClass.getMetaClass().defineAnnotatedMethods(OldStyleExtensionInherited.class);
}
addToJavaPackageModule(proxyClass);
}
@@ -506,12 +511,7 @@ else if ( clazz == Object.class ) {
// include interface modules into the proxy class
final Class<?>[] interfaces = clazz.getInterfaces();
for ( int i = interfaces.length; --i >= 0; ) {
JavaClass ifaceClass = JavaClass.get(runtime, interfaces[i]);
// java.util.Map type object has its own proxy, but following
// is needed. Unless kind_of?(is_a?) test will fail.
//if (interfaces[i] != java.util.Map.class) {
proxyClass.includeModule(getInterfaceModule(runtime, ifaceClass));
//}
proxyClass.includeModule(getInterfaceModule(runtime, interfaces[i]));
}
if ( Modifier.isPublic(clazz.getModifiers()) ) {
addToJavaPackageModule(proxyClass);
@@ -555,8 +555,6 @@ private static RubyClass createProxyClass(final Ruby runtime,

if ( invokeInherited ) proxyClass.inherit(superClass);

// add java_method for unbound use

Initializer.setupProxyClass(runtime, javaClass, proxyClass);

return proxyClass;
26 changes: 8 additions & 18 deletions core/src/main/java/org/jruby/javasupport/JavaClass.java
Original file line number Diff line number Diff line change
@@ -74,23 +74,11 @@ public class JavaClass extends JavaObject {
private volatile RubyArray constructors;

public RubyModule getProxyModule() {
// allow proxy to be read without synchronization. if proxy
// is under construction, only the building thread can see it.
RubyModule proxy = getRuntime().getJavaSupport().getProxyClassFromCache((Class)getValue());
if ( proxy != null ) return proxy; // proxy is complete, return it

// proxy may be under construction, return thread-local instance
return getRuntime().getJavaSupport().getUnfinishedProxyClassCache().get((Class) getValue()).get();
return Java.getProxyClass(getRuntime(), (Class)getValue());
}

public RubyClass getProxyClass() {
// allow proxy to be read without synchronization. if proxy
// is under construction, only the building thread can see it.
RubyModule proxy = getRuntime().getJavaSupport().getProxyClassFromCache((Class)getValue());
if ( proxy != null ) return (RubyClass)proxy; // proxy is complete, return it

// proxy may be under construction, return thread-local instance
return (RubyClass) getRuntime().getJavaSupport().getUnfinishedProxyClassCache().get((Class) getValue()).get();
return (RubyClass)Java.getProxyClass(getRuntime(), (Class)getValue());
}

public JavaClass(final Ruby runtime, final Class<?> javaClass) {
@@ -109,12 +97,14 @@ public int hashCode() {
}

public void addProxyExtender(final IRubyObject extender) {
if ( ! extender.respondsTo("extend_proxy") ) {
throw getRuntime().newTypeError("proxy extender must have an extend_proxy method");
Ruby runtime = getRuntime();

if (!extender.respondsTo("extend_proxy")) {
throw runtime.newTypeError("proxy extender must have an extend_proxy method");
}

ThreadContext context = getRuntime().getCurrentContext();
RubyModule proxy = getRuntime().getJavaSupport().getProxyClassFromCache(javaClass());
ThreadContext context = runtime.getCurrentContext();
RubyModule proxy = Java.getProxyClass(runtime, javaClass());
extendProxy(context, extender, proxy);
}

2 changes: 0 additions & 2 deletions core/src/main/java/org/jruby/javasupport/JavaSupport.java
Original file line number Diff line number Diff line change
@@ -139,8 +139,6 @@ public JavaClass computeValue(Class<?> cls) {
this.proxyClassCache = CLASS_VALUE_CONSTRUCTOR.newInstance(new ClassValueCalculator<RubyModule>() {
@Override
public RubyModule computeValue(Class<?> cls) {
RubyModule unfinished = unfinishedProxyClassCache.get(cls).get();
if (unfinished != null) return unfinished;
return Java.createProxyClassForClass(runtime, cls);
}
});
Original file line number Diff line number Diff line change
@@ -375,7 +375,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
}

private static void setJavaClassFor(final Class<?> javaClass, final RubyModule proxy) {
proxy.setInstanceVariable("@java_class", new JavaClass(proxy.getRuntime(), javaClass));
proxy.setInstanceVariable("@java_class", proxy.getRuntime().getJavaSupport().getJavaClassFromCache(javaClass));
proxy.dataWrapStruct(javaClass);
}

Original file line number Diff line number Diff line change
@@ -15,12 +15,15 @@ public MapBasedClassValue(ClassValueCalculator<T> calculator) {
public T get(Class cls) {
T obj = cache.get(cls);

if (obj == null) {
T newObj = calculator.computeValue(cls);
obj = cache.putIfAbsent(cls, newObj);
if (obj == null) {
obj = newObj;
}
if (obj != null) return obj;

synchronized (this) {
obj = cache.get(cls);

if (obj != null) return obj;

obj = calculator.computeValue(cls);
cache.put(cls, obj);
}

return obj;