Skip to content

Commit 17e333f

Browse files
committed
Use NORMAL call type for to_s method_missing in dstr
When calling to_s for a dynamic string, it should dispatch without regards to visibility (like functional or variable call type) but produce a NoMethodError when missing (like normal call type). This hack allows specifying a different "effective call type" to be used for site setup when using SelfInvokeSite to skip visibility checks. The original logic used CallType to indicate both the structure of arguments passed in from the invokedynamic call site and to indicate whether to perform visibility checks. This does not fully disentangle the logic from this dual-meaning but it is sufficient to fix the related issue. Fixes jruby#9222
1 parent a66cf51 commit 17e333f

4 files changed

Lines changed: 28 additions & 22 deletions

File tree

core/src/main/java/org/jruby/ir/targets/indy/ArrayDerefInvokeSite.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public IRubyObject invoke(ThreadContext context, IRubyObject caller, IRubyObject
7878
args[0] = dupString(context, (RubyString) args[0]);
7979

8080
if (methodMissing(entry, caller)) {
81-
return callMethodMissing(entry, callType, context, self, selfClass, methodName, args, block);
81+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, methodName, args, block);
8282
}
8383

8484
mh = getHandle(context, self, entry);
@@ -131,7 +131,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s
131131
entry = selfClass.searchWithCache(name);
132132

133133
if (methodMissing(entry, caller)) {
134-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, block);
134+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, block);
135135
}
136136

137137
cache = entry;

core/src/main/java/org/jruby/ir/targets/indy/BuildDynamicStringSite.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.jruby.Appendable;
66
import org.jruby.RubyString;
77
import org.jruby.api.Convert;
8+
import org.jruby.runtime.CallType;
89
import org.jruby.runtime.ThreadContext;
910
import org.jruby.runtime.builtin.IRubyObject;
1011
import org.jruby.util.ByteList;
@@ -127,7 +128,9 @@ public BuildDynamicStringSite(MethodType type, Object[] stringArgs) {
127128
private static MethodHandle constructGuardedToStringFilter() {
128129
// create an invoke site for the to_s call
129130
MethodType toSType = MethodType.methodType(IRubyObject.class, ThreadContext.class, IRubyObject.class);
130-
CallSite toS = SelfInvokeSite.bootstrap(MethodHandles.lookup(), "invokeFunctional:to_s", toSType, 0, 0, "", -1);
131+
MethodHandles.Lookup lookup = MethodHandles.lookup();
132+
InvokeSite site = new SelfInvokeSite(toSType, "to_s", CallType.FUNCTIONAL, CallType.NORMAL, false, 0, "", -1);
133+
CallSite toS = InvokeSite.bootstrap(site, lookup);
131134
MethodHandle toS_handle = toS.dynamicInvoker();
132135

133136
// Cast the result to RubyString, or else call anyToString on the original

core/src/main/java/org/jruby/ir/targets/indy/InvokeSite.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public abstract class InvokeSite extends MutableCallSite {
9494
public final Signature fullSignature;
9595
public final int arity;
9696
protected final String methodName;
97+
protected final CallType visibilityCallType;
9798
final MethodHandle fallback;
9899
private final SiteTracker tracker = new SiteTracker();
99100
private final long siteID = SITE_ID.getAndIncrement();
@@ -695,25 +696,27 @@ public String name() {
695696
return methodName;
696697
}
697698

698-
public final CallType callType;
699-
700699
public InvokeSite(MethodType type, String name, CallType callType, boolean literalClosure, int flags, String file, int line) {
700+
this(type, name, callType, callType, literalClosure, flags, file, line);
701+
}
702+
703+
protected InvokeSite(MethodType type, String name, CallType structuralCallType, CallType visibilityCallType, boolean literalClosure, int flags, String file, int line) {
701704
super(type);
702705
this.methodName = name;
703-
this.callType = callType;
706+
this.visibilityCallType = visibilityCallType;
704707
this.literalClosure = literalClosure;
705708
this.file = file;
706709
this.line = line;
707710
this.flags = flags;
708711

709712
Signature startSig;
710713

711-
if (callType == CallType.SUPER) {
714+
if (structuralCallType == CallType.SUPER) {
712715
// super calls receive current class argument, so offsets and signature are different
713716
startSig = JRubyCallSite.STANDARD_SUPER_SIG;
714717
functional = false;
715718
argOffset = 4;
716-
} else if (callType == CallType.FUNCTIONAL || callType == CallType.VARIABLE) {
719+
} else if (structuralCallType == CallType.FUNCTIONAL || structuralCallType == CallType.VARIABLE) {
717720
startSig = JRubyCallSite.STANDARD_FSITE_SIG;
718721
functional = true;
719722
argOffset = 2;
@@ -818,7 +821,7 @@ private CacheEntry methodMissingEntry(ThreadContext context, RubyClass selfClass
818821
logMethodMissing();
819822
}
820823
Visibility visibility = entry.method.getVisibility();
821-
return Helpers.createMethodMissingEntry(context, selfClass, callType, visibility, entry.token, methodName);
824+
return Helpers.createMethodMissingEntry(context, selfClass, visibilityCallType, visibility, entry.token, methodName);
822825
}
823826

824827
private void finishBinding(CacheEntry entry, MethodHandle mh, IRubyObject self, RubyClass selfClass, SwitchPoint switchPoint) {
@@ -916,7 +919,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s
916919
entry = selfClass.searchWithCache(name);
917920

918921
if (methodMissing(entry, caller)) {
919-
return callMethodMissing(entry, callType, context, self, selfClass, name, args, block);
922+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, args, block);
920923
}
921924

922925
cache = entry;
@@ -941,7 +944,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject[]
941944
entry = selfClass.searchWithCache(name);
942945

943946
if (methodMissing(entry)) {
944-
return callMethodMissing(entry, callType, context, self, selfClass, name, args, block);
947+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, args, block);
945948
}
946949

947950
cache = entry;
@@ -980,7 +983,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s
980983
entry = selfClass.searchWithCache(name);
981984

982985
if (methodMissing(entry, caller)) {
983-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, block);
986+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, block);
984987
}
985988

986989
cache = entry;
@@ -1005,7 +1008,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject ar
10051008
entry = selfClass.searchWithCache(name);
10061009

10071010
if (methodMissing(entry)) {
1008-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, block);
1011+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, block);
10091012
}
10101013

10111014
cache = entry;
@@ -1030,7 +1033,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s
10301033
entry = selfClass.searchWithCache(name);
10311034

10321035
if (methodMissing(entry, caller)) {
1033-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, block);
1036+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, arg1, block);
10341037
}
10351038

10361039
cache = entry;
@@ -1055,7 +1058,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject ar
10551058
entry = selfClass.searchWithCache(name);
10561059

10571060
if (methodMissing(entry)) {
1058-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, block);
1061+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, arg1, block);
10591062
}
10601063

10611064
cache = entry;
@@ -1080,7 +1083,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s
10801083
entry = selfClass.searchWithCache(name);
10811084

10821085
if (methodMissing(entry, caller)) {
1083-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, arg2, block);
1086+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, arg1, arg2, block);
10841087
}
10851088

10861089
cache = entry;
@@ -1105,7 +1108,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject ar
11051108
entry = selfClass.searchWithCache(name);
11061109

11071110
if (methodMissing(entry)) {
1108-
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, arg2, block);
1111+
return callMethodMissing(entry, visibilityCallType, context, self, selfClass, name, arg0, arg1, arg2, block);
11091112
}
11101113

11111114
cache = entry;
@@ -1537,7 +1540,7 @@ public void setInitialTarget(MethodHandle target) {
15371540
public boolean methodMissing(CacheEntry entry, IRubyObject caller) {
15381541
DynamicMethod method = entry.method;
15391542

1540-
return method.isUndefined() || (!methodName.equals("method_missing") && !method.isCallableFrom(caller, callType));
1543+
return method.isUndefined() || (!methodName.equals("method_missing") && !method.isCallableFrom(caller, visibilityCallType));
15411544
}
15421545

15431546
public boolean methodMissing(CacheEntry entry) {

core/src/main/java/org/jruby/ir/targets/indy/SelfInvokeSite.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
* Created by headius on 10/23/14.
2222
*/
2323
public class SelfInvokeSite extends InvokeSite {
24-
public SelfInvokeSite(MethodType type, String name, CallType callType, boolean literalClosure, int flags, String file, int line) {
25-
super(type, name, callType, literalClosure, flags, file, line);
24+
public SelfInvokeSite(MethodType type, String name, CallType structuralCallType, CallType visibilityCallType, boolean literalClosure, int flags, String file, int line) {
25+
super(type, name, structuralCallType, visibilityCallType, literalClosure, flags, file, line);
2626
}
2727

2828
public SelfInvokeSite(MethodType type, String name, CallType callType, int flags, String file, int line) {
29-
this(type, name, callType, false, flags, file, line);
29+
this(type, name, callType, callType, false, flags, file, line);
3030
}
3131

3232
public static final Handle BOOTSTRAP = new Handle(
@@ -41,7 +41,7 @@ public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, Metho
4141
List<String> nameComponents = StringSupport.split(name, ':');
4242
String methodName = JavaNameMangler.demangleMethodName(nameComponents.get(1));
4343
CallType callType = nameComponents.get(0).equals("callFunctional") ? CallType.FUNCTIONAL : CallType.VARIABLE;
44-
InvokeSite site = new SelfInvokeSite(type, methodName, callType, literalClosure, flags, file, line);
44+
InvokeSite site = new SelfInvokeSite(type, methodName, callType, callType, literalClosure, flags, file, line);
4545

4646
return InvokeSite.bootstrap(site, lookup);
4747
}

0 commit comments

Comments
 (0)