/*
* 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.baseline.ia32;
import static org.jikesrvm.ia32.StackframeLayoutConstants.BYTES_IN_STACKSLOT;
import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_WORD;
import static org.jikesrvm.tests.util.AssertUnboxed.assertEquals;
import static org.jikesrvm.tests.util.AssertUnboxed.assertZero;
import static org.jikesrvm.tests.util.TestingTools.createNonMovableWordArray;
import org.jikesrvm.architecture.ArchConstants;
import org.jikesrvm.classloader.NormalMethod;
import org.jikesrvm.compilers.common.CompiledMethod;
import org.jikesrvm.junit.runners.RequiresBuiltJikesRVM;
import org.jikesrvm.junit.runners.RequiresIA32;
import org.jikesrvm.junit.runners.VMRequirements;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.tests.util.MethodsForTests;
import org.jikesrvm.tests.util.TestingTools;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.AddressArray;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
import org.vmmagic.unboxed.WordArray;
@RunWith(VMRequirements.class)
@Category({RequiresIA32.class, RequiresBuiltJikesRVM.class})
public class BaselineGCMapIteratorTest {
private static final Offset NO_OFFSET = Offset.zero();
private static final Address NO_FP = Address.zero();
private AddressArray registerLocations;
private BaselineGCMapIterator gcMapIter;
@Before
public void setUp() {
registerLocations = AddressArray.create(ArchConstants.getNumberOfGPRs());
gcMapIter = new BaselineGCMapIterator(registerLocations);
}
@BeforeClass
public static void ensureUsedMethodsAreCompiled() {
MethodsForTests.emptyStaticMethodWithoutAnnotations();
MethodsForTests.emptyStaticMethodWithObjectParam(null);
}
// This test case is only documentation. It musn't be run
// because it would cause a NPE in uninterruptible code which
// would lead to a crash in Jikes RVM.
@Ignore
@Test(expected = NullPointerException.class)
public void usingIteratorBeforeCallToSetupIsNotPossible() {
gcMapIter.reset();
}
// The following test cases use JikesRVMSupport to access the actual
// compiled methods. This is obviously not possible on VMs other than
// Jikes RVM.
@Test
public void setupOfIteratorRequiresOnlyCompiledMethod() throws Exception {
NormalMethod nm = TestingTools.getNormalMethod(MethodsForTests.class, "emptyStaticMethodWithoutAnnotations");
CompiledMethod cm = nm.getCurrentCompiledMethod();
gcMapIter.setupIterator(cm, NO_OFFSET, NO_FP);
}
@Test
public void getNextReturnAddressAddressReturnsZeroIfNoJSRsArePresent() throws Exception {
NormalMethod nm = TestingTools.getNormalMethod(MethodsForTests.class, "emptyStaticMethodWithoutAnnotations");
CompiledMethod cm = nm.getCurrentCompiledMethod();
gcMapIter.setupIterator(cm, NO_OFFSET, NO_FP);
Address returnAddressAddress = gcMapIter.getNextReturnAddressAddress();
assertZero(returnAddressAddress);
}
@Test
public void getNextReferenceAddressReturnsZeroIfNoReferencesArePresent() throws Exception {
NormalMethod nm = TestingTools.getNormalMethod(MethodsForTests.class, "emptyStaticMethodWithoutAnnotations");
CompiledMethod cm = nm.getCurrentCompiledMethod();
gcMapIter.setupIterator(cm, NO_OFFSET, NO_FP);
Address referenceAddr = gcMapIter.getNextReferenceAddress();
assertZero(referenceAddr);
}
@Test
public void getNextReferenceAddressReturnsCorrectReferenceIfReferencesArePresent() throws Exception {
NormalMethod nm = TestingTools.getNormalMethod(MethodsForTests.class, "emptyStaticMethodWithObjectParam", Object.class);
CompiledMethod cm = nm.getCurrentCompiledMethod();
// Fake a stack frame
int stackWords = 5;
WordArray wa = createNonMovableWordArray(stackWords);
for (int i = 0; i < wa.length(); i++) {
wa.set(i, Word.fromIntSignExtend(5 * i));
}
int targetSlot = wa.length() - 1;
Address fp = Magic.objectAsAddress(wa).plus(targetSlot * BYTES_IN_WORD);
// local 0 is reference.
// +/- 0 words: FP
// - 1 words: CMID
// - 2 words: saved GPRs (EDI)
// - 3 words: saved GPRs (EBX)
// - 4 words: local0 == reference
Address targetAddress = fp.minus(4 * BYTES_IN_STACKSLOT);
Word targetContents = targetAddress.loadWord();
gcMapIter.setupIterator(cm, Offset.fromIntZeroExtend(cm.getEntryCodeArray().length()), fp);
Address referenceAddr = gcMapIter.getNextReferenceAddress();
assertEquals(targetAddress, referenceAddr);
assertEquals(targetContents, referenceAddr.loadWord());
}
}