fix: micro tasks not handled properly

This commit is contained in:
TopchetoEU 2023-11-25 18:58:35 +02:00
parent b127aadcf6
commit 4b1ec671e2
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4

View File

@ -2,7 +2,7 @@ package me.topchetoeu.jscript.engine;
import java.util.HashMap; import java.util.HashMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.PriorityBlockingQueue;
import me.topchetoeu.jscript.Filename; import me.topchetoeu.jscript.Filename;
import me.topchetoeu.jscript.Location; import me.topchetoeu.jscript.Location;
@ -35,18 +35,25 @@ public class Engine implements DebugController {
} }
} }
private static class Task { private static class Task implements Comparable<Task> {
public final FunctionValue func; public final FunctionValue func;
public final Object thisArg; public final Object thisArg;
public final Object[] args; public final Object[] args;
public final DataNotifier<Object> notifier = new DataNotifier<>(); public final DataNotifier<Object> notifier = new DataNotifier<>();
public final Context ctx; public final Context ctx;
public final boolean micro;
public Task(Context ctx, FunctionValue func, Object thisArg, Object[] args) { public Task(Context ctx, FunctionValue func, Object thisArg, Object[] args, boolean micro) {
this.ctx = ctx; this.ctx = ctx;
this.func = func; this.func = func;
this.thisArg = thisArg; this.thisArg = thisArg;
this.args = args; this.args = args;
this.micro = micro;
}
@Override
public int compareTo(Task other) {
return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1);
} }
} }
@ -62,8 +69,7 @@ public class Engine implements DebugController {
private DebugController debugger; private DebugController debugger;
private Thread thread; private Thread thread;
private LinkedBlockingDeque<Task> macroTasks = new LinkedBlockingDeque<>(); private PriorityBlockingQueue<Task> tasks = new PriorityBlockingQueue<>();
private LinkedBlockingDeque<Task> microTasks = new LinkedBlockingDeque<>();
public boolean attachDebugger(DebugController debugger) { public boolean attachDebugger(DebugController debugger) {
if (!debugging || this.debugger != null) return false; if (!debugging || this.debugger != null) return false;
@ -91,18 +97,12 @@ public class Engine implements DebugController {
} }
} }
public void run(boolean untilEmpty) { public void run(boolean untilEmpty) {
while (!untilEmpty || !macroTasks.isEmpty()) { while (!untilEmpty || !tasks.isEmpty()) {
try { try {
runTask(macroTasks.take()); runTask(tasks.take());
while (!microTasks.isEmpty()) {
runTask(microTasks.take());
}
} }
catch (InterruptedException | InterruptException e) { catch (InterruptedException | InterruptException e) {
for (var msg : macroTasks) { for (var msg : tasks) msg.notifier.error(new InterruptException(e));
msg.notifier.error(new InterruptException(e));
}
break; break;
} }
} }
@ -127,9 +127,8 @@ public class Engine implements DebugController {
} }
public Awaitable<Object> pushMsg(boolean micro, Context ctx, FunctionValue func, Object thisArg, Object ...args) { public Awaitable<Object> pushMsg(boolean micro, Context ctx, FunctionValue func, Object thisArg, Object ...args) {
var msg = new Task(ctx == null ? new Context(this) : ctx, func, thisArg, args); var msg = new Task(ctx == null ? new Context(this) : ctx, func, thisArg, args, micro);
if (micro) microTasks.addLast(msg); tasks.add(msg);
else macroTasks.addLast(msg);
return msg.notifier; return msg.notifier;
} }
public Awaitable<Object> pushMsg(boolean micro, Context ctx, Filename filename, String raw, Object thisArg, Object ...args) { public Awaitable<Object> pushMsg(boolean micro, Context ctx, Filename filename, String raw, Object thisArg, Object ...args) {