From eb5bbd42b81fba2829f3d334f8eb29740ac45bca Mon Sep 17 00:00:00 2001 From: TudbuT Date: Fri, 29 Apr 2022 18:30:10 +0200 Subject: [PATCH] attempts at fixing multithread functionstack/garbage collector issues --- bootstrap/ISBPL.java | 141 ++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/bootstrap/ISBPL.java b/bootstrap/ISBPL.java index e5cdc92..c79bfde 100644 --- a/bootstrap/ISBPL.java +++ b/bootstrap/ISBPL.java @@ -21,13 +21,13 @@ public class ISBPL { static boolean debug = false, printCalls = false; public ISBPLDebugger.IPC debuggerIPC = new ISBPLDebugger.IPC(); ArrayList types = new ArrayList<>(); - HashMap level0 = new HashMap<>(); - final ISBPLThreadLocal>> functionStack = ISBPLThreadLocal.withInitial(() -> { - Stack> stack = new Stack<>(); - stack.push(level0); - return stack; - }); + ISBPLFrame level0 = new ISBPLFrame(); final ISBPLThreadLocal> fileStack = ISBPLThreadLocal.withInitial(Stack::new); + final ISBPLThreadLocal> frameStack = ISBPLThreadLocal.withInitial(() -> { + Stack frames = new Stack<>(); + frames.push(level0); + return frames; + }); HashMap varLinks = new HashMap<>(); HashMap vars = new HashMap<>(); final ISBPLThreadLocal> lastWords = ISBPLThreadLocal.withInitial(() -> new ArrayList<>(16)); @@ -62,7 +62,7 @@ public class ISBPL { return (idx, words, file, stack) -> { idx++; AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable callable = readBlock(i, words, file, false); + ISBPLCallable callable = readBlock(i, words, file); if(stack.pop().isTruthy()) { callable.call(stack); } @@ -72,9 +72,9 @@ public class ISBPL { return (idx, words, file, stack) -> { idx++; AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable cond = readBlock(i, words, file, false); + ISBPLCallable cond = readBlock(i, words, file); i.getAndIncrement(); - ISBPLCallable block = readBlock(i, words, file, false); + ISBPLCallable block = readBlock(i, words, file); cond.call(stack); while (stack.pop().isTruthy()) { block.call(stack); @@ -105,9 +105,9 @@ public class ISBPL { } } AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable block = readBlock(i, words, file, false); + ISBPLCallable block = readBlock(i, words, file); i.getAndIncrement(); - ISBPLCallable catcher = readBlock(i, words, file, false); + ISBPLCallable catcher = readBlock(i, words, file); try { block.call(stack); } catch (ISBPLError error) { @@ -135,9 +135,9 @@ public class ISBPL { return (idx, words, file, stack) -> { idx++; AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable block = readBlock(i, words, file, false); + ISBPLCallable block = readBlock(i, words, file); i.getAndIncrement(); - ISBPLCallable catcher = readBlock(i, words, file, false); + ISBPLCallable catcher = readBlock(i, words, file); try { block.call(stack); } finally { @@ -149,15 +149,7 @@ public class ISBPL { case "{": return (idx, words, file, stack) -> { AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable block = readBlock(i, words, file, true); - stack.push(new ISBPLObject(getType("func"), block)); - return i.get(); - }; - // Returns open function (lambda behaviour) - case "?": - return (idx, words, file, stack) -> { - AtomicInteger i = new AtomicInteger(idx + 1); - ISBPLCallable block = readBlock(i, words, file, false); + ISBPLCallable block = readBlock(i, words, file); stack.push(new ISBPLObject(getType("func"), block)); return i.get(); }; @@ -170,8 +162,7 @@ public class ISBPL { for(ISBPLObject obj : stack) { s.push(obj); } - // This cant be a non-function, unless we clone vars aswell to avoid garbage collecting them accidentally. - ISBPLCallable block = readBlock(i, words, file, true); + ISBPLCallable block = readBlock(i, words, file); long tid = Thread.currentThread().getId(); new Thread(() -> { debuggerIPC.run.put(Thread.currentThread().getId(), debuggerIPC.run.getOrDefault(tid, -1) == -1 ? -1 : 0); @@ -333,7 +324,7 @@ public class ISBPL { ISBPLObject i = stack.pop(); ISBPLObject s = stack.pop(); i.checkType(getType("int")); - functionStack.get().get(functionStack.get().size() - 1 - ((int) i.object)).get(toJavaString(s)).call(stack); + frameStack.get().get(frameStack.get().size() - 1 - ((int) i.object)).resolve(toJavaString(s)).call(stack); }; break; case "reload": @@ -842,11 +833,11 @@ public class ISBPL { break; case "_getvars": func = (Stack stack) -> { - ISBPLObject[] objects = new ISBPLObject[functionStack.get().size()]; + ISBPLObject[] objects = new ISBPLObject[frameStack.get().size()]; int i = 0; - for (HashMap map : functionStack.get()) { + for (ISBPLFrame map : frameStack.get()) { ArrayList strings = new ArrayList<>(); - for (String key : map.keySet()) { + for (String key : map.all().keySet()) { if(key.startsWith("=")) { strings.add(toISBPLString(key.substring(1))); } @@ -1224,8 +1215,8 @@ public class ISBPL { } public void addFunction(String name, ISBPLCallable callable) { - functionStack.get().peek().put(name, callable); - functionStack.get().peek().put("&" + name, stack -> stack.push(new ISBPLObject(getType("func"), callable))); + frameStack.get().peek().add(name, callable); + frameStack.get().peek().add("&" + name, stack -> stack.push(new ISBPLObject(getType("func"), callable))); } private String getFilePathForInclude(Stack stack, Stack file) { @@ -1253,13 +1244,13 @@ public class ISBPL { i++; String name = words[i]; AtomicInteger integer = new AtomicInteger(++i); - ISBPLCallable callable = readBlock(integer, words, file, true); + ISBPLCallable callable = readBlock(integer, words, file); i = integer.get(); addFunction(name, callable); return i; } - private ISBPLCallable readBlock(AtomicInteger idx, String[] words, File file, boolean isFunction) { + private ISBPLCallable readBlock(AtomicInteger idx, String[] words, File file) { ArrayList newWords = new ArrayList<>(); int i = idx.get(); i++; @@ -1276,10 +1267,24 @@ public class ISBPL { } idx.set(i); String[] theWords = newWords.toArray(new String[0]); + ISBPLFrame frame = frameStack.get().peek(); return (stack) -> { fileStack.get().push(file); - interpretRaw(theWords, stack, isFunction); - fileStack.get().pop(); + frameStack.get().push(new ISBPLFrame(frame)); + try { + interpretRaw(theWords, stack); + } finally { + HashMap fstack = frameStack.get().pop().map; + for(Map.Entry c : fstack.entrySet()) { + if(varLinks.containsKey(c.getValue())) { + vars.remove(varLinks.remove(c.getValue())); + if(printCalls) { + System.err.println("Garbage collector: removed " + c.getKey()); + } + } + } + fileStack.get().pop(); + } }; } @@ -1332,13 +1337,11 @@ public class ISBPL { fileStack.get().push(file); code = cleanCode(code); String[] words = splitWords(code); - interpretRaw(words, stack, false); + interpretRaw(words, stack); fileStack.get().pop(); } - private void interpretRaw(String[] words, Stack stack, boolean isFunction) { - if(isFunction) - functionStack.get().push(new HashMap<>()); + private void interpretRaw(String[] words, Stack stack) { try { nextWord: for (int i = 0 ; i < words.length ; i++) { String word = words[i]; @@ -1346,7 +1349,7 @@ public class ISBPL { continue; if(printCalls) { StringBuilder s = new StringBuilder(); - for (int x = 0 ; x < functionStack.get().size() ; x++) { + for (int x = 0 ; x < frameStack.get().size() ; x++) { s.append("\t"); } System.err.println(s + word + "\t\t" + (debug ? stack : "")); @@ -1397,12 +1400,7 @@ public class ISBPL { } } } - ISBPLCallable func = functionStack.get().peek().get(word); - if(func != null) { - func.call(stack); - continue; - } - func = functionStack.get().get(0).get(word); + ISBPLCallable func = frameStack.get().peek().resolve(word); if(func != null) { func.call(stack); continue; @@ -1437,19 +1435,6 @@ public class ISBPL { catch (InterruptedException e) { e.printStackTrace(); } - finally { - if(isFunction) { - HashMap fstack = functionStack.get().pop(); - for(Map.Entry c : fstack.entrySet()) { - if(varLinks.containsKey(c.getValue())) { - vars.remove(varLinks.remove(c.getValue())); - if(printCalls) { - System.err.println("Garbage collector: removed " + c.getKey()); - } - } - } - } - } } // Magic, please test before pushing changes! @@ -1867,10 +1852,11 @@ class ISBPLDebugger extends Thread { case "dump": try { System.err.println("VAR DUMP\n----------------"); - for (HashMap map : isbpl.functionStack.map.get(tid)) { - for (String key : map.keySet()) { + for (ISBPLFrame map : isbpl.frameStack.map.get(tid)) { + HashMap all = map.all(); + for (String key : all.keySet()) { if (key.startsWith("=")) { - map.get(key.substring(1)).call(isbpl.debuggerIPC.stack.get(tid)); + all.get(key.substring(1)).call(isbpl.debuggerIPC.stack.get(tid)); System.err.println("\t" + key.substring(1) + ": \t" + isbpl.debuggerIPC.stack.get(tid).pop()); } } @@ -2138,8 +2124,37 @@ class ISBPLStack extends Stack { @Override public T push(T t) { - //if(t == null) - //throw new IllegalArgumentException("item is null"); + if(t == null && false) + throw new IllegalArgumentException("item is null"); return super.push(t); } } + +class ISBPLFrame { + + public ISBPLFrame parent; + public HashMap map = new HashMap<>(); + + public ISBPLFrame() { } + public ISBPLFrame(ISBPLFrame parentFrame) { + parent = parentFrame; + } + + public ISBPLCallable resolve(String name) { + if(map.containsKey(name)) + return map.get(name); + if(parent != null) + return parent.resolve(name); + return null; + } + + public void add(String name, ISBPLCallable callable) { + map.put(name, callable); + } + + public HashMap all() { + HashMap r = parent == null ? new HashMap<>() : parent.all(); + r.putAll(map); + return r; + } +}