/* * 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.junit.Assert.assertEquals; import java.util.Arrays; import java.util.List; import java.util.Map; import org.adoptopenjdk.jitwatch.jarscan.sequencecount.InstructionSequence; import org.adoptopenjdk.jitwatch.jarscan.sequencecount.SequenceCountOperation; import org.adoptopenjdk.jitwatch.loader.BytecodeLoader; import org.adoptopenjdk.jitwatch.model.bytecode.BytecodeInstruction; import org.adoptopenjdk.jitwatch.model.bytecode.MemberBytecode; import org.adoptopenjdk.jitwatch.model.bytecode.Opcode; import org.junit.Test; public class TestJarScan { public static final boolean SHOW_OUTPUT = false; private List<BytecodeInstruction> getInstructions(String[] lines) { StringBuilder builder = new StringBuilder(); for (String line : lines) { builder.append(line).append("\n"); } List<BytecodeInstruction> instructions = BytecodeLoader.parseInstructions(builder.toString()); return instructions; } private MemberBytecode createMemberBytecode(String[] lines) { MemberBytecode mbc = new MemberBytecode(null, null); mbc.setInstructions(getInstructions(lines)); return mbc; } @Test public void testLongBytecodeChain1() { String[] lines = new String[] { "0: aload_1", "1: invokevirtual #38 // Method org/adoptopenjdk/jitwatch/model/Tag.getName:()Ljava/lang/String;", "4: astore_3", "5: iconst_m1", "6: istore 4", "8: aload_3", "9: invokevirtual #39 // Method java/lang/String.hashCode:()I", "12: lookupswitch { // 3", " -1067517155: 63", " 106437299: 48", " 922165544: 78", " default: 90", " }", "48: aload_3", "49: ldc #14 // String parse", "51: invokevirtual #40 // Method java/lang/String.equals:(Ljava/lang/Object;)Z", "54: ifeq 90", "57: iconst_0", "58: istore 4", "60: goto 90", "63: aload_3", "64: ldc #41 // String eliminate_allocation", "66: invokevirtual #40 // Method java/lang/String.equals:(Ljava/lang/Object;)Z", "69: ifeq 90", "72: iconst_1", "73: istore 4", "75: goto 90", "78: aload_3", "79: ldc #42 // String eliminate_lock", "81: invokevirtual #40 // Method java/lang/String.equals:(Ljava/lang/Object;)Z", "84: ifeq 90", "87: iconst_2", "88: istore 4", "90: iload 4", "92: tableswitch { // 0 to 2", " 0: 120", " 1: 129", " 2: 138", " default: 147", " }", "120: aload_0", "121: aload_1", "122: aload_2", "123: invokespecial #43 // Method visitTagParse:(Lorg/adoptopenjdk/jitwatch/model/Tag;Lorg/adoptopenjdk/jitwatch/model/IParseDictionary;)V", "126: goto 152", "129: aload_0", "130: aload_1", "131: aload_2", "132: invokespecial #44 // Method visitTagEliminateAllocation:(Lorg/adoptopenjdk/jitwatch/model/Tag;Lorg/adoptopenjdk/jitwatch/model/IParseDictionary;)V", "135: goto 152", "138: aload_0", "139: aload_1", "140: aload_2", "141: invokespecial #45 // Method visitTagEliminateLock:(Lorg/adoptopenjdk/jitwatch/model/Tag;Lorg/adoptopenjdk/jitwatch/model/IParseDictionary;)V", "144: goto 152", "147: aload_0", "148: aload_1", "149: invokevirtual #46 // Method handleOther:(Lorg/adoptopenjdk/jitwatch/model/Tag;)V", "152: return" }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(1); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(19, result.size()); checkSequence(result, 5, Opcode.ALOAD_1); checkSequence(result, 6, Opcode.INVOKEVIRTUAL); checkSequence(result, 1, Opcode.ASTORE_3); checkSequence(result, 1, Opcode.ICONST_M1); checkSequence(result, 4, Opcode.ISTORE); checkSequence(result, 4, Opcode.ALOAD_3); checkSequence(result, 1, Opcode.LOOKUPSWITCH); checkSequence(result, 3, Opcode.LDC); checkSequence(result, 3, Opcode.IFEQ); checkSequence(result, 1, Opcode.ICONST_0); checkSequence(result, 1, Opcode.ICONST_1); checkSequence(result, 1, Opcode.ICONST_2); checkSequence(result, 1, Opcode.ILOAD); checkSequence(result, 1, Opcode.TABLESWITCH); checkSequence(result, 4, Opcode.ALOAD_0); checkSequence(result, 3, Opcode.ALOAD_2); checkSequence(result, 3, Opcode.INVOKESPECIAL); checkSequence(result, 5, Opcode.GOTO); checkSequence(result, 1, Opcode.RETURN); } @Test public void testLongBytecodeChain6() { String[] lines = new String[] { "0: aload_1", "1: invokevirtual #38 // Method org/adoptopenjdk/jitwatch/model/Tag.getName:()Ljava/lang/String;", "4: astore_3", "5: iconst_m1", "6: istore 4", "8: aload_3", "9: invokevirtual #39 // Method java/lang/String.hashCode:()I", "12: lookupswitch { // 3", " -1067517155: 63", " 106437299: 48", " 922165544: 78", " default: 90", " }", "48: aload_3", "49: ldc #14 // String parse", "51: invokevirtual #40 // Method java/lang/String.equals:(Ljava/lang/Object;)Z", "54: ifeq 90", "57: iconst_0", "58: istore 4", "60: goto 90", "63: aload_3", "64: ldc #41 // String eliminate_allocation", "66: invokevirtual #40 // Method java/lang/String.equals:(Ljava/lang/Object;)Z", "69: ifeq 90", "72: iconst_1", "73: istore 4", "75: goto 90", "78: aload_3", "79: ldc #42 // String eliminate_lock", "81: invokevirtual #40 // Method java/lang/String.equals:(Ljava/lang/Object;)Z", "84: ifeq 90", "87: iconst_2", "88: istore 4", "90: iload 4", "92: tableswitch { // 0 to 2", " 0: 120", " 1: 129", " 2: 138", " default: 147", " }", "120: aload_0", "121: aload_1", "122: aload_2", "123: invokespecial #43 // Method visitTagParse:(Lorg/adoptopenjdk/jitwatch/model/Tag;Lorg/adoptopenjdk/jitwatch/model/IParseDictionary;)V", "126: goto 152", "129: aload_0", "130: aload_1", "131: aload_2", "132: invokespecial #44 // Method visitTagEliminateAllocation:(Lorg/adoptopenjdk/jitwatch/model/Tag;Lorg/adoptopenjdk/jitwatch/model/IParseDictionary;)V", "135: goto 152", "138: aload_0", "139: aload_1", "140: aload_2", "141: invokespecial #45 // Method visitTagEliminateLock:(Lorg/adoptopenjdk/jitwatch/model/Tag;Lorg/adoptopenjdk/jitwatch/model/IParseDictionary;)V", "144: goto 152", "147: aload_0", "148: aload_1", "149: invokevirtual #46 // Method handleOther:(Lorg/adoptopenjdk/jitwatch/model/Tag;)V", "152: return" }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(6); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(29, result.size()); checkSequence(result, 1, Opcode.ALOAD_1, Opcode.INVOKEVIRTUAL, Opcode.ASTORE_3, Opcode.ICONST_M1, Opcode.ISTORE, Opcode.ALOAD_3); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.ASTORE_3, Opcode.ICONST_M1, Opcode.ISTORE, Opcode.ALOAD_3, Opcode.INVOKEVIRTUAL); checkSequence(result, 1, Opcode.ASTORE_3, Opcode.ICONST_M1, Opcode.ISTORE, Opcode.ALOAD_3, Opcode.INVOKEVIRTUAL, Opcode.LOOKUPSWITCH); checkSequence(result, 1, Opcode.ICONST_M1, Opcode.ISTORE, Opcode.ALOAD_3, Opcode.INVOKEVIRTUAL, Opcode.LOOKUPSWITCH, Opcode.ALOAD_3); checkSequence(result, 1, Opcode.ISTORE, Opcode.ALOAD_3, Opcode.INVOKEVIRTUAL, Opcode.LOOKUPSWITCH, Opcode.ALOAD_3, Opcode.LDC); checkSequence(result, 1, Opcode.ALOAD_3, Opcode.INVOKEVIRTUAL, Opcode.LOOKUPSWITCH, Opcode.ALOAD_3, Opcode.LDC, Opcode.INVOKEVIRTUAL); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.LOOKUPSWITCH, Opcode.ALOAD_3, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ); checkSequence(result, 1, Opcode.LOOKUPSWITCH, Opcode.ALOAD_3, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_0); checkSequence(result, 1, Opcode.ALOAD_3, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_0, Opcode.ISTORE); checkSequence(result, 1, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_0, Opcode.ISTORE, Opcode.GOTO); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_0, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD); checkSequence(result, 1, Opcode.IFEQ, Opcode.ICONST_0, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD, Opcode.TABLESWITCH); checkSequence(result, 1, Opcode.ICONST_0, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0); checkSequence(result, 2, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0, Opcode.ALOAD_1); checkSequence(result, 2, Opcode.GOTO, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0, Opcode.ALOAD_1, Opcode.ALOAD_2); checkSequence(result, 1, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0, Opcode.ALOAD_1, Opcode.ALOAD_2, Opcode.INVOKESPECIAL); checkSequence(result, 1, Opcode.TABLESWITCH, Opcode.ALOAD_0, Opcode.ALOAD_1, Opcode.ALOAD_2, Opcode.INVOKESPECIAL, Opcode.GOTO); checkSequence(result, 3, Opcode.ALOAD_0, Opcode.ALOAD_1, Opcode.ALOAD_2, Opcode.INVOKESPECIAL, Opcode.GOTO, Opcode.RETURN); checkSequence(result, 1, Opcode.ALOAD_3, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_1, Opcode.ISTORE); checkSequence(result, 1, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_1, Opcode.ISTORE, Opcode.GOTO); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_1, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD); checkSequence(result, 1, Opcode.IFEQ, Opcode.ICONST_1, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD, Opcode.TABLESWITCH); checkSequence(result, 1, Opcode.ICONST_1, Opcode.ISTORE, Opcode.GOTO, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0); checkSequence(result, 1, Opcode.ALOAD_3, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_2, Opcode.ISTORE); checkSequence(result, 1, Opcode.LDC, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_2, Opcode.ISTORE, Opcode.ILOAD); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.IFEQ, Opcode.ICONST_2, Opcode.ISTORE, Opcode.ILOAD, Opcode.TABLESWITCH); checkSequence(result, 1, Opcode.IFEQ, Opcode.ICONST_2, Opcode.ISTORE, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0); checkSequence(result, 1, Opcode.ICONST_2, Opcode.ISTORE, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0, Opcode.ALOAD_1); checkSequence(result, 1, Opcode.ISTORE, Opcode.ILOAD, Opcode.TABLESWITCH, Opcode.ALOAD_0, Opcode.ALOAD_1, Opcode.ALOAD_2); } private InstructionSequence buildSequence(Opcode... opcodes) { return new InstructionSequence(Arrays.asList(opcodes)); } private void checkSequence(Map<InstructionSequence, Integer> scoreMap, int count, Opcode... opcodes) { InstructionSequence key = buildSequence(opcodes); int score = scoreMap.get(key); assertEquals(count, score); } private void log(Map<InstructionSequence, Integer> result) { if (SHOW_OUTPUT) { for (Map.Entry<InstructionSequence, Integer> entry : result.entrySet()) { System.out.println(entry.getValue() + "\t=>\t" + entry.getKey()); } } } @Test public void testInfiniteLoopChain1() { String[] lines = new String[] { "0: aload_1", "1: invokevirtual #38 // Method org/adoptopenjdk/jitwatch/model/Tag.getName:()Ljava/lang/String;", "4: astore_3", "5: iconst_m1", "6: istore 4", "8: goto 0" }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(1); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(6, result.size()); checkSequence(result, 1, Opcode.ALOAD_1); checkSequence(result, 1, Opcode.INVOKEVIRTUAL); checkSequence(result, 1, Opcode.ASTORE_3); checkSequence(result, 1, Opcode.ICONST_M1); checkSequence(result, 1, Opcode.ISTORE); checkSequence(result, 1, Opcode.GOTO); } @Test public void testInfiniteLoopChain2() { String[] lines = new String[] { "0: aload_1", "1: invokevirtual #38 // Method org/adoptopenjdk/jitwatch/model/Tag.getName:()Ljava/lang/String;", "4: astore_3", "5: iconst_m1", "6: istore 4", "8: goto 0" }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(2); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(6, result.size()); checkSequence(result, 1, Opcode.ALOAD_1, Opcode.INVOKEVIRTUAL); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.ASTORE_3); checkSequence(result, 1, Opcode.ASTORE_3, Opcode.ICONST_M1); checkSequence(result, 1, Opcode.ICONST_M1, Opcode.ISTORE); checkSequence(result, 1, Opcode.ISTORE, Opcode.GOTO); checkSequence(result, 1, Opcode.GOTO, Opcode.ALOAD_1); } @Test public void testInfiniteLoopChain3() { String[] lines = new String[] { "0: aload_1", "1: invokevirtual #38 // Method org/adoptopenjdk/jitwatch/model/Tag.getName:()Ljava/lang/String;", "4: astore_3", "5: iconst_m1", "6: istore 4", "8: goto 0" }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(3); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(6, result.size()); checkSequence(result, 1, Opcode.ALOAD_1, Opcode.INVOKEVIRTUAL, Opcode.ASTORE_3); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.ASTORE_3, Opcode.ICONST_M1); checkSequence(result, 1, Opcode.ASTORE_3, Opcode.ICONST_M1, Opcode.ISTORE); checkSequence(result, 1, Opcode.ICONST_M1, Opcode.ISTORE, Opcode.GOTO); checkSequence(result, 1, Opcode.ISTORE, Opcode.GOTO, Opcode.ALOAD_1); checkSequence(result, 1, Opcode.GOTO, Opcode.ALOAD_1, Opcode.INVOKEVIRTUAL); } @Test public void testFollowGotoChain1() { String[] lines = new String[] { "0: goto 2", "1: goto 3", "2: goto 1", "3: return " }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(1); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(2, result.size()); checkSequence(result, 3, Opcode.GOTO); checkSequence(result, 1, Opcode.RETURN); } @Test public void testFollowGotoChain2() { String[] lines = new String[] { "0: goto 2", "1: goto 3", "2: goto 1", "3: return " }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(2); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(2, result.size()); checkSequence(result, 2, Opcode.GOTO, Opcode.GOTO); checkSequence(result, 1, Opcode.GOTO, Opcode.RETURN); } @Test public void testAthrow() { String[] lines = new String[] { "0: getstatic #5 // Field socketImplCtor:Ljava/lang/reflect/Constructor;", "3: iconst_0 ", "4: anewarray #6 // class java/lang/Object", "7: invokevirtual #7 // Method java/lang/reflect/Constructor.newInstance:([Ljava/lang/Object;)Ljava/lang/Object;", "10: checkcast #8 // class java/net/SocketImpl", "13: areturn ", "14: astore_0 ", "15: new #10 // class java/lang/AssertionError", "18: dup ", "19: aload_0 ", "20: invokespecial #11 // Method java/lang/AssertionError.\"<init>\":(Ljava/lang/Object;)V", "23: athrow ", "24: astore_0 ", "25: new #10 // class java/lang/AssertionError", "28: dup ", "29: aload_0 ", "30: invokespecial #11 // Method java/lang/AssertionError.\"<init>\":(Ljava/lang/Object;)V", "33: athrow ", "34: astore_0 ", "35: new #10 // class java/lang/AssertionError", "38: dup ", "39: aload_0 ", "40: invokespecial #11 // Method java/lang/AssertionError.\"<init>\":(Ljava/lang/Object;)V", "43: athrow " }; MemberBytecode memberBytecode = createMemberBytecode(lines); SequenceCountOperation counter = new SequenceCountOperation(3); counter.processInstructions("Foo", memberBytecode); Map<InstructionSequence, Integer> result = counter.getSequenceScores(); log(result); assertEquals(8, result.size()); checkSequence(result, 1, Opcode.GETSTATIC, Opcode.ICONST_0, Opcode.ANEWARRAY); checkSequence(result, 1, Opcode.ICONST_0, Opcode.ANEWARRAY, Opcode.INVOKEVIRTUAL); checkSequence(result, 1, Opcode.ANEWARRAY, Opcode.INVOKEVIRTUAL, Opcode.CHECKCAST); checkSequence(result, 1, Opcode.INVOKEVIRTUAL, Opcode.CHECKCAST, Opcode.ARETURN); checkSequence(result, 3, Opcode.ASTORE_0, Opcode.NEW, Opcode.DUP); checkSequence(result, 3, Opcode.NEW, Opcode.DUP, Opcode.ALOAD_0); checkSequence(result, 3, Opcode.DUP, Opcode.ALOAD_0, Opcode.INVOKESPECIAL); checkSequence(result, 3, Opcode.ALOAD_0, Opcode.INVOKESPECIAL, Opcode.ATHROW); } }