blob: 27fbff1ae5f0475550a8e69b5c22d3c05543877f [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* 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 com.google.gwt.dev.jjs.impl;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JVariable;
import java.util.Collection;
/**
* A visitor for optimizing an AST.
* <p>
* Subclasses of JChangeTrackingVisitor should override enter/exit instead of visit/endVisit for
* JMethod, JConstructor, JVariable and JField
* <p>
* Passes that modify the Java AST while an OptimizerContext is in effect should subclass this
* class (JChangeTrackingVisitor) instead of {@link JModVisitor} or interact with
* {@link OptimizerContext} directly.
* <p>
* Passes that would like to act only on parts of the tree related to the modification that happened
* since the pass was last run should do something like:
* {@code
* String passName = "SomeUniqueNameForThisPass";
* int lastSeenOptmizationStep = optimizerContext.getLastStepFor(passName);
* Set<JMethod> modifiedMethods =
* optimizerContext.getModifiedMethodsSince(lastSeenOptmizationStep)
* Set<JField> modifiedFields =
* optimizerContext.getModifiedFieldsSince(lastSeenOptmizationStep)
* // compute potentially affected fields and methods and run the optimizer just on those
* ....
* //
* optimizerContext.setLastStepFor(passName, optimizerContext.getCurrentOptimizationStep());
* optimizerContext.incOptimizationStep;
* }
*/
public abstract class JChangeTrackingVisitor extends JModVisitor {
private JField currentField;
private JMethod currentMethod;
private final OptimizerContext optimizerCtx;
private boolean fieldModified = false;
private boolean methodModified = false;
public JChangeTrackingVisitor(OptimizerContext optimizerCtx) {
this.optimizerCtx = optimizerCtx;
}
@Override
public final void endVisit(JConstructor x, Context ctx) {
exit(x, ctx);
if (methodModified) {
optimizerCtx.markModified(x);
}
currentMethod = null;
}
@Override
public final void endVisit(JField x, Context ctx) {
exit(x, ctx);
if (fieldModified) {
optimizerCtx.markModified(x);
}
currentField = null;
}
@Override
public final void endVisit(JMethod x, Context ctx) {
exit(x, ctx);
currentMethod = null;
if (!methodModified) {
return;
}
optimizerCtx.markModified(x);
if (JProgram.isClinit(x) || JProgram.isInit(x)) {
// Mark all class static fields as modified when a class clinit is modified to reflect
// that when inline declaration statements are modified the corresponding field must
// be considered modified.
for (JField potentiallyModifiedField: x.getEnclosingType().getFields()) {
if (potentiallyModifiedField.isStatic() && JProgram.isClinit(x)
|| !potentiallyModifiedField.isStatic() && !JProgram.isClinit(x)) {
optimizerCtx.markModified(potentiallyModifiedField);
}
}
}
}
@Override
public final void endVisit(JVariable x, Context ctx) {
exit(x, ctx);
}
public boolean enter(JConstructor x, Context ctx) {
return enter((JMethod) x, ctx);
}
public boolean enter(JField x, Context ctx) {
return enter((JVariable) x, ctx);
}
public boolean enter(JMethod x, Context ctx) {
return true;
}
public boolean enter(JVariable x, Context ctx) {
return true;
}
public void exit(JConstructor x, Context ctx) {
exit((JMethod) x, ctx);
}
public void exit(JField x, Context ctx) {
exit((JVariable) x, ctx);
}
public void exit(JMethod x, Context ctx) {
return;
}
public void exit(JVariable x, Context ctx) {
return;
}
public JField getCurrentField() {
return currentField;
}
public JMethod getCurrentMethod() {
return currentMethod;
}
@Override
public final boolean visit(JConstructor x, Context ctx) {
currentMethod = x;
methodModified = false;
return enter(x, ctx);
}
@Override
public final boolean visit(JField x, Context ctx) {
currentField = x;
fieldModified = false;
return enter(x, ctx);
}
@Override
public final boolean visit(JMethod x, Context ctx) {
currentMethod = x;
methodModified = false;
return enter(x, ctx);
}
@Override
public final boolean visit(JVariable x, Context ctx) {
return enter(x, ctx);
}
public final void wasRemoved(JField field) {
optimizerCtx.remove(field);
}
public final void wasRemoved(JMethod method) {
optimizerCtx.remove(method);
}
public final void methodsWereRemoved(Collection<JMethod> methods) {
optimizerCtx.removeMethods(methods);
}
public final void fieldsWereRemoved(Collection<JField> fields) {
optimizerCtx.removeFields(fields);
}
@Override
protected final void madeChanges() {
super.madeChanges();
if (currentMethod != null) {
methodModified = true;
}
if (currentField != null) {
fieldModified = true;
}
}
}