org.codehaus.groovy.classgen.asm.sc.StaticTypesClosureWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy-all Show documentation
Show all versions of groovy-all Show documentation
Groovy: A powerful, dynamic language for the JVM
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.classgen.asm.sc;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.classgen.asm.ClosureWriter;
import org.codehaus.groovy.classgen.asm.WriterController;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
import org.codehaus.groovy.transform.stc.StaticTypesMarker;
import org.objectweb.asm.Opcodes;
import java.util.List;
/**
* Writer responsible for generating closure classes in statically compiled mode.
*
* @author Cedric Champeau
*/
public class StaticTypesClosureWriter extends ClosureWriter {
public StaticTypesClosureWriter(WriterController wc) {
super(wc);
}
@Override
protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) {
ClassNode closureClass = super.createClosureClass(expression, mods);
List methods = closureClass.getDeclaredMethods("call");
List doCall = closureClass.getMethods("doCall");
if (doCall.size() != 1) {
throw new GroovyBugError("Expected to find one (1) doCall method on generated closure, but found " + doCall.size());
}
MethodNode doCallMethod = doCall.get(0);
if (methods.isEmpty() && doCallMethod.getParameters().length == 1) {
createDirectCallMethod(closureClass, doCallMethod);
}
MethodTargetCompletionVisitor visitor = new MethodTargetCompletionVisitor(doCallMethod);
Object dynamic = expression.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION);
if (dynamic != null) {
doCallMethod.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, dynamic);
}
for (MethodNode method : methods) {
visitor.visitMethod(method);
}
closureClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE);
return closureClass;
}
private void createDirectCallMethod(final ClassNode closureClass, final MethodNode doCallMethod) {
// in case there is no "call" method on the closure, we can create a "fast invocation" paths
// to avoid going through ClosureMetaClass by call(Object...) method
// we can't have a specialized version of call(Object...) because the dispatch logic in ClosureMetaClass
// is too complex!
// call(Object)
Parameter args = new Parameter(ClassHelper.OBJECT_TYPE, "args");
MethodCallExpression doCall1arg = new MethodCallExpression(
new VariableExpression("this", closureClass),
"doCall",
new ArgumentListExpression(new VariableExpression(args))
);
doCall1arg.setImplicitThis(true);
doCall1arg.setMethodTarget(doCallMethod);
closureClass.addMethod(
new MethodNode("call",
Opcodes.ACC_PUBLIC,
ClassHelper.OBJECT_TYPE,
new Parameter[]{args},
ClassNode.EMPTY_ARRAY,
new ReturnStatement(doCall1arg)));
// call()
MethodCallExpression doCallNoArgs = new MethodCallExpression(new VariableExpression("this", closureClass), "doCall", new ArgumentListExpression(new ConstantExpression(null)));
doCallNoArgs.setImplicitThis(true);
doCallNoArgs.setMethodTarget(doCallMethod);
closureClass.addMethod(
new MethodNode("call",
Opcodes.ACC_PUBLIC,
ClassHelper.OBJECT_TYPE,
Parameter.EMPTY_ARRAY,
ClassNode.EMPTY_ARRAY,
new ReturnStatement(doCallNoArgs)));
}
private static class MethodTargetCompletionVisitor extends ClassCodeVisitorSupport {
private final MethodNode doCallMethod;
private MethodTargetCompletionVisitor(final MethodNode doCallMethod) {
this.doCallMethod = doCallMethod;
}
@Override
protected SourceUnit getSourceUnit() {
return null;
}
@Override
public void visitMethodCallExpression(final MethodCallExpression call) {
super.visitMethodCallExpression(call);
MethodNode mn = call.getMethodTarget();
if (mn == null) {
call.setMethodTarget(doCallMethod);
}
}
}
}