WIP: paritally add ISBPLUsable to avoid memory leaks

This commit is contained in:
Daniella 2022-06-24 19:55:33 +02:00
parent d6461db848
commit 2132c7c8a4

View file

@ -121,19 +121,21 @@ public class ISBPL {
ISBPLCallable catcher = readCallable("catch", i, words, file); ISBPLCallable catcher = readCallable("catch", i, words, file);
int stackHeight = stack.size(); int stackHeight = stack.size();
try { try {
block.call(stack); try {
} catch (ISBPLError error) { block.call(stack);
if (Arrays.asList(allowed).contains(error.type) || allowed.length == 1 && allowed[0].equals("all")) { } catch (ISBPLError error) {
stack.push(new ISBPLObject(getType("error"), error)); if (Arrays.asList(allowed).contains(error.type) || allowed.length == 1 && allowed[0].equals("all")) {
stack.push(toISBPLString(error.message)); stack.push(new ISBPLObject(getType("error"), error));
stack.push(toISBPLString(error.type)); stack.push(toISBPLString(error.message));
catcher.call(stack); stack.push(toISBPLString(error.type));
} catcher.call(stack);
else { }
throw error; else {
throw error;
}
} }
} catch (Throwable e) { } catch (Throwable e) {
if (Arrays.asList(allowed).contains("Java") || allowed.length == 1 && allowed[0].equals("all")) { if (Arrays.asList(allowed).contains("Java")) {
stack.push(new ISBPLObject(getType("error"), e)); stack.push(new ISBPLObject(getType("error"), e));
stack.push(toISBPL(e)); stack.push(toISBPL(e));
stack.push(toISBPLString(e.getClass().getName())); stack.push(toISBPLString(e.getClass().getName()));
@ -1420,28 +1422,31 @@ public class ISBPL {
} }
public void addFunction(ISBPLType type, String name, ISBPLCallable callable) { public void addFunction(ISBPLType type, String name, ISBPLCallable callable) {
callable.usedBy(type);
type.methods.put(name, callable); type.methods.put(name, callable);
type.methods.put("&" + name, stack -> {stack.pop(); stack.push(new ISBPLObject(getType("func"), callable)); }); type.methods.put("&" + name, stack -> {stack.drop(); stack.push(new ISBPLObject(getType("func"), callable)); });
} }
private String getFilePathForInclude(Stack<ISBPLObject> stack, Stack<File> file) { private String getFilePathForInclude(Stack<ISBPLObject> stack, Stack<File> file) {
ISBPLObject s = stack.pop(); ISBPLObject s = stack.pop();
String filepath = toJavaString(s); try {
for (File f : file) { String filepath = toJavaString(s);
filepath = toJavaString(s); for (File f : file) {
processPath: filepath = toJavaString(s);
{ processPath:
if (filepath.startsWith("/")) {
break processPath; if (filepath.startsWith("/"))
if (filepath.startsWith("#")) { break processPath;
filepath = System.getenv().getOrDefault("ISBPL_PATH", "/usr/lib/isbpl") + "/" + filepath.substring(1); if (filepath.startsWith("#")) {
break processPath; filepath = System.getenv().getOrDefault("ISBPL_PATH", "/usr/lib/isbpl") + "/" + filepath.substring(1);
break processPath;
}
filepath = f.getParentFile().getAbsolutePath() + "/" + filepath;
} }
filepath = f.getParentFile().getAbsolutePath() + "/" + filepath; if(new File(filepath).exists())
return filepath;
} }
if(new File(filepath).exists()) } finally { s.unusedBy(stack); }
return filepath;
}
return filepath; return filepath;
} }
@ -1764,7 +1769,9 @@ public class ISBPL {
for (String key : all.keySet()) { for (String key : all.keySet()) {
if (key.startsWith("=")) { if (key.startsWith("=")) {
all.get(key.substring(1)).call(stack); all.get(key.substring(1)).call(stack);
ISBPL.gErrorStream.println("\t" + key.substring(1) + ": \t" + stack.pop()); ISBPLObject o = stack.pop();
ISBPL.gErrorStream.println("\t" + key.substring(1) + ": \t" + o);
o.unusedBy(stack);
} }
} }
ISBPL.gErrorStream.println("----------------"); ISBPL.gErrorStream.println("----------------");
@ -1786,7 +1793,7 @@ public class ISBPL {
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
ISBPL.gErrorStream.println("!!! STACK CORRUPTED!"); ISBPL.gErrorStream.println("!!! STACK CORRUPTED!");
stack.pop(); stack.drop();
ISBPL.gErrorStream.println("Popped. Trying again."); ISBPL.gErrorStream.println("Popped. Trying again.");
} }
} }
@ -1872,15 +1879,66 @@ public class ISBPL {
} }
} }
interface ISBPLUsable {
static HashMap<ISBPLUsable, Integer> uses = new HashMap<>();
static HashMap<ISBPLUsable, ArrayList<ISBPLUsable>> children = new HashMap<>();
default void usedBy(ISBPLUsable other) {
setUses(getUses() + 1);
other.addChild(this);
}
default void unusedBy(ISBPLUsable other) {
other.removeChild(this);
removeUse();
}
default void addUse() {
setUses(getUses() + 1);
}
default void removeUse() {
setUses(getUses() - 1);
if(getUses() == 0) {
// Now useless, delete.
useless();
ISBPLUsable[] usables = getChildren();
for(int i = 0; i < usables.length; i++) {
usables[i].unusedBy(this);
}
uses.remove(this);
children.remove(this);
}
}
default void setUses(int i) {
uses.put(this, i);
}
default int getUses() {
return uses.get(this);
}
default ArrayList<ISBPLUsable> getChildren() {
if(!children.containsKey(this))
children.put(this, new ArrayList<>());
return children.get(this);
}
default void addChild(ISBPLUsable it) {
getChildren().add(it);
}
default void removeChild(ISBPLUsable it) {
getChildren().remove(it);
}
default void useless() {}
}
interface ISBPLKeyword { interface ISBPLKeyword {
int call(int idx, String[] words, File file, Stack<ISBPLObject> stack); int call(int idx, String[] words, File file, Stack<ISBPLObject> stack);
} }
interface ISBPLCallable { interface ISBPLCallable extends ISBPLUsable {
void call(Stack<ISBPLObject> stack); void call(Stack<ISBPLObject> stack);
} }
class ISBPLType { class ISBPLType implements ISBPLUsable {
int id; int id;
String name; String name;
HashMap<String, ISBPLCallable> methods = new HashMap<>(); HashMap<String, ISBPLCallable> methods = new HashMap<>();
@ -1934,13 +1992,23 @@ class ISBPLType {
} }
} }
class ISBPLObject { class ISBPLObject implements ISBPLUsable {
ISBPLType type; ISBPLType type;
Object object; Object object;
int users = 0;
public ISBPLObject(ISBPLType type, Object object) { public ISBPLObject(ISBPLType type, Object object) {
this.type = type; this.type = type;
this.object = object; this.object = object;
type.usedBy(this);
if(object instanceof ISBPLUsable) {
object.usedBy(this);
}
}
public void useless() {
object = null;
type = null;
} }
public boolean isTruthy() { public boolean isTruthy() {
@ -2113,6 +2181,10 @@ class ISBPLDebugger extends Thread {
public ISBPLDebugger(ISBPL isbpl) { public ISBPLDebugger(ISBPL isbpl) {
this.isbpl = isbpl; this.isbpl = isbpl;
} }
public ISBPLStack<ISBPLObject> stack(int tid) {
return stack(tid);
}
@Override @Override
public void run() { public void run() {
@ -2177,7 +2249,7 @@ class ISBPLDebugger extends Thread {
isbpl.debuggerIPC.run.put(tid, -3); isbpl.debuggerIPC.run.put(tid, -3);
isbpl.debuggerIPC.threadID = Thread.currentThread().getId(); isbpl.debuggerIPC.threadID = Thread.currentThread().getId();
try { try {
isbpl.interpret(new File("_debug").getAbsoluteFile(), line.substring(5), isbpl.debuggerIPC.stack.get(tid)); isbpl.interpret(new File("_debug").getAbsoluteFile(), line.substring(5), stack(tid));
} }
catch (ISBPLStop stop) { catch (ISBPLStop stop) {
System.exit(isbpl.exitCode); System.exit(isbpl.exitCode);
@ -2187,13 +2259,13 @@ class ISBPLDebugger extends Thread {
boolean fixed = false; boolean fixed = false;
while (!fixed) { while (!fixed) {
try { try {
ISBPL.gErrorStream.println("Stack recovered: " + isbpl.debuggerIPC.stack.get(tid)); ISBPL.gErrorStream.println("Stack recovered: " + stack(tid));
fixed = true; fixed = true;
} }
catch (Exception e1) { catch (Exception e1) {
e.printStackTrace(); e.printStackTrace();
ISBPL.gErrorStream.println("!!! STACK CORRUPTED!"); ISBPL.gErrorStream.println("!!! STACK CORRUPTED!");
isbpl.debuggerIPC.stack.get(tid).pop(); stack(tid).drop();
ISBPL.gErrorStream.println("Popped. Trying again."); ISBPL.gErrorStream.println("Popped. Trying again.");
} }
} }
@ -2206,8 +2278,10 @@ class ISBPLDebugger extends Thread {
HashMap<String, ISBPLCallable> all = map.all(); HashMap<String, ISBPLCallable> all = map.all();
for (String key : all.keySet()) { for (String key : all.keySet()) {
if (key.startsWith("=")) { if (key.startsWith("=")) {
all.get(key.substring(1)).call(isbpl.debuggerIPC.stack.get(tid)); all.get(key.substring(1)).call(stack(tid));
ISBPL.gErrorStream.println("\t" + key.substring(1) + ": \t" + isbpl.debuggerIPC.stack.get(tid).pop()); ISBPLObject o = stack(tid).pop();
ISBPL.gErrorStream.println("\t" + key.substring(1) + ": \t" + o);
o.unusedBy(stack(tid));
} }
} }
ISBPL.gErrorStream.println("----------------"); ISBPL.gErrorStream.println("----------------");
@ -2222,7 +2296,7 @@ class ISBPLDebugger extends Thread {
while (!fixed) { while (!fixed) {
try { try {
ISBPL.gErrorStream.println("STACK DUMP"); ISBPL.gErrorStream.println("STACK DUMP");
for (ISBPLObject object : isbpl.debuggerIPC.stack.get(tid)) { for (ISBPLObject object : stack(tid)) {
ISBPL.gErrorStream.println("\t" + object); ISBPL.gErrorStream.println("\t" + object);
} }
fixed = true; fixed = true;
@ -2230,7 +2304,7 @@ class ISBPLDebugger extends Thread {
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
ISBPL.gErrorStream.println("!!! STACK CORRUPTED!"); ISBPL.gErrorStream.println("!!! STACK CORRUPTED!");
isbpl.debuggerIPC.stack.get(tid).pop(); stack(tid).drop();
ISBPL.gErrorStream.println("Popped. Trying again."); ISBPL.gErrorStream.println("Popped. Trying again.");
} }
} }
@ -2361,6 +2435,7 @@ class ISBPLStreamer {
}); });
streams.add(stream); streams.add(stream);
stack.push(new ISBPLObject(isbpl.getType("int"), stream.id)); stack.push(new ISBPLObject(isbpl.getType("int"), stream.id));
s.unusedBy(stack);
break; break;
case CREATE_FILE_OUT: case CREATE_FILE_OUT:
s = stack.pop(); s = stack.pop();
@ -2374,6 +2449,7 @@ class ISBPLStreamer {
}, Files.newOutputStream(f.toPath())); }, Files.newOutputStream(f.toPath()));
streams.add(stream); streams.add(stream);
stack.push(new ISBPLObject(isbpl.getType("int"), stream.id)); stack.push(new ISBPLObject(isbpl.getType("int"), stream.id));
s.unusedBy(stack);
break; break;
case CREATE_SOCKET: case CREATE_SOCKET:
i = stack.pop(); i = stack.pop();
@ -2384,6 +2460,8 @@ class ISBPLStreamer {
stream = new ISBPLStream(socket.getInputStream(), socket.getOutputStream()); stream = new ISBPLStream(socket.getInputStream(), socket.getOutputStream());
streams.add(stream); streams.add(stream);
stack.push(new ISBPLObject(isbpl.getType("int"), stream.id)); stack.push(new ISBPLObject(isbpl.getType("int"), stream.id));
i.unusedBy(stack);
s.unusedBy(stack);
break; break;
case CREATE_SERVER: case CREATE_SERVER:
i = stack.pop(); i = stack.pop();
@ -2404,6 +2482,7 @@ class ISBPLStreamer {
}); });
streams.add(stream); streams.add(stream);
stack.push(new ISBPLObject(isbpl.getType("int"), stream.id)); stack.push(new ISBPLObject(isbpl.getType("int"), stream.id));
i.unusedBy(stack);
break; break;
case READ: case READ:
i = stack.pop(); i = stack.pop();
@ -2413,6 +2492,7 @@ class ISBPLStreamer {
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
throw new ISBPLError("IllegalArgument", "streamid STREAM_READ stream called with non-existing stream argument"); throw new ISBPLError("IllegalArgument", "streamid STREAM_READ stream called with non-existing stream argument");
} }
i.unusedBy(stack);
break; break;
case WRITE: case WRITE:
i = stack.pop(); i = stack.pop();
@ -2424,6 +2504,8 @@ class ISBPLStreamer {
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
throw new ISBPLError("IllegalArgument", "byte streamid STREAM_WRITE stream called with non-existing stream argument"); throw new ISBPLError("IllegalArgument", "byte streamid STREAM_WRITE stream called with non-existing stream argument");
} }
bte.unusedBy(stack);
i.unusedBy(stack);
break; break;
case CLOSE: case CLOSE:
i = stack.pop(); i = stack.pop();
@ -2434,6 +2516,7 @@ class ISBPLStreamer {
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
throw new ISBPLError("IllegalArgument", "streamid STREAM_CLOSE stream called with non-existing stream argument"); throw new ISBPLError("IllegalArgument", "streamid STREAM_CLOSE stream called with non-existing stream argument");
} }
i.unusedBy(stack);
break; break;
default: default:
throw new ISBPLError("NotImplemented", "Not implemented"); throw new ISBPLError("NotImplemented", "Not implemented");
@ -2470,17 +2553,22 @@ class ISBPLThreadLocal<T> {
} }
} }
class ISBPLStack<T> extends Stack<T> { class ISBPLStack<T implements ISBPLUsable> extends Stack<T> implements ISBPLUsable {
@Override @Override
public T push(T t) { public T push(T t) {
if(t == null) if(t == null)
new IllegalArgumentException("item is null").printStackTrace(); new IllegalArgumentException("item is null").printStackTrace();
t.usedBy(this);
return super.push(t); return super.push(t);
} }
public void drop() {
super.pop().removeUse(this);
}
} }
class ISBPLFrame { class ISBPLFrame implements ISBPLUsable {
public ISBPL context; public ISBPL context;
public ISBPLFrame parent; public ISBPLFrame parent;
@ -2515,13 +2603,20 @@ class ISBPLFrame {
public void add(String name, ISBPLCallable callable) { public void add(String name, ISBPLCallable callable) {
map.put(name, callable); map.put(name, callable);
callable.usedBy(this);
} }
public void define(String name, ISBPLObject value) { public void define(String name, ISBPLObject value) {
Object var = new Object(); Object var = new Object();
variables.put(var, value); variables.put(var, value);
add(name, (stack) -> stack.push(variables.get(var))); add(name, (stack) -> stack.push(variables.get(var)));
add("=" + name, (stack) -> variables.put(var, stack.pop())); add("=" + name, (stack) -> {
ISBPLObject o = stack.pop();
o.usedBy(this);
o.unusedBy(stack);
variables.put(var, o).unusedBy(this);
});
value.usedBy(this);
} }
public HashMap<String, ISBPLCallable> all() { public HashMap<String, ISBPLCallable> all() {