blob: 8d3ead7d5818eaabda2cb5dffee558cbfa7b91b1 [file] [log] [blame]
/*
* Copyright 2010 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;
import com.google.gwt.core.client.impl.ArtificialRescue;
import com.google.gwt.core.client.impl.ArtificialRescue.Rescue;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
import com.google.gwt.dev.jjs.ast.JAnnotation;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JNode;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.impl.JsniRefLookup;
import com.google.gwt.dev.util.JsniRef;
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.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Process ArtificialRescue annotations.
*/
public class ArtificialRescueRecorder {
private class Recorder extends JVisitor {
private JDeclaredType currentClass;
@Override
public void endVisit(JAnnotation x, Context ctx) {
if (x.getType() == artificialRescueType) {
ArtificialRescue annotation = JAnnotation.createAnnotation(
ArtificialRescue.class, x);
for (Rescue rescue : annotation.value()) {
process(rescue);
}
}
}
@Override
public void endVisit(JDeclaredType x, Context ctx) {
assert currentClass == x;
}
@Override
public boolean visit(JDeclaredType x, Context ctx) {
currentClass = x;
/*
* We only care about annotations declared on the type itself, so we can
* skip the traversal of fields and methods.
*/
accept(x.getAnnotations());
return false;
}
private void process(Rescue rescue) {
assert rescue != null : "rescue";
String typeName = rescue.className();
JReferenceType classType = (JReferenceType) program.getTypeFromJsniRef(typeName);
String[] fields = rescue.fields();
boolean instantiable = rescue.instantiable();
String[] methods = rescue.methods();
assert classType != null : "classType " + typeName;
assert fields != null : "fields";
assert methods != null : "methods";
if (instantiable) {
currentClass.addArtificialRescue(classType);
// Make sure that a class literal for the type has been allocated
program.getLiteralClass(classType);
}
if (classType instanceof JDeclaredType) {
List<String> toRescue = new ArrayList<String>();
Collections.addAll(toRescue, fields);
Collections.addAll(toRescue, methods);
for (String name : toRescue) {
JsniRef ref = JsniRef.parse("@" + classType.getName() + "::" + name);
final String[] errors = {null};
HasEnclosingType node = JsniRefLookup.findJsniRefTarget(ref, program,
new JsniRefLookup.ErrorReporter() {
public void reportError(String error) {
errors[0] = error;
}
});
if (errors[0] != null) {
// Should have been caught by ArtificialRescueChecker
throw new InternalCompilerException(
"Unable to artificially rescue " + name + ": " + errors[0]);
}
currentClass.addArtificialRescue((JNode) node);
if (node instanceof JField) {
JField field = (JField) node;
if (!field.isFinal()) {
field.setVolatile();
}
}
}
}
}
}
public static void exec(JProgram program) {
Event artificialRescueReorderEvent =
SpeedTracerLogger.start(CompilerEventType.ARTIFICIAL_RESCUE_REORDER);
new ArtificialRescueRecorder(program).execImpl();
artificialRescueReorderEvent.end();
}
private final JInterfaceType artificialRescueType;
private final JProgram program;
private ArtificialRescueRecorder(JProgram program) {
this.program = program;
artificialRescueType = (JInterfaceType) program.getFromTypeMap(ArtificialRescue.class.getName());
}
private void execImpl() {
new Recorder().accept(program);
}
}