Skip to content

Commit

Permalink
Bind IRubyObject-assignable Java set/get directly with indy.
Browse files Browse the repository at this point in the history
  • Loading branch information
headius committed Aug 3, 2018
1 parent c8c51bd commit 5aa064b
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
80 changes: 80 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/InvokeSite.java
Expand Up @@ -18,6 +18,9 @@
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.PartialDelegatingMethod;
import org.jruby.ir.JIT;
import org.jruby.java.invokers.InstanceFieldGetter;
import org.jruby.java.invokers.InstanceFieldSetter;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallType;
import org.jruby.runtime.Helpers;
Expand All @@ -36,11 +39,13 @@
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import static java.lang.invoke.MethodHandles.constant;
import static java.lang.invoke.MethodHandles.insertArguments;
import static java.lang.invoke.MethodHandles.lookup;

Expand Down Expand Up @@ -332,6 +337,7 @@ MethodHandle getHandle(IRubyObject self, RubyClass dispatchClass, DynamicMethod
MethodHandle mh = buildNewInstanceHandle(method, self);
if (mh == null) mh = buildNotEqualHandle(method, self);
if (mh == null) mh = Bootstrap.buildNativeHandle(this, method, blockGiven);
if (mh == null) mh = buildJavaFieldHandle(this, method, self);
if (mh == null) mh = Bootstrap.buildIndyHandle(this, method, method.getImplementationClass());
if (mh == null) mh = Bootstrap.buildJittedHandle(this, method, blockGiven);
if (mh == null) mh = Bootstrap.buildAttrHandle(this, method, self, dispatchClass);
Expand All @@ -344,6 +350,80 @@ MethodHandle getHandle(IRubyObject self, RubyClass dispatchClass, DynamicMethod
return mh;
}

MethodHandle buildJavaFieldHandle(InvokeSite site, DynamicMethod method, IRubyObject self) throws Throwable {
if (method instanceof InstanceFieldGetter) {
// only matching arity
if (site.arity != 0 || site.signature.lastArgType() == Block.class) return null;

Field field = ((InstanceFieldGetter) method).getField();

// only IRubyObject subs for now
if (!IRubyObject.class.isAssignableFrom(field.getType())) return null;

MethodHandle fieldHandle = (MethodHandle) method.getHandle();

if (fieldHandle != null) {
return fieldHandle;
}

fieldHandle = LOOKUP.unreflectGetter(field);

MethodHandle filter = self.getRuntime().getNullToNilHandle();

MethodHandle receiverConverter = Binder
.from(field.getDeclaringClass(), IRubyObject.class)
.cast(Object.class, IRubyObject.class)
.invokeStaticQuiet(lookup(), JavaUtil.class, "objectFromJavaProxy");

fieldHandle = Binder
.from(site.type())
.permute(2)
.filter(0, receiverConverter)
.filterReturn(filter)
.cast(fieldHandle.type())
.invoke(fieldHandle);

method.setHandle(fieldHandle);

return fieldHandle;
} else if (method instanceof InstanceFieldSetter) {
// only matching arity
if (site.arity != 1 || site.signature.lastArgType() == Block.class) return null;

Field field = ((InstanceFieldSetter) method).getField();

// only IRubyObject subs for now
if (!IRubyObject.class.isAssignableFrom(field.getType())) return null;

MethodHandle fieldHandle = (MethodHandle) method.getHandle();

if (fieldHandle != null) {
return fieldHandle;
}

fieldHandle = LOOKUP.unreflectSetter(field);

MethodHandle receiverConverter = Binder
.from(field.getDeclaringClass(), IRubyObject.class)
.cast(Object.class, IRubyObject.class)
.invokeStaticQuiet(lookup(), JavaUtil.class, "objectFromJavaProxy");

fieldHandle = Binder
.from(site.type())
.permute(2, 3)
.filter(0, receiverConverter)
.filterReturn(constant(IRubyObject.class, self.getRuntime().getNil()))
.cast(fieldHandle.type())
.invoke(fieldHandle);

method.setHandle(fieldHandle);

return fieldHandle;
}

return null;
}

MethodHandle buildNewInstanceHandle(DynamicMethod method, IRubyObject self) {
MethodHandle mh = null;

Expand Down
Expand Up @@ -19,6 +19,10 @@ public abstract class FieldMethodOne extends JavaMethod.JavaMethodOne {
this(host, field, name);
}

public Field getField() {
return field;
}

protected FieldMethodOne(RubyModule host, Field field, String name) {
super(host, Visibility.PUBLIC, name);
if ( ! Ruby.isSecurityRestricted() ) field.setAccessible(true);
Expand Down
Expand Up @@ -20,6 +20,10 @@ public abstract class FieldMethodZero extends JavaMethod.JavaMethodZero {
this(host, field, name);
}

public Field getField() {
return field;
}

protected FieldMethodZero(RubyModule host, Field field, String name) {
super(host, Visibility.PUBLIC, name);
if ( ! Ruby.isSecurityRestricted() ) field.setAccessible(true);
Expand Down

0 comments on commit 5aa064b

Please sign in to comment.