diff --git a/src/main/java/jd/core/process/analyzer/classfile/visitor/SearchInstructionByTypeVisitor.java b/src/main/java/jd/core/process/analyzer/classfile/visitor/SearchInstructionByTypeVisitor.java new file mode 100644 index 00000000..813c9f9d --- /dev/null +++ b/src/main/java/jd/core/process/analyzer/classfile/visitor/SearchInstructionByTypeVisitor.java @@ -0,0 +1,460 @@ +/******************************************************************************* + * Copyright (C) 2007-2023 Emmanuel Dupuy GPLv3 and other contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ******************************************************************************/ +package jd.core.process.analyzer.classfile.visitor; + +import org.apache.bcel.Const; + +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; + +import jd.core.model.instruction.bytecode.ByteCodeConstants; +import jd.core.model.instruction.bytecode.instruction.ANewArray; +import jd.core.model.instruction.bytecode.instruction.AThrow; +import jd.core.model.instruction.bytecode.instruction.ArrayLength; +import jd.core.model.instruction.bytecode.instruction.ArrayStoreInstruction; +import jd.core.model.instruction.bytecode.instruction.AssertInstruction; +import jd.core.model.instruction.bytecode.instruction.BinaryOperatorInstruction; +import jd.core.model.instruction.bytecode.instruction.CheckCast; +import jd.core.model.instruction.bytecode.instruction.ComplexConditionalBranchInstruction; +import jd.core.model.instruction.bytecode.instruction.ConvertInstruction; +import jd.core.model.instruction.bytecode.instruction.DupStore; +import jd.core.model.instruction.bytecode.instruction.GetField; +import jd.core.model.instruction.bytecode.instruction.IfCmp; +import jd.core.model.instruction.bytecode.instruction.IfInstruction; +import jd.core.model.instruction.bytecode.instruction.IncInstruction; +import jd.core.model.instruction.bytecode.instruction.InitArrayInstruction; +import jd.core.model.instruction.bytecode.instruction.InstanceOf; +import jd.core.model.instruction.bytecode.instruction.Instruction; +import jd.core.model.instruction.bytecode.instruction.InvokeInstruction; +import jd.core.model.instruction.bytecode.instruction.InvokeNoStaticInstruction; +import jd.core.model.instruction.bytecode.instruction.LookupSwitch; +import jd.core.model.instruction.bytecode.instruction.MonitorEnter; +import jd.core.model.instruction.bytecode.instruction.MonitorExit; +import jd.core.model.instruction.bytecode.instruction.MultiANewArray; +import jd.core.model.instruction.bytecode.instruction.NewArray; +import jd.core.model.instruction.bytecode.instruction.Pop; +import jd.core.model.instruction.bytecode.instruction.PutField; +import jd.core.model.instruction.bytecode.instruction.PutStatic; +import jd.core.model.instruction.bytecode.instruction.ReturnInstruction; +import jd.core.model.instruction.bytecode.instruction.StoreInstruction; +import jd.core.model.instruction.bytecode.instruction.TableSwitch; +import jd.core.model.instruction.bytecode.instruction.TernaryOpStore; +import jd.core.model.instruction.bytecode.instruction.TernaryOperator; +import jd.core.model.instruction.bytecode.instruction.UnaryOperatorInstruction; +import jd.core.model.instruction.fast.FastConstants; +import jd.core.model.instruction.fast.instruction.FastDeclaration; +import jd.core.model.instruction.fast.instruction.FastFor; +import jd.core.model.instruction.fast.instruction.FastForEach; +import jd.core.model.instruction.fast.instruction.FastInstruction; +import jd.core.model.instruction.fast.instruction.FastLabel; +import jd.core.model.instruction.fast.instruction.FastList; +import jd.core.model.instruction.fast.instruction.FastSwitch; +import jd.core.model.instruction.fast.instruction.FastSwitch.Pair; +import jd.core.model.instruction.fast.instruction.FastSynchronized; +import jd.core.model.instruction.fast.instruction.FastTest2Lists; +import jd.core.model.instruction.fast.instruction.FastTestList; +import jd.core.model.instruction.fast.instruction.FastTry; +import jd.core.model.instruction.fast.instruction.FastTry.FastCatch; + +public final class SearchInstructionByTypeVisitor +{ + private final Class type; + private final Predicate predicate; + + public SearchInstructionByTypeVisitor(Class type, Predicate predicate) { + this.type = type; + this.predicate = predicate; + } + + public T visit(Instruction instruction) + throws RuntimeException + { + Objects.requireNonNull(instruction, "Null instruction"); + + if (type.isInstance(instruction)) { + T convertedInstruction = type.cast(instruction); + if (predicate.test(convertedInstruction)) { + return convertedInstruction; + } + } + + switch (instruction.getOpcode()) + { + case Const.ARRAYLENGTH: + return visit(((ArrayLength)instruction).getArrayref()); + case Const.AASTORE, + ByteCodeConstants.ARRAYSTORE: + return visit(((ArrayStoreInstruction)instruction).getArrayref()); + case ByteCodeConstants.ASSERT: + { + AssertInstruction ai = (AssertInstruction)instruction; + T tmp = visit(ai.getTest()); + if (tmp != null) { + return tmp; + } + if (ai.getMsg() == null) { + return null; + } + return visit(ai.getMsg()); + } + case Const.ATHROW: + return visit(((AThrow)instruction).getValue()); + case ByteCodeConstants.UNARYOP: + return visit(((UnaryOperatorInstruction)instruction).getValue()); + case ByteCodeConstants.BINARYOP, + ByteCodeConstants.ASSIGNMENT: + { + BinaryOperatorInstruction boi = + (BinaryOperatorInstruction)instruction; + T tmp = visit(boi.getValue1()); + if (tmp != null) { + return tmp; + } + return visit(boi.getValue2()); + } + case Const.CHECKCAST: + return visit(((CheckCast)instruction).getObjectref()); + case ByteCodeConstants.STORE, + Const.ASTORE, + Const.ISTORE: + return visit(((StoreInstruction)instruction).getValueref()); + case ByteCodeConstants.DUPSTORE: + return visit(((DupStore)instruction).getObjectref()); + case ByteCodeConstants.CONVERT, + ByteCodeConstants.IMPLICITCONVERT: + return visit(((ConvertInstruction)instruction).getValue()); + case ByteCodeConstants.IFCMP: + { + IfCmp ifCmp = (IfCmp)instruction; + T tmp = visit(ifCmp.getValue1()); + if (tmp != null) { + return tmp; + } + return visit(ifCmp.getValue2()); + } + case ByteCodeConstants.IF, + ByteCodeConstants.IFXNULL: + return visit(((IfInstruction)instruction).getValue()); + case ByteCodeConstants.COMPLEXIF: + { + List branchList = + ((ComplexConditionalBranchInstruction)instruction).getInstructions(); + for (int i=branchList.size()-1; i>=0; --i) + { + T tmp = visit(branchList.get(i)); + if (tmp != null) { + return tmp; + } + } + } + break; + case Const.INSTANCEOF: + return visit(((InstanceOf)instruction).getObjectref()); + case Const.INVOKEINTERFACE, + Const.INVOKESPECIAL, + Const.INVOKEVIRTUAL: + { + T result = visit( + ((InvokeNoStaticInstruction)instruction).getObjectref()); + if (result != null) { + return result; + } + } + // intended fall through + case Const.INVOKESTATIC, + ByteCodeConstants.INVOKENEW: + { + List list = ((InvokeInstruction)instruction).getArgs(); + for (int i=list.size()-1; i>=0; --i) + { + T tmp = visit(list.get(i)); + if (tmp != null) { + return tmp; + } + } + } + break; + case Const.LOOKUPSWITCH: + return visit(((LookupSwitch)instruction).getKey()); + case Const.MONITORENTER: + return visit(((MonitorEnter)instruction).getObjectref()); + case Const.MONITOREXIT: + return visit(((MonitorExit)instruction).getObjectref()); + case Const.MULTIANEWARRAY: + { + Instruction[] dimensions = ((MultiANewArray)instruction).getDimensions(); + for (int i=dimensions.length-1; i>=0; --i) + { + T tmp = visit(dimensions[i]); + if (tmp != null) { + return tmp; + } + } + } + break; + case Const.NEWARRAY: + return visit(((NewArray)instruction).getDimension()); + case Const.ANEWARRAY: + return visit(((ANewArray)instruction).getDimension()); + case Const.POP: + return visit(((Pop)instruction).getObjectref()); + case Const.PUTFIELD: + { + PutField putField = (PutField)instruction; + T tmp = visit(putField.getObjectref()); + if (tmp != null) { + return tmp; + } + return visit(putField.getValueref()); + } + case Const.PUTSTATIC: + return visit(((PutStatic)instruction).getValueref()); + case ByteCodeConstants.XRETURN: + return visit(((ReturnInstruction)instruction).getValueref()); + case Const.TABLESWITCH: + return visit(((TableSwitch)instruction).getKey()); + case ByteCodeConstants.TERNARYOPSTORE: + return visit(((TernaryOpStore)instruction).getObjectref()); + case ByteCodeConstants.PREINC, + ByteCodeConstants.POSTINC: + return visit(((IncInstruction)instruction).getValue()); + case Const.GETFIELD: + return visit(((GetField)instruction).getObjectref()); + case ByteCodeConstants.INITARRAY, + ByteCodeConstants.NEWANDINITARRAY: + { + InitArrayInstruction iai = (InitArrayInstruction)instruction; + T tmp = visit(iai.getNewArray()); + if (tmp != null) { + return tmp; + } + if (iai.getValues() != null) { + return visit(iai.getValues()); + } + } + break; + case ByteCodeConstants.TERNARYOP: + { + TernaryOperator to = (TernaryOperator)instruction; + T tmp = visit(to.getValue1()); + if (tmp != null) { + return tmp; + } + return visit(to.getValue2()); + } + case FastConstants.TRY: + { + FastTry ft = (FastTry)instruction; + T tmp = visit(ft.getInstructions()); + if (tmp != null) { + return tmp; + } + List catches = ft.getCatches(); + for (int i=catches.size()-1; i>=0; --i) + { + tmp = visit(catches.get(i).instructions()); + if (tmp != null) { + return tmp; + } + } + if (ft.getFinallyInstructions() != null) { + return visit(ft.getFinallyInstructions()); + } + } + break; + case FastConstants.SYNCHRONIZED: + { + FastSynchronized fsy = (FastSynchronized)instruction; + T tmp = visit(fsy.getMonitor()); + if (tmp != null) { + return tmp; + } + return visit(fsy.getInstructions()); + } + case FastConstants.FOR: + { + FastFor ff = (FastFor)instruction; + if (ff.getInit() != null) + { + T tmp = visit(ff.getInit()); + if (tmp != null) { + return tmp; + } + } + if (ff.getInc() != null) + { + T tmp = visit(ff.getInc()); + if (tmp != null) { + return tmp; + } + } + } + // intended fall through + case FastConstants.WHILE, + FastConstants.DO_WHILE, + FastConstants.IF_SIMPLE: + { + FastTestList ftl = (FastTestList)instruction; + if (ftl.getTest() != null) + { + T tmp = visit(ftl.getTest()); + if (tmp != null) { + return tmp; + } + } + } + // intended fall through + case FastConstants.INFINITE_LOOP: + { + List instructions = + ((FastList)instruction).getInstructions(); + if (instructions != null) { + return visit(instructions); + } + } + break; + case FastConstants.FOREACH: + { + FastForEach ffe = (FastForEach)instruction; + T tmp = visit(ffe.getVariable()); + if (tmp != null) { + return tmp; + } + tmp = visit(ffe.getValues()); + if (tmp != null) { + return tmp; + } + return visit(ffe.getInstructions()); + } + case FastConstants.IF_ELSE: + { + FastTest2Lists ft2l = (FastTest2Lists)instruction; + T tmp = visit(ft2l.getTest()); + if (tmp != null) { + return tmp; + } + tmp = visit(ft2l.getInstructions()); + if (tmp != null) { + return tmp; + } + return visit(ft2l.getInstructions2()); + } + case FastConstants.IF_CONTINUE, + FastConstants.IF_BREAK, + FastConstants.IF_LABELED_BREAK, + FastConstants.GOTO_CONTINUE, + FastConstants.GOTO_BREAK, + FastConstants.GOTO_LABELED_BREAK: + { + FastInstruction fi = (FastInstruction)instruction; + if (fi.getInstruction() != null) { + return visit(fi.getInstruction()); + } + } + break; + case FastConstants.DECLARE: + { + FastDeclaration fd = (FastDeclaration)instruction; + if (fd.getInstruction() != null) { + return visit(fd.getInstruction()); + } + } + break; + case FastConstants.SWITCH, + FastConstants.SWITCH_ENUM, + FastConstants.SWITCH_STRING: + { + FastSwitch fs = (FastSwitch)instruction; + T tmp = visit(fs.getTest()); + if (tmp != null) { + return tmp; + } + + Pair[] pairs = fs.getPairs(); + for (int i=pairs.length-1; i>=0; --i) + { + List instructions = pairs[i].getInstructions(); + if (instructions != null) + { + tmp = visit(instructions); + if (tmp != null) { + return tmp; + } + } + } + } + break; + case FastConstants.LABEL: + { + FastLabel fla = (FastLabel)instruction; + if (fla.getInstruction() != null) { + return visit(fla.getInstruction()); + } + } + break; + case Const.ACONST_NULL, + ByteCodeConstants.ARRAYLOAD, + ByteCodeConstants.LOAD, + Const.ALOAD, + Const.ILOAD, + Const.BIPUSH, + ByteCodeConstants.ICONST, + ByteCodeConstants.LCONST, + ByteCodeConstants.FCONST, + ByteCodeConstants.DCONST, + ByteCodeConstants.DUPLOAD, + ByteCodeConstants.EXCEPTIONLOAD, + Const.GETSTATIC, + ByteCodeConstants.OUTERTHIS, + Const.GOTO, + Const.IINC, + Const.JSR, + Const.LDC, + Const.LDC2_W, + Const.NEW, + Const.NOP, + Const.RET, + Const.RETURN, + Const.INVOKEDYNAMIC, + ByteCodeConstants.RETURNADDRESSLOAD, + Const.SIPUSH: + break; + default: + System.err.println( + "Can not search instruction in " + + instruction.getClass().getName() + + "=" + instruction.getOpcode()); + } + + return null; + } + + private T visit(List instructions) + throws RuntimeException + { + for (int i=instructions.size()-1; i>=0; --i) + { + T instruction = visit(instructions.get(i)); + if (instruction != null) { + return instruction; + } + } + + return null; + } +} diff --git a/src/main/java/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java b/src/main/java/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java index 7407d813..15bf295b 100644 --- a/src/main/java/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java +++ b/src/main/java/jd/core/process/analyzer/instruction/fast/FastInstructionListBuilder.java @@ -105,6 +105,7 @@ import jd.core.process.analyzer.classfile.reconstructor.AssignmentOperatorReconstructor; import jd.core.process.analyzer.classfile.visitor.RemoveCheckCastVisitor; import jd.core.process.analyzer.classfile.visitor.SearchInstructionByOpcodeVisitor; +import jd.core.process.analyzer.classfile.visitor.SearchInstructionByTypeVisitor; import jd.core.process.analyzer.instruction.bytecode.ComparisonInstructionAnalyzer; import jd.core.process.analyzer.instruction.bytecode.reconstructor.AssertInstructionReconstructor; import jd.core.process.analyzer.instruction.bytecode.util.ByteCodeUtil; @@ -140,8 +141,10 @@ * AnalyzeXXXXSwitch -------------------------------------------------+ */ public final class FastInstructionListBuilder { + private FastInstructionListBuilder() { } + /** Declaration constants. */ private static final boolean DECLARED = true; private static final boolean NOT_DECLARED = false; @@ -1574,17 +1577,15 @@ private static Set addDeclarations(List list, Loca if (length > 0) { // 1) Ajout de declaration sur les instructions 'store' et 'for' - LocalVariable lv; int lastOffset = list.get(length - 1).getOffset(); - Instruction instruction; for (int i = 0; i < length; i++) { - instruction = list.get(i); + Instruction instruction = list.get(i); if (instruction instanceof StoreInstruction) { StoreInstruction si = (StoreInstruction) instruction; - lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); if (lv != null && lv.hasDeclarationFlag() == NOT_DECLARED) { ReturnInstruction returnInstruction = findReturnInstructionForStore(list, length, i, si); if (returnInstruction == null || returnInstruction.getLineNumber() != si.getLineNumber()) { @@ -1611,7 +1612,7 @@ private static Set addDeclarations(List list, Loca if (ff.getInit() != null && (ff.getInit().getOpcode() == Const.ASTORE || ff.getInit().getOpcode() == Const.ISTORE || ff.getInit().getOpcode() == ByteCodeConstants.STORE)) { StoreInstruction si = (StoreInstruction) ff.getInit(); - lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); if (lv != null && lv.hasDeclarationFlag() == NOT_DECLARED && beforeListOffset < lv.getStartPc() && lv.getStartPc() + lv.getLength() - 1 <= lastOffset @@ -1626,7 +1627,7 @@ private static Set addDeclarations(List list, Loca instruction, ByteCodeConstants.ASSIGNMENT); if (asi != null && asi.getValue1() instanceof LoadInstruction) { LoadInstruction li = (LoadInstruction) asi.getValue1(); - lv = localVariables.getLocalVariableWithIndexAndOffset(li.getIndex(), li.getOffset()); + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(li.getIndex(), li.getOffset()); if (lv != null && lv.hasDeclarationFlag() == NOT_DECLARED && beforeListOffset < lv.getStartPc() && lv.getStartPc() + lv.getLength() - 1 <= lastOffset) { FastDeclaration fastDeclaration = new FastDeclaration(lv.getStartPc(), @@ -1635,13 +1636,16 @@ private static Set addDeclarations(List list, Loca lv.setDeclarationFlag(DECLARED); } } else { - StoreInstruction si = (StoreInstruction) SearchInstructionByOpcodeVisitor.visit( - instruction, ByteCodeConstants.STORE, Const.ISTORE, Const.ASTORE); + SearchInstructionByTypeVisitor visitor = new SearchInstructionByTypeVisitor<>( + StoreInstruction.class, si -> { + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); + return lv != null && lv.hasDeclarationFlag() == NOT_DECLARED && beforeListOffset < lv.getStartPc() + && lv.getStartPc() + lv.getLength() - 1 <= lastOffset; + }); + StoreInstruction si = visitor.visit(instruction); if (si != null) { - lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); - if (lv != null && lv.hasDeclarationFlag() == NOT_DECLARED && beforeListOffset < lv.getStartPc() - && lv.getStartPc() + lv.getLength() - 1 <= lastOffset - && !declarationFound(list, lv) && CheckLocalVariableUsedVisitor.visit(lv, list)) { + LocalVariable lv = localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset()); + if (!declarationFound(list, lv)) { FastDeclaration fastDeclaration = new FastDeclaration(lv.getStartPc(), Instruction.UNKNOWN_LINE_NUMBER, lv, null); list.add(i, fastDeclaration); @@ -1678,7 +1682,7 @@ private static Set addDeclarations(List list, Loca // } final int lvLength = Optional.ofNullable(localVariables).map(LocalVariables::size).orElse(0); for (int i = 0; i < lvLength; i++) { - lv = localVariables.getLocalVariableAt(i); + LocalVariable lv = localVariables.getLocalVariableAt(i); if (lv.hasDeclarationFlag() == NOT_DECLARED && !lv.isToBeRemoved() && beforeListOffset < lv.getStartPc() && lv.getStartPc() + lv.getLength() - 1 <= lastOffset && !INTERNAL_OBJECT_SIGNATURE.equals(lv.getName(classFile.getConstantPool()))) { int indexForNewDeclaration = InstructionUtil.getIndexForOffset(list, lv.getStartPc()); @@ -1696,7 +1700,18 @@ private static Set addDeclarations(List list, Loca Instruction.UNKNOWN_LINE_NUMBER, lv, null); if (addDeclarations) { if (!declarationFound(list, lv) && CheckLocalVariableUsedVisitor.visit(lv, list)) { - list.add(indexForNewDeclaration, fastDeclaration); + Instruction instruction = list.get(indexForNewDeclaration); + if (instruction instanceof StoreInstruction) { + StoreInstruction si = (StoreInstruction) instruction; + if (lv == localVariables.getLocalVariableWithIndexAndOffset(si.getIndex(), si.getOffset())) { + fastDeclaration = new FastDeclaration(si.getOffset(), si.getLineNumber(), lv, si); + } + } + if (fastDeclaration.getInstruction() == null) { + list.add(indexForNewDeclaration, fastDeclaration); + } else { + list.set(indexForNewDeclaration, fastDeclaration); + } } } else { outerDeclarations.add(fastDeclaration); diff --git a/src/test/java/jd/core/test/EventCountCircuitBreakerTest.java b/src/test/java/jd/core/test/EventCountCircuitBreakerTest.java new file mode 100644 index 00000000..010c269b --- /dev/null +++ b/src/test/java/jd/core/test/EventCountCircuitBreakerTest.java @@ -0,0 +1,18 @@ +package jd.core.test; + +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertEquals; + +public class EventCountCircuitBreakerTest extends AbstractTestCase { + + @Test + public void test() throws IOException { + String output = decompile("org/apache/commons/lang3/concurrent/EventCountCircuitBreaker"); + assertEquals(IOUtils.toString(getClass().getResource("EventCountCircuitBreaker.txt"), StandardCharsets.UTF_8), output); + } +} diff --git a/src/test/resources/jd/core/test/EventCountCircuitBreaker.txt b/src/test/resources/jd/core/test/EventCountCircuitBreaker.txt new file mode 100644 index 00000000..7e491138 --- /dev/null +++ b/src/test/resources/jd/core/test/EventCountCircuitBreaker.txt @@ -0,0 +1,564 @@ +/* */ package org.apache.commons.lang3.concurrent; +/* */ +/* */ import java.util.EnumMap; +/* */ import java.util.Map; +/* */ import java.util.concurrent.TimeUnit; +/* */ import java.util.concurrent.atomic.AtomicReference; +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public class EventCountCircuitBreaker +/* */ extends AbstractCircuitBreaker +/* */ { +/* */ private final AtomicReference checkIntervalData; +/* */ private final int openingThreshold; +/* */ private final long openingInterval; +/* */ private final int closingThreshold; +/* */ private final long closingInterval; +/* 141 */ private static final Map STRATEGY_MAP = createStrategyMap(); +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public EventCountCircuitBreaker(int openingThreshold, long openingInterval, TimeUnit openingUnit, int closingThreshold, long closingInterval, TimeUnit closingUnit) +/* */ { +/* 177 */ this.checkIntervalData = new AtomicReference<>(new CheckIntervalData(0, 0L)); +/* 178 */ this.openingThreshold = openingThreshold; +/* 179 */ this.openingInterval = openingUnit.toNanos(openingInterval); +/* 180 */ this.closingThreshold = closingThreshold; +/* 181 */ this.closingInterval = closingUnit.toNanos(closingInterval); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public EventCountCircuitBreaker(int openingThreshold, long checkInterval, TimeUnit checkUnit, int closingThreshold) +/* */ { +/* 199 */ this(openingThreshold, checkInterval, checkUnit, closingThreshold, checkInterval, checkUnit); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public EventCountCircuitBreaker(int threshold, long checkInterval, TimeUnit checkUnit) +/* */ { +/* 214 */ this(threshold, checkInterval, checkUnit, threshold); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public int getOpeningThreshold() +/* */ { +/* 225 */ return this.openingThreshold; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public long getOpeningInterval() +/* */ { +/* 234 */ return this.openingInterval; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public int getClosingThreshold() +/* */ { +/* 245 */ return this.closingThreshold; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public long getClosingInterval() +/* */ { +/* 254 */ return this.closingInterval; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ @Override +/* */ public boolean checkState() +/* */ { +/* 264 */ return performStateCheck(0); +/* */ } +/* */ +/* */ +/* */ +/* */ @Override +/* */ public boolean incrementAndCheckState(Integer increment) +/* */ { +/* 272 */ return performStateCheck(increment.intValue()); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public boolean incrementAndCheckState() +/* */ { +/* 284 */ return incrementAndCheckState(Integer.valueOf(1)); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ @Override +/* */ public void open() +/* */ { +/* 295 */ super.open(); +/* 296 */ this.checkIntervalData.set(new CheckIntervalData(0, nanoTime())); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ @Override +/* */ public void close() +/* */ { +/* 307 */ super.close(); +/* 308 */ this.checkIntervalData.set(new CheckIntervalData(0, nanoTime())); +/* */ } +/* */ +/* */ +/* */ +/* */ private boolean performStateCheck(int increment) +/* */ { +/* */ CheckIntervalData nextData; +/* */ +/* */ +/* */ CheckIntervalData currentData; +/* */ +/* */ AbstractCircuitBreaker.State currentState; +/* */ +/* */ do +/* */ { +/* 324 */ long time = nanoTime(); +/* 325 */ currentState = (AbstractCircuitBreaker.State)this.state.get(); +/* 326 */ currentData = (CheckIntervalData)this.checkIntervalData.get(); +/* 327 */ nextData = nextCheckIntervalData(increment, currentData, currentState, time); +/* 328 */ } while (!updateCheckIntervalData(currentData, nextData)); +/* */ +/* */ +/* */ +/* 332 */ if (stateStrategy(currentState).isStateTransition(this, currentData, nextData)) { +/* 333 */ currentState = currentState.oppositeState(); +/* 334 */ changeStateAndStartNewCheckInterval(currentState); +/* */ } +/* 336 */ return !isOpen(currentState); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private boolean updateCheckIntervalData(CheckIntervalData currentData, CheckIntervalData nextData) +/* */ { +/* 351 */ return currentData == nextData || +/* 352 */ this.checkIntervalData.compareAndSet(currentData, nextData); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private void changeStateAndStartNewCheckInterval(AbstractCircuitBreaker.State newState) +/* */ { +/* 362 */ changeState(newState); +/* 363 */ this.checkIntervalData.set(new CheckIntervalData(0, nanoTime())); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private CheckIntervalData nextCheckIntervalData(int increment, CheckIntervalData currentData, AbstractCircuitBreaker.State currentState, long time) +/* */ { +/* */ CheckIntervalData nextData; +/* */ +/* */ +/* */ +/* */ +/* */ +/* 380 */ if (stateStrategy(currentState).isCheckIntervalFinished(this, currentData, time)) { +/* 381 */ nextData = new CheckIntervalData(increment, time); +/* */ } else { +/* 383 */ nextData = currentData.increment(increment); +/* */ } +/* 385 */ return nextData; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ long nanoTime() +/* */ { +/* 395 */ return System.nanoTime(); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private static StateStrategy stateStrategy(AbstractCircuitBreaker.State state) +/* */ { +/* 406 */ return (StateStrategy)STRATEGY_MAP.get(state); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private static Map createStrategyMap() +/* */ { +/* 416 */ Map map = new EnumMap<>(AbstractCircuitBreaker.State.class); +/* 417 */ map.put(AbstractCircuitBreaker.State.CLOSED, new StateStrategyClosed()); +/* 418 */ map.put(AbstractCircuitBreaker.State.OPEN, new StateStrategyOpen()); +/* 419 */ return map; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private static class CheckIntervalData +/* */ { +/* */ private final int eventCount; +/* */ +/* */ +/* */ +/* */ +/* */ private final long checkIntervalStart; +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ CheckIntervalData(int count, long intervalStart) +/* */ { +/* 441 */ this.eventCount = count; +/* 442 */ this.checkIntervalStart = intervalStart; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public int getEventCount() +/* */ { +/* 451 */ return this.eventCount; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public long getCheckIntervalStart() +/* */ { +/* 460 */ return this.checkIntervalStart; +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public CheckIntervalData increment(int delta) +/* */ { +/* 471 */ return delta == 0 ? this : new CheckIntervalData(getEventCount() + delta, +/* 472 */ getCheckIntervalStart()); +/* */ } +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private static abstract class StateStrategy +/* */ { +/* */ public boolean isCheckIntervalFinished(EventCountCircuitBreaker breaker, EventCountCircuitBreaker.CheckIntervalData currentData, long now) +/* */ { +/* 492 */ return now - currentData.getCheckIntervalStart() > fetchCheckInterval(breaker); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ public abstract boolean isStateTransition(EventCountCircuitBreaker paramEventCountCircuitBreaker, EventCountCircuitBreaker.CheckIntervalData paramCheckIntervalData1, EventCountCircuitBreaker.CheckIntervalData paramCheckIntervalData2); +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ protected abstract long fetchCheckInterval(EventCountCircuitBreaker paramEventCountCircuitBreaker); +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private static class StateStrategyClosed +/* */ extends EventCountCircuitBreaker.StateStrategy +/* */ { +/* */ @Override +/* */ public boolean isStateTransition(EventCountCircuitBreaker breaker, EventCountCircuitBreaker.CheckIntervalData currentData, EventCountCircuitBreaker.CheckIntervalData nextData) +/* */ { +/* 529 */ return nextData.getEventCount() > breaker.getOpeningThreshold(); +/* */ } +/* */ +/* */ +/* */ +/* */ @Override +/* */ protected long fetchCheckInterval(EventCountCircuitBreaker breaker) +/* */ { +/* 537 */ return breaker.getOpeningInterval(); +/* */ } +/* */ } +/* */ +/* */ +/* */ +/* */ +/* */ +/* */ private static class StateStrategyOpen +/* */ extends EventCountCircuitBreaker.StateStrategy +/* */ { +/* */ @Override +/* */ public boolean isStateTransition(EventCountCircuitBreaker breaker, EventCountCircuitBreaker.CheckIntervalData currentData, EventCountCircuitBreaker.CheckIntervalData nextData) +/* */ { +/* 551 */ return +/* 552 */ nextData.getCheckIntervalStart() != currentData.getCheckIntervalStart() && +/* 553 */ currentData.getEventCount() < breaker.getClosingThreshold(); +/* */ } +/* */ +/* */ +/* */ +/* */ @Override +/* */ protected long fetchCheckInterval(EventCountCircuitBreaker breaker) +/* */ { +/* 561 */ return breaker.getClosingInterval(); +/* */ } +/* */ } +/* */ } diff --git a/src/test/resources/jd/core/test/Pass2Verifier.txt b/src/test/resources/jd/core/test/Pass2Verifier.txt index c2244fe0..4259a06a 100644 --- a/src/test/resources/jd/core/test/Pass2Verifier.txt +++ b/src/test/resources/jd/core/test/Pass2Verifier.txt @@ -176,7 +176,7 @@ /* */ /* */ /* 178 */ CodeException[] excTable = obj.getExceptionTable(); -/* 179 */ int excIndex; ConstantClass cc; String cname; JavaClass t; JavaClass o; for (CodeException element : excTable) { +/* 179 */ JavaClass o; JavaClass t; String cname; ConstantClass cc; int excIndex; for (CodeException element : excTable) { /* 180 */ excIndex = element.getCatchType(); /* 181 */ if (excIndex != 0) { /* 182 */ checkIndex(obj, excIndex, this.CONST_Class); @@ -806,8 +806,8 @@ /* 806 */ Type act = t; /* 807 */ if ((act instanceof ArrayType)) /* 808 */ act = ((ArrayType)act).getBasicType(); -/* */ Verifier v; -/* 810 */ VerificationResult vr; if ((act instanceof ObjectType)) { +/* */ VerificationResult vr; +/* 810 */ Verifier v; if ((act instanceof ObjectType)) { /* 811 */ v = VerifierFactory.getVerifier(((ObjectType)act).getClassName()); /* 812 */ vr = v.doPass1(); /* 813 */ if (vr != VerificationResult.VR_OK)