Skip to content

Commit de4ee7e

Browse files
authored
Merge pull request jruby#9230 from headius/normal_to_s_call_for_dstr
Use normal call type error for missing dynamic string to_s
2 parents a66cf51 + 7ef881a commit de4ee7e

5 files changed

Lines changed: 34 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
}

spec/ruby/language/string_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ class << obj
133133
"#{obj}".should == '42'
134134
end
135135

136+
it "raise NoMethodError when #to_s is not defined for the object" do
137+
obj = BasicObject.new
138+
139+
-> { "#{obj}" }.should raise_error(NoMethodError)
140+
end
141+
136142
it "uses an internal representation when #to_s doesn't return a String" do
137143
obj = mock('to_s')
138144
obj.stub!(:to_s).and_return(42)

0 commit comments

Comments
 (0)