/*
* Copyright (c) 2013-2016 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.test;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_SEMICOLON;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_EMPTY;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_OPTIMIZED_VIRTUAL_CALL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.adoptopenjdk.jitwatch.core.JITWatchConstants;
import org.adoptopenjdk.jitwatch.model.IMetaMember;
import org.adoptopenjdk.jitwatch.model.JITDataModel;
import org.adoptopenjdk.jitwatch.model.MemberSignatureParts;
import org.adoptopenjdk.jitwatch.model.MetaClass;
import org.adoptopenjdk.jitwatch.model.assembly.AssemblyInstruction;
import org.adoptopenjdk.jitwatch.model.assembly.AssemblyLabels;
import org.adoptopenjdk.jitwatch.model.bytecode.BytecodeInstruction;
import org.adoptopenjdk.jitwatch.model.bytecode.ClassBC;
import org.adoptopenjdk.jitwatch.model.bytecode.MemberBytecode;
import org.adoptopenjdk.jitwatch.optimizedvcall.OptimizedVirtualCall;
import org.adoptopenjdk.jitwatch.optimizedvcall.OptimizedVirtualCallFinder;
import org.adoptopenjdk.jitwatch.optimizedvcall.VirtualCallSite;
import org.adoptopenjdk.jitwatch.util.ClassUtil;
import org.junit.Test;
public class TestFindOptimizedVirtualCall
{
@Test
public void testNoOptimizedVirtualCallFoundWithEmptyComment()
{
String annotation = null;
long address = 1;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String firstComment = S_EMPTY;
AssemblyInstruction ins = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, firstComment, new AssemblyLabels());
assertFalse(ins.isOptimizedVCall());
assertNull(ins.getOptimizedVirtualCallSiteOrNull());
JITDataModel model = new JITDataModel();
List<String> classLocations = new ArrayList<>();
OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(model, classLocations);
OptimizedVirtualCall vCall = finder.findOptimizedCall(ins);
assertNull(vCall);
}
@Test
public void testNoOptimizedVirtualCallFoundWithNullComment()
{
String annotation = null;
long address = 1;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String firstComment = null;
AssemblyInstruction ins = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, firstComment, new AssemblyLabels());
assertFalse(ins.isOptimizedVCall());
assertNull(ins.getOptimizedVirtualCallSiteOrNull());
JITDataModel model = new JITDataModel();
List<String> classLocations = new ArrayList<>();
OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(model, classLocations);
OptimizedVirtualCall vCall = finder.findOptimizedCall(ins);
assertNull(vCall);
}
@Test
public void testNoOptimizedVirtualCallFoundWithNonVCallComment()
{
String annotation = null;
long address = 1;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String firstComment = "; Every day sends future a past.";
AssemblyInstruction ins = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, firstComment, new AssemblyLabels());
assertFalse(ins.isOptimizedVCall());
assertNull(ins.getOptimizedVirtualCallSiteOrNull());
JITDataModel model = new JITDataModel();
List<String> classLocations = new ArrayList<>();
OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(model, classLocations);
OptimizedVirtualCall vCall = finder.findOptimizedCall(ins);
assertNull(vCall);
}
@Test
public void testNoOptimizedVirtualCallFoundWithOnlyVCallSiteComment()
{
String annotation = null;
long address = 1;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String firstComment = "; - FooClass::fooMethod@1 (line 42)";
AssemblyInstruction ins = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, firstComment, new AssemblyLabels());
assertFalse(ins.isOptimizedVCall());
assertNull(ins.getOptimizedVirtualCallSiteOrNull());
JITDataModel model = new JITDataModel();
List<String> classLocations = new ArrayList<>();
OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(model, classLocations);
OptimizedVirtualCall vCall = finder.findOptimizedCall(ins);
assertNull(vCall);
}
@Test
public void testNoOptimizedVirtualCallFoundWithOVCTagNoCallSiteComment()
{
String annotation = null;
long address = 1;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String firstComment = C_SEMICOLON + S_OPTIMIZED_VIRTUAL_CALL;
AssemblyInstruction ins = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, firstComment, new AssemblyLabels());
assertFalse(ins.isOptimizedVCall());
assertNull(ins.getOptimizedVirtualCallSiteOrNull());
JITDataModel model = new JITDataModel();
List<String> classLocations = new ArrayList<>();
OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(model, classLocations);
OptimizedVirtualCall vCall = finder.findOptimizedCall(ins);
assertNull(vCall);
}
private AssemblyInstruction buildInstructionForValidCallSite(String callSiteComment)
{
String annotation = null;
long address = 1;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String comment0 = " ; OopMap{rbp=Oop off=940}";
AssemblyInstruction ins = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, comment0, new AssemblyLabels());
ins.addCommentLine(";*invokevirtual toString");
ins.addCommentLine(callSiteComment);
ins.addCommentLine("; " + S_OPTIMIZED_VIRTUAL_CALL);
return ins;
}
@Test
public void testBuildCallSite()
{
AssemblyInstruction ins = buildInstructionForValidCallSite("; - FooClass::fooMethod@1 (line 42)");
assertTrue(ins.isOptimizedVCall());
VirtualCallSite callSite = ins.getOptimizedVirtualCallSiteOrNull();
assertNotNull(callSite);
assertEquals("FooClass", callSite.getClassName());
assertEquals("fooMethod", callSite.getMemberName());
assertEquals(1, callSite.getBytecodeOffset());
assertEquals(42, callSite.getSourceLine());
}
@Test
public void testOptimizedVirtualCallRegexConstructor()
{
AssemblyInstruction ins = buildInstructionForValidCallSite("; - FooClass::<init>@1 (line 42)");
assertTrue(ins.isOptimizedVCall());
VirtualCallSite callSite = ins.getOptimizedVirtualCallSiteOrNull();
assertNotNull(callSite);
assertEquals("FooClass", callSite.getClassName());
assertEquals("<init>", callSite.getMemberName());
assertEquals(1, callSite.getBytecodeOffset());
assertEquals(42, callSite.getSourceLine());
}
@Test
public void testOptimizedVirtualCallRegexNegativeBCI()
{
AssemblyInstruction ins = buildInstructionForValidCallSite("; - FooClass::foo@-1 (line 42)");
assertTrue(ins.isOptimizedVCall());
VirtualCallSite callSite = ins.getOptimizedVirtualCallSiteOrNull();
assertNotNull(callSite);
assertEquals("FooClass", callSite.getClassName());
assertEquals("foo", callSite.getMemberName());
assertEquals(-1, callSite.getBytecodeOffset());
assertEquals(42, callSite.getSourceLine());
}
@Test
public void testOptimizedVirtualCallRegexInnerClass()
{
AssemblyInstruction ins = buildInstructionForValidCallSite("; - FooClass$Inner::foo@-1 (line 42)");
assertTrue(ins.isOptimizedVCall());
VirtualCallSite callSite = ins.getOptimizedVirtualCallSiteOrNull();
assertNotNull(callSite);
assertEquals("FooClass$Inner", callSite.getClassName());
assertEquals("foo", callSite.getMemberName());
assertEquals(-1, callSite.getBytecodeOffset());
assertEquals(42, callSite.getSourceLine());
}
@Test
public void testOptimizedVirtualCallRegexInvalid()
{
assertNull(buildInstructionForValidCallSite("; - FooClass::foo@ (line 42)").getOptimizedVirtualCallSiteOrNull());
assertNull(buildInstructionForValidCallSite("; - FooClass::foo@bar (line 42)").getOptimizedVirtualCallSiteOrNull());
assertNull(buildInstructionForValidCallSite("; - FooClass::foo@5 (line )").getOptimizedVirtualCallSiteOrNull());
assertNull(buildInstructionForValidCallSite("; - FooClass::foo@5 (line bar)").getOptimizedVirtualCallSiteOrNull());
assertNull(buildInstructionForValidCallSite("; - ::@").getOptimizedVirtualCallSiteOrNull());
assertNull(buildInstructionForValidCallSite("In the trail of fire I know we will be free again")
.getOptimizedVirtualCallSiteOrNull());
}
private static final int sourceLine = 279; // TODO this must match call to test2() within test1() method
public void test1()
{
test2();
}
public void test2()
{
System.out.println("Raise the anchor, bring it on home");
}
@Test
public void testCallSiteFoundMultiLineComment() throws ClassNotFoundException
{
String fqClassName = getClass().getName();
String annotation = null;
long address = 16;
String mnemonic = "ADD";
List<String> operands = new ArrayList<>();
operands.add("%rdx");
operands.add("%rax");
String callerMethod = "test1";
String calleeMethod = "test2";
int vCallBCI = 1;
String comment0 = "; OopMap{rbp=Oop off=940}";
String comment1 = "; *invokespecial " + calleeMethod;
String comment2 = "; - " + fqClassName + "::" + callerMethod + "@" + vCallBCI + " (line " + sourceLine + ")";
String comment3 = "; " + JITWatchConstants.S_OPTIMIZED_VIRTUAL_CALL;
AssemblyInstruction instruction = new AssemblyInstruction(annotation, address, Collections.<String>emptyList(), mnemonic, operands, comment0, new AssemblyLabels());
instruction.addCommentLine(comment1);
instruction.addCommentLine(comment2);
instruction.addCommentLine(comment3);
assertTrue(instruction.isOptimizedVCall());
VirtualCallSite callSite = instruction.getOptimizedVirtualCallSiteOrNull();
assertNotNull(callSite);
assertEquals(fqClassName, callSite.getClassName());
assertEquals(callerMethod, callSite.getMemberName());
assertEquals(vCallBCI, callSite.getBytecodeOffset());
assertEquals(sourceLine, callSite.getSourceLine());
JITDataModel model = new JITDataModel();
MetaClass metaClass = UnitTestUtil.createMetaClassFor(model, fqClassName);
String bcSigTest1 = "public void test1();";
String bcSigTest2 = "public void test2();";
MemberSignatureParts mspTest1 = MemberSignatureParts.fromBytecodeSignature(fqClassName, bcSigTest1);
MemberSignatureParts mspTest2 = MemberSignatureParts.fromBytecodeSignature(fqClassName, bcSigTest2);
IMetaMember memberTest1 = metaClass.getMemberForSignature(mspTest1);
IMetaMember memberTest2 = metaClass.getMemberForSignature(mspTest2);
List<String> classLocations = ClassUtil.getCurrentClasspathElements();
OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(model, classLocations);
OptimizedVirtualCall ovc = finder.findOptimizedCall(instruction);
assertNotNull(ovc);
assertEquals(callSite, ovc.getCallsite());
assertEquals(memberTest1, ovc.getCallerMember());
assertEquals(memberTest2, ovc.getCalleeMember());
ClassBC classBytecode = metaClass.getClassBytecode(model, classLocations);
MemberBytecode bytecodeMemberTest1 = classBytecode.getMemberBytecode(memberTest1);
BytecodeInstruction bytecodeInstruction = bytecodeMemberTest1.getBytecodeAtOffset(vCallBCI);
assertEquals(bytecodeInstruction, ovc.getBytecodeInstruction());
}
}