IJ-CR-108265 [java-decompiler] IDEA-198397 add cancelled checks for java-decompiler. Refresh api

GitOrigin-RevId: 0edb31b19b393df6981c3785d2a7368226c70114
This commit is contained in:
Mikhail Pyltsin
2023-06-14 12:11:19 +02:00
committed by intellij-monorepo-bot
parent d795671583
commit 59b359c191
8 changed files with 73 additions and 78 deletions

View File

@@ -8,24 +8,18 @@ import org.jetbrains.annotations.NotNull;
public interface CancellationManager {
/**
* @throws CanceledException if the process has been canceled.
* @throws TimeExceedException if limit timeout is exceeded.
*/
void checkCanceled() throws CanceledException, TimeExceedException;
void checkCanceled() throws CanceledException;
/**
* @param sec - limit timeout (seconds)
* Called every time the body of a new method is started to be decompiled
*/
void setMaxSec(int sec);
void startMethod(String className, String methodName);
/**
* Call to start counting down the timeout
* Called every time the method decompilation is finished
*/
void startMethod();
/**
* Call to reset timer
*/
void finishMethod();
void finishMethod(String className, String methodName);
@ApiStatus.Experimental
class CanceledException extends RuntimeException {
@@ -33,22 +27,30 @@ public interface CancellationManager {
public CanceledException(@NotNull Throwable cause) {
super(cause);
}
public CanceledException() {
super();
}
}
@ApiStatus.Experimental
class TimeExceedException extends RuntimeException {
class TimeExceedException extends CanceledException {
}
static CancellationManager getSimpleWithTimeout() {
return new SimpleWithTimeoutCancellationManager();
static CancellationManager getSimpleWithTimeout(int maxMethodTimeoutSec) {
return new TimeoutCancellationManager(maxMethodTimeoutSec);
}
class SimpleWithTimeoutCancellationManager implements CancellationManager {
private long maxMilis = 0;
class TimeoutCancellationManager implements CancellationManager {
private final long maxMilis;
private long startMilis = 0;
protected TimeoutCancellationManager(int maxMethodTimeoutSec) {
this.maxMilis = maxMethodTimeoutSec * 1000L;
}
@Override
public void checkCanceled() throws CanceledException, TimeExceedException {
public void checkCanceled() throws CanceledException {
if (maxMilis <= 0 || startMilis <= 0) {
return;
}
@@ -59,17 +61,12 @@ public interface CancellationManager {
}
@Override
public void setMaxSec(int sec) {
maxMilis = sec * 1_000L;
}
@Override
public void startMethod() {
public void startMethod(String className, String methodName) {
startMilis = System.currentTimeMillis();
}
@Override
public void finishMethod() {
public void finishMethod(String className, String methodName) {
startMilis = 0;
}
}

View File

@@ -1,6 +1,8 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.java.decompiler.main.collectors.BytecodeSourceMapper;
import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
@@ -19,36 +21,46 @@ public class DecompilerContext {
public static final String CURRENT_CLASS_NODE = "CURRENT_CLASS_NODE";
public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
@NotNull
private final Map<String, Object> properties;
@NotNull
private final IFernflowerLogger logger;
@NotNull
private final StructContext structContext;
@NotNull
private final ClassesProcessor classProcessor;
@Nullable
private final PoolInterceptor poolInterceptor;
@NotNull
private final CancellationManager cancellationManager;
private ImportCollector importCollector;
private VarProcessor varProcessor;
private CounterContainer counterContainer;
private BytecodeSourceMapper bytecodeSourceMapper;
public DecompilerContext(Map<String, Object> properties,
IFernflowerLogger logger,
StructContext structContext,
ClassesProcessor classProcessor,
PoolInterceptor interceptor) {
this(properties, logger, structContext, classProcessor, interceptor, CancellationManager.getSimpleWithTimeout());
public DecompilerContext(@NotNull Map<String, Object> properties,
@NotNull IFernflowerLogger logger,
@NotNull StructContext structContext,
@NotNull ClassesProcessor classProcessor,
@Nullable PoolInterceptor interceptor) {
this(properties, logger, structContext, classProcessor, interceptor, null);
}
public DecompilerContext(Map<String, Object> properties,
IFernflowerLogger logger,
StructContext structContext,
ClassesProcessor classProcessor,
PoolInterceptor interceptor,
CancellationManager cancellationManager) {
public DecompilerContext(@NotNull Map<String, Object> properties,
@NotNull IFernflowerLogger logger,
@NotNull StructContext structContext,
@NotNull ClassesProcessor classProcessor,
@Nullable PoolInterceptor interceptor,
@Nullable CancellationManager cancellationManager) {
Objects.requireNonNull(properties);
Objects.requireNonNull(logger);
Objects.requireNonNull(structContext);
Objects.requireNonNull(classProcessor);
Objects.requireNonNull(cancellationManager);
if (cancellationManager == null) {
Object object = properties.get(IFernflowerPreferences.MAX_PROCESSING_METHOD);
object = object == null ? "0" : object;
cancellationManager = CancellationManager.getSimpleWithTimeout(Integer.parseInt(object.toString()));
}
this.properties = properties;
this.logger = logger;
@@ -118,16 +130,9 @@ public class DecompilerContext {
public static ClassesProcessor getClassProcessor() {
return getCurrentContext().classProcessor;
}
public static CancellationManager getCancellationManager() {
DecompilerContext context = getCurrentContext();
if (context != null) {
return context.cancellationManager;
}
CancellationManager simpleWithTimeout = CancellationManager.getSimpleWithTimeout();
int maxSec = Integer.parseInt(getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
simpleWithTimeout.setMaxSec(maxSec);
return simpleWithTimeout;
public static CancellationManager getCancellationManager() {
return getCurrentContext().cancellationManager;
}
public static PoolInterceptor getPoolInterceptor() {

View File

@@ -1,6 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.extern.*;
import org.jetbrains.java.decompiler.modules.renamer.ConverterHelper;
@@ -25,12 +26,9 @@ public class Fernflower implements IDecompiledData {
public Fernflower(IBytecodeProvider provider,
IResultSaver saver,
Map<String, Object> customProperties,
@Nullable Map<String, Object> customProperties,
IFernflowerLogger logger,
CancellationManager cancellationManager) {
if (cancellationManager == null) {
cancellationManager = CancellationManager.getSimpleWithTimeout();
}
@Nullable CancellationManager cancellationManager) {
Map<String, Object> properties = new HashMap<>(IFernflowerPreferences.DEFAULTS);
if (customProperties != null) {
properties.putAll(customProperties);
@@ -63,7 +61,7 @@ public class Fernflower implements IDecompiledData {
}
public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> customProperties, IFernflowerLogger logger) {
this(provider, saver, customProperties, logger, CancellationManager.getSimpleWithTimeout());
this(provider, saver, customProperties, logger, null);
}
private static IIdentifierRenamer loadHelper(String className, IFernflowerLogger logger) {

View File

@@ -1,6 +1,7 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.decompiler;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.java.decompiler.main.CancellationManager;
import org.jetbrains.java.decompiler.main.Fernflower;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
@@ -14,12 +15,12 @@ import java.util.Map;
public class BaseDecompiler {
private final Fernflower engine;
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
this(provider, saver, options, logger, CancellationManager.getSimpleWithTimeout());
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, @Nullable Map<String, Object> options, IFernflowerLogger logger) {
this(provider, saver, options, logger, null);
}
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger,
CancellationManager cancellationManager) {
public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, @Nullable Map<String, Object> options, IFernflowerLogger logger,
@Nullable CancellationManager cancellationManager) {
engine = new Fernflower(provider, saver, options, logger, cancellationManager);
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.java.decompiler.main.rels;
import org.jetbrains.java.decompiler.code.CodeConstants;
@@ -42,15 +42,8 @@ public class ClassWrapper {
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_WRAPPER, this);
DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
int maxSec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
boolean testMode = DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE);
CancellationManager cancellationManager = DecompilerContext.getCancellationManager();
if (testMode) {
cancellationManager.setMaxSec(0);
}
else {
cancellationManager.setMaxSec(maxSec);
}
for (StructMethod mt : classStruct.getMethods()) {
cancellationManager.checkCanceled();
DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
@@ -68,13 +61,13 @@ public class ClassWrapper {
try {
if (mt.containsCode()) {
if (maxSec == 0 || testMode) {
if (testMode) {
root = MethodProcessorRunnable.codeToJava(classStruct, mt, md, varProc);
}
else {
DecompilerContext context = DecompilerContext.getCurrentContext();
try {
cancellationManager.startMethod();
cancellationManager.startMethod(classStruct.qualifiedName, mt.getName());
MethodProcessorRunnable mtProc =
new MethodProcessorRunnable(classStruct, mt, md, varProc, DecompilerContext.getCurrentContext());
mtProc.run();
@@ -83,7 +76,7 @@ public class ClassWrapper {
}
finally {
DecompilerContext.setCurrentContext(context);
cancellationManager.finishMethod();
cancellationManager.finishMethod(classStruct.qualifiedName, mt.getName());
}
}
}

View File

@@ -39,19 +39,15 @@ public class CancellableTest {
}
@Override
public void setMaxSec(int sec) {
public void startMethod(String className, String methodName) {
}
@Override
public void startMethod() {
public void finishMethod(String className, String methodName) {
}
@Override
public void finishMethod() {
}
private void check() {
if (myAtomicInteger.incrementAndGet() > MIN_CALL_NUMBERS) {

View File

@@ -7,10 +7,14 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.java.decompiler.main.CancellationManager;
@ApiStatus.Experimental
public class IdeaCancellationManager extends CancellationManager.SimpleWithTimeoutCancellationManager {
public class IdeaCancellationManager extends CancellationManager.TimeoutCancellationManager {
public IdeaCancellationManager(int maxMethodTimeoutSec) {
super(maxMethodTimeoutSec);
}
@Override
public void checkCanceled() throws CanceledException, TimeExceedException {
public void checkCanceled() throws CanceledException {
try {
ProgressManager.checkCanceled();
}

View File

@@ -147,8 +147,9 @@ class IdeaDecompiler : ClassFileDecompilers.Light() {
val provider = MyBytecodeProvider(files)
val saver = MyResultSaver()
val maxSecProcessingMethod = options[IFernflowerPreferences.MAX_PROCESSING_METHOD]?.toString()?.toIntOrNull() ?: 0
val decompiler = BaseDecompiler(provider, saver, options, myLogger.value,
IdeaCancellationManager())
IdeaCancellationManager(maxSecProcessingMethod))
files.forEach { decompiler.addSource(File(it.path)) }
try {
decompiler.decompileContext()