All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.dev.jjs.impl.Finalizer Maven / Gradle / Ivy

There is a newer version: 2.11.0
Show newest version
/*
 * Copyright 2007 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.CanBeSetFinal;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JPostfixOperation;
import com.google.gwt.dev.jjs.ast.JPrefixOperation;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVariableRef;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting;
import com.google.gwt.thirdparty.guava.common.collect.Sets;

import java.util.Set;

/**
 * Finds all items are effectively final. That is, methods that are never  overridden and variables
 * that are never reassigned.
 * 

* NOTE: Classes should not be marked final, since the analysis for classes is done through * {@link JAnalysisDecoratedType}. */ public class Finalizer { /** * Any items that weren't marked during MarkVisitor can be set final. * * Open question: What does it mean if an interface/abstract method becomes * final? Is this possible after Pruning? I guess it means that someone tried * to make a call to method that wasn't actually implemented anywhere in the * program. But if it wasn't implemented, then the enclosing class should have * come up as not instantiated and been culled. So I think it's not possible. */ private class FinalizeVisitor extends JChangeTrackingVisitor { public FinalizeVisitor(OptimizerContext optimizerCtx) { super(optimizerCtx); } @Override public void exit(JConstructor x, Context ctx) { // Not applicable. } @Override public void exit(JField x, Context ctx) { if (x.isVolatile() || x.canBeImplementedExternally() || x.canBeReferencedExternally()) { return; } maybeFinalize(x); } @Override public void endVisit(JLocal x, Context ctx) { maybeFinalize(x); } @Override public void exit(JMethod x, Context ctx) { if (!x.isFinal() && x.getOverridingMethods().isEmpty()) { setFinal(x); } } @Override public void endVisit(JParameter x, Context ctx) { maybeFinalize(x); } @Override public boolean visit(JClassType x, Context ctx) { // Don't visit external types, because we can't change their final // specifiers. return !x.isExternal(); } @Override public boolean visit(JMethodBody x, Context ctx) { for (JLocal local : x.getLocals()) { maybeFinalize(local); } return false; } private void maybeFinalize(JVariable x) { if (!x.isFinal() && !isReassigned.contains(x)) { setFinal(x); } } private void setFinal(CanBeSetFinal x) { x.setFinal(); assert x.isFinal(); madeChanges(); } } /** * Find all items that ARE overridden/subclassed/reassigned. */ private class MarkVisitor extends JVisitor { @Override public void endVisit(JBinaryOperation x, Context ctx) { if (x.getOp().isAssignment()) { recordAssignment(x.getLhs()); } } @Override public void endVisit(JConstructor x, Context ctx) { // Never overridden. } @Override public void endVisit(JDeclarationStatement x, Context ctx) { // This is should only be considered a reassignment if the uninitialized value for this field // is observable. // TODO(rluble): do static analysis to improve this pass. if (x.getVariableRef() instanceof JFieldRef) { JField field = ((JFieldRef) x.getVariableRef()).getField(); if (field.getLiteralInitializer() != null && !field.getLiteralInitializer().equals(field.getType().getDefaultValue())) { recordAssignment(x.getVariableRef()); } } } @Override public void endVisit(JPostfixOperation x, Context ctx) { if (x.getOp().isModifying()) { recordAssignment(x.getArg()); } } @Override public void endVisit(JPrefixOperation x, Context ctx) { if (x.getOp().isModifying()) { recordAssignment(x.getArg()); } } @Override public void endVisit(JsniFieldRef x, Context ctx) { if (x.isLvalue()) { recordAssignment(x); } } @Override public boolean visit(JClassType x, Context ctx) { // Don't visit external types, because we can't change their final // specifiers. return !x.isExternal(); } private void recordAssignment(JExpression lhs) { if (lhs instanceof JVariableRef) { JVariableRef variableRef = (JVariableRef) lhs; isReassigned.add(variableRef.getTarget()); } } } private static final String NAME = Finalizer.class.getSimpleName(); private Finalizer(JProgram program) { this.program = program; } @VisibleForTesting static OptimizerStats exec(JProgram program) { return exec(program, OptimizerContext.NULL_OPTIMIZATION_CONTEXT); } public static OptimizerStats exec(JProgram program, OptimizerContext optimizerCtx) { Event optimizeEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE, "optimizer", NAME); OptimizerStats stats = new Finalizer(program).execImpl(optimizerCtx); optimizerCtx.incOptimizationStep(); optimizeEvent.end("didChange", "" + stats.didChange()); return stats; } private final Set isReassigned = Sets.newHashSet(); private final JProgram program; private OptimizerStats execImpl(OptimizerContext optimizerCtx) { MarkVisitor marker = new MarkVisitor(); marker.accept(program); FinalizeVisitor finalizer = new FinalizeVisitor(optimizerCtx); finalizer.accept(program); JavaAstVerifier.assertProgramIsConsistent(program); return new OptimizerStats(NAME).recordModified(finalizer.getNumMods()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy