/* * 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.bc2ir; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.sameInstance; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; import org.jikesrvm.compilers.opt.ir.operand.Operand; import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand; import org.jikesrvm.junit.runners.RequiresBootstrapVM; import org.jikesrvm.junit.runners.VMRequirements; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @RunWith(VMRequirements.class) @Category(RequiresBootstrapVM.class) public class OperandStackTest { private OperandStack stack; private void createOperandStackWithSize(int size) { stack = new OperandStack(size); } @Test public void newlyCreatedOperandStackIsEmpty() { createOperandStackWithSize(1); assertThat(stack.isEmpty(), is(true)); } @Test public void stacksMayBeCreatedWithCapacityOfZero() throws Exception { createOperandStackWithSize(0); } @Test public void getSizeReturnsNumberOfOperandsOnTheStack() throws Exception { createOperandStackWithSize(25); stack.push(mockOperand()); stack.push(mockOperand()); stack.push(mockOperand()); stack.push(mockOperand()); assertThat(stack.getSize(), is(4)); } @Test(expected = NegativeArraySizeException.class) public void stacksWithNegativeCapacityCannotBeCreated() throws Exception { createOperandStackWithSize(-1); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void popOnEmptyStackCausesException() throws Exception { createOperandStackWithSize(1); stack.pop(); } private Operand mockOperand() { return mock(Operand.class); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void stacksCannotAcceptMorePushesThanCapacityAllows() throws Exception { createOperandStackWithSize(1); stack.push(mockOperand()); stack.push(mockOperand()); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void usingPopMoreOftenThanPushLeadsToExceptions() throws Exception { createOperandStackWithSize(1); stack.push(mockOperand()); stack.pop(); stack.pop(); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void poppingMoreThanWasPushedLeadsToExceptions() throws Exception { createOperandStackWithSize(1); stack.push(mockOperand()); stack.pop2(); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void pop2OnEmptyStackCausesException() throws Exception { createOperandStackWithSize(1); stack.pop2(); } @Test public void negativeArgumentsForGetFromTopNeedNotCauseException() throws Exception { createOperandStackWithSize(1); stack.getFromTop(-1); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void largeNegativeArgumentsForGetFromTopCauseException() throws Exception { createOperandStackWithSize(1); stack.getFromTop(-2); } @Test public void getFromTopWith0ReturnsTheOperandFromTheTopOfTheStack() throws Exception { createOperandStackWithSize(1); Operand val = mockOperand(); stack.push(val); Operand fromStack = stack.getFromTop(0); assertThat(fromStack, sameInstance(val)); } @Test public void getFromTopWithXReturnsItemAtPlaceXFromTheTopOfTheStack() throws Exception { createOperandStackWithSize(3); Operand bottom = mockOperand(); stack.push(bottom); Operand middle = mockOperand(); stack.push(middle); Operand top = mockOperand(); stack.push(top); Operand topFromStack = stack.getFromTop(0); assertThat(topFromStack, sameInstance(top)); Operand midldeFromStack = stack.getFromTop(1); assertThat(midldeFromStack, sameInstance(middle)); Operand bottomFromStack = stack.getFromTop(2); assertThat(bottomFromStack, sameInstance(bottom)); } @Test public void getFromBottomOnEmptyStackReturnsNull() throws Exception { createOperandStackWithSize(1); Operand fromStack = stack.getFromBottom(0); assertNull(fromStack); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void getFromBottomOnEmptyStackWithCapacityZeroCausesException() throws Exception { createOperandStackWithSize(0); stack.getFromBottom(0); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void getFromBottomCausesExceptionsForNegativeArguments() throws Exception { createOperandStackWithSize(1); stack.getFromBottom(-1); } @Test public void getFromBottomWith0ReturnsTheOperandFromTheBottomOfTheStack() throws Exception { createOperandStackWithSize(1); Operand val = mockOperand(); stack.push(val); Operand fromStack = stack.getFromBottom(0); assertThat(fromStack, sameInstance(val)); } @Test public void getFromBottomWithXReturnsItemAtPlaceXFromTheBottomOfTheStack() throws Exception { createOperandStackWithSize(3); Operand bottom = mockOperand(); stack.push(bottom); Operand middle = mockOperand(); stack.push(middle); Operand top = mockOperand(); stack.push(top); Operand bottomFromStack = stack.getFromBottom(0); assertThat(bottomFromStack, sameInstance(bottom)); Operand midldeFromStack = stack.getFromBottom(1); assertThat(midldeFromStack, sameInstance(middle)); Operand topFromStack = stack.getFromBottom(2); assertThat(topFromStack, sameInstance(top)); } @Test public void negativeArgumentsForReplaceFromTopNeedNotCauseException() throws Exception { createOperandStackWithSize(1); stack.replaceFromTop(-1, mockOperand()); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void largeNegativeArgumentsForReplaceFromTopCauseException() throws Exception { createOperandStackWithSize(1); stack.replaceFromTop(-2, mockOperand()); } @Test public void replaceFromTopForTopmostOperandReplacesTheOperand() throws Exception { createOperandStackWithSize(1); Operand val = mockOperand(); stack.push(val); Operand newOp = mockOperand(); stack.replaceFromTop(0, newOp); Operand replacedOp = stack.getFromTop(0); assertThat(replacedOp, sameInstance(newOp)); } @Test public void replaceFromTopStackWithXReturnsItemAtPlaceXFromTheTopOfTheStack() throws Exception { createOperandStackWithSize(3); Operand bottom = mockOperand(); stack.push(bottom); Operand middle = mockOperand(); stack.push(middle); Operand top = mockOperand(); stack.push(top); Operand newMiddleForStack = mockOperand(); stack.replaceFromTop(1, newMiddleForStack); Operand midldeFromStack = stack.getFromTop(1); assertThat(midldeFromStack, sameInstance(newMiddleForStack)); Operand newBottomForStack = mockOperand(); stack.replaceFromTop(2, newBottomForStack); Operand bottomFromStack = stack.getFromTop(2); assertThat(bottomFromStack, sameInstance(newBottomForStack)); } @Test public void swapSwapsTwoOperandsWhenTwoOperandsAreOnStack() throws Exception { createOperandStackWithSize(2); Operand oldBottom = mockOperand(); stack.push(oldBottom); Operand oldTop = mockOperand(); stack.push(oldTop); stack.swap(); assertThat(stack.getFromTop(0), is(oldBottom)); assertThat(stack.getFromTop(1), is(oldTop)); } @Test public void swapSwapsTheTwoTopmostOperandsWhenEnoughOperandsAreOnStack() throws Exception { createOperandStackWithSize(3); Operand oldBottom = mockOperand(); stack.push(oldBottom); Operand oldMiddle = mockOperand(); stack.push(oldMiddle); Operand oldTop = mockOperand(); stack.push(oldTop); stack.swap(); assertThat(stack.getFromTop(0), is(oldMiddle)); assertThat(stack.getFromTop(1), is(oldTop)); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void swapFailsIfStackContainsNoOperand() throws Exception { createOperandStackWithSize(1); stack.swap(); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void swapFailsIfStackContainsOnlyOneOperand() throws Exception { createOperandStackWithSize(1); stack.push(mockOperand()); stack.swap(); } private void createNonEmptyStack() { createOperandStackWithSize(2); stack.push(mockOperand()); stack.push(mockOperand()); } @Test public void clearMakesStackSeemEmpty() throws Exception { createNonEmptyStack(); stack.clear(); assertThat(stack.isEmpty(), is(true)); } @Test public void clearMakesStackSizeZero() throws Exception { createNonEmptyStack(); stack.clear(); assertThat(stack.getSize(), is(0)); } @Test(expected = ArrayIndexOutOfBoundsException.class) public void clearMakesStackSeemEmptyForAlmostAllOperations() throws Exception { createNonEmptyStack(); stack.clear(); stack.pop(); } @Test public void stackDoesNotAppearAsEmptyForGetFromBottom() throws Exception { createNonEmptyStack(); stack.clear(); stack.getFromBottom(1); } @Test public void deepCopyCopiesAllOperandsInAStack() throws Exception { createOperandStackWithSize(3); IntConstantOperand bottom = new IntConstantOperand(-2); stack.push(bottom); TrueGuardOperand top = new TrueGuardOperand(); stack.push(top); OperandStack copy = stack.deepCopy(); assertThat(copy.getSize(), is(stack.getSize())); TrueGuardOperand topFromCopiedStack = (TrueGuardOperand) copy.getFromTop(0); assertThat(topFromCopiedStack, not(sameInstance(top))); assertThat(copy.getFromTop(0).similar(top), is(true)); IntConstantOperand bottomFromCopiedStack = (IntConstantOperand) copy.getFromTop(1); assertThat(bottomFromCopiedStack, not(sameInstance(bottom))); assertThat(copy.getFromTop(1).similar(bottom), is(true)); } @Test public void createEmptyOperandStackWithSameCapacityReturnsAnEmptyOperandStack() throws Exception { createOperandStackWithSize(3); stack.push(mockOperand()); OperandStack newStack = stack.createEmptyOperandStackWithSameCapacity(); assertThat(newStack.isEmpty(), is(true)); } @Test public void createEmptyOperandStackWithSameCapacityReturnsAStackWithTheSameCapacity() throws Exception { createOperandStackWithSize(3); stack.push(mockOperand()); OperandStack newStack = stack.createEmptyOperandStackWithSameCapacity(); newStack.push(mockOperand()); newStack.push(mockOperand()); newStack.push(mockOperand()); assertThat(newStack.getSize(), is(3)); boolean stackHasRightCapacity = false; try { newStack.push(mockOperand()); } catch (ArrayIndexOutOfBoundsException e) { stackHasRightCapacity = true; } assertThat(stackHasRightCapacity, is(true)); } }