001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.jjs.impl;
017:
018: import com.google.gwt.dev.jjs.ast.Context;
019: import com.google.gwt.dev.jjs.ast.JClassType;
020: import com.google.gwt.dev.jjs.ast.JInterfaceType;
021: import com.google.gwt.dev.jjs.ast.JMethod;
022: import com.google.gwt.dev.jjs.ast.JProgram;
023: import com.google.gwt.dev.jjs.ast.JReferenceType;
024: import com.google.gwt.dev.jjs.ast.JVisitor;
025:
026: import java.util.HashSet;
027: import java.util.Set;
028:
029: /**
030: * Finds all methods and classes are effectively final. That is, methods that
031: * are never overriden and classes that are never subclassed. Mark all such
032: * methods and classes as final, since it helps us optimize.
033: */
034: public class MethodAndClassFinalizer {
035:
036: /**
037: * Any method and classes that weren't marked during MarkVisitor can be set
038: * final.
039: *
040: * Open question: What does it mean if an interface/abstract method becomes
041: * final? Is this possible after Pruning? I guess it means that someone tried
042: * to make a call to method that wasn't actually implemented anywhere in the
043: * program. But if it wasn't implemented, then the enclosing class should have
044: * come up as not instantiated and been culled. So I think it's not possible.
045: */
046: private class FinalizeVisitor extends JVisitor {
047:
048: private boolean didChange = false;
049:
050: public boolean didChange() {
051: return didChange;
052: }
053:
054: // @Override
055: public boolean visit(JClassType x, Context ctx) {
056: if (!x.isFinal() && !isSubclassed.contains(x)) {
057: x.setFinal(true);
058: didChange = true;
059: }
060: for (int i = 0; i < x.methods.size(); ++i) {
061: JMethod method = (JMethod) x.methods.get(i);
062: accept(method);
063: }
064: return false;
065: }
066:
067: // @Override
068: public boolean visit(JInterfaceType x, Context ctx) {
069: for (int i = 0; i < x.methods.size(); ++i) {
070: JMethod method = (JMethod) x.methods.get(i);
071: accept(method);
072: }
073: return false;
074: }
075:
076: // @Override
077: public boolean visit(JMethod x, Context ctx) {
078: if (!x.isFinal() && !isOverriden.contains(x)) {
079: x.setFinal(true);
080: didChange = true;
081: }
082: return false;
083: }
084: }
085:
086: /**
087: * Find all methods and classes that ARE overriden/subclassed.
088: */
089: private class MarkVisitor extends JVisitor {
090:
091: // @Override
092: public boolean visit(JClassType x, Context ctx) {
093: if (x.extnds != null) {
094: isSubclassed.add(x.extnds);
095: }
096:
097: for (int i = 0; i < x.methods.size(); ++i) {
098: JMethod method = (JMethod) x.methods.get(i);
099: accept(method);
100: }
101: return false;
102: }
103:
104: // @Override
105: public boolean visit(JInterfaceType x, Context ctx) {
106: for (int i = 0; i < x.methods.size(); ++i) {
107: JMethod method = (JMethod) x.methods.get(i);
108: accept(method);
109: }
110: return false;
111: }
112:
113: // @Override
114: public boolean visit(JMethod x, Context ctx) {
115: for (int i = 0; i < x.overrides.size(); ++i) {
116: JMethod it = (JMethod) x.overrides.get(i);
117: isOverriden.add(it);
118: }
119: return false;
120: }
121:
122: // @Override
123: public boolean visit(JProgram x, Context ctx) {
124: for (int i = 0; i < x.getDeclaredTypes().size(); ++i) {
125: JReferenceType type = (JReferenceType) x
126: .getDeclaredTypes().get(i);
127: accept(type);
128: }
129: return false;
130: }
131: }
132:
133: public static boolean exec(JProgram program) {
134: return new MethodAndClassFinalizer().execImpl(program);
135: }
136:
137: private final Set/* <JMethod> */isOverriden = new HashSet/* <JMethod> */();
138:
139: private final Set/* <JClassType> */isSubclassed = new HashSet/* <JClassType> */();
140:
141: private MethodAndClassFinalizer() {
142: }
143:
144: private boolean execImpl(JProgram program) {
145: MarkVisitor marker = new MarkVisitor();
146: marker.accept(program);
147:
148: FinalizeVisitor finalizer = new FinalizeVisitor();
149: finalizer.accept(program);
150: return finalizer.didChange();
151: }
152:
153: }
|