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: 9a3b2621dbeb
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 63ffd3f9fe41
Choose a head ref
  • 5 commits
  • 9 files changed
  • 1 contributor

Commits on Aug 14, 2016

  1. Copy the full SHA
    73c9e5a View commit details
  2. [ji] make proxy.java_class exception "cheaper" (not throwing)

    ... also added a isProxyType checker (for later re-use)
    kares committed Aug 14, 2016
    Copy the full SHA
    0d2c26e View commit details
  3. Copy the full SHA
    040dfe6 View commit details
  4. [ji] move Class#java_class internal impl to Java (for potential re-use)

    ... should be also faster + matters very little if its not Ruby-friendly
    kares committed Aug 14, 2016
    Copy the full SHA
    91ff2b8 View commit details
  5. Copy the full SHA
    63ffd3f View commit details
37 changes: 23 additions & 14 deletions core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
***** END LICENSE BLOCK *****/
package org.jruby;

import org.jruby.javasupport.JavaClass;
import org.jruby.runtime.Arity;
import org.jruby.runtime.JavaSites;
import org.jruby.runtime.callsite.CachingCallSite;
@@ -1755,6 +1756,17 @@ public Class<? extends IRubyObject> getReifiedClass() {
return reifiedClass;
}

public static Class<? extends IRubyObject> nearestReifiedClass(final RubyClass klass) {
RubyClass current = klass;
do {
Class<? extends IRubyObject> reified = current.getReifiedClass();
if ( reified != null ) return reified;
current = current.getSuperClass();
}
while ( current != null );
return null;
}

public Map<String, List<Map<Class, Map<String,Object>>>> getParameterAnnotations() {
if (parameterAnnotations == null) return Collections.EMPTY_MAP;
return parameterAnnotations;
@@ -1855,34 +1867,31 @@ public synchronized void addClassAnnotation(Class annotation, Map fields) {
}

@Override
public Object toJava(Class klass) {
if (klass == Class.class) {
public Object toJava(final Class target) {
if (target == Class.class) {
if (reifiedClass == null) reifyWithAncestors(); // possibly auto-reify
// Class requested; try java_class or else return nearest reified class
if (respondsTo("java_class")) {
return callMethod("java_class").toJava(klass);
}
for (RubyClass current = this; current != null; current = current.getSuperClass()) {
Class reifiedClazz = current.getReifiedClass();
if ( reifiedClazz != null ) return reifiedClazz;
}
final ThreadContext context = getRuntime().getCurrentContext();
IRubyObject javaClass = JavaClass.java_class(context, this);
if ( ! javaClass.isNil() ) return javaClass.toJava(target);

Class reifiedClass = nearestReifiedClass(this);
if ( reifiedClass != null ) return reifiedClass;
// should never fall through, since RubyObject has a reified class
}

if (klass.isAssignableFrom(RubyClass.class)) {
if (target.isAssignableFrom(RubyClass.class)) {
// they're asking for something RubyClass extends, give them that
return this;
}

return defaultToJava(klass);
return defaultToJava(target);
}

/**
* An enum defining the type of marshaling a given class's objects employ.
*/
private static enum MarshalType {
DEFAULT, NEW_USER, OLD_USER, DEFAULT_SLOW, NEW_USER_SLOW, USER_SLOW
}
private enum MarshalType { DEFAULT, NEW_USER, OLD_USER, DEFAULT_SLOW, NEW_USER_SLOW, USER_SLOW }

/**
* A tuple representing the mechanism by which objects should be marshaled.
9 changes: 5 additions & 4 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@
import org.jruby.ir.IRMethod;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.targets.Bootstrap;
import org.jruby.javasupport.JavaClass;
import org.jruby.javasupport.binding.Initializer;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
@@ -4653,11 +4654,11 @@ public void setCacheProxy(boolean cacheProxy) {
}

@Override
public Object toJava(Class target) {
public Object toJava(final Class target) {
if (target == Class.class) { // try java_class for proxy modules
if ( respondsTo("java_class") ) {
return callMethod("java_class").toJava(target);
}
final ThreadContext context = getRuntime().getCurrentContext();
IRubyObject javaClass = JavaClass.java_class(context, this);
if ( ! javaClass.isNil() ) return javaClass.toJava(target);
}

return super.toJava(target);
43 changes: 20 additions & 23 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -383,37 +383,36 @@ private static boolean isJavaExceptionHandled(ThreadContext context, IRubyObject
IRubyObject testType = testTypes.eltInternal(i);
if (IRRuntimeHelpers.isJavaExceptionHandled(context, testType, throwable, true)) {
IRubyObject exceptionObj;
if (n == 1 && testType == runtime.getNativeException()) {
// wrap Throwable in a NativeException object
exceptionObj = new NativeException(runtime, runtime.getNativeException(), throwable);
((NativeException)exceptionObj).prepareIntegratedBacktrace(context, throwable.getStackTrace());
} else {
// wrap as normal JI object
if (n == 1) {
exceptionObj = wrapJavaException(context, testType, throwable);
} else { // wrap as normal JI object
exceptionObj = JavaUtil.convertJavaToUsableRubyObject(runtime, throwable);
}

runtime.getGlobalVariables().set("$!", exceptionObj);
return true;
}
}
} else if (Helpers.checkJavaException(throwable, excType, context)) {
IRubyObject exceptionObj;
if (excType == runtime.getNativeException()) {
// wrap Throwable in a NativeException object
exceptionObj = new NativeException(runtime, runtime.getNativeException(), throwable);
((NativeException)exceptionObj).prepareIntegratedBacktrace(context, throwable.getStackTrace());
} else {
// wrap as normal JI object
exceptionObj = JavaUtil.convertJavaToUsableRubyObject(runtime, throwable);
}

runtime.getGlobalVariables().set("$!", exceptionObj);
}
else if (Helpers.checkJavaException(throwable, excType, context)) {
runtime.getGlobalVariables().set("$!", wrapJavaException(context, excType, throwable));
return true;
}

return false;
}

private static IRubyObject wrapJavaException(final ThreadContext context, final IRubyObject excType, final Throwable throwable) {
final Ruby runtime = context.runtime;
if (excType == runtime.getNativeException()) { // wrap Throwable in a NativeException object
NativeException exception = new NativeException(runtime, runtime.getNativeException(), throwable);
exception.prepareIntegratedBacktrace(context, throwable.getStackTrace());
return exception;
}
// wrap as normal JI object
return JavaUtil.convertJavaToUsableRubyObject(runtime, throwable);
}

private static boolean isRubyExceptionHandled(ThreadContext context, IRubyObject excType, Object excObj) {
if (excType instanceof RubyArray) {
RubyArray testTypes = (RubyArray)excType;
@@ -462,10 +461,9 @@ public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRu
IRubyObject eqqVal = isUndefValue ? v : callSite.call(context, v, v, value);
if (eqqVal.isTrue()) return eqqVal;
}
return context.runtime.newBoolean(false);
} else {
return isUndefValue ? receiver : callSite.call(context, receiver, receiver, value);
return context.runtime.getFalse();
}
return isUndefValue ? receiver : callSite.call(context, receiver, receiver, value);
}

@Deprecated
@@ -477,8 +475,7 @@ public static IRubyObject newProc(Ruby runtime, Block block) {
return (block == Block.NULL_BLOCK) ? runtime.getNil() : runtime.newProc(Block.Type.PROC, block);
}

public static IRubyObject yield(ThreadContext context, Block b, IRubyObject yieldArg, boolean unwrapArray) {
IRubyObject yieldVal = (IRubyObject)yieldArg;
public static IRubyObject yield(ThreadContext context, Block b, IRubyObject yieldVal, boolean unwrapArray) {
return (unwrapArray && (yieldVal instanceof RubyArray)) ? b.yieldArray(context, yieldVal, null) : b.yield(context, yieldVal);
}

26 changes: 26 additions & 0 deletions core/src/main/java/org/jruby/java/addons/ClassJavaAddons.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.jruby.java.addons;

import org.jruby.RubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaClass;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

/**
* @author kares
*/
public abstract class ClassJavaAddons {

// Get the native (or reified) (a la become_java!) class for this Ruby class.
@JRubyMethod
public static IRubyObject java_class(ThreadContext context, final IRubyObject self) {
Class reifiedClass = RubyClass.nearestReifiedClass((RubyClass) self);
if ( reifiedClass == null ) return context.nil;
// TODO: java_class is used for different things with Java proxy modules/classes
// returning a JavaClass here would break stuff - simply needs to get through ...
// return JavaClass.get(context.runtime, reifiedClass);
return Java.getInstance(context.runtime, reifiedClass);
}

}
24 changes: 10 additions & 14 deletions core/src/main/java/org/jruby/java/addons/KernelJavaAddons.java
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@
import org.jruby.java.proxies.JavaProxy;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaClass;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

@@ -80,32 +79,29 @@ public static IRubyObject java_field(IRubyObject recv, IRubyObject[] args) {
}

private static JavaClass getTargetType(ThreadContext context, Ruby runtime, IRubyObject type) {
JavaClass targetType;

if (type instanceof RubyString || type instanceof RubySymbol) {
final String className = type.toString();
targetType = runtime.getJavaSupport().getNameClassMap().get(className);
JavaClass targetType = runtime.getJavaSupport().getNameClassMap().get(className);
if ( targetType == null ) targetType = JavaClass.forNameVerbose(runtime, className);
return targetType;
}
else if (type instanceof JavaProxy) {
if (type instanceof JavaProxy) {
final Object wrapped = ((JavaProxy) type).getObject();
if ( wrapped instanceof Class ) {
targetType = JavaClass.get(runtime, (Class) wrapped);
} else {
throw runtime.newTypeError("not a valid target type: " + type);
return JavaClass.get(runtime, (Class) wrapped);
}
throw runtime.newTypeError("not a valid target type: " + type);
}
else if (type instanceof JavaClass) {
if (type instanceof JavaClass) {
return (JavaClass) type;
}
else if (type instanceof RubyModule && type.respondsTo("java_class")) {
targetType = (JavaClass) Helpers.invoke(context, type, "java_class");
}
else {
throw runtime.newTypeError("unable to convert to type: " + type);
if (type instanceof RubyModule) {
IRubyObject java_class = JavaClass.java_class(context, (RubyModule) type);
if ( ! java_class.isNil() ) return (JavaClass) java_class;
}

return targetType;
throw runtime.newTypeError("unable to convert to type: " + type);
}

}
9 changes: 4 additions & 5 deletions core/src/main/java/org/jruby/java/proxies/JavaProxy.java
Original file line number Diff line number Diff line change
@@ -112,14 +112,14 @@ public Class<?> getJavaClass() {
}

static JavaClass java_class(final ThreadContext context, final RubyModule module) {
return (JavaClass) Helpers.invoke(context, module, "java_class");
return (JavaClass) JavaClass.java_class(context, module);
}

@JRubyMethod(meta = true, frame = true) // framed for invokeSuper
public static IRubyObject inherited(ThreadContext context, IRubyObject recv, IRubyObject subclass) {
IRubyObject subJavaClass = Helpers.invoke(context, subclass, "java_class");
IRubyObject subJavaClass = JavaClass.java_class(context, (RubyClass) subclass);
if (subJavaClass.isNil()) {
subJavaClass = Helpers.invoke(context, recv, "java_class");
subJavaClass = JavaClass.java_class(context, (RubyClass) recv);
Helpers.invoke(context, subclass, "java_class=", subJavaClass);
}
return Helpers.invokeSuper(context, recv, subclass, Block.NULL_BLOCK);
@@ -265,8 +265,7 @@ private static void findFields(final ThreadContext context,

// We could not find all of them print out first one (we could print them all?)
if ( ! fieldMap.isEmpty() ) {
throw JavaClass.undefinedFieldError(context.runtime,
topModule.getName(), fieldMap.keySet().iterator().next());
throw JavaClass.undefinedFieldError(context.runtime, topModule.getName(), fieldMap.keySet().iterator().next());
}

}
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/javasupport/Java.java
Original file line number Diff line number Diff line change
@@ -79,6 +79,7 @@
import org.jruby.internal.runtime.methods.JavaMethod.JavaMethodN;
import org.jruby.internal.runtime.methods.JavaMethod.JavaMethodZero;
import org.jruby.java.addons.ArrayJavaAddons;
import org.jruby.java.addons.ClassJavaAddons;
import org.jruby.java.addons.IOJavaAddons;
import org.jruby.java.addons.KernelJavaAddons;
import org.jruby.java.addons.StringJavaAddons;
@@ -187,6 +188,7 @@ public static RubyModule createJavaModule(final Ruby runtime) {
runtime.getKernel().defineAnnotatedMethods(KernelJavaAddons.class);
runtime.getString().defineAnnotatedMethods(StringJavaAddons.class);
runtime.getIO().defineAnnotatedMethods(IOJavaAddons.class);
runtime.getClassClass().defineAnnotatedMethods(ClassJavaAddons.class);

if ( runtime.getObject().isConstantDefined("StringIO") ) {
((RubyClass) runtime.getObject().getConstant("StringIO")).defineAnnotatedMethods(IOJavaAddons.AnyIO.class);
60 changes: 47 additions & 13 deletions core/src/main/java/org/jruby/javasupport/JavaClass.java
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.java.addons.ClassJavaAddons;
import org.jruby.java.proxies.ArrayJavaProxy;
import org.jruby.java.proxies.ConcreteJavaProxy;
import org.jruby.java.util.ArrayUtils;
@@ -54,6 +55,7 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import org.jruby.util.CodegenUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -63,8 +65,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import org.jruby.util.CodegenUtils;

import static org.jruby.RubyModule.undefinedMethodMessage;

@@ -156,22 +156,56 @@ public final Class javaClass() {
return (Class<?>) getValue();
}

/**
* Get the associated JavaClass for a proxy module.
*
* The passed module/class is assumed to be a Java proxy module/class!
* @param context
* @param proxy
* @return class
*/
public static Class<?> getJavaClass(final ThreadContext context, final RubyModule proxy) {
final IRubyObject javaClass = Helpers.invoke(context, proxy, "java_class");
return ((JavaClass) javaClass).javaClass();
return ((JavaClass) java_class(context, proxy)).javaClass();
}

/**
* Retieve a JavaClass if the passed module/class is a Java proxy.
* @param context
* @param proxy
* @return class or null if not a Java proxy
*
* @note Class objects have a java_class method but they're not considered Java proxies!
*/
public static Class<?> getJavaClassIfProxy(final ThreadContext context, final RubyModule proxy) {
final IRubyObject javaClass;
try {
javaClass = Helpers.invoke(context, proxy, "java_class");
}
catch (RuntimeException e) {
// clear $! since our "java_class" invoke above may have failed and set it
context.setErrorInfo(context.nil);
return null;
IRubyObject java_class = java_class(context, proxy);
return ( java_class instanceof JavaClass ) ? ((JavaClass) java_class).javaClass() : null;
}

//public static boolean isProxyType(final ThreadContext context, final RubyModule proxy) {
// IRubyObject java_class = proxy.getInstanceVariable("@java_class");
// return (java_class != null && java_class.isTrue()) ||
// proxy.respondsTo("java_class"); // not all proxy types have @java_class set
//}

/**
* Returns the (reified or proxied) Java class if the passed Ruby module/class has one.
* @param context
* @param proxy
* @return Java proxy class, Java reified class or nil
*/
public static IRubyObject java_class(final ThreadContext context, final RubyModule proxy) {
// NOTE: without this "hack" we would always need to call java_class (and catch RaiseException)
//if ( proxy instanceof RubyClass ) return ClassJavaAddons.java_class(context, proxy);

IRubyObject java_class = proxy.getInstanceVariable("@java_class");
if ( java_class == null ) { // || java_class.isNil()
if ( proxy.respondsTo("java_class") ) { // NOTE: quite bad since built-in Ruby classes will return
// a Ruby Java proxy for java.lang.Class while Java proxies will return a JavaClass instance !
java_class = Helpers.invoke(context, proxy, "java_class");
}
else java_class = context.nil; // we return != null (just like callMethod would)
}
return ( javaClass instanceof JavaClass ) ? ((JavaClass) javaClass).javaClass() : null;
return java_class;
}

static boolean isPrimitiveName(final String name) {
Loading