/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.controlflow;
import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.compilers.opt.OptOptions;
import org.jikesrvm.compilers.opt.ir.Call;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
import org.jikesrvm.junit.runners.RequiresBuiltJikesRVM;
import org.jikesrvm.junit.runners.RequiresOptCompiler;
import org.jikesrvm.junit.runners.VMRequirements;
import org.jikesrvm.tests.util.MethodsForTests;
import org.jikesrvm.tests.util.TestingTools;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
@RunWith(VMRequirements.class)
@Category({RequiresBuiltJikesRVM.class, RequiresOptCompiler.class})
public class TailRecursionEliminationTest {
// TODO The test is currently incomplete. Ideas for tests:
// - tail recursion elimination on CALL
// - tail recursion elimination on SYSCALL
// - normal calls aren't changed
// - elimination of tail recursion requires a prologue instructions
// - tail recursion with branch elimination
private TailRecursionElimination tailRecursionElimination;
@Before
public void createPhase() {
tailRecursionElimination = new TailRecursionElimination();
}
@Test
public void willNotBePerformedOnOptLevel0() {
OptOptions options = new OptOptions();
options.setOptLevel(0);
assertFalse(tailRecursionElimination.shouldPerform(options));
}
@Test
public void willBePerformedOnOptLevel1() {
OptOptions options = new OptOptions();
options.setOptLevel(1);
assertTrue(tailRecursionElimination.shouldPerform(options));
}
@Test
public void willBePerformedOnOptLevel2() {
OptOptions options = new OptOptions();
options.setOptLevel(2);
assertTrue(tailRecursionElimination.shouldPerform(options));
}
@Test
public void doesNotThrowExceptionsOnCFGWithoutInstructions() {
OptOptions opts = new OptOptions();
IR ir = new IR(null, null, opts);
opts.setOptLevel(1);
TestingTools.addEmptyCFGToIR(ir);
tailRecursionElimination.perform(ir);
}
@Test
public void unannotatedCallsAreSubjectToOptimization() throws Exception {
Class<?>[] types = {};
RVMMethod m = TestingTools.getNormalMethod(MethodsForTests.class, "emptyStaticMethodWithoutAnnotations", types);
MethodOperand methOp = MethodOperand.STATIC(m);
Instruction call = Call.create(CALL, null, null, methOp, 0);
assertTrue(tailRecursionElimination.allowedToOptimize(call));
}
@Test
public void callsWithNoTailCallEliminationAnnotationArentSubjectToOptimization() throws Exception {
Class<?>[] types = {};
RVMMethod m = TestingTools.getNormalMethod(MethodsForTests.class, "emptyStaticMethodWithNoTailCallEliminationAnnotation", types);
MethodOperand methOp = MethodOperand.STATIC(m);
Instruction call = Call.create(CALL, null, null, methOp, 0);
assertFalse(tailRecursionElimination.allowedToOptimize(call));
}
}