Skip to content

Commit

Permalink
GROOVY-2433, GROOVY-3073, GROOVY-9987: this.privateMethod() in closure
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Jul 17, 2023
1 parent 32cfd9f commit 0738ed1
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
import org.apache.groovy.util.SystemUtil;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.reflection.ClassInfo;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.NullObject;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.SwitchPoint;
Expand Down Expand Up @@ -204,7 +204,7 @@ protected static void invalidateSwitchPoints() {
* @return the produced CallSite
* @since Groovy 2.1.0
*/
public static CallSite bootstrap(Lookup caller, String callType, MethodType type, String name, int flags) {
public static CallSite bootstrap(MethodHandles.Lookup caller, String callType, MethodType type, String name, int flags) {
CallType ct = CallType.fromCallSiteName(callType);
if (null == ct) throw new GroovyBugError("Unknown call type: " + callType);

Expand All @@ -219,13 +219,17 @@ public static CallSite bootstrap(Lookup caller, String callType, MethodType type
/**
* backing bootstrap method with all parameters
*/
private static CallSite realBootstrap(Lookup caller, String name, int callID, MethodType type, boolean safe, boolean thisCall, boolean spreadCall) {
// since indy does not give us the runtime types
// we produce first a dummy call site, which then changes the target to one when INDY_OPTIMIZE_THRESHOLD is reached,
// that does the method selection including the direct call to the
// real method.
private static CallSite realBootstrap(MethodHandles.Lookup caller, String name, int callID, MethodType type, boolean safe, boolean thisCall, boolean spreadCall) {
// first produce a dummy call site, since indy doesn't give the runtime types;
// the site then changes to the target when INDY_OPTIMIZE_THRESHOLD is reached
// that does the method selection including the direct call to the real method
CacheableCallSite mc = new CacheableCallSite(type);
final Class<?> sender = caller.lookupClass();
Class<?> sender = caller.lookupClass();
if (thisCall) {
while (GeneratedClosure.class.isAssignableFrom(sender)) {
sender = sender.getEnclosingClass(); // GROOVY-2433
}
}
MethodHandle mh = makeAdapter(mc, sender, name, callID, type, safe, thisCall, spreadCall);
mc.setTarget(mh);
mc.setDefaultTarget(mh);
Expand Down
70 changes: 70 additions & 0 deletions src/test/groovy/ClosureTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,76 @@ final class ClosureTest {
assert err.message.contains('"methodMissing" implementations are not supported on static inner classes as a synthetic version of "methodMissing" is added during compilation for the purpose of outer class delegation.')
}

// GROOVY-2433, GROOVY-3073, GROOVY-9987
@Test
void testClosureAccessToEnclosingClassPrivateMethod() {
assertScript '''
class C {
def getIds() {
populateIds()
}
def populateIds = { ->
this.sort([ 1, 5, 3, 4, 2 ])
}
private sort(list) {
list.sort{ one, two -> one <=> two }
}
}
class D extends C {
void test() {
assert ids == [1,2,3,4,5]
}
}
new D().test()
'''

assertScript '''
class C {
protected String protectedMethod() {
def closure = { ->
this.privateMethod()
}
closure()
}
private String privateMethod() {
'hello world'
}
}
class D extends C {
void test() {
def result = protectedMethod()
assert result == 'hello world'
}
}
new D().test()
'''

assertScript '''
class C {
def publicMethod() {
[1].each {
this.privateStaticMethod()
}
}
private static privateStaticMethod() {
'hello world'
}
}
class D extends C {
void test() {
publicMethod()
}
}
new D().test()
'''
}

// GROOVY-3142
@Test
void testClosureAccessToEnclosingClassPrivateField() {
Expand Down

0 comments on commit 0738ed1

Please sign in to comment.