WIP: paritally add ISBPLUsable to avoid memory leaks
This commit is contained in:
parent
d6461db848
commit
2132c7c8a4
1 changed files with 137 additions and 42 deletions
179
ISBPL.java
179
ISBPL.java
|
@ -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() {
|
||||||
|
|
Loading…
Reference in a new issue