Skip to content

Commit

Permalink
IJ-CR-108265 [java-decompiler] IDEA-198397 add cancelled checks for j…
Browse files Browse the repository at this point in the history
…ava-decompiler. Refresh api

GitOrigin-RevId: 0edb31b19b393df6981c3785d2a7368226c70114
  • Loading branch information
Mikhail Pyltsin authored and intellij-monorepo-bot committed Jun 14, 2023
1 parent 05d02ec commit 34d476f
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 76 deletions.
47 changes: 22 additions & 25 deletions src/org/jetbrains/java/decompiler/main/CancellationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,50 @@
@ApiStatus.Experimental
public interface CancellationManager {
/**
* @throws CanceledException if the process has been canceled.
* @throws TimeExceedException if limit timeout is exceeded.
* @throws CanceledException if the process has been canceled.
*/
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 {

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;
}
Expand All @@ -59,17 +61,12 @@ public void checkCanceled() throws CanceledException, TimeExceedException {
}

@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;
}
}
Expand Down
53 changes: 29 additions & 24 deletions src/org/jetbrains/java/decompiler/main/DecompilerContext.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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(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) {
this(properties, logger, structContext, classProcessor, interceptor, null);
}

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;
Expand Down Expand Up @@ -118,16 +130,9 @@ public static StructContext getStructContext() {
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() {
Expand Down
10 changes: 4 additions & 6 deletions src/org/jetbrains/java/decompiler/main/Fernflower.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -63,7 +61,7 @@ public Fernflower(IBytecodeProvider provider,
}

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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -14,12 +15,12 @@
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);
}

Expand Down
15 changes: 4 additions & 11 deletions src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -42,15 +42,8 @@ public void init() {
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());
Expand All @@ -68,13 +61,13 @@ public void init() {

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();
Expand All @@ -83,7 +76,7 @@ public void init() {
}
finally {
DecompilerContext.setCurrentContext(context);
cancellationManager.finishMethod();
cancellationManager.finishMethod(classStruct.qualifiedName, mt.getName());
}
}
}
Expand Down
8 changes: 2 additions & 6 deletions test/org/jetbrains/java/decompiler/CancellableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,15 @@ public void checkCanceled() throws CanceledException {
}

@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) {
Expand Down

0 comments on commit 34d476f

Please sign in to comment.