blob: de82f67b8913587feec9520213aaf882e5506f30 [file] [log] [blame]
/*
* Copyright 2008 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.gflow.constants;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JFloatLiteral;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JParameterRef;
import com.google.gwt.dev.jjs.ast.JValueLiteral;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
/**
* Assumption deducer analyzes the expression, knowing its value, and deduces
* variables constant values assumptions from it.
*/
final class AssumptionDeducer extends JVisitor {
/**
* Deduce assumptions, knowing that <code>expression</code> evaluates to
* <code>value</code> and stores individual variable assumptions in the
* <code>assumption</code> parameter. It will never override any existing
* constant assumptions. It will override top and bottom assumptions though.
*/
static void deduceAssumption(
JExpression expression, final JValueLiteral value,
final ConstantsAssumption.Updater assumption) {
new AssumptionDeducer(value, assumption).accept(expression);
}
private final ConstantsAssumption.Updater assumption;
/**
* Contains the value of evaluating expression we're currently visiting.
* Is <code>null</code> if we do not know current expression value.
*/
private JValueLiteral currentValue;
AssumptionDeducer(JValueLiteral value, ConstantsAssumption.Updater assumption) {
this.assumption = assumption;
currentValue = value;
}
@SuppressWarnings("incomplete-switch")
@Override
public boolean visit(JBinaryOperation x, Context ctx) {
switch (x.getOp()) {
case EQ:
if (isTrue(currentValue)) {
if (x.getRhs() instanceof JValueLiteral &&
isSubstitutableIfEquals(x.getRhs())) {
currentValue = (JValueLiteral) x.getRhs();
accept(x.getLhs());
return false;
} else if (x.getLhs() instanceof JValueLiteral &&
isSubstitutableIfEquals(x.getLhs())) {
currentValue = (JValueLiteral) x.getLhs();
accept(x.getRhs());
return false;
}
}
break;
case NEQ:
if (isFalse(currentValue)) {
if (x.getRhs() instanceof JValueLiteral &&
isSubstitutableIfEquals(x.getRhs())) {
currentValue = (JValueLiteral) x.getRhs();
accept(x.getLhs());
return false;
} else if (x.getLhs() instanceof JValueLiteral &&
isSubstitutableIfEquals(x.getLhs())) {
currentValue = (JValueLiteral) x.getLhs();
accept(x.getRhs());
return false;
}
}
break;
case AND:
if (isTrue(currentValue)) {
accept(x.getLhs());
currentValue = JBooleanLiteral.get(true);
accept(x.getRhs());
return false;
}
break;
case OR:
if (isFalse(currentValue)) {
accept(x.getLhs());
currentValue = JBooleanLiteral.FALSE;
accept(x.getRhs());
return false;
}
break;
}
currentValue = null;
return true;
}
@Override
public boolean visit(JExpression x, Context ctx) {
// Unknown expression. Do not go inside.
return false;
}
@Override
public boolean visit(JLocalRef x, Context ctx) {
if (assumption.hasAssumption(x.getTarget())) {
// Expression evaluation can't change existing assumptions
return false;
}
assumption.set(x.getTarget(), currentValue);
return false;
}
@Override
public boolean visit(JMultiExpression x, Context ctx) {
// Knowing the value multi expression, we know the value of its last
// expression only.
accept(x.exprs.get(x.exprs.size() - 1));
return false;
}
@Override
public boolean visit(JParameterRef x, Context ctx) {
if (assumption.hasAssumption(x.getTarget())) {
// Expression evaluation shouldn't change existing assumptions
return false;
}
assumption.set(x.getTarget(), currentValue);
return false;
}
private boolean isFalse(JValueLiteral value) {
return value instanceof JBooleanLiteral &&
!((JBooleanLiteral) value).getValue();
}
/**
* Checks that if some expression equals <code>e</code>, then we can freely
* substitute it by e.
*/
private boolean isSubstitutableIfEquals(JExpression e) {
if (!(e instanceof JValueLiteral)) {
return false;
}
if (e instanceof JFloatLiteral &&
((JFloatLiteral) e).getValue() == 0.0f) {
// There are +0.0 and -0.0. And both of them are equal.
// We can't substitute 0.0 instead of them.
return false;
}
if (e instanceof JDoubleLiteral &&
((JDoubleLiteral) e).getValue() == 0.0d) {
// There are +0.0 and -0.0. And both of them are equal.
// We can't substitute 0.0 instead of them.
return false;
}
return true;
}
private boolean isTrue(JValueLiteral value) {
return value instanceof JBooleanLiteral &&
((JBooleanLiteral) value).getValue();
}
}