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

Commits on Apr 22, 2016

  1. Copy the full SHA
    ba7cbb1 View commit details
  2. Search all scopes in turn for refinements.

    We were not properly handling the case of a method starting in a
    scope that is not a cref (class/module/script) body. The old logic
    would grab the current scope, find no refinements, and then move
    to the previous cref scope. This unfortunately would jump out of
    the current lexical cref into the containing lexical cref and miss
    any refinements in the current class body.
    
    We may be able to improve this by only searching cref scopes.
    
    Fixes #3548. See that bug for a reproduction.
    headius committed Apr 22, 2016
    Copy the full SHA
    745654f View commit details
  3. Search for refinements for target class and all superclasses.

    If you refine Integer, then calls against Fixnum should see that
    refinement.
    
    Obviously this is super inefficient right now and caches nothing.
    
    Relates to #3548.
    headius committed Apr 22, 2016
    Copy the full SHA
    7a3c637 View commit details
35 changes: 35 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.util.Arrays;
import java.util.Map;

public class IRRuntimeHelpers {
private static final Logger LOG = LoggerFactory.getLogger("IRRuntimeHelpers");
@@ -1858,4 +1859,38 @@ public static IRubyObject callOptimizedAref(ThreadContext context, IRubyObject c

return site.call(context, caller, target, keyStr.strDup(context.runtime));
}

public static DynamicMethod getRefinedMethod(ThreadContext context, RubyClass selfType, String methodName) {
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (true) {
if (refinedScope == null) break;

refinements = refinedScope.getOverlayModule(context).getRefinements();

if (!refinements.isEmpty()) {

for (Map.Entry<RubyClass, RubyModule> refinementEntry : refinements.entrySet()) {

if (selfType.isKindOfModule(refinementEntry.getKey())) {

refinement = refinementEntry.getValue();
method = refinement.searchMethod(methodName);

if (!method.isUndefined()) {
break;
}

method = null;
}
}
}

refinedScope = refinedScope.getEnclosingScope();
}
return method;
}
}
Original file line number Diff line number Diff line change
@@ -414,7 +414,7 @@ protected IRubyObject callMethodMissing(ThreadContext context, IRubyObject self,

protected abstract boolean methodMissing(DynamicMethod method, IRubyObject caller);

private static RubyClass getClass(IRubyObject self) {
protected static RubyClass getClass(IRubyObject self) {
// the cast in the following line is necessary due to lacking optimizations in Hotspot
return ((RubyBasicObject) self).getMetaClass();
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
package org.jruby.runtime.callsite;

import org.jruby.RubyBasicObject;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.RubyFloat;
import org.jruby.RubyModule;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.internal.runtime.methods.UndefinedMethod;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.CallType;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

@@ -26,21 +20,9 @@ public RefinedCachingCallSite(String methodName, CallType callType) {
@Override
public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject... args) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, args);
}

@@ -49,21 +31,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, args, block);
}

@@ -72,21 +42,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self);
}

@@ -95,21 +53,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, Block block) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, block);
}

@@ -118,21 +64,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, arg0);
}

@@ -141,21 +75,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, Block block) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, arg0, block);
}

@@ -164,21 +86,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, arg0, arg1);
}

@@ -187,21 +97,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1, Block block) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, arg0, arg1, block);
}

@@ -210,21 +108,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, arg0, arg1, arg2);
}

@@ -233,21 +119,9 @@ public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject s

public IRubyObject call(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2, Block block) {
RubyClass selfType = getClass(self);
StaticScope refinedScope = context.getCurrentStaticScope();
Map<RubyClass, RubyModule> refinements;
RubyModule refinement;
DynamicMethod method = null;

while (refinedScope != null &&
(
(refinements = refinedScope.getOverlayModule(context).getRefinements()).isEmpty() ||
(refinement = refinements.get(selfType)) == null ||
(method = refinement.searchMethod(methodName)).isUndefined())
) {
refinedScope = refinedScope.getPreviousCRefScope();
}
DynamicMethod method = IRRuntimeHelpers.getRefinedMethod(context, selfType, methodName);

if (refinedScope == null) {
if (method == null) {
return super.call(context, caller, self, arg0, arg1, arg2, block);
}

@@ -258,9 +132,4 @@ protected boolean methodMissing(DynamicMethod method, IRubyObject caller) {
// doing full "normal" MM check rather than multiple refined sites by call types
return method.isUndefined() || (!methodName.equals("method_missing") && !method.isCallableFrom(caller, callType));
}

private static RubyClass getClass(IRubyObject self) {
// the cast in the following line is necessary due to lacking optimizations in Hotspot
return ((RubyBasicObject) self).getMetaClass();
}
}