blob: d3c36e0f582e0eb50ef7593c4e9e4d43db6cf769 [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.impl.gflow.Analysis;
import com.google.gwt.dev.jjs.impl.gflow.CfgAnalysisTestBase;
import com.google.gwt.dev.jjs.impl.gflow.cfg.Cfg;
import com.google.gwt.dev.jjs.impl.gflow.cfg.CfgEdge;
import com.google.gwt.dev.jjs.impl.gflow.cfg.CfgNode;
public class ConstantsAnalysisTest extends CfgAnalysisTestBase<ConstantsAssumption> {
@Override
protected void setUp() throws Exception {
super.setUp();
addSnippetClassDecl("static int i;");
addSnippetClassDecl("static int j;");
addSnippetClassDecl("static int k;");
addSnippetClassDecl("static int l;");
addSnippetClassDecl("static int m;");
addSnippetClassDecl("static int foo() { return 0; };");
addSnippetClassDecl("static void bar(Object o) { };");
addSnippetClassDecl("static int baz(Object o) { return 0; };");
}
public void testDeclWithConstInit() throws Exception {
analyze("void", "int i = 1;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(i, 1) -> [* {i = 1}]",
"END");
}
public void testDeclWithConstOps() throws Exception {
analyze("void", "int i = 1 + 1;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(i, 2) -> [* {i = 2}]",
"END");
}
public void testDeclWithNonconstInit() throws Exception {
analyze("void", "int i = foo();").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"OPTTHROW(foo()) -> [NOTHROW=* T, RE=1 T, E=1 T]",
"CALL(foo) -> [* T]",
"WRITE(i, EntryPoint.foo()) -> [* T]",
"1: END");
}
public void testReassign() throws Exception {
analyze("void", "int i = 1; i = 2;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(i, 1) -> [* {i = 1}]",
"STMT -> [* {i = 1}]",
"WRITE(i, 2) -> [* {i = 2}]",
"END");
analyze("void", "int i; i = 3;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"STMT -> [* T]",
"WRITE(i, 3) -> [* {i = 3}]",
"END");
}
public void test2Vars() throws Exception {
analyze("void", "int i = 1; int j = 2;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(i, 1) -> [* {i = 1}]",
"STMT -> [* {i = 1}]",
"WRITE(j, 2) -> [* {i = 1, j = 2}]",
"END");
}
public void testSequence() throws Exception {
analyze("void", "int i = 1; int j = i; int k = j; int l = k;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(i, 1) -> [* {i = 1}]",
"STMT -> [* {i = 1}]",
"READ(i) -> [* {i = 1}]",
"WRITE(j, i) -> [* {i = 1, j = 1}]",
"STMT -> [* {i = 1, j = 1}]",
"READ(j) -> [* {i = 1, j = 1}]",
"WRITE(k, j) -> [* {i = 1, j = 1, k = 1}]",
"STMT -> [* {i = 1, j = 1, k = 1}]",
"READ(k) -> [* {i = 1, j = 1, k = 1}]",
"WRITE(l, k) -> [* {i = 1, j = 1, k = 1, l = 1}]",
"END");
}
public void testIfStatement() throws Exception {
analyze("void", "int i = k; if (i == 1) { int j = i; } else { int j = i; } ").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"READ(k) -> [* T]",
"WRITE(i, EntryPoint.k) -> [* T]",
"STMT -> [* T]",
"READ(i) -> [* T]",
"COND (i == 1) -> [THEN=* {i = 1}, ELSE=1 T]",
"BLOCK -> [* {i = 1}]",
"STMT -> [* {i = 1}]",
"READ(i) -> [* {i = 1}]",
"WRITE(j, i) -> [2 {i = 1, j = 1}]",
"1: BLOCK -> [* T]",
"STMT -> [* T]",
"READ(i) -> [* T]",
"WRITE(j, i) -> [* T]",
"2: END");
analyze("int", "int j = 0; if (foo() == 1) j = 1; return j;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(j, 0) -> [* {j = 0}]",
"STMT -> [* {j = 0}]",
"OPTTHROW(foo()) -> [NOTHROW=* {j = 0}, RE=2 {j = 0}, E=2 {j = 0}]",
"CALL(foo) -> [* {j = 0}]",
"COND (EntryPoint.foo() == 1) -> [THEN=* {j = 0}, ELSE=1 {j = 0}]",
"STMT -> [* {j = 0}]",
"WRITE(j, 1) -> [* {j = 1}]",
"1: STMT -> [* T]",
"READ(j) -> [* T]",
"GOTO -> [* T]",
"2: END");
analyze("int", "int j = 0; if (foo() == 1) j = foo(); return j;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(j, 0) -> [* {j = 0}]",
"STMT -> [* {j = 0}]",
"OPTTHROW(foo()) -> [NOTHROW=* {j = 0}, RE=2 {j = 0}, E=2 {j = 0}]",
"CALL(foo) -> [* {j = 0}]",
"COND (EntryPoint.foo() == 1) -> [THEN=* {j = 0}, ELSE=1 {j = 0}]",
"STMT -> [* {j = 0}]",
"OPTTHROW(foo()) -> [NOTHROW=* {j = 0}, RE=2 {j = 0}, E=2 {j = 0}]",
"CALL(foo) -> [* {j = 0}]",
"WRITE(j, EntryPoint.foo()) -> [* T]",
"1: STMT -> [* T]",
"READ(j) -> [* T]",
"GOTO -> [* T]",
"2: END");
}
public void testWhileLoop1() throws Exception {
analyze("void", "int j = 1; while (j > 0) ++j;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(j, 1) -> [* {j = 1}]",
"STMT -> [* {j = 1}]",
"1: READ(j) -> [* T]",
"COND (j > 0) -> [THEN=* T, ELSE=2 T]",
"STMT -> [* T]",
"READWRITE(j, null) -> [1 T]",
"2: END");
}
public void testWhileLoop2() throws Exception {
analyze("void", "int j = 0; while (j > 0) {};").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(j, 0) -> [* {j = 0}]",
"STMT -> [* {j = 0}]",
"1: READ(j) -> [* {j = 0}]",
"COND (j > 0) -> [THEN=* {j = 0}, ELSE=2 {j = 0}]",
"BLOCK -> [1 {j = 0}]",
"2: END");
}
public void testConditionalExpressions() throws Exception {
analyze("void", "boolean b1 = false; boolean b2 = false; if (b1 && (b2 = true)) b1 = true;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(b1, false) -> [* {b1 = false}]",
"STMT -> [* {b1 = false}]",
"WRITE(b2, false) -> [* {b1 = false, b2 = false}]",
"STMT -> [* {b1 = false, b2 = false}]",
"READ(b1) -> [* {b1 = false, b2 = false}]",
"COND (b1) -> [THEN=* {b1 = false, b2 = false}, ELSE=1 {b1 = false, b2 = false}]",
"WRITE(b2, true) -> [* {b1 = false, b2 = true}]",
"1: COND (b1 && (b2 = true)) -> [THEN=* {b1 = false}, ELSE=2 {b1 = false}]",
"STMT -> [* {b1 = false}]",
"WRITE(b1, true) -> [* {b1 = true}]",
"2: END");
}
// Various real-world stuff
public void testVariousStuff() throws Exception {
addSnippetClassDecl("static Object f = null;");
analyze("void",
"Object e = null;" +
"if (f != null) if (e == null)" +
" return;" +
"boolean b = e == null;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"WRITE(e, null) -> [* {e = null}]",
"STMT -> [* {e = null}]",
"READ(f) -> [* {e = null}]",
"COND (EntryPoint.f != null) -> [THEN=* {e = null}, ELSE=1 {e = null}]",
"STMT -> [* {e = null}]",
"READ(e) -> [* {e = null}]",
"COND (e == null) -> [THEN=* {e = null}, ELSE=1 {e = null}]",
"STMT -> [* {e = null}]",
"GOTO -> [2 {e = null}]",
"1: STMT -> [* {e = null}]",
"READ(e) -> [* {e = null}]",
"WRITE(b, e == null) -> [* {b = true, e = null}]",
"2: END"
);
}
/**
* Parameters should have an initial assumption of non-constant.
*/
public void testParamNonConstant() throws Exception {
analyzeWithParams("void", "int i, int j", "if (j == 0) { i = 0; } j=i; j=0;").into(
"BLOCK -> [* T]",
"STMT -> [* T]",
"READ(j) -> [* T]",
"COND (j == 0) -> [THEN=* {j = 0}, ELSE=1 T]",
"BLOCK -> [* {j = 0}]",
"STMT -> [* {j = 0}]",
"WRITE(i, 0) -> [* {i = 0, j = 0}]",
"1: STMT -> [* T]",
"READ(i) -> [* T]",
"WRITE(j, i) -> [* T]",
"STMT -> [* T]",
"WRITE(j, 0) -> [* {j = 0}]",
"END"
);
}
@Override
protected Analysis<CfgNode<?>, CfgEdge, Cfg, ConstantsAssumption> createAnalysis() {
return new ConstantsAnalysis();
}
}