/* * Copyright 2009-2010 MBTE Sweden AB. * * Licensed 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.mbte.groovypp.compiler; import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.ast.stmt.ExpressionStatement; import org.codehaus.groovy.ast.stmt.ReturnStatement; import org.codehaus.groovy.ast.stmt.Statement; import org.codehaus.groovy.syntax.Token; import org.codehaus.groovy.syntax.Types; import org.objectweb.asm.Opcodes; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class SourceUnitContext { private int syntheticAccessorNumber = 1979; private int tempVarNumber = 1979; public Map<FieldNode, MethodNode> generatedFieldGetters = new HashMap<FieldNode, MethodNode>(); public Map<FieldNode, MethodNode> generatedFieldSetters = new HashMap<FieldNode, MethodNode>(); public Map<MethodNode, MethodNode> generatedMethodDelegates = new HashMap<MethodNode, MethodNode>(); private Map<MethodNode, Integer> generatedSuperMethodAccessorNumbers = new HashMap<MethodNode, Integer>(); private Set<ClassNode> outerClassInstanceUsers = new HashSet<ClassNode>(); public MethodNode getFieldGetter(FieldNode field) { MethodNode getter = generatedFieldGetters.get(field); if (getter == null) { initAccessors(field); getter = generatedFieldGetters.get(field); } return getter; } public MethodNode getFieldSetter(FieldNode field) { MethodNode setter = generatedFieldSetters.get(field); if (setter == null) { initAccessors(field); setter = generatedFieldSetters.get(field); } return setter; } private void initAccessors(FieldNode field) { int num = syntheticAccessorNumber++; String getterName = "getField" + num; int modifiers = field.getModifiers() & Opcodes.ACC_STATIC; MethodNode getter = new MethodNode(getterName, modifiers, field.getType(), new Parameter[0], new ClassNode[0], new ReturnStatement(new VariableExpression(field))); ClassNode clazz = field.getDeclaringClass(); getter.setDeclaringClass(clazz); clazz.addMethod(getter); generatedFieldGetters.put(field, getter); if (!field.isFinal()) { String setterName = "setField" + num; Parameter[] setterParams = {new Parameter(field.getType(), "p")}; ExpressionStatement code = new ExpressionStatement(new BinaryExpression(new VariableExpression(field), Token.newSymbol(Types.ASSIGN, -1, -1), new VariableExpression("p"))); MethodNode setter = new MethodNode(setterName, modifiers, ClassHelper.VOID_TYPE, setterParams, new ClassNode[0], code); setter.setDeclaringClass(clazz); clazz.addMethod(setter); generatedFieldSetters.put(field, setter); } ClassNodeCache.clearCache(clazz); } public MethodNode getMethodDelegate(MethodNode method) { MethodNode delegate = generatedMethodDelegates.get(method); if (delegate == null) { int num = syntheticAccessorNumber++; String name = "delegate" + num; int modifiers = method.getModifiers() & Opcodes.ACC_STATIC; Expression[] exprs = new Expression[method.getParameters().length]; for (int i = 0; i < exprs.length; i++) { exprs[i] = new VariableExpression(method.getParameters()[i]); } Expression argList = new ArgumentListExpression(exprs); delegate = new MethodNode(name, modifiers, method.getReturnType(), method.getParameters(), new ClassNode[0], new ReturnStatement(new MethodCallExpression(new VariableExpression("this", ClassHelper.DYNAMIC_TYPE), method.getName(), argList))); delegate.setGenericsTypes(method.getGenericsTypes()); generatedMethodDelegates.put(method, delegate); ClassNode clazz = method.getDeclaringClass(); delegate.setDeclaringClass(clazz); clazz.addMethod(delegate); ClassNodeCache.clearCache(clazz); } return delegate; } public MethodNode getConstructorDelegate(MethodNode constructor) { MethodNode delegate = generatedMethodDelegates.get(constructor); if (delegate == null) { int num = syntheticAccessorNumber++; String name = "delegate" + num; int modifiers = Opcodes.ACC_STATIC; Expression[] exprs = new Expression[constructor.getParameters().length]; for (int i = 0; i < exprs.length; i++) { exprs[i] = new VariableExpression(constructor.getParameters()[i]); } Expression argList = new ArgumentListExpression(exprs); delegate = new MethodNode(name, modifiers, constructor.getDeclaringClass(), constructor.getParameters(), new ClassNode[0], new ReturnStatement(new ConstructorCallExpression(constructor.getDeclaringClass(), argList))); generatedMethodDelegates.put(constructor, delegate); ClassNode clazz = constructor.getDeclaringClass(); delegate.setDeclaringClass(clazz); clazz.addMethod(delegate); ClassNodeCache.clearCache(clazz); } return delegate; } public MethodNode getSuperMethodDelegate(MethodNode superMethod, ClassNode placeClass) { Integer num = generatedSuperMethodAccessorNumbers.get(superMethod); if (num == null) { num = syntheticAccessorNumber++; generatedSuperMethodAccessorNumbers.put(superMethod, num); } String name = "delegate" + num; final ClassNode declaringClass = superMethod.getDeclaringClass(); final Parameter[] superParams = superMethod.getParameters(); Parameter[] params = new Parameter[superParams.length]; for (int i = 0; i < params.length; i++) { ClassNode type = TypeUtil.mapTypeFromSuper(superParams[i].getType(), declaringClass, placeClass); params[i] = new Parameter(type, superParams[i].getName()); } MethodNode delegate = placeClass.getMethod(name, superParams); if (delegate == null) { Expression[] exprs = new Expression[superParams.length]; for (int i = 0; i < exprs.length; i++) { exprs[i] = new VariableExpression(params[i]); } Expression argList = new ArgumentListExpression(exprs); ClassNode ret = TypeUtil.mapTypeFromSuper(superMethod.getReturnType(), declaringClass, placeClass); final MethodCallExpression call = new MethodCallExpression(new VariableExpression("super", ClassHelper.DYNAMIC_TYPE), superMethod.getName(), argList); final Statement statement = ret != ClassHelper.VOID_TYPE ? new ReturnStatement(call) : new ExpressionStatement(call); final int modifiers = superMethod.getModifiers() & ~Opcodes.ACC_ABSTRACT; delegate = new MethodNode(name, modifiers, ret, params, new ClassNode[0], statement); delegate.setDeclaringClass(placeClass); placeClass.addMethod(delegate); ClassNodeCache.clearCache(placeClass); } return delegate; } public void setOuterClassInstanceUsed(ClassNode node) { outerClassInstanceUsers.add(node); } public boolean isOuterClassInstanceUsed(ClassNode node) { return outerClassInstanceUsers.contains(node); } public String getNextTempVarName() { return "$temp" + (tempVarNumber++); } }