This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new c42a509f64 GROOVY-10687: SC: replace access bridge methods with direct
field access
c42a509f64 is described below
commit c42a509f64616f8ca8c97d37e79d713dfb99a8ac
Author: Eric Milles <[email protected]>
AuthorDate: Mon Sep 23 14:17:35 2024 -0500
GROOVY-10687: SC: replace access bridge methods with direct field access
---
.../groovy/classgen/AsmClassGenerator.java | 40 +++++++-
.../codehaus/groovy/classgen/GeneratorContext.java | 5 +
...icTypesBinaryExpressionMultiTypeDispatcher.java | 62 ++++--------
.../classgen/asm/sc/StaticTypesCallSiteWriter.java | 20 ++--
.../sc/StaticCompilationMetadataKeys.java | 29 ++++--
.../transform/sc/StaticCompilationVisitor.java | 1 +
.../PropertyExpressionTransformer.java | 27 ++++++
.../VariableExpressionTransformer.java | 8 +-
.../transform/stc/StaticTypeCheckingVisitor.java | 3 +-
.../groovy/classgen/asm/NestHostTests.groovy | 15 +++
.../sc/FieldsAndPropertiesStaticCompileTest.groovy | 108 +++++++++++----------
11 files changed, 200 insertions(+), 118 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index da58703feb..d4410759c9 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -27,6 +27,7 @@ import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
@@ -138,6 +139,7 @@ import static
org.apache.groovy.ast.tools.ClassNodeUtils.getNestHost;
import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
import static org.apache.groovy.ast.tools.ExpressionUtils.isSuperExpression;
import static org.codehaus.groovy.ast.ClassHelper.isClassType;
+import static org.codehaus.groovy.ast.ClassHelper.isFunctionalInterface;
import static org.codehaus.groovy.ast.ClassHelper.isObjectType;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveByte;
@@ -381,6 +383,7 @@ public class AsmClassGenerator extends ClassGenerator {
// GROOVY-10687
if (classNode.getOuterClass() == null &&
classNode.getInnerClasses().hasNext()) {
makeNestmateEntries(classNode);
+ moreNestmateEntries(classNode);
}
// GROOVY-4649, GROOVY-6750, GROOVY-6808
for (Iterator<InnerClassNode> it = classNode.getInnerClasses();
it.hasNext(); ) {
@@ -460,6 +463,38 @@ public class AsmClassGenerator extends ClassGenerator {
}
}
+ private void moreNestmateEntries(final ClassNode classNode) {
+ // edge case: nest host closures-within-closures
+ int[] n = {this.context.getClosureClassIndex()};
+ for (ClassNode innerClass : getInnerClasses()) {
+ if (innerClass instanceof InterfaceHelperClassNode) continue;
+ var doCall = innerClass.getMethods().get(0);
+ doCall.getCode().visit(new CodeVisitorSupport() {
+ private String name =
BytecodeHelper.getClassInternalName(innerClass);
+ private void visitNested(final String kind, final
ClosureExpression expr) {
+ String save = name;
+ name += "$_" + kind + n[0]++;
+ classVisitor.visitNestMember(name);
+ super.visitClosureExpression(expr);
+ name = save;
+ }
+ @Override
+ public void visitClosureExpression(final ClosureExpression
expression) {
+ visitNested("closure", expression);
+ }
+ @Override
+ public void visitLambdaExpression(final LambdaExpression
expression) {
+ if
(Boolean.TRUE.equals(innerClass.getNodeMetaData(org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.STATIC_COMPILE_NODE))
+ &&
isFunctionalInterface(expression.getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.PARAMETER_TYPE)))
{
+ visitNested("lambda", expression);
+ } else {
+ super.visitLambdaExpression(expression);
+ }
+ }
+ });
+ }
+ }
+
/*
* See
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6-300-D.2-5
* for what flags are allowed depending on the fact we are writing the
inner class table
@@ -1063,8 +1098,9 @@ public class AsmClassGenerator extends ClassGenerator {
// any member is accessible from the declaring class
if (accessingClass.equals(declaringClass)) return true;
- // a private member isn't accessible beyond the declaring class
- if (Modifier.isPrivate(modifiers)) return false;
+ // a private member is accessible from any nestmates
+ if (Modifier.isPrivate(modifiers))
+ return
getNestHost(accessingClass).equals(getNestHost(declaringClass));
// a protected member is accessible from any subclass of the declaring
class
if (Modifier.isProtected(modifiers) &&
accessingClass.isDerivedFrom(declaringClass)) return true;
diff --git a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
index fcd115a280..0a0b78b270 100644
--- a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
+++ b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
@@ -43,6 +43,11 @@ public class GeneratorContext {
this.innerClassIdx = innerClassOffset;
}
+ // for ACG nestmate determination !
+ int getClosureClassIndex() {
+ return closureClassIdx;
+ }
+
public int getNextInnerClassIdx() {
return innerClassIdx++;
}
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
index 7e0284cd01..45c89d41df 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
@@ -48,23 +48,20 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import static org.apache.groovy.ast.tools.ExpressionUtils.isThisExpression;
-import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.isNumberType;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveChar;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveDouble;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveFloat;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveLong;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.declX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
import static org.codehaus.groovy.ast.tools.GeneralUtils.nullX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
import static
org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.PRIVATE_FIELDS_MUTATORS;
@@ -96,8 +93,6 @@ import static org.objectweb.asm.Opcodes.LSUB;
*/
public class StaticTypesBinaryExpressionMultiTypeDispatcher extends
BinaryExpressionMultiTypeDispatcher {
- private static final MethodNode CLOSURE_GETTHISOBJECT_METHOD =
CLOSURE_TYPE.getMethod("getThisObject", Parameter.EMPTY_ARRAY);
-
private final AtomicInteger labelCounter = new AtomicInteger();
public StaticTypesBinaryExpressionMultiTypeDispatcher(final
WriterController wc) {
@@ -116,7 +111,7 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher
extends BinaryExpres
}
ClassNode top = controller.getOperandStack().getTopOperand();
- if (ClassHelper.isPrimitiveType(top) && (ClassHelper.isNumberType(top)
|| isPrimitiveChar(top))) {
+ if (isPrimitiveType(top) && (isNumberType(top) ||
isPrimitiveChar(top))) {
MethodVisitor mv = controller.getMethodVisitor();
visitInsnByType(top, mv, ICONST_1, LCONST_1, FCONST_1, DCONST_1);
if ("next".equals(method)) {
@@ -303,39 +298,24 @@ public class
StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpres
}
private boolean makeSetPrivateFieldWithBridgeMethod(final Expression
receiver, final ClassNode receiverType, final String fieldName, final
Expression arguments, final boolean safe, final boolean spreadSafe, final
boolean implicitThis) {
- FieldNode field = receiverType.getField(fieldName);
- ClassNode outerClass = receiverType.getOuterClass();
- if (field == null && implicitThis && outerClass != null &&
!receiverType.isStaticClass()) {
- Expression pexp;
- if (controller.isInGeneratedFunction()) {
- MethodCallExpression mce = callThisX("getThisObject");
- mce.setImplicitThis(true);
- mce.setMethodTarget(CLOSURE_GETTHISOBJECT_METHOD);
- mce.putNodeMetaData(INFERRED_TYPE, controller.getThisType());
- pexp = castX(controller.getThisType(), mce);
- } else {
- pexp = propX(classX(outerClass), "this");
- ((PropertyExpression) pexp).setImplicitThis(true);
- }
- pexp.putNodeMetaData(INFERRED_TYPE, outerClass);
- pexp.setSourcePosition(receiver);
- return makeSetPrivateFieldWithBridgeMethod(pexp, outerClass,
fieldName, arguments, safe, spreadSafe, true);
- }
- ClassNode classNode = controller.getClassNode();
- if (field != null && field.isPrivate() &&
!receiverType.equals(classNode)
- &&
(StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType,
classNode)
- ||
StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode,
receiverType))) {
- Map<String, MethodNode> mutators =
receiverType.redirect().getNodeMetaData(PRIVATE_FIELDS_MUTATORS);
- if (mutators != null) {
- MethodNode methodNode = mutators.get(fieldName);
- if (methodNode != null) {
- MethodCallExpression call = callX(receiver,
methodNode.getName(), args(field.isStatic() ? nullX() : receiver, arguments));
- call.setImplicitThis(implicitThis);
- call.setMethodTarget(methodNode);
- call.setSafe(safe);
- call.setSpreadSafe(spreadSafe);
- call.visit(controller.getAcg());
- return true;
+ FieldNode fieldNode = receiverType.getField(fieldName);
+ if (fieldNode != null) {
+ ClassNode classNode = controller.getClassNode();
+ if (fieldNode.isPrivate() && !receiverType.equals(classNode)
+ &&
(StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType,
classNode)
+ ||
StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode,
receiverType))) {
+ Map<String, MethodNode> mutators =
receiverType.redirect().getNodeMetaData(PRIVATE_FIELDS_MUTATORS);
+ if (mutators != null) {
+ MethodNode methodNode = mutators.get(fieldName);
+ if (methodNode != null) {
+ MethodCallExpression call = callX(receiver,
methodNode.getName(), args(fieldNode.isStatic() ? nullX() : receiver,
arguments));
+ call.setImplicitThis(implicitThis);
+ call.setMethodTarget(methodNode);
+ call.setSafe(safe);
+ call.setSpreadSafe(spreadSafe);
+ call.visit(controller.getAcg());
+ return true;
+ }
}
}
}
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index 985e640108..1bb0415a61 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -827,28 +827,30 @@ public class StaticTypesCallSiteWriter extends
CallSiteWriter {
return receiverType;
}
- // this is just a simple set field handling static and non-static, but not
Closure and inner classes
private boolean setField(final PropertyExpression expression, final
Expression objectExpression, final ClassNode receiverType, final String name) {
- if (expression.isSafe()) return false;
+ if (expression.isSafe() || expression.isSpreadSafe()) return false;
+
FieldNode fn =
AsmClassGenerator.getDeclaredFieldOfCurrentClassOrAccessibleFieldOfSuper(controller.getClassNode(),
receiverType, name, false);
if (fn == null) return false;
- OperandStack stack = controller.getOperandStack();
- stack.doGroovyCast(fn.getType());
+
+ OperandStack os = controller.getOperandStack();
+ os.doGroovyCast(fn.getType());
MethodVisitor mv = controller.getMethodVisitor();
if (!fn.isStatic()) {
controller.getCompileStack().pushLHS(false);
objectExpression.visit(controller.getAcg());
controller.getCompileStack().popLHS();
- if (!receiverType.equals(stack.getTopOperand())) {
+ if (!receiverType.equals(os.getTopOperand())) {
BytecodeHelper.doCast(mv, receiverType);
- stack.replace(receiverType);
+ os.replace(receiverType);
}
- stack.swap();
+ os.swap(); // stack: operand, receiver, ...
mv.visitFieldInsn(PUTFIELD,
BytecodeHelper.getClassInternalName(fn.getOwner()), name,
BytecodeHelper.getTypeDescription(fn.getType()));
- stack.remove(1);
- } else {
+ os.remove(2);
+ } else { // stack: operand, ...
mv.visitFieldInsn(PUTSTATIC,
BytecodeHelper.getClassInternalName(receiverType), name,
BytecodeHelper.getTypeDescription(fn.getType()));
+ os.remove(1);
}
return true;
diff --git
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
index 7183bb3c04..8c32ebad55 100644
---
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
+++
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationMetadataKeys.java
@@ -22,13 +22,24 @@ package org.codehaus.groovy.transform.sc;
* Static compilation AST node metadata keys.
*/
public enum StaticCompilationMetadataKeys {
- STATIC_COMPILE_NODE, // used to mark a section of code as to be statically
compiled
- BINARY_EXP_TARGET, // use to tell which method should be used in a binary
expression
- PRIVATE_BRIDGE_METHODS, // private bridge methods are methods used by an
outer class to access an inner class method
- PRIVATE_FIELDS_ACCESSORS, // private fields accessors are methods used by
an inner class to access an outer class field
- PRIVATE_FIELDS_MUTATORS, // private fields mutators are methods used by an
inner class to set an outer class field
- DYNAMIC_OUTER_NODE_CALLBACK, // callback for dynamic classes that contain
statically compiled inner classes or methods
- PROPERTY_OWNER, // the type of the class which owns the property
- COMPONENT_TYPE, // for list.property expressions, we need the inferred
component type
- RECEIVER_OF_DYNAMIC_PROPERTY // if a receiver is the receiver of a dynamic
property (for mixed mode compilation)
+ /** Marks a section of code for static compilation. */
+ STATIC_COMPILE_NODE,
+ /** Tells which method should be used in a binary expression. */
+ BINARY_EXP_TARGET,
+ /** Private bridge methods are methods used to access a nestmate's method.
*/
+ PRIVATE_BRIDGE_METHODS,
+ /** Private fields accessors are methods used to read a nestmate's field.
*/
+ @Deprecated(since = "5.0.0")
+ PRIVATE_FIELDS_ACCESSORS,
+ /** Private fields mutators are methods used to write a nestmate's field.
*/
+ @Deprecated(since = "5.0.0")
+ PRIVATE_FIELDS_MUTATORS,
+ /** Callback for dynamic classes that contain statically compiled inner
classes or methods. */
+ DYNAMIC_OUTER_NODE_CALLBACK,
+ /** The type of the class which owns the property. */
+ PROPERTY_OWNER,
+ /** For list.property expressions, we need the inferred component type. */
+ COMPONENT_TYPE,
+ /** If a receiver is the receiver of a dynamic property (for mixed-mode
compilation). */
+ RECEIVER_OF_DYNAMIC_PROPERTY
}
diff --git
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index 758731783b..462e49c3d0 100644
---
a/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -429,6 +429,7 @@ public class StaticCompilationVisitor extends
StaticTypeCheckingVisitor {
/**
* Adds special accessors and mutators for private fields so that inner
classes can get/set them.
*/
+ @Deprecated(since = "5.0.0")
private static void addPrivateFieldsAccessors(final ClassNode node) {
Map<String, MethodNode> privateFieldAccessors =
node.getNodeMetaData(PRIVATE_FIELDS_ACCESSORS);
Map<String, MethodNode> privateFieldMutators =
node.getNodeMetaData(PRIVATE_FIELDS_MUTATORS);
diff --git
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
index fc54a954f9..f4811f5779 100644
---
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
+++
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/PropertyExpressionTransformer.java
@@ -18,13 +18,18 @@
*/
package org.codehaus.groovy.transform.sc.transformers;
+import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import static org.apache.groovy.ast.tools.ExpressionUtils.isThisExpression;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
class PropertyExpressionTransformer {
@@ -48,6 +53,28 @@ class PropertyExpressionTransformer {
return mce;
}
+ FieldNode field =
pe.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
+ if (field == null) {
+ field = pe.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
+ }
+ if (field != null) {
+ AttributeExpression ae;
+ if (field.isStatic()) {
+ ae = new
AttributeExpression(classX(field.getDeclaringClass()), pe.getProperty());
+ } else if (!isThisExpression(pe.getObjectExpression())) {
+ ae = new
AttributeExpression(scTransformer.transform(pe.getObjectExpression()),
pe.getProperty(), pe.isSafe());
+ } else {
+ ae = new AttributeExpression(new
PropertyExpression(classX(field.getDeclaringClass()), "this"),
pe.getProperty(), pe.isSafe());
+
+
ae.getObjectExpression().putNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER,
field.getDeclaringClass());
+
ae.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE,
field.getDeclaringClass());
+ }
+ ae.setSpreadSafe(pe.isSpreadSafe());
+ ae.setSourcePosition(pe);
+ ae.copyNodeMetaData(pe);
+ return ae;
+ }
+
return scTransformer.superTransform(pe);
}
}
diff --git
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
index f15915513b..c2d3d44fa7 100644
---
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
+++
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -28,10 +28,10 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.attrX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
class VariableExpressionTransformer {
@@ -86,9 +86,9 @@ class VariableExpressionTransformer {
return null;
}
- // access to a private field from a section of code that normally
doesn't have access to it, like a closure block or an inner class
- PropertyExpression pe = !field.isStatic() ? thisPropX(true,
ve.getName()) : propX(classX(field.getDeclaringClass()), ve.getName());
- // store the declaring class so that the class writer knows that it
will have to call a bridge method
+ // access to a private field from a section of code that normally
doesn't have access to it, like a closure block or inner class
+ Expression fieldOwner = field.isStatic() ?
classX(field.getDeclaringClass()) : propX(classX(field.getDeclaringClass()),
"this");
+ PropertyExpression pe = attrX(fieldOwner, ve.getName()); //
GROOVY-10687, GROOVY-11412: direct access
pe.getObjectExpression().putNodeMetaData(StaticTypesMarker.INFERRED_TYPE,
field.getDeclaringClass());
pe.putNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE,
field.getOriginType());
pe.getProperty().setSourcePosition(ve);
diff --git
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 2d46571a71..87ed4596a2 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -592,8 +592,7 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
ClassNode declaringClass = fn.getDeclaringClass();
ClassNode enclosingClass =
typeCheckingContext.getEnclosingClassNode();
if (declaringClass == enclosingClass ?
typeCheckingContext.getEnclosingClosure() != null : getNestHost(declaringClass)
== getNestHost(enclosingClass)) {
- StaticTypesMarker accessKind = lhsOfAssignment ?
PV_FIELDS_MUTATION : PV_FIELDS_ACCESS;
- addPrivateFieldOrMethodAccess(source, declaringClass,
accessKind, fn);
+ source.putNodeMetaData(lhsOfAssignment ? PV_FIELDS_MUTATION :
PV_FIELDS_ACCESS, fn);
}
}
}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
b/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
index 3ccf2a2f96..db63589cda 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/NestHostTests.groovy
@@ -119,4 +119,19 @@ final class NestHostTests {
assert type.nestMembers*.name.sort() == ['C', 'C$D',
'C$D$_m_lambda1', 'C$D$_m_lambda1$_lambda2']
}
}
+
+ @Test
+ void testNestHost6() {
+ def types = compileScript '''
+ @groovy.transform.CompileStatic
+ class C {
+ def closure = { -> { -> Optional.empty().orElseGet(() -> 42) }
}
+ }
+ '''
+
+ types.each { type ->
+ assert type.nestHost.name == 'C'
+ assert type.nestMembers*.name.sort() == ['C', 'C$_closure1',
'C$_closure1$_closure2', 'C$_closure1$_closure2$_lambda3']
+ }
+ }
}
diff --git
a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
index 4e2b2d5bd5..f9a5f17f8a 100644
---
a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
+++
b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
@@ -616,45 +616,35 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new Bar().test()
'''
- String bar = astTrees['Bar'][1]
- assert bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/lang/Long;)V')
- assert bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/util/Date;)V')
+ String bar = astTrees['Bar'][1]
+ assert bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/lang/Long;)V')
+ assert bar.contains('INVOKEVIRTUAL Bar.setX (Ljava/util/Date;)V')
assert !bar.contains('INVOKESTATIC
org/codehaus/groovy/runtime/ScriptBytecodeAdapter.setGroovyObjectProperty ')
}
- void testPrivateFieldMutationInClosureUsesBridgeMethod() {
- assertScript '''
- class Foo {
- private String s
- Closure c = { this.s = 'abc' }
-
- void test() {
- c()
- assert s == 'abc'
- }
- }
- new Foo().test()
- '''
- assert astTrees['Foo$_closure1'][1].contains('INVOKESTATIC
Foo.pfaccess$00 (LFoo;Ljava/lang/String;)Ljava/lang/String')
- }
-
- void testImplicitPrivateFieldMutationInClosureUsesBridgeMethod() {
- assertScript '''
- class Foo {
- private String s
- Closure c = { s = 'abc' }
+ // GROOVY-7705, GROOVY-10687
+ void testPrivateFieldMutationInClosureUsesDirectAccess() {
+ for (prefix in ['','this.','thisObject.','getThisObject().']) {
+ assertScript """
+ class Foo {
+ Closure c = { -> ${prefix}s = 'abc' }
+ private s
- String test() {
- c()
- assert s == 'abc'
+ void test() {
+ c()
+ assert s == 'abc'
+ }
}
- }
- new Foo().test()
- '''
- assert astTrees['Foo$_closure1'][1].contains('INVOKESTATIC
Foo.pfaccess$00 (LFoo;Ljava/lang/String;)Ljava/lang/String')
+ new Foo().test()
+ """
+ String c = astTrees['Foo$_closure1'][1]
+ assert c.contains('PUTFIELD Foo.s') // JEP 181: nestmate access
+ assert !c.contains('INVOKESTATIC Foo.pfaccess$00
(LFoo;Ljava/lang/Object;)')
+ }
}
- void testPrivateStaticFieldMutationInClosureUsesBridgeMethod() {
+ // GROOVY-7705, GROOVY-10687
+ void testPrivateStaticFieldMutationInClosureUsesDirectAccess() {
assertScript '''
class Foo {
private static String s
@@ -667,10 +657,13 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new Foo().test()
'''
- assert astTrees['Foo$_closure1'][1].contains('INVOKESTATIC
Foo.pfaccess$00 (LFoo;Ljava/lang/String;)Ljava/lang/String')
+ String c = astTrees['Foo$_closure1'][1]
+ assert c.contains('PUTSTATIC Foo.s') // JEP 181: nestmate access
+ assert !c.contains('INVOKESTATIC Foo.pfaccess$00
(LFoo;Ljava/lang/String;)')
}
- void testPrivateFieldMutationInAICUsesBridgeMethod() {
+ // GROOVY-7705, GROOVY-10687
+ void testPrivateFieldMutationInAICUsesDirectAccess() {
assertScript '''
class C {
private int x
@@ -682,10 +675,13 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new C().test()
'''
- assert astTrees['C$1'][1].contains('INVOKESTATIC C.pfaccess$00
(LC;I)I')
+ String aic = astTrees['C$1'][1]
+ assert aic.contains('PUTFIELD C.x') // direct access
+ assert !aic.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
}
- void testImplicitPrivateFieldMutationInAICUsesBridgeMethod() {
+ // GROOVY-7705, GROOVY-10687
+ void testImplicitPrivateFieldMutationInAICUsesDirectAccess() {
assertScript '''
class C {
private int x
@@ -697,10 +693,13 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new C().test()
'''
- assert astTrees['C$1'][1].contains('INVOKESTATIC C.pfaccess$00
(LC;I)I')
+ String aic = astTrees['C$1'][1]
+ assert aic.contains('PUTFIELD C.x') // direct access
+ assert !aic.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
}
- void testPrivateStaticFieldMutationInAICUsesBridgeMethod() {
+ // GROOVY-7705, GROOVY-10687
+ void testPrivateStaticFieldMutationInAICUsesDirectAccess() {
assertScript '''
class C {
private static int x
@@ -712,10 +711,13 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new C().test()
'''
- assert astTrees['C$1'][1].contains('INVOKESTATIC C.pfaccess$00
(LC;I)I')
+ String aic = astTrees['C$1'][1]
+ assert aic.contains('PUTSTATIC C.x') // direct access
+ assert !aic.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
}
- void testMultiplePrivateFieldMutatorBridgeMethods() {
+ // GROOVY-7705, GROOVY-10687
+ void testMultiplePrivateFieldMutatorDirectAccess() {
assertScript '''
class C {
private int x
@@ -730,10 +732,14 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new C().test()
'''
- assert astTrees['C$_closure1'][1].contains('INVOKESTATIC C.pfaccess$00
(LC;I)I')
- assert astTrees['C$_closure1'][1].contains('INVOKESTATIC C.pfaccess$01
(LC;Ljava/lang/String;)Ljava/lang/String;')
+ String closure = astTrees['C$_closure1'][1]
+ assert closure.contains('PUTFIELD C.x') // direct access
+ assert closure.contains('PUTFIELD C.y') // direct access
+ assert !closure.contains('INVOKESTATIC C.pfaccess$00 (LC;I)I')
+ assert !closure.contains('INVOKESTATIC C.pfaccess$01
(LC;Ljava/lang/String;)Ljava/lang/String;')
}
+ // GROOVY-7705, GROOVY-9385, GROOVY-10687
void testPrivateFieldBridgeMethodsAreGeneratedAsNecessary() {
assertScript '''
class C {
@@ -754,16 +760,16 @@ final class FieldsAndPropertiesStaticCompileTest extends
FieldsAndPropertiesSTCT
}
new C().test()
'''
- String dump = astTrees['C'][1]
- assert dump.contains('pfaccess$0') // accessor bridge method for
'accessed'
- assert !dump.contains('pfaccess$00') // no mutator bridge method for
'accessed'
- assert dump.contains('pfaccess$01') // mutator bridge method for
'mutated'
- assert dump.contains('pfaccess$1') // accessor bridge method for
'mutated' -- GROOVY-9385
- assert dump.contains('pfaccess$2') // accessor bridge method for
'accessedAndMutated'
- assert dump.contains('pfaccess$02') // mutator bridge method for
'accessedAndMutated'
+ String dump = astTrees['C'][1]
+ assert !dump.contains('pfaccess$0') // no access bridge method for
'accessed'
+ assert !dump.contains('pfaccess$00') // no mutate bridge method for
'accessed'
+ assert !dump.contains('pfaccess$01') // no mutate bridge method for
'mutated'
+ assert !dump.contains('pfaccess$1') // no access bridge method for
'mutated'
+ assert !dump.contains('pfaccess$2') // no access bridge method for
'accessedAndMutated'
+ assert !dump.contains('pfaccess$02') // no mutate bridge method for
'accessedAndMutated'
dump = astTrees['C$_closure1'][1]
- assert dump.contains('INVOKESTATIC C.pfaccess$2
(LC;)Ljava/lang/String;')
- assert dump.contains('INVOKESTATIC C.pfaccess$02
(LC;Ljava/lang/String;)Ljava/lang/String;')
+ assert !dump.contains('INVOKESTATIC C.pfaccess$2
(LC;)Ljava/lang/String;')
+ assert !dump.contains('INVOKESTATIC C.pfaccess$02
(LC;Ljava/lang/String;)Ljava/lang/String;')
}
// GROOVY-8369