mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-18 10:58:22 +00:00
outofmemory exception handling, command line option for setting the process affinity and priority, some functions was executed on a different thread when parallel option was disabled
This commit is contained in:
@@ -127,6 +127,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -650,37 +651,61 @@ public class SWF {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<File> exportActionScript3(AbortRetryIgnoreHandler handler, String outdir, ExportMode exportMode, boolean parallel) {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(parallel ? 20 : 1);
|
||||
List<Future<File>> futureResults = new ArrayList<>();
|
||||
AtomicInteger cnt = new AtomicInteger(1);
|
||||
List<ABCContainerTag> abcTags = new ArrayList<>();
|
||||
public List<File> exportActionScript3(final AbortRetryIgnoreHandler handler, final String outdir, final ExportMode exportMode, final boolean parallel) {
|
||||
final AtomicInteger cnt = new AtomicInteger(1);
|
||||
final List<ABCContainerTag> abcTags = new ArrayList<>();
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof ABCContainerTag) {
|
||||
abcTags.add((ABCContainerTag) t);
|
||||
}
|
||||
}
|
||||
List<MyEntry<ClassPath, ScriptPack>> packs = getAS3Packs();
|
||||
for (MyEntry<ClassPath, ScriptPack> item : packs) {
|
||||
Future<File> future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel));
|
||||
futureResults.add(future);
|
||||
}
|
||||
|
||||
List<File> ret = new ArrayList<>();
|
||||
for (int f = 0; f < futureResults.size(); f++) {
|
||||
final List<File> ret = new ArrayList<>();
|
||||
final List<MyEntry<ClassPath, ScriptPack>> packs = getAS3Packs();
|
||||
|
||||
if (!parallel || packs.size() < 2) {
|
||||
try {
|
||||
ret.add(futureResults.get(f).get());
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
|
||||
Helper.timedCall(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
for (MyEntry<ClassPath, ScriptPack> item : packs) {
|
||||
ExportPackTask task = new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel);
|
||||
try {
|
||||
ret.add(task.call());
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException ex) {
|
||||
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
|
||||
}
|
||||
} else {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(20);
|
||||
List<Future<File>> futureResults = new ArrayList<>();
|
||||
for (MyEntry<ClassPath, ScriptPack> item : packs) {
|
||||
Future<File> future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.key, item.value, outdir, abcTags, exportMode, parallel));
|
||||
futureResults.add(future);
|
||||
}
|
||||
|
||||
for (int f = 0; f < futureResults.size(); f++) {
|
||||
try {
|
||||
ret.add(futureResults.get(f).get());
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Error during ABC export", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(Configuration.DECOMPILATION_TIMEOUT, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(ABC.class.getName()).log(Level.SEVERE, Helper.formatTimeToText(Configuration.DECOMPILATION_TIMEOUT) + " ActionScript export limit reached", ex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -606,7 +607,7 @@ public class SWFInputStream extends InputStream {
|
||||
|
||||
/**
|
||||
* Reads list of tags from the stream. Reading ends with End tag(=0) or end
|
||||
* of the stream. Optinally can skip AS1/2 tags when file is AS3
|
||||
* of the stream. Optionally can skip AS1/2 tags when file is AS3
|
||||
*
|
||||
* @param swf
|
||||
* @param level
|
||||
@@ -633,10 +634,11 @@ public class SWFInputStream extends InputStream {
|
||||
*/
|
||||
public List<Tag> readTagList(SWF swf, int level, boolean parallel, boolean skipUnusualTags, boolean parseTags) throws IOException {
|
||||
ExecutorService executor = null;
|
||||
List<Future<Tag>> futureResults = new ArrayList<>();
|
||||
if (parallel) {
|
||||
executor = Executors.newFixedThreadPool(20);
|
||||
futureResults = new ArrayList<>();
|
||||
}
|
||||
List<Future<Tag>> futureResults = new ArrayList<>();
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
Tag tag;
|
||||
Tag previousTag = null;
|
||||
@@ -659,7 +661,7 @@ public class SWFInputStream extends InputStream {
|
||||
}
|
||||
tag.previousTag = previousTag;
|
||||
previousTag = tag;
|
||||
boolean doParse = false;
|
||||
boolean doParse;
|
||||
if (!skipUnusualTags) {
|
||||
doParse = true;
|
||||
} else {
|
||||
@@ -718,7 +720,7 @@ public class SWFInputStream extends InputStream {
|
||||
for (Future<Tag> future : futureResults) {
|
||||
try {
|
||||
tags.add(future.get());
|
||||
} catch (Exception e) {
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, "Error during tag reading", e);
|
||||
}
|
||||
}
|
||||
@@ -1005,21 +1007,6 @@ public class SWFInputStream extends InputStream {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one Tag from the stream
|
||||
*
|
||||
* @param swf
|
||||
* @param level
|
||||
* @param pos
|
||||
* @param parallel
|
||||
* @param skipUnusualTags
|
||||
* @return Tag or null when End tag
|
||||
* @throws IOException
|
||||
*/
|
||||
public Tag readTag(SWF swf, int level, long pos, boolean parallel, boolean skipUnusualTags) throws IOException {
|
||||
return readTag(swf, level, pos, true, parallel, skipUnusualTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one Tag from the stream with optional resolving (= reading tag
|
||||
* content)
|
||||
|
||||
@@ -135,40 +135,38 @@ public class Traits implements Serializable {
|
||||
}
|
||||
|
||||
public HilightedTextWriter convert(Trait parent, String path, List<ABCContainerTag> abcTags, ABC abc, boolean isStatic, ExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, HilightedTextWriter writer, List<String> fullyQualifiedNames, boolean parallel) {
|
||||
ExecutorService executor = null;
|
||||
List<Future<String>> futureResults = null;
|
||||
List<TraitConvertTask> traitConvertTasks = null;
|
||||
|
||||
if (parallel) {
|
||||
executor = Executors.newFixedThreadPool(20);
|
||||
futureResults = new ArrayList<>();
|
||||
} else {
|
||||
traitConvertTasks = new ArrayList<>();
|
||||
}
|
||||
for (int t = 0; t < traits.length; t++) {
|
||||
HilightedTextWriter writer2 = new HilightedTextWriter(writer.getIsHighlighted(), writer.getIndent());
|
||||
TraitConvertTask task = new TraitConvertTask(traits[t], parent, makePackages, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer2, fullyQualifiedNames, t, parallel);
|
||||
if (parallel) {
|
||||
Future<String> future = executor.submit(task);
|
||||
futureResults.add(future);
|
||||
} else {
|
||||
traitConvertTasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
int taskCount = parallel ? futureResults.size() : traitConvertTasks.size();
|
||||
for (int f = 0; f < taskCount; f++) {
|
||||
if (f > 0) {
|
||||
if (!parallel || traits.length < 2) {
|
||||
for (int t = 0; t < traits.length; t++) {
|
||||
if (t > 0) {
|
||||
writer.newLine();
|
||||
}
|
||||
TraitConvertTask task = new TraitConvertTask(traits[t], parent, makePackages, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, t, parallel);
|
||||
task.call();
|
||||
writer.newLine();
|
||||
}
|
||||
try {
|
||||
String taskResult = parallel ? futureResults.get(f).get() : traitConvertTasks.get(f).call();
|
||||
writer.appendWithoutIndent(taskResult);
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Error during traits converting", ex);
|
||||
} else {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(20);
|
||||
List<Future<String>> futureResults = null;
|
||||
|
||||
futureResults = new ArrayList<>();
|
||||
for (int t = 0; t < traits.length; t++) {
|
||||
HilightedTextWriter writer2 = new HilightedTextWriter(writer.getIsHighlighted(), writer.getIndent());
|
||||
TraitConvertTask task = new TraitConvertTask(traits[t], parent, makePackages, path, abcTags, abc, isStatic, exportMode, scriptIndex, classIndex, writer2, fullyQualifiedNames, t, parallel);
|
||||
Future<String> future = executor.submit(task);
|
||||
futureResults.add(future);
|
||||
}
|
||||
|
||||
for (int f = 0; f < futureResults.size(); f++) {
|
||||
if (f > 0) {
|
||||
writer.newLine();
|
||||
}
|
||||
try {
|
||||
String taskResult = futureResults.get(f).get();
|
||||
writer.appendWithoutIndent(taskResult);
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Error during traits converting", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parallel) {
|
||||
executor.shutdown();
|
||||
}
|
||||
return writer;
|
||||
|
||||
@@ -281,12 +281,16 @@ public class Main {
|
||||
if (Main.inputStream instanceof FileInputStream) {
|
||||
Main.inputStream.close();
|
||||
}
|
||||
} catch (OutOfMemoryError ex) {
|
||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||
View.showMessageDialog(null, "Cannot load SWF file. Out of memory.");
|
||||
loadingDialog.setVisible(false);
|
||||
swf = null;
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||
View.showMessageDialog(null, "Cannot load SWF file.");
|
||||
loadingDialog.setVisible(false);
|
||||
swf = null;
|
||||
//return false;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -966,6 +970,65 @@ public class Main {
|
||||
}
|
||||
|
||||
pos++;
|
||||
} else if (args[pos].equals("-affinity")) {
|
||||
parameterProcessed = true;
|
||||
pos++;
|
||||
if (Platform.isWindows()) {
|
||||
if (args.length <= pos) {
|
||||
System.err.println("affinity parameter expected");
|
||||
badArguments();
|
||||
}
|
||||
try {
|
||||
int affinityMask = Integer.parseInt(args[pos]);
|
||||
Kernel32.INSTANCE.SetProcessAffinityMask(Kernel32.INSTANCE.GetCurrentProcess(), affinityMask);
|
||||
} catch (NumberFormatException nex) {
|
||||
System.err.println("Bad affinityMask value");
|
||||
}
|
||||
|
||||
pos++;
|
||||
} else {
|
||||
System.err.println("Process affinity setting is only available on Windows platform.");
|
||||
}
|
||||
} else if (args[pos].equals("-priority")) {
|
||||
parameterProcessed = true;
|
||||
pos++;
|
||||
if (Platform.isWindows()) {
|
||||
if (args.length <= pos) {
|
||||
System.err.println("priority parameter expected");
|
||||
badArguments();
|
||||
}
|
||||
String priority = args[pos];
|
||||
int priorityClass = 0;
|
||||
switch (priority) {
|
||||
case "low":
|
||||
priorityClass = Kernel32.IDLE_PRIORITY_CLASS;
|
||||
break;
|
||||
case "belownormal":
|
||||
priorityClass = Kernel32.BELOW_NORMAL_PRIORITY_CLASS;
|
||||
break;
|
||||
case "normal":
|
||||
priorityClass = Kernel32.NORMAL_PRIORITY_CLASS;
|
||||
break;
|
||||
case "abovenormal":
|
||||
priorityClass = Kernel32.ABOVE_NORMAL_PRIORITY_CLASS;
|
||||
break;
|
||||
case "high":
|
||||
priorityClass = Kernel32.HIGH_PRIORITY_CLASS;
|
||||
break;
|
||||
case "realtime":
|
||||
priorityClass = Kernel32.REALTIME_PRIORITY_CLASS;
|
||||
break;
|
||||
default:
|
||||
System.err.println("Bad affinityMask value");
|
||||
}
|
||||
if (priorityClass != 0) {
|
||||
Kernel32.INSTANCE.SetPriorityClass(Kernel32.INSTANCE.GetCurrentProcess(), priorityClass);
|
||||
}
|
||||
|
||||
pos++;
|
||||
} else {
|
||||
System.err.println("Process priority setting is only available on Windows platform.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args[pos].equals("-removefromcontextmenu")) {
|
||||
@@ -1119,7 +1182,7 @@ public class Main {
|
||||
default:
|
||||
exportOK = false;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
} catch (OutOfMemoryError | Exception ex) {
|
||||
exportOK = false;
|
||||
System.err.print("FAIL: Exporting Failed on Exception - ");
|
||||
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
@@ -109,7 +109,18 @@ public interface Kernel32 extends WinNT {
|
||||
// Define the well known values for CreateNamedPipe nMaxInstances
|
||||
//
|
||||
public static final int PIPE_UNLIMITED_INSTANCES = 255;
|
||||
|
||||
//
|
||||
// Define the values for process priority
|
||||
//
|
||||
public static final int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
|
||||
public static final int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
|
||||
public static final int HIGH_PRIORITY_CLASS = 0x00000080;
|
||||
public static final int IDLE_PRIORITY_CLASS = 0x00000040;
|
||||
public static final int NORMAL_PRIORITY_CLASS = 0x00000020;
|
||||
public static final int PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000;
|
||||
public static final int PROCESS_MODE_BACKGROUND_END = 0x00200000;
|
||||
public static final int REALTIME_PRIORITY_CLASS = 0x00000100;
|
||||
|
||||
// __out
|
||||
// HANDLE
|
||||
// WINAPI
|
||||
@@ -172,6 +183,10 @@ public interface Kernel32 extends WinNT {
|
||||
*/
|
||||
HANDLE GetCurrentProcess();
|
||||
|
||||
int SetProcessAffinityMask(HANDLE hProcess, int mask);
|
||||
|
||||
int SetPriorityClass(HANDLE hProcess, int dwPriorityClass);
|
||||
|
||||
/**
|
||||
* This function returns a handle to an existing process object.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user