| /* |
| * 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.js; |
| |
| import com.google.gwt.dev.jjs.InternalCompilerException; |
| import com.google.gwt.dev.jjs.impl.OptimizerStats; |
| import com.google.gwt.dev.js.ast.JsContext; |
| import com.google.gwt.dev.js.ast.JsExprStmt; |
| import com.google.gwt.dev.js.ast.JsFunction; |
| import com.google.gwt.dev.js.ast.JsModVisitor; |
| import com.google.gwt.dev.js.ast.JsName; |
| import com.google.gwt.dev.js.ast.JsNameRef; |
| import com.google.gwt.dev.js.ast.JsProgram; |
| import com.google.gwt.dev.js.ast.JsVisitor; |
| import com.google.gwt.dev.util.collect.IdentityHashSet; |
| 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 java.util.Set; |
| |
| /** |
| * Removes JsFunctions that are never referenced in the program. |
| */ |
| public class JsUnusedFunctionRemover { |
| private class RemovalVisitor extends JsModVisitor { |
| |
| @Override |
| public void endVisit(JsExprStmt x, JsContext ctx) { |
| if (!(x.getExpression() instanceof JsFunction)) { |
| return; |
| } |
| |
| JsFunction f = (JsFunction) x.getExpression(); |
| JsName name = f.getName(); |
| |
| // Anonymous function, ignore it |
| if (name == null || seen.contains(name)) { |
| return; |
| } |
| |
| // Removing a static initializer indicates a problem in JsInliner. |
| if (f.isClinit()) { |
| throw new InternalCompilerException("Tried to remove clinit " |
| + name.getStaticRef().toSource()); |
| } |
| // Remove the statement |
| ctx.removeMe(); |
| } |
| } |
| |
| /** |
| * Finds all function references in the program. |
| */ |
| private class RescueVisitor extends JsVisitor { |
| |
| @Override |
| public void endVisit(JsNameRef x, JsContext ctx) { |
| seen.add(x.getName()); |
| } |
| } |
| |
| public static final String NAME = JsUnusedFunctionRemover.class.getSimpleName(); |
| |
| public static OptimizerStats exec(JsProgram program) { |
| Event optimizeJsEvent = |
| SpeedTracerLogger.start(CompilerEventType.OPTIMIZE_JS, "optimizer", NAME); |
| OptimizerStats stats = new JsUnusedFunctionRemover(program).execImpl(); |
| optimizeJsEvent.end("didChange", "" + stats.didChange()); |
| return stats; |
| } |
| |
| private final JsProgram program; |
| private final Set<JsName> seen = new IdentityHashSet<JsName>(); |
| |
| public JsUnusedFunctionRemover(JsProgram program) { |
| this.program = program; |
| } |
| |
| public OptimizerStats execImpl() { |
| OptimizerStats stats = new OptimizerStats(NAME); |
| |
| // Rescue all referenced functions. |
| new RescueVisitor().accept(program); |
| |
| // Remove the unused functions from the JsProgram |
| RemovalVisitor removalVisitor = new RemovalVisitor(); |
| removalVisitor.accept(program); |
| |
| if (removalVisitor.didChange()) { |
| stats.recordModified(); |
| } |
| return stats; |
| } |
| } |