Package org.aspectj.ajdt.internal.compiler.ast

Source Code of org.aspectj.ajdt.internal.compiler.ast.ThisJoinPointVisitor

/* *******************************************************************
* 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
*/

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;
  }

}
TOP

Related Classes of org.aspectj.ajdt.internal.compiler.ast.ThisJoinPointVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.