Logo Search packages:      
Sourcecode: aspectj version File versions  Download package

ThisJoinPointVisitor.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.ajdt.internal.compiler.ast;

import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.bridge.context.ContextToken;
import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NameReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.weaver.Advice;

/**
 * Takes a method that already has the three extra parameters thisJoinPointStaticPart, thisJoinPoint and
 * thisEnclosingJoinPointStaticPart
 */

00039 public class ThisJoinPointVisitor extends ASTVisitor {
      boolean needsDynamic = false;
      boolean needsStatic = false;
      boolean needsStaticEnclosing = false;
      boolean hasEffectivelyStaticRef = false;
      boolean hasConstantReference = false;
      boolean constantReferenceValue = false; // only has valid value when hasConstantReference is true

      LocalVariableBinding thisJoinPointDec;
      LocalVariableBinding thisJoinPointStaticPartDec;
      LocalVariableBinding thisEnclosingJoinPointStaticPartDec;

      LocalVariableBinding thisJoinPointDecLocal;
      LocalVariableBinding thisJoinPointStaticPartDecLocal;
      LocalVariableBinding thisEnclosingJoinPointStaticPartDecLocal;

      boolean replaceEffectivelyStaticRefs = false;

      AbstractMethodDeclaration method;

      ThisJoinPointVisitor(AbstractMethodDeclaration method) {
            this.method = method;
            int index = method.arguments.length - 3;

            thisJoinPointStaticPartDecLocal = method.scope.locals[index];
            thisJoinPointStaticPartDec = method.arguments[index++].binding;
            thisJoinPointDecLocal = method.scope.locals[index];
            thisJoinPointDec = method.arguments[index++].binding;
            thisEnclosingJoinPointStaticPartDecLocal = method.scope.locals[index];
            thisEnclosingJoinPointStaticPartDec = method.arguments[index++].binding;
      }

      public void computeJoinPointParams() {
            // walk my body to see what is needed
            method.traverse(this, (ClassScope) null);

            // ??? add support for option to disable this optimization
            // System.err.println("walked: " + method);
            // System.err.println("check:  "+ hasEffectivelyStaticRef + ", " + needsDynamic);
            if (hasEffectivelyStaticRef && !needsDynamic) {
                  // replace effectively static refs with thisJoinPointStaticPart
                  replaceEffectivelyStaticRefs = true;
                  needsStatic = true;
                  method.traverse(this, (ClassScope) null);
            }
            // System.err.println("done: " + method);
      }

      boolean isRef(NameReference ref, Binding binding) {
            // System.err.println("check ref: " + ref + " is " + System.identityHashCode(ref));
            return ref.binding == binding;
      }

      boolean isRef(Expression expr, Binding binding) {
            return expr != null && expr instanceof NameReference && isRef((NameReference) expr, binding);
      }

      public void endVisit(SingleNameReference ref, BlockScope scope) {
            if (isRef(ref, thisJoinPointDec)) {
                  needsDynamic = true;
            } else if (isRef(ref, thisJoinPointStaticPartDec)) {
                  needsStatic = true;
            } else if (isRef(ref, thisEnclosingJoinPointStaticPartDec)) {
                  needsStaticEnclosing = true;
            } else if (ref.constant != null && ref.constant != Constant.NotAConstant) {
                  if (ref.constant instanceof BooleanConstant) {
                        hasConstantReference = true;
                        constantReferenceValue = ((BooleanConstant) ref.constant).booleanValue();
                  }
            }
      }

      boolean canTreatAsStatic(String id) {
            return id.equals("toString") || id.equals("toShortString") || id.equals("toLongString") || id.equals("getKind")
                        || id.equals("getSignature") || id.equals("getSourceLocation");
            // TODO: This is a good optimization, but requires more work than the above
            // we have to replace a call with a direct reference, not just a different call
            // || id.equals("getStaticPart");
      }

      // boolean canTreatAsStatic(VarExpr varExpr) {
      // ASTObject parent = varExpr.getParent();
      // if (parent instanceof CallExpr) {
      // Method calledMethod = ((CallExpr)parent).getMethod();
      // return canTreatAsStatic(calledMethod);
      //
      // //??? should add a case here to catch
      // //??? tjp.getEnclosingExecutionJoinPoint().STATIC_METHOD()
      // } else if (parent instanceof BinopExpr) {
      // BinopExpr binop = (BinopExpr)parent;
      // if (binop.getType().isEquivalent(this.getTypeManager().getStringType())) {
      // return true;
      // } else {
      // return false;
      // }
      // } else {
      // return false;
      // }
      // }

      boolean inBlockThatCantRun = false;

      public boolean visit(MessageSend call, BlockScope scope) {
            ContextToken tok = CompilationAndWeavingContext.enteringPhase(
                        CompilationAndWeavingContext.OPTIMIZING_THIS_JOIN_POINT_CALLS, call.selector);
            Expression receiver = call.receiver;
            if (isRef(receiver, thisJoinPointDec)) {
                  if (canTreatAsStatic(new String(call.selector))) {
                        if (replaceEffectivelyStaticRefs) {
                              replaceEffectivelyStaticRef(call);
                        } else {
                              // System.err.println("has static reg");
                              hasEffectivelyStaticRef = true;
                              if (call.arguments != null) {
                                    int argumentsLength = call.arguments.length;
                                    for (int i = 0; i < argumentsLength; i++)
                                          call.arguments[i].traverse(this, scope);
                              }
                              CompilationAndWeavingContext.leavingPhase(tok);
                              return false;
                        }
                  }
            }

            boolean ret = super.visit(call, scope);
            CompilationAndWeavingContext.leavingPhase(tok);
            return ret;
      }

      private void replaceEffectivelyStaticRef(MessageSend call) {
            NameReference receiver = (NameReference) call.receiver;

            // Don't continue if the call binding is null, as we are going to report an error about this line of code!
            if (call.binding == null)
                  return;

            // System.err.println("replace static ref: " + receiver + " is " + System.identityHashCode(receiver));
            receiver.binding = thisJoinPointStaticPartDecLocal; // thisJoinPointStaticPartDec;
            receiver.codegenBinding = thisJoinPointStaticPartDecLocal;

            ReferenceBinding thisJoinPointStaticPartType = (ReferenceBinding) thisJoinPointStaticPartDec.type;

            receiver.actualReceiverType = receiver.resolvedType = thisJoinPointStaticPartType;

            call.setActualReceiverType(thisJoinPointStaticPartType);

            AstUtil.replaceMethodBinding(call, getEquivalentStaticBinding(call.binding));
      }

      private MethodBinding getEquivalentStaticBinding(MethodBinding template) {
            ReferenceBinding b = (ReferenceBinding) thisJoinPointStaticPartDec.type;
            return b.getExactMethod(template.selector, template.parameters, null);
      }

      public int removeUnusedExtraArguments() {
            int extraArgumentFlags = 0;

            this.computeJoinPointParams();
            MethodBinding binding = method.binding;

            int index = binding.parameters.length - 3;
            if (needsStaticEnclosing) {
                  extraArgumentFlags |= Advice.ThisEnclosingJoinPointStaticPart;
            } else {
                  removeParameter(index + 2);
            }

            if (needsDynamic) {
                  extraArgumentFlags |= Advice.ThisJoinPoint;
            } else {
                  removeParameter(index + 1);
            }

            if (needsStatic) {
                  extraArgumentFlags |= Advice.ThisJoinPointStaticPart;
            } else {
                  removeParameter(index + 0);
            }

            return extraArgumentFlags;
      }

      private void removeParameter(int indexToRemove) {
            // TypeBinding[] parameters = method.binding.parameters;
            method.scope.locals = removeLocalBinding(indexToRemove, method.scope.locals);
            method.scope.localIndex -= 1;
            method.binding.parameters = removeParameter(indexToRemove, method.binding.parameters);
      }

      private static TypeBinding[] removeParameter(int index, TypeBinding[] bindings) {
            int len = bindings.length;
            TypeBinding[] ret = new TypeBinding[len - 1];
            System.arraycopy(bindings, 0, ret, 0, index);
            System.arraycopy(bindings, index + 1, ret, index, len - index - 1);
            return ret;
      }

      private static LocalVariableBinding[] removeLocalBinding(int index, LocalVariableBinding[] bindings) {
            int len = bindings.length;
            // ??? for performance we should do this in-place
            LocalVariableBinding[] ret = new LocalVariableBinding[len - 1];
            System.arraycopy(bindings, 0, ret, 0, index);
            System.arraycopy(bindings, index + 1, ret, index, len - index - 1);
            return ret;
      }

}

Generated by  Doxygen 1.6.0   Back to index