From 8617aa910cd299272a923f5d7ec117d9f80e9aec Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 19 Dec 2023 20:35:32 +0100 Subject: [PATCH 01/40] Avoid deopt loop in `PrimRelinquishProcessorNode` --- .../trufflesqueak/model/ContextObject.java | 9 +- .../nodes/bytecodes/JumpBytecodes.java | 4 +- ...e.java => CheckForInterruptsFullNode.java} | 11 +-- .../CheckForInterruptsInLoopNode.java | 85 +++++++++++++++++++ .../primitives/impl/ControlPrimitives.java | 4 +- .../nodes/process/AddLastLinkToListNode.java | 6 ++ .../nodes/process/PutToSleepNode.java | 8 ++ .../nodes/process/ResumeProcessNode.java | 31 +++++-- .../nodes/process/SignalSemaphoreNode.java | 17 +++- .../process/WakeHighestPriorityNode.java | 2 +- 10 files changed, 151 insertions(+), 26 deletions(-) rename src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/{CheckForInterruptsNode.java => CheckForInterruptsFullNode.java} (86%) create mode 100644 src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java index a46364985..ee2970c1e 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java @@ -29,7 +29,6 @@ import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; -import de.hpi.swa.trufflesqueak.nodes.process.GetActiveProcessNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; import de.hpi.swa.trufflesqueak.util.MiscUtils; import de.hpi.swa.trufflesqueak.util.ObjectGraphUtils.ObjectTracer; @@ -506,13 +505,13 @@ private Object[] getReceiverAndNArguments(final int numArgs) { return arguments; } - public void transferTo(final SqueakImageContext image, final PointersObject newProcess, final ContextObject newActiveContext, final AbstractPointersObjectWriteNode writeNode, - final GetActiveProcessNode getActiveProcessNode, final Node inlineTarget) { + public void transferTo(final SqueakImageContext image, final PointersObject newProcess, final PointersObject activeProcess, final ContextObject newActiveContext, + final AbstractPointersObjectWriteNode writeNode, final Node inlineTarget) { // Record a process to be awakened on the next interpreter cycle. final PointersObject scheduler = image.getScheduler(); - assert newProcess != getActiveProcessNode.execute(inlineTarget) : "trying to switch to already active process"; + assert newProcess != activeProcess : "trying to switch to already active process"; // overwritten in next line. - final PointersObject oldProcess = getActiveProcessNode.execute(inlineTarget); + final PointersObject oldProcess = activeProcess; writeNode.execute(inlineTarget, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS, newProcess); writeNode.execute(inlineTarget, oldProcess, PROCESS.SUSPENDED_CONTEXT, this); writeNode.executeNil(inlineTarget, newProcess, PROCESS.LIST); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java index 836ba4e18..f1237eb7b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java @@ -19,7 +19,7 @@ import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodes.AbstractSendNode; import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackPopNode; -import de.hpi.swa.trufflesqueak.nodes.interrupts.CheckForInterruptsNode; +import de.hpi.swa.trufflesqueak.nodes.interrupts.CheckForInterruptsInLoopNode; import de.hpi.swa.trufflesqueak.nodes.primitives.impl.BlockClosurePrimitives.AbstractClosurePrimitiveNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; import de.hpi.swa.trufflesqueak.util.LogUtils; @@ -152,7 +152,7 @@ public void executeCheck(final VirtualFrame frame) { } protected static final class UnconditionalJumpWithCheckNode extends AbstractUnconditionalJumpNode { - @Child private CheckForInterruptsNode interruptHandlerNode = CheckForInterruptsNode.create(); + @Child private CheckForInterruptsInLoopNode interruptHandlerNode = CheckForInterruptsInLoopNode.create(); protected UnconditionalJumpWithCheckNode(final CompiledCodeObject code, final int index, final int numBytecodes, final int offset) { super(code, index, numBytecodes, offset); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java similarity index 86% rename from src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsNode.java rename to src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java index b660d44b6..01cf7b3c9 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java @@ -6,7 +6,6 @@ */ package de.hpi.swa.trufflesqueak.nodes.interrupts; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -17,29 +16,27 @@ import de.hpi.swa.trufflesqueak.nodes.process.SignalSemaphoreNode; import de.hpi.swa.trufflesqueak.util.LogUtils; -public final class CheckForInterruptsNode extends Node { +public final class CheckForInterruptsFullNode extends Node { @Child private SignalSemaphoreNode signalSemaporeNode; private final Object[] specialObjects; private final CheckForInterruptsState istate; - private CheckForInterruptsNode(final SqueakImageContext image) { + private CheckForInterruptsFullNode(final SqueakImageContext image) { specialObjects = image.specialObjectsArray.getObjectStorage(); istate = image.interrupt; signalSemaporeNode = SignalSemaphoreNode.create(); } @NeverDefault - public static CheckForInterruptsNode create() { - return new CheckForInterruptsNode(SqueakImageContext.getSlow()); + public static CheckForInterruptsFullNode create() { + return new CheckForInterruptsFullNode(SqueakImageContext.getSlow()); } public void execute(final VirtualFrame frame) { if (!istate.shouldTrigger()) { return; } - /* Exclude interrupts case from compilation. */ - CompilerDirectives.transferToInterpreter(); if (istate.interruptPending()) { LogUtils.INTERRUPTS.fine("User interrupt"); istate.interruptPending = false; // reset interrupt flag diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java new file mode 100644 index 000000000..ab94309c4 --- /dev/null +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017-2023 Software Architecture Group, Hasso Plattner Institute + * Copyright (c) 2021-2023 Oracle and/or its affiliates + * + * Licensed under the MIT License. + */ +package de.hpi.swa.trufflesqueak.nodes.interrupts; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.DenyReplace; +import com.oracle.truffle.api.nodes.Node; + +import de.hpi.swa.trufflesqueak.image.SqueakImageContext; +import de.hpi.swa.trufflesqueak.model.ArrayObject; +import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.SPECIAL_OBJECT; +import de.hpi.swa.trufflesqueak.nodes.AbstractNode; +import de.hpi.swa.trufflesqueak.nodes.process.SignalSemaphoreNode; +import de.hpi.swa.trufflesqueak.util.LogUtils; + +@DenyReplace +public final class CheckForInterruptsInLoopNode extends AbstractNode { + private static final CheckForInterruptsInLoopNode SINGLETON = new CheckForInterruptsInLoopNode(); + + private CheckForInterruptsInLoopNode() { + } + + @NeverDefault + public static CheckForInterruptsInLoopNode create() { + return SINGLETON; + } + + public void execute(final VirtualFrame frame) { + final SqueakImageContext image = getContext(); + final CheckForInterruptsState istate = image.interrupt; + if (!istate.shouldTrigger()) { + return; + } + /* Exclude interrupts case from compilation. */ + CompilerDirectives.transferToInterpreter(); + final Object[] specialObjects = image.specialObjectsArray.getObjectStorage(); + if (istate.interruptPending()) { + LogUtils.INTERRUPTS.fine("User interrupt"); + istate.interruptPending = false; // reset interrupt flag + SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_INTERRUPT_SEMAPHORE]); + } + if (istate.nextWakeUpTickTrigger()) { + LogUtils.INTERRUPTS.fine("Timer interrupt"); + istate.nextWakeupTick = 0; // reset timer interrupt + SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_TIMER_SEMAPHORE]); + } + if (istate.pendingFinalizationSignals()) { // signal any pending finalizations + LogUtils.INTERRUPTS.fine("Finalization interrupt"); + istate.setPendingFinalizations(false); + SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_FINALIZATION_SEMAPHORE]); + } + if (istate.hasSemaphoresToSignal()) { + LogUtils.INTERRUPTS.fine("Semaphore interrupt"); + final ArrayObject externalObjects = (ArrayObject) specialObjects[SPECIAL_OBJECT.EXTERNAL_OBJECTS_ARRAY]; + if (!externalObjects.isEmptyType()) { // signal external semaphores + final Object[] semaphores = externalObjects.getObjectStorage(); + Integer semaIndex; + while ((semaIndex = istate.nextSemaphoreToSignal()) != null) { + SignalSemaphoreNode.executeUncached(frame, image, semaphores[semaIndex - 1]); + } + } + } + } + + @Override + public boolean isAdoptable() { + return false; + } + + @Override + public Node copy() { + return SINGLETON; + } + + @Override + public Node deepCopy() { + return copy(); + } +} diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java index 0ed33a9b0..8be1e96a4 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java @@ -82,7 +82,7 @@ import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSendNode.DispatchSendSelectorNode; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSendNode.DispatchSendSyntaxErrorNode; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSendNodeFactory.DispatchSendSelectorNodeGen; -import de.hpi.swa.trufflesqueak.nodes.interrupts.CheckForInterruptsNode; +import de.hpi.swa.trufflesqueak.nodes.interrupts.CheckForInterruptsFullNode; import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractSingletonPrimitiveNode; @@ -1246,7 +1246,7 @@ protected static final AbstractPrimitiveNode createPrimitiveNode(final CompiledC protected abstract static class PrimRelinquishProcessorNode extends AbstractPrimitiveStackIncrementNode implements BinaryPrimitiveFallback { @Specialization protected final Object doRelinquish(final VirtualFrame frame, final Object receiver, final long timeMicroseconds, - @Cached final CheckForInterruptsNode interruptNode) { + @Cached final CheckForInterruptsFullNode interruptNode) { MiscUtils.sleep(timeMicroseconds / 1000); /* * Perform interrupt check (even if interrupt handler is not active), otherwise diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/AddLastLinkToListNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/AddLastLinkToListNode.java index 2bca0ea5b..97165a80b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/AddLastLinkToListNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/AddLastLinkToListNode.java @@ -26,6 +26,12 @@ @GenerateCached(false) public abstract class AddLastLinkToListNode extends AbstractNode { + public static void executeUncached(final PointersObject process, final PointersObject list) { + final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); + final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); + addLastLinkToList(null, process, list, readNode, readNode, writeNode, writeNode, writeNode); + } + public abstract void execute(Node node, PointersObject process, PointersObject list); @Specialization diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/PutToSleepNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/PutToSleepNode.java index 1ba7da260..6b112fc01 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/PutToSleepNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/PutToSleepNode.java @@ -12,6 +12,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; +import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.ArrayObject; import de.hpi.swa.trufflesqueak.model.PointersObject; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; @@ -27,6 +28,13 @@ @GenerateCached(false) public abstract class PutToSleepNode extends AbstractNode { + public static final void executeUncached(final SqueakImageContext image, final PointersObject process) { + final long priority = (Long) process.instVarAt0Slow(PROCESS.PRIORITY); + final ArrayObject processLists = (ArrayObject) image.getScheduler().instVarAt0Slow(PROCESS_SCHEDULER.PROCESS_LISTS); + final PointersObject processList = (PointersObject) processLists.getObject(priority - 1); + AddLastLinkToListNode.executeUncached(process, processList); + } + public abstract void executePutToSleep(Node node, PointersObject process); @Specialization diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java index 6dc68f52d..27b278ac5 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java @@ -6,6 +6,7 @@ */ package de.hpi.swa.trufflesqueak.nodes.process; +import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.GenerateCached; @@ -14,6 +15,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.ContextObject; import de.hpi.swa.trufflesqueak.model.PointersObject; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; @@ -26,21 +28,35 @@ @GenerateCached(false) public abstract class ResumeProcessNode extends AbstractNode { + public static void executeUncached(final VirtualFrame frame, final SqueakImageContext image, final PointersObject newProcess) { + final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); + final PointersObject activeProcess = image.getActiveProcessSlow(); + if (hasHigherPriority(newProcess, activeProcess, readNode, null)) { + PutToSleepNode.executeUncached(image, activeProcess); + final ContextObject newActiveContext = (ContextObject) readNode.execute(null, newProcess, PROCESS.SUSPENDED_CONTEXT); + final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); + GetOrCreateContextNode.getOrCreateUncached(frame).transferTo(image, newProcess, activeProcess, newActiveContext, writeNode, null); + } else { + PutToSleepNode.executeUncached(image, newProcess); + } + } + public abstract void executeResume(VirtualFrame frame, Node node, PointersObject newProcess); - @Specialization(guards = "hasHigherPriority(newProcess, pointersReadNode, getActiveProcessNode, node)") + @Specialization(guards = "hasHigherPriority(newProcess, activeProcess, pointersReadNode, node)") protected static final void doTransferTo(final VirtualFrame frame, final Node node, final PointersObject newProcess, @Shared("putToSleepNode") @Cached final PutToSleepNode putToSleepNode, @Shared("pointersReadNode") @Cached final AbstractPointersObjectReadNode pointersReadNode, - @Shared("getActiveProcessNode") @Cached final GetActiveProcessNode getActiveProcessNode, + @SuppressWarnings("unused") @Shared("getActiveProcessNode") @Cached final GetActiveProcessNode getActiveProcessNode, + @Bind("getActiveProcessNode.execute(node)") final PointersObject activeProcess, @Cached final AbstractPointersObjectWriteNode pointersWriteNode, @Cached final GetOrCreateContextNode contextNode) { - putToSleepNode.executePutToSleep(node, getActiveProcessNode.execute(node)); + putToSleepNode.executePutToSleep(node, activeProcess); final ContextObject newActiveContext = (ContextObject) pointersReadNode.execute(node, newProcess, PROCESS.SUSPENDED_CONTEXT); - contextNode.executeGet(frame, node).transferTo(getContext(node), newProcess, newActiveContext, pointersWriteNode, getActiveProcessNode, node); + contextNode.executeGet(frame, node).transferTo(getContext(node), newProcess, activeProcess, newActiveContext, pointersWriteNode, node); } - @Specialization(guards = "!hasHigherPriority(newProcess, pointersReadNode, getActiveProcessNode, node)") + @Specialization(guards = "!hasHigherPriority(newProcess, getActiveProcessNode.execute(node), pointersReadNode, node)") protected static final void doSleep(final Node node, final PointersObject newProcess, @SuppressWarnings("unused") @Shared("pointersReadNode") @Cached final AbstractPointersObjectReadNode pointersReadNode, @SuppressWarnings("unused") @Shared("getActiveProcessNode") @Cached final GetActiveProcessNode getActiveProcessNode, @@ -48,8 +64,7 @@ protected static final void doSleep(final Node node, final PointersObject newPro putToSleepNode.executePutToSleep(node, newProcess); } - protected static final boolean hasHigherPriority(final PointersObject newProcess, final AbstractPointersObjectReadNode readNode, final GetActiveProcessNode getActiveProcessNode, - final Node inlineTarget) { - return readNode.executeLong(inlineTarget, newProcess, PROCESS.PRIORITY) > readNode.executeLong(inlineTarget, getActiveProcessNode.execute(inlineTarget), PROCESS.PRIORITY); + protected static final boolean hasHigherPriority(final PointersObject newProcess, final PointersObject activeProcess, final AbstractPointersObjectReadNode readNode, final Node inlineTarget) { + return readNode.executeLong(inlineTarget, newProcess, PROCESS.PRIORITY) > readNode.executeLong(inlineTarget, activeProcess, PROCESS.PRIORITY); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/SignalSemaphoreNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/SignalSemaphoreNode.java index e1fb777d7..e6685aaf7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/SignalSemaphoreNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/SignalSemaphoreNode.java @@ -15,6 +15,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.NilObject; import de.hpi.swa.trufflesqueak.model.PointersObject; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.SEMAPHORE; @@ -31,7 +32,21 @@ public static SignalSemaphoreNode create() { return SignalSemaphoreNodeGen.create(); } - public abstract void executeSignal(VirtualFrame frame, Node node, Object semaphore); + public static final void executeUncached(final VirtualFrame frame, final SqueakImageContext image, final Object semaphoreOrNil) { + if (!(semaphoreOrNil instanceof final PointersObject semaphore) || !image.isSemaphoreClass(semaphore.getSqueakClass())) { + return; + } + final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); + final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); + if (semaphore.isEmptyList(AbstractPointersObjectReadNode.getUncached(), null)) { + writeNode.execute(null, semaphore, SEMAPHORE.EXCESS_SIGNALS, + readNode.executeLong(null, semaphore, SEMAPHORE.EXCESS_SIGNALS) + 1); + } else { + ResumeProcessNode.executeUncached(frame, image, semaphore.removeFirstLinkOfList(readNode, writeNode, null)); + } + } + + public abstract void executeSignal(VirtualFrame frame, Node node, Object semaphoreOrNil); @Specialization(guards = {"isSemaphore(semaphore)", "semaphore.isEmptyList(readNode, node)"}, limit = "1") protected static final void doSignalEmpty(final Node node, final PointersObject semaphore, diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java index 0f21cef70..46943f30e 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java @@ -51,7 +51,7 @@ protected static final void doWake(final VirtualFrame frame, final Node node, final PointersObject newProcess = processList.removeFirstLinkOfList(pointersReadNode, pointersWriteNode, node); final Object newContext = pointersReadNode.execute(node, newProcess, PROCESS.SUSPENDED_CONTEXT); if (newContext instanceof final ContextObject newActiveContext) { - contextNode.executeGet(frame, node).transferTo(image, newProcess, newActiveContext, pointersWriteNode, getActiveProcessNode, node); + contextNode.executeGet(frame, node).transferTo(image, newProcess, getActiveProcessNode.execute(node), newActiveContext, pointersWriteNode, node); throw SqueakException.create("Should not be reached"); } } From 0bcf8bc9f9072a2865c49d46dc23a8da6fb88d40 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 19 Dec 2023 21:03:08 +0100 Subject: [PATCH 02/40] Fix and improve interrupt handling - Fix: Reset `shouldTrigger` when performing a check. This avoid excessive interrupt checks - Use one node for send and loop checks - Check for timing interrupts in sends - Turn `CheckForInterruptsQuickImplNode` into singleton --- .../nodes/StartContextRootNode.java | 2 +- .../nodes/bytecodes/JumpBytecodes.java | 4 +- .../CheckForInterruptsFullNode.java | 1 + .../CheckForInterruptsInLoopNode.java | 85 ------------------- .../CheckForInterruptsQuickNode.java | 60 +++++++++---- .../interrupts/CheckForInterruptsState.java | 12 +-- .../process/WakeHighestPriorityNode.java | 2 + 7 files changed, 51 insertions(+), 115 deletions(-) delete mode 100644 src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/StartContextRootNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/StartContextRootNode.java index 4bd37aebd..05a5b99d6 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/StartContextRootNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/StartContextRootNode.java @@ -40,7 +40,7 @@ public final class StartContextRootNode extends AbstractRootNode { public StartContextRootNode(final SqueakLanguage language, final CompiledCodeObject code) { super(language, code); - interruptHandlerNode = CheckForInterruptsQuickNode.create(code); + interruptHandlerNode = CheckForInterruptsQuickNode.createForSend(code); executeBytecodeNode = new ExecuteBytecodeNode(code); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java index f1237eb7b..cb7ec4f7e 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/JumpBytecodes.java @@ -19,7 +19,7 @@ import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; import de.hpi.swa.trufflesqueak.nodes.bytecodes.SendBytecodes.AbstractSendNode; import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackPopNode; -import de.hpi.swa.trufflesqueak.nodes.interrupts.CheckForInterruptsInLoopNode; +import de.hpi.swa.trufflesqueak.nodes.interrupts.CheckForInterruptsQuickNode; import de.hpi.swa.trufflesqueak.nodes.primitives.impl.BlockClosurePrimitives.AbstractClosurePrimitiveNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; import de.hpi.swa.trufflesqueak.util.LogUtils; @@ -152,7 +152,7 @@ public void executeCheck(final VirtualFrame frame) { } protected static final class UnconditionalJumpWithCheckNode extends AbstractUnconditionalJumpNode { - @Child private CheckForInterruptsInLoopNode interruptHandlerNode = CheckForInterruptsInLoopNode.create(); + @Child private CheckForInterruptsQuickNode interruptHandlerNode = CheckForInterruptsQuickNode.createForLoop(); protected UnconditionalJumpWithCheckNode(final CompiledCodeObject code, final int index, final int numBytecodes, final int offset) { super(code, index, numBytecodes, offset); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java index 01cf7b3c9..da0a02b7c 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java @@ -37,6 +37,7 @@ public void execute(final VirtualFrame frame) { if (!istate.shouldTrigger()) { return; } + istate.resetTrigger(); if (istate.interruptPending()) { LogUtils.INTERRUPTS.fine("User interrupt"); istate.interruptPending = false; // reset interrupt flag diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java deleted file mode 100644 index ab94309c4..000000000 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsInLoopNode.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2017-2023 Software Architecture Group, Hasso Plattner Institute - * Copyright (c) 2021-2023 Oracle and/or its affiliates - * - * Licensed under the MIT License. - */ -package de.hpi.swa.trufflesqueak.nodes.interrupts; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.NeverDefault; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.DenyReplace; -import com.oracle.truffle.api.nodes.Node; - -import de.hpi.swa.trufflesqueak.image.SqueakImageContext; -import de.hpi.swa.trufflesqueak.model.ArrayObject; -import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.SPECIAL_OBJECT; -import de.hpi.swa.trufflesqueak.nodes.AbstractNode; -import de.hpi.swa.trufflesqueak.nodes.process.SignalSemaphoreNode; -import de.hpi.swa.trufflesqueak.util.LogUtils; - -@DenyReplace -public final class CheckForInterruptsInLoopNode extends AbstractNode { - private static final CheckForInterruptsInLoopNode SINGLETON = new CheckForInterruptsInLoopNode(); - - private CheckForInterruptsInLoopNode() { - } - - @NeverDefault - public static CheckForInterruptsInLoopNode create() { - return SINGLETON; - } - - public void execute(final VirtualFrame frame) { - final SqueakImageContext image = getContext(); - final CheckForInterruptsState istate = image.interrupt; - if (!istate.shouldTrigger()) { - return; - } - /* Exclude interrupts case from compilation. */ - CompilerDirectives.transferToInterpreter(); - final Object[] specialObjects = image.specialObjectsArray.getObjectStorage(); - if (istate.interruptPending()) { - LogUtils.INTERRUPTS.fine("User interrupt"); - istate.interruptPending = false; // reset interrupt flag - SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_INTERRUPT_SEMAPHORE]); - } - if (istate.nextWakeUpTickTrigger()) { - LogUtils.INTERRUPTS.fine("Timer interrupt"); - istate.nextWakeupTick = 0; // reset timer interrupt - SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_TIMER_SEMAPHORE]); - } - if (istate.pendingFinalizationSignals()) { // signal any pending finalizations - LogUtils.INTERRUPTS.fine("Finalization interrupt"); - istate.setPendingFinalizations(false); - SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_FINALIZATION_SEMAPHORE]); - } - if (istate.hasSemaphoresToSignal()) { - LogUtils.INTERRUPTS.fine("Semaphore interrupt"); - final ArrayObject externalObjects = (ArrayObject) specialObjects[SPECIAL_OBJECT.EXTERNAL_OBJECTS_ARRAY]; - if (!externalObjects.isEmptyType()) { // signal external semaphores - final Object[] semaphores = externalObjects.getObjectStorage(); - Integer semaIndex; - while ((semaIndex = istate.nextSemaphoreToSignal()) != null) { - SignalSemaphoreNode.executeUncached(frame, image, semaphores[semaIndex - 1]); - } - } - } - } - - @Override - public boolean isAdoptable() { - return false; - } - - @Override - public Node copy() { - return SINGLETON; - } - - @Override - public Node deepCopy() { - return copy(); - } -} diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsQuickNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsQuickNode.java index 830e0f786..c3abde23a 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsQuickNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsQuickNode.java @@ -7,6 +7,7 @@ package de.hpi.swa.trufflesqueak.nodes.interrupts; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DenyReplace; import com.oracle.truffle.api.nodes.Node; @@ -15,13 +16,14 @@ import de.hpi.swa.trufflesqueak.model.ArrayObject; import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.SPECIAL_OBJECT; +import de.hpi.swa.trufflesqueak.nodes.AbstractNode; import de.hpi.swa.trufflesqueak.nodes.process.SignalSemaphoreNode; import de.hpi.swa.trufflesqueak.util.LogUtils; -public abstract class CheckForInterruptsQuickNode extends Node { +public abstract class CheckForInterruptsQuickNode extends AbstractNode { private static final int MIN_NUMBER_OF_BYTECODE_FOR_INTERRUPT_CHECKS = 32; - public static CheckForInterruptsQuickNode create(final CompiledCodeObject code) { + public static final CheckForInterruptsQuickNode createForSend(final CompiledCodeObject code) { final SqueakImageContext image = code.getSqueakClass().getImage(); /* * Only check for interrupts if method is relatively large. Avoid check if primitive method @@ -34,12 +36,12 @@ public static CheckForInterruptsQuickNode create(final CompiledCodeObject code) code.isCompiledBlock() || code.hasOuterMethod()) { return NoCheckForInterruptsNode.SINGLETON; } else { - return new CheckForInterruptsQuickImplNode(image); + return CheckForInterruptsQuickImplNode.SINGLETON; } } - public static CheckForInterruptsQuickNode create() { - return new CheckForInterruptsQuickImplNode(SqueakImageContext.getSlow()); + public static final CheckForInterruptsQuickNode createForLoop() { + return CheckForInterruptsQuickImplNode.SINGLETON; } public abstract void execute(VirtualFrame frame); @@ -69,34 +71,43 @@ public Node deepCopy() { } } - private static final class CheckForInterruptsQuickImplNode extends CheckForInterruptsQuickNode { - private final Object[] specialObjects; - private final CheckForInterruptsState istate; + @DenyReplace + public static final class CheckForInterruptsQuickImplNode extends CheckForInterruptsQuickNode { + private static final CheckForInterruptsQuickImplNode SINGLETON = new CheckForInterruptsQuickImplNode(); - @Child private SignalSemaphoreNode signalSemaporeNode = SignalSemaphoreNode.create(); + private CheckForInterruptsQuickImplNode() { + } - protected CheckForInterruptsQuickImplNode(final SqueakImageContext image) { - specialObjects = image.specialObjectsArray.getObjectStorage(); - istate = image.interrupt; + @NeverDefault + public static CheckForInterruptsQuickImplNode create() { + return SINGLETON; } @Override public void execute(final VirtualFrame frame) { - if (CompilerDirectives.inCompiledCode() && !CompilerDirectives.inCompilationRoot() || !istate.shouldTriggerNoTimer()) { + final SqueakImageContext image = getContext(); + final CheckForInterruptsState istate = image.interrupt; + if (!istate.shouldTrigger()) { return; } /* Exclude interrupts case from compilation. */ CompilerDirectives.transferToInterpreter(); + istate.resetTrigger(); + final Object[] specialObjects = image.specialObjectsArray.getObjectStorage(); if (istate.interruptPending()) { LogUtils.INTERRUPTS.fine("User interrupt"); istate.interruptPending = false; // reset interrupt flag - signalSemaporeNode.executeSignal(frame, this, specialObjects[SPECIAL_OBJECT.THE_INTERRUPT_SEMAPHORE]); + SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_INTERRUPT_SEMAPHORE]); + } + if (istate.nextWakeUpTickTrigger()) { + LogUtils.INTERRUPTS.fine("Timer interrupt"); + istate.nextWakeupTick = 0; // reset timer interrupt + SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_TIMER_SEMAPHORE]); } - // Timer interrupts skipped if (istate.pendingFinalizationSignals()) { // signal any pending finalizations LogUtils.INTERRUPTS.fine("Finalization interrupt"); istate.setPendingFinalizations(false); - signalSemaporeNode.executeSignal(frame, this, specialObjects[SPECIAL_OBJECT.THE_FINALIZATION_SEMAPHORE]); + SignalSemaphoreNode.executeUncached(frame, image, specialObjects[SPECIAL_OBJECT.THE_FINALIZATION_SEMAPHORE]); } if (istate.hasSemaphoresToSignal()) { LogUtils.INTERRUPTS.fine("Semaphore interrupt"); @@ -105,10 +116,25 @@ public void execute(final VirtualFrame frame) { final Object[] semaphores = externalObjects.getObjectStorage(); Integer semaIndex; while ((semaIndex = istate.nextSemaphoreToSignal()) != null) { - signalSemaporeNode.executeSignal(frame, this, semaphores[semaIndex - 1]); + SignalSemaphoreNode.executeUncached(frame, image, semaphores[semaIndex - 1]); } } } } + + @Override + public boolean isAdoptable() { + return false; + } + + @Override + public Node copy() { + return SINGLETON; + } + + @Override + public Node deepCopy() { + return copy(); + } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java index 99ec9228c..bbaac89af 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java @@ -40,7 +40,6 @@ public final class CheckForInterruptsState { * the interrupt handler mechanism, we can use a standard boolean here for better compilation. */ private boolean shouldTrigger; - private boolean shouldTriggerNoTimer; private ScheduledFuture interruptChecks; @@ -64,7 +63,6 @@ public void start() { interruptChecks = executor.scheduleWithFixedDelay(() -> { if (!shouldTrigger) { shouldTrigger = isActive && (nextWakeUpTickTrigger() || pendingFinalizationSignals() || hasSemaphoresToSignal()); - shouldTriggerNoTimer = isActive && (pendingFinalizationSignals() || hasSemaphoresToSignal()); } }, INTERRUPT_CHECKS_EVERY_N_MILLISECONDS, INTERRUPT_CHECKS_EVERY_N_MILLISECONDS, TimeUnit.MILLISECONDS); } @@ -79,7 +77,6 @@ public void shutdown() { public void setInterruptPending() { interruptPending = true; shouldTrigger = isActive; - shouldTriggerNoTimer = isActive; } public void setNextWakeupTick(final long msTime) { @@ -107,7 +104,7 @@ public void activate() { public void deactivate() { isActive = false; - resetTriggers(); + resetTrigger(); } protected boolean interruptPending() { @@ -154,13 +151,8 @@ public boolean shouldTrigger() { return shouldTrigger; } - public boolean shouldTriggerNoTimer() { - return shouldTriggerNoTimer; - } - - private void resetTriggers() { + public void resetTrigger() { shouldTrigger = false; - shouldTriggerNoTimer = false; } /* diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java index 46943f30e..899104d8b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java @@ -53,6 +53,8 @@ protected static final void doWake(final VirtualFrame frame, final Node node, if (newContext instanceof final ContextObject newActiveContext) { contextNode.executeGet(frame, node).transferTo(image, newProcess, getActiveProcessNode.execute(node), newActiveContext, pointersWriteNode, node); throw SqueakException.create("Should not be reached"); + } else { + assert false : "evicted zombie process from run queue"; } } } From f81f4bc5727b7e1cbd4c3c778040c2862216ea7c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 01:14:50 +0100 Subject: [PATCH 03/40] Update test map after fixing interrupt handling --- .../src/de/hpi/swa/trufflesqueak/test/runCuisTests.st | 3 ++- .../src/de/hpi/swa/trufflesqueak/test/tests.properties | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st index 7cc9fb1bf..9660faaeb 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st @@ -21,8 +21,9 @@ failingTests := OrderedCollection new. { #FloatTest -> #(#testIsDenormalized #testPrimTruncated). #ProcessorTest -> #("flaky" #testGrabProcessor #testGrabProcessorOnlyForNoTimeout #testGrabProcessorOnlyForTimeout #testValueUnpreemptively). - #ProcessTerminateUnwindNonLocalReturn -> #(test1ATerminate #test1BTerminate #test2ATerminate #test2BTerminate #test3ATerminate #test3BTerminate #test4ATerminate #test4BTerminate #test5ATerminate #test5BTerminate #test6ATerminate #test6BTerminate #test7ATerminate #test7BTerminate #test8ATerminate #test8BTerminate). + #ProcessTerminateUnwindNonLocalReturn -> #(test1ATerminate #test1BTerminate #test2ATerminate #test2BTerminate #test3ATerminate #test3BTerminate #test4ATerminate #test4BTerminate #test5ATerminate #test5BTerminate "flaky" #test5DTerminate #test6ATerminate #test6BTerminate "flaky" #test6DTerminate #test7ATerminate #test7BTerminate #test8ATerminate #test8BTerminate). #SmallIntegerTest -> #(#testMaxVal #testMinVal #testPrintString). + #TestValueWithinFix -> #("flaky" #testValueWithinTimingRepeat). #WeakIdentitySetTest -> #(#test). "Failing (or flaky?) on TruffleSqueak Native" } collect: [:assoc | | testCase | testCase := Smalltalk at: assoc key. diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties index 8549f9f94..98b635339 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties @@ -1294,7 +1294,7 @@ DebuggerTests>>test04DebuggerSuspendsProcess=passing DebuggerTests>>test05DebuggerTerminatesProcess=not_terminating DebuggerTests>>test06DebugSpecificContext=not_terminating DebuggerTests>>test07DebuggerNotifier=not_terminating -DebuggerTests>>test08DebuggerFull=passing +DebuggerTests>>test08DebuggerFull=not_terminating DebuggerTests>>test09DebuggerNotifierOrFull=not_terminating DebuggerTests>>test10DebugBlock=not_terminating DebuggerTests>>test11DebugBlockAtContext=not_terminating @@ -1302,7 +1302,7 @@ DebuggerTests>>test12ToolSetHandleError=passing DebuggerTests>>test13ToolSetHandleWarning=passing DebuggerTests>>test14ToolSetHandleUserInterruptRequest=passing DebuggerTests>>test15ToolSetDebugProcess=passing -DebuggerTests>>test16HandleSimulationError=passing +DebuggerTests>>test16HandleSimulationError=not_terminating DebuggerTests>>test17HandleBlockCannotReturn=failing DebuggerTests>>test18HandleNestedBlockCannotReturn=not_terminating DebuggerTests>>test19Abandon=not_terminating From d5b811afd93bc2700219570c0556da948fe767c2 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 11:25:02 +0100 Subject: [PATCH 04/40] Check for user interrupts in handler thread --- .../trufflesqueak/nodes/interrupts/CheckForInterruptsState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java index bbaac89af..982935da9 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java @@ -62,7 +62,7 @@ public void start() { }); interruptChecks = executor.scheduleWithFixedDelay(() -> { if (!shouldTrigger) { - shouldTrigger = isActive && (nextWakeUpTickTrigger() || pendingFinalizationSignals() || hasSemaphoresToSignal()); + shouldTrigger = isActive && (interruptPending() || nextWakeUpTickTrigger() || pendingFinalizationSignals() || hasSemaphoresToSignal()); } }, INTERRUPT_CHECKS_EVERY_N_MILLISECONDS, INTERRUPT_CHECKS_EVERY_N_MILLISECONDS, TimeUnit.MILLISECONDS); } From 32785a42cc27d6da1c1856fe12a5187b5335799b Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 12:08:55 +0100 Subject: [PATCH 05/40] Drop unused `exceptionClass` --- .../hpi/swa/trufflesqueak/image/SqueakImageContext.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java index a8d734bb0..c23f6b67d 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java @@ -157,7 +157,6 @@ public final class SqueakImageContext { private ContextObject interopExceptionThrowingContextPrototype; public ContextObject lastSeenContext; - @CompilationFinal private ClassObject exceptionClass; @CompilationFinal private ClassObject fractionClass; private PointersObject parserSharedInstance; private AbstractSqueakObject requestorSharedInstanceOrNil; @@ -551,14 +550,6 @@ public void setDebugSyntaxErrorSelector(final NativeObject nativeObject) { debugSyntaxErrorSelector = nativeObject; } - public ClassObject getExceptionClass() { - if (exceptionClass == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - exceptionClass = (ClassObject) evaluate("Exception"); - } - return exceptionClass; - } - public ClassObject getByteSymbolClass() { return byteSymbolClass; } From ee78f9ce0965c5970b819f83c7c08cc860e6d2a0 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 11:24:33 +0100 Subject: [PATCH 06/40] Clear interrupt handler after each test case Test cases usually set a timing event, which could interfere with running other test cases. Also, distinguish between evaluation requests that can be interrupted or not. --- .../test/AbstractSqueakTestCaseWithImage.java | 3 ++- .../de/hpi/swa/trufflesqueak/SqueakImage.java | 2 +- .../image/SqueakImageContext.java | 23 +++++++++++++++---- .../interrupts/CheckForInterruptsState.java | 14 +++++++---- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java index 48edf702b..edb7ac584 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java @@ -184,6 +184,8 @@ protected static TestResult runTestCase(final TestRequest request) { throw new RuntimeException("Test was interrupted"); } catch (final ExecutionException e) { return TestResult.fromException("failed with an error", e.getCause()); + } finally { + image.interrupt.clear(); } } @@ -195,7 +197,6 @@ protected static R runWithTimeout(final T argument, final Function } finally { testWithImageIsActive = false; } - }); try { return future.get(timeout, TimeUnit.SECONDS); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakImage.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakImage.java index 42026fc51..a179d66d3 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakImage.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakImage.java @@ -79,7 +79,7 @@ public boolean isMemberReadable(@SuppressWarnings("unused") final String member) @ExportMessage public Object getMembers(@SuppressWarnings("unused") final boolean includeInternal) { - return image.evaluate("Smalltalk globals keys collect: [:ea | ea asString]"); + return image.evaluateUninterruptably("Smalltalk globals keys collect: [:ea | ea asString]"); } @ExportMessage diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java index c23f6b67d..80b53c0e7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java @@ -257,6 +257,19 @@ public Object evaluate(final String sourceCode) { return getDoItContextNode(sourceCode, false).getCallTarget().call(); } + @TruffleBoundary + public Object evaluateUninterruptably(final String sourceCode) { + final boolean wasActive = interrupt.isActive(); + interrupt.deactivate(); + try { + return evaluate(sourceCode); + } finally { + if (wasActive) { + interrupt.activate(); + } + } + } + @TruffleBoundary public Object lookup(final String member) { return smalltalk.send(this, "at:ifAbsent:", asByteSymbol(member), NilObject.SINGLETON); @@ -292,7 +305,7 @@ public DoItRootNode getDoItContextNode(final ParsingRequest request) { sourceCode = String.format("[ :%s | %s ]", String.join(" :", request.getArgumentNames()), source.getCharacters().toString()); } } - return DoItRootNode.create(this, language, evaluate(sourceCode)); + return DoItRootNode.create(this, language, evaluateUninterruptably(sourceCode)); } private static boolean isFileInFormat(final Source source) { @@ -358,8 +371,8 @@ private ExecuteTopLevelContextNode getDoItContextNode(final String source, final */ public ContextObject getInteropExceptionThrowingContext() { if (interopExceptionThrowingContextPrototype == null) { - assert evaluate("Interop") != NilObject.SINGLETON : "Interop class must be present"; - final CompiledCodeObject onDoMethod = (CompiledCodeObject) evaluate("BlockClosure>>#on:do:"); + assert evaluateUninterruptably("Interop") != NilObject.SINGLETON : "Interop class must be present"; + final CompiledCodeObject onDoMethod = (CompiledCodeObject) evaluateUninterruptably("BlockClosure>>#on:do:"); interopExceptionThrowingContextPrototype = ContextObject.create(this, onDoMethod.getSqueakContextSize()); interopExceptionThrowingContextPrototype.setCodeObject(onDoMethod); interopExceptionThrowingContextPrototype.setReceiver(NilObject.SINGLETON); @@ -367,12 +380,12 @@ public ContextObject getInteropExceptionThrowingContext() { * Need to catch all exceptions here. Otherwise, the contexts sender is used to find the * next handler context (see Context>>#nextHandlerContext). */ - interopExceptionThrowingContextPrototype.atTempPut(0, evaluate("Exception")); + interopExceptionThrowingContextPrototype.atTempPut(0, evaluateUninterruptably("Exception")); /* * Throw Error and Halt as interop, ignore warnings, handle all other exceptions the * usual way via UndefinedObject>>#handleSignal:. */ - interopExceptionThrowingContextPrototype.atTempPut(1, evaluate( + interopExceptionThrowingContextPrototype.atTempPut(1, evaluateUninterruptably( "[ :e | ((e isKindOf: Error) or: [ e isKindOf: Halt ]) ifTrue: [ Interop throwException: e \"rethrow as interop\" ] ifFalse: [(e isKindOf: Warning) ifTrue: [ e resume \"ignore\" ] " + "ifFalse: [ nil handleSignal: e \"handle the usual way\" ] ] ]")); interopExceptionThrowingContextPrototype.atTempPut(2, BooleanObject.TRUE); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java index 982935da9..9668b16d5 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java @@ -159,18 +159,22 @@ public void resetTrigger() { * TESTING */ + public void clear() { + nextWakeupTick = 0; + interruptPending = false; + pendingFinalizationSignals = false; + clearWeakPointersQueue(); + semaphoresToSignal.clear(); + } + public void reset() { CompilerAsserts.neverPartOfCompilation("Resetting interrupt handler only supported for testing purposes"); isActive = true; - nextWakeupTick = 0; if (interruptChecks != null) { interruptChecks.cancel(true); } shutdown(); - interruptPending = false; - pendingFinalizationSignals = false; - clearWeakPointersQueue(); - semaphoresToSignal.clear(); + clear(); } private void clearWeakPointersQueue() { From 83b5c02d751ea38236a5d4656db204947cfdbc8d Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 12:54:34 +0100 Subject: [PATCH 07/40] Always collect and upload compiler dumps --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0e376e5e..411bcbd33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,9 +114,11 @@ jobs: bash <(curl -Ls https://coverage.codacy.com/get.sh) report -r jacoco.xml if: ${{ env.RUN_WITH_COVERAGE == 'true' && job.status == 'success' }} - name: Zip Graal compiler dumps + if: always() shell: bash run: "[[ -d graal_dumps ]] && zip -r graal_dumps.zip graal_dumps || true" - name: Upload Graal compiler dumps + if: always() uses: actions/upload-artifact@v3 with: name: graal_dumps From 760db517151e5bcdb7d5f2abd25619297a10a742 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 13:28:40 +0100 Subject: [PATCH 08/40] Bump timeout to 90s for slow CI machines --- .../swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java index edb7ac584..81df43ae3 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java @@ -36,7 +36,7 @@ import de.hpi.swa.trufflesqueak.util.DebugUtils; public class AbstractSqueakTestCaseWithImage extends AbstractSqueakTestCase { - private static final int SQUEAK_TIMEOUT_SECONDS = 60 * (DebugUtils.UNDER_DEBUG ? 1000 : 1); + private static final int SQUEAK_TIMEOUT_SECONDS = 90 * (DebugUtils.UNDER_DEBUG ? 1000 : 1); private static final int TIMEOUT_SECONDS = SQUEAK_TIMEOUT_SECONDS + 2; private static final int TEST_IMAGE_LOAD_TIMEOUT_SECONDS = 45 * (DebugUtils.UNDER_DEBUG ? 1000 : 1); private static final int PRIORITY_10_LIST_INDEX = 9; From 6e1330f5457dd36796aaa8765dd1502508e22257 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 18:07:57 +0100 Subject: [PATCH 09/40] Revise `getClassName` so that it also works for Cuis --- .../hpi/swa/trufflesqueak/model/ClassObject.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java index 991de16f2..961fa2563 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java @@ -115,30 +115,26 @@ public String toString() { public String getClassName() { if (image.isMetaClass(getSqueakClass())) { final Object classInstance = pointers[METACLASS.THIS_CLASS - CLASS_DESCRIPTION.SIZE]; - if (classInstance != NilObject.SINGLETON && ((ClassObject) classInstance).pointers[CLASS.NAME] != NilObject.SINGLETON) { - return ((ClassObject) classInstance).getClassNameUnsafe() + " class"; + if (classInstance != NilObject.SINGLETON && ((ClassObject) classInstance).pointers[CLASS.NAME] instanceof final NativeObject metaClassName) { + return metaClassName.asStringUnsafe() + " class"; } else { return "Unknown metaclass"; } } else if (isAClassTrait()) { final ClassObject traitInstance = (ClassObject) pointers[CLASS_TRAIT.BASE_TRAIT - CLASS_DESCRIPTION.SIZE]; - if (traitInstance.pointers[CLASS.NAME] != NilObject.SINGLETON) { - return traitInstance.getClassNameUnsafe() + " classTrait"; + if (traitInstance.pointers[CLASS.NAME] instanceof final NativeObject traitClassName) { + return traitClassName.asStringUnsafe() + " classTrait"; } else { return "Unknown classTrait"; } - } else if (size() >= 10 && pointers[CLASS.NAME] != NilObject.SINGLETON) { + } else if (size() >= CLASS.NAME && pointers[CLASS.NAME] instanceof final NativeObject className) { // this also works for traits, since TRAIT.NAME == CLASS.NAME - return getClassNameUnsafe(); + return className.asStringUnsafe(); } else { return "Unknown behavior"; } } - public String getClassNameUnsafe() { - return ((NativeObject) pointers[CLASS.NAME]).asStringUnsafe(); - } - public ArrayObject getSubclasses() { return (ArrayObject) pointers[CLASS.SUBCLASSES]; } From 9136534c854c00c475156b9587daa02133d32b61 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 20:54:57 +0100 Subject: [PATCH 10/40] Keep `EventSensor` and `Project` in startUp list --- .../hpi/swa/trufflesqueak/image/SqueakImageContext.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java index 80b53c0e7..3d369d623 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java @@ -217,9 +217,6 @@ public void ensureLoaded() { "Remove active context." Processor activeProcess instVarNamed: #suspendedContext put: nil. - "Modify StartUpList for headless execution." - {EventSensor. Project} do: [:ea | Smalltalk removeFromStartUpList: ea]. - "Start up image (see SmalltalkImage>>#snapshot:andQuit:withExitCode:embedded:)." Smalltalk clearExternalObjects; @@ -231,15 +228,14 @@ public void ensureLoaded() { Utilities authorName: 'TruffleSqueak'; setAuthorInitials: 'TruffleSqueak'. - - "Initialize fresh MorphicUIManager." - Project current instVarNamed: #uiManager put: MorphicUIManager new. """; try { evaluate(prepareHeadlessImageScript); } catch (final Exception e) { printToStdErr("startUpList failed:"); printToStdErr(e); + } finally { + interrupt.clear(); } } } From 7383c138070e147f9d7f07599f63936219ace899 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 21:22:36 +0100 Subject: [PATCH 11/40] Clean up AnsiCodes --- .../src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java index 963561279..57e411b44 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java @@ -234,10 +234,8 @@ protected static final class AnsiCodes { protected static final String BOLD = "\033[1m"; protected static final String RED = "\033[31;1m"; protected static final String GREEN = "\033[32;1m"; - protected static final String BLUE = "\033[34m"; + protected static final String BLUE = "\033[34;1m"; protected static final String YELLOW = "\033[33;1m"; protected static final String RESET = "\033[0m"; - protected static final String CLEAR = "\033[0K"; - protected static final String CR = "\r"; } } From a4cf97e4058b774ed5597b8b34d3fb1d388a0dd4 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 21:26:30 +0100 Subject: [PATCH 12/40] Update slow tests in test map They may run not so slow anymore thanks to OSR --- .../swa/trufflesqueak/test/tests.properties | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties index 98b635339..f65fc3da4 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/tests.properties @@ -351,7 +351,7 @@ ByteArrayTest>>testUnCategorizedMethods=passing # Fails with assertion error: Unexpected argument size, maybe dummy frame had wrong size? BytecodeDecodingTests>>testPCPreviousTo=ignored -BytecodeDecodingTests>>testWillReallyStore=slowly_passing +BytecodeDecodingTests>>testWillReallyStore=passing ByteEncoderTest>>testIntegerByteEncoded=passing CaseErrorTest>>testCaseError=passing CaseErrorTest>>testCaseErrorInPrintOn=passing @@ -1196,7 +1196,7 @@ DateAndTimeTest>>testAsSecondsIsTheSameInAnyTimezone=passing DateAndTimeTest>>testAsSecondsMatchesFromSecondsUsingAnyOffset=passing DateAndTimeTest>>testAsSecondsMatchesFromSecondsUsingCurrentLocalOffset=passing DateAndTimeTest>>testAsSecondsMatchesFromSecondsUsingZeroOffset=passing -DateAndTimeTest>>testAsStringFromString=slowly_passing +DateAndTimeTest>>testAsStringFromString=passing DateAndTimeTest>>testClassComment=passing DateAndTimeTest>>testCoverage=passing DateAndTimeTest>>testDateTimeDenotation1=passing @@ -3199,7 +3199,7 @@ HashedCollectionTest>>testGoodPrimeAtLeast=passing HashedCollectionTest>>testGoodPrimes=passing HashedCollectionTest>>testSizeFor=passing HashTesterTest>>testBasicBehaviour=passing -HeapMapTest>>test32BitHeapMap=slowly_passing +HeapMapTest>>test32BitHeapMap=passing HeapTest>>test1=passing HeapTest>>testAdd=passing HeapTest>>testAddAndRemoveFirst=passing @@ -3378,7 +3378,7 @@ IntegerTest>>testIntegerPadding=passing IntegerTest>>testIntegerReadFrom=passing IntegerTest>>testIsInteger=passing IntegerTest>>testIsPowerOfTwo=passing -IntegerTest>>testIsPrime=slowly_passing +IntegerTest>>testIsPrime=passing IntegerTest>>testIsProbablyPrime=passing IntegerTest>>testLargePrimesUpTo=passing IntegerTest>>testLn=passing @@ -4482,15 +4482,12 @@ PackageDependencyTest>>testChronologyCore=passing PackageDependencyTest>>testCollections=broken_in_squeak PackageDependencyTest>>testCompiler=broken_in_squeak PackageDependencyTest>>testCompression=passing - -# expected_failure, but slow -PackageDependencyTest>>testEtoys=slowly_failing - +PackageDependencyTest>>testEtoys=slowly_passing PackageDependencyTest>>testFiles=passing PackageDependencyTest>>testGraphics=passing PackageDependencyTest>>testInstaller=passing PackageDependencyTest>>testKernel=broken_in_squeak -PackageDependencyTest>>testMonticello=slowly_passing +PackageDependencyTest>>testMonticello=passing PackageDependencyTest>>testMorphic=slowly_passing PackageDependencyTest>>testMorphicExtras=passing PackageDependencyTest>>testMultilingual=passing @@ -4877,7 +4874,7 @@ PureBehaviorTest>>testChangeSuperclass=passing PureBehaviorTest>>testClassesWithTraits=passing PureBehaviorTest>>testIsAliasSelector=passing PureBehaviorTest>>testIsLocalAliasSelector=slowly_passing -PureBehaviorTest>>testLocalSelectors=passing +PureBehaviorTest>>testLocalSelectors=slowly_passing PureBehaviorTest>>testMethodCategoryReorganization=slowly_passing PureBehaviorTest>>testOwnMethodsTakePrecedenceOverTraitsMethods=passing PureBehaviorTest>>testPropagationOfChangesInTraits=slowly_passing @@ -4908,7 +4905,7 @@ RandomTest>>testExpectedValuesAndFinalStates=passing RandomTest>>testInitialStates=passing RandomTest>>testNew=passing RandomTest>>testNext=passing -RandomTest>>testNextInt=slowly_passing +RandomTest>>testNextInt=passing RandomTest>>testNextIntLarge=slowly_passing RandomTest>>testRoll=passing RandomTest>>testUnCategorizedMethods=passing @@ -5394,7 +5391,7 @@ SemaphoreTest>>testCriticalIfError=passing SemaphoreTest>>testNew=passing SemaphoreTest>>testSemaAfterCriticalWait=passing SemaphoreTest>>testSemaAfterCriticalWaitSuspended=passing -SemaphoreTest>>testSemaCriticalBlockedInEnsure=ignored +SemaphoreTest>>testSemaCriticalBlockedInEnsure=passing SemaphoreTest>>testSemaInCriticalEnsureArgument=passing SemaphoreTest>>testSemaInCriticalWait=passing SemaphoreTest>>testSuspendAndResume=passing @@ -5819,14 +5816,14 @@ ST80MenusTest>>testSupplyAnswerOfFillInTheBlank=passing ST80MenusTest>>testSupplySpecificAnswerToQuestion=passing ST80MenusTest>>testSuppressInform=passing ST80PackageDependencyTest>>testST80=broken_in_squeak -StackInterpreterSimulatorTests>>testEmptySimulatorCanCloneSimulation=slowly_passing +StackInterpreterSimulatorTests>>testEmptySimulatorCanCloneSimulation=broken_in_squeak StackInterpreterSimulatorTests>>testEmptySimulatorCloneCanLoadImage=broken_in_squeak StackInterpreterSimulatorTests>>testHackBits=broken_in_squeak StackInterpreterSimulatorTests>>testPluginSimulators=slowly_failing StackInterpreterSimulatorTests>>testSimulatorCanReloadImage=broken_in_squeak StackInterpreterTests>>testByteMemoryAccess=passing -StackInterpreterTests>>testImmediateFloats=slowly_passing -StackInterpreterTests>>testPointerTaggingDetagging=slowly_passing +StackInterpreterTests>>testImmediateFloats=broken_in_squeak +StackInterpreterTests>>testPointerTaggingDetagging=broken_in_squeak StackInterpreterTests>>testShortMemoryAccess=passing StackInterpreterTests>>testUnalignedMemoryAccess=passing StackTest>>testEmptyError=passing From dfa17af882219de1efc7b2f4ab82be1a15479ef7 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 22:28:48 +0100 Subject: [PATCH 13/40] Let WakeHighestPriorityNode return ProcessSwitch --- .../nodes/primitives/impl/ControlPrimitives.java | 15 +++++---------- .../nodes/process/WakeHighestPriorityNode.java | 5 +++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java index 8be1e96a4..446e07b44 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java @@ -388,7 +388,7 @@ protected final PointersObject doWaitExcessSignals(final VirtualFrame frame, fin } else { addLastLinkToListNode.execute(node, getActiveProcessNode.execute(node), receiver); try { - wakeHighestPriorityNode.executeWake(frame, node); + throw wakeHighestPriorityNode.executeWake(frame, node); } catch (final ProcessSwitch ps) { /* * Leave receiver on stack. It has not been removed from the stack yet, so it is @@ -397,7 +397,6 @@ protected final PointersObject doWaitExcessSignals(final VirtualFrame frame, fin getFrameStackPointerIncrementNode().execute(frame); throw ps; } - throw CompilerDirectives.shouldNotReachHere(); } } } @@ -441,13 +440,12 @@ protected static final Object doSuspendActiveProcess(final VirtualFrame frame, @ @Cached final WakeHighestPriorityNode wakeHighestPriorityNode, @Cached final FrameStackPushNode pushNode) { try { - wakeHighestPriorityNode.executeWake(frame, node); + throw wakeHighestPriorityNode.executeWake(frame, node); } catch (final ProcessSwitch ps) { /* Leave `nil` as result on stack. */ pushNode.execute(frame, NilObject.SINGLETON); throw ps; } - throw CompilerDirectives.shouldNotReachHere(); } @Specialization(guards = {"receiver != getActiveProcessNode.execute(node)"}, limit = "1") @@ -480,13 +478,12 @@ protected static final Object doSuspendActiveProcess(final VirtualFrame frame, @ @Cached final WakeHighestPriorityNode wakeHighestPriorityNode, @Cached final FrameStackPushNode pushNode) { try { - wakeHighestPriorityNode.executeWake(frame, node); + throw wakeHighestPriorityNode.executeWake(frame, node); } catch (final ProcessSwitch ps) { /* Leave `nil` as result on stack. */ pushNode.execute(frame, NilObject.SINGLETON); throw ps; } - return NilObject.SINGLETON; } @Specialization(guards = {"receiver != getActiveProcessNode.execute(node)"}, limit = "1") @@ -939,7 +936,7 @@ protected final Object doYield(final VirtualFrame frame, final PointersObject sc } addLastLinkToListNode.execute(node, activeProcess, processList); try { - wakeHighestPriorityNode.executeWake(frame, node); + throw wakeHighestPriorityNode.executeWake(frame, node); } catch (final ProcessSwitch ps) { /* * Leave receiver on stack. It has not been removed from the stack yet, so it is @@ -948,7 +945,6 @@ protected final Object doYield(final VirtualFrame frame, final PointersObject sc getFrameStackPointerIncrementNode().execute(frame); throw ps; } - throw CompilerDirectives.shouldNotReachHere(); } } @@ -1061,13 +1057,12 @@ protected static final Object doEnter(final VirtualFrame frame, final Node node, @Cached(inline = false) final FrameStackPushNode pushNode) { addLastLinkToListNode.execute(node, effectiveProcess, mutex); try { - wakeHighestPriorityNode.executeWake(frame, node); + throw wakeHighestPriorityNode.executeWake(frame, node); } catch (final ProcessSwitch ps) { /* Leave `false` as result on stack. */ pushNode.execute(frame, BooleanObject.FALSE); throw ps; } - throw CompilerDirectives.shouldNotReachHere(); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java index 899104d8b..f7e5998a7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java @@ -13,6 +13,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import de.hpi.swa.trufflesqueak.exceptions.ProcessSwitch; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.ArrayObject; @@ -31,10 +32,10 @@ @GenerateCached(false) public abstract class WakeHighestPriorityNode extends AbstractNode { - public abstract void executeWake(VirtualFrame frame, Node node); + public abstract ProcessSwitch executeWake(VirtualFrame frame, Node node); @Specialization - protected static final void doWake(final VirtualFrame frame, final Node node, + protected static final ProcessSwitch doWake(final VirtualFrame frame, final Node node, @Cached final ArrayObjectReadNode arrayReadNode, @Cached final ArrayObjectSizeNode arraySizeNode, @Cached final AbstractPointersObjectReadNode pointersReadNode, From 79540345bf508c74245e266edfc5e68959487d8b Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 22:57:19 +0100 Subject: [PATCH 14/40] Implement system attribute 1005 for all platforms --- .../swa/trufflesqueak/image/SqueakSystemAttributes.java | 4 ++-- .../src/de/hpi/swa/trufflesqueak/util/OS.java | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakSystemAttributes.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakSystemAttributes.java index 0d920a445..25ccd0f4a 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakSystemAttributes.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakSystemAttributes.java @@ -54,7 +54,7 @@ public SqueakSystemAttributes(final SqueakImageContext image) { final String separator = File.separator; vmPath = asByteString(System.getProperty("java.home") + separator + "bin" + separator + "java"); - platformName = asByteString(OS.getSqueakPlatformName()); + platformName = asByteString(OS.findSqueakOSName()); String value; if (OS.isMacOS()) { @@ -91,7 +91,7 @@ public SqueakSystemAttributes(final SqueakImageContext image) { */ vmVersion = asByteString("Croquet " + SqueakLanguageConfig.IMPLEMENTATION_NAME + " " + SqueakLanguageConfig.VERSION + " VMMaker.fn.9999"); - windowSystemName = asByteString("Aqua"); + windowSystemName = asByteString(OS.findWindowSystemName()); final String date = new SimpleDateFormat("MMM dd yyyy HH:mm:ss zzz", Locale.US).format(new Date(MiscUtils.getStartTime())); vmBuildId = asByteString(String.format("%s %s (%s) built on %s", osName, osVersion, osArch, date)); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/OS.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/OS.java index 40a2eab4c..b5c049775 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/OS.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/OS.java @@ -14,7 +14,6 @@ public enum OS { Windows; private static final OS THE_OS = findOS(); - private static final String SQUEAK_PLATFORM_NAME = findSqueakOSName(); private static OS findOS() { final String name = System.getProperty("os.name"); @@ -38,8 +37,12 @@ public static String findSqueakOSName() { }; } - public static String getSqueakPlatformName() { - return SQUEAK_PLATFORM_NAME; + public static String findWindowSystemName() { + return switch (THE_OS) { + case macOS -> "Aqua"; + case Windows -> "Windows"; + case Linux -> "X11"; + }; } public static boolean isLinux() { From 9da5515f85ef53ff2ff29cde44494faff18586bb Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 20 Dec 2023 23:52:08 +0100 Subject: [PATCH 15/40] Retry failures to reduce CI noise --- .../src/de/hpi/swa/trufflesqueak/test/runCuisTests.st | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st index 9660faaeb..eb558afc8 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st @@ -38,7 +38,14 @@ testSuite tests removeAllSuchThat: [:ea | nonTerminatingTestCases anySatisfy: [: testSuite tests removeAllSuchThat: [:ea | failingTests anySatisfy: [:t | ea class == t class and: [ ea selector == t selector ]]]. result := testSuite run. result printReport. -exitCode := (result hasFailures or: [ result hasErrors ]) ifTrue: [ 1 ] ifFalse: [ 0 ]. + +"To reduce noise, retry any failures" +testSuiteRetry := TestSuite new. +testSuiteRetry tests addAll: result failures. +resultRetry := testSuiteRetry run. +resultRetry printReport. + +exitCode := (resultRetry hasFailures or: [ result hasErrors ]) ifTrue: [ 1 ] ifFalse: [ 0 ]. StdIOWriteStream stdout newLine; nextPutAll: 'Failing and Flaky TestCases:'; newLine; flush. testSuite := TestSuite new. From 8f6b9731a6779fc7cddb06c07adb3bfa77dea33d Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Thu, 21 Dec 2023 00:40:58 +0100 Subject: [PATCH 16/40] Use `CommandLineToolSet` in headless mode --- .../src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java index 3d369d623..6343b6442 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java @@ -217,6 +217,9 @@ public void ensureLoaded() { "Remove active context." Processor activeProcess instVarNamed: #suspendedContext put: nil. + "Avoid interactive windows and instead exit on errors." + ToolSet default: CommandLineToolSet. + "Start up image (see SmalltalkImage>>#snapshot:andQuit:withExitCode:embedded:)." Smalltalk clearExternalObjects; From c773884c03147ddeb552f2c619ac5fff3df68b7c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 10:32:35 +0100 Subject: [PATCH 17/40] Fix bug in Sista bytecode decoder Add missing number of extension bytes to relevant bytecode nodes. --- .../nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java index b4b19afc9..2969d4575 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/bytecodes/SqueakBytecodeSistaV1Decoder.java @@ -199,11 +199,11 @@ yield switch (primitiveIndex) { default -> new MiscellaneousBytecodes.UnknownBytecodeNode(code, index, 3, b); }; } - case 0xF9 -> PushBytecodes.AbstractPushFullClosureNode.createExtended(code, index, 3, extA, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); + case 0xF9 -> PushBytecodes.AbstractPushFullClosureNode.createExtended(code, index, 3 + extBytes, extA, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); case 0xFA -> PushBytecodes.PushClosureNode.createExtended(code, index, 3 + extBytes, extA, extB, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); - case 0xFB -> PushBytecodes.PushRemoteTempNode.create(code, index, 3, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); - case 0xFC -> new StoreBytecodes.StoreIntoRemoteTempNode(code, index, 3, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); - case 0xFD -> new StoreBytecodes.PopIntoRemoteTempNode(code, index, 3, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); + case 0xFB -> PushBytecodes.PushRemoteTempNode.create(code, index, 3 + extBytes, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); + case 0xFC -> new StoreBytecodes.StoreIntoRemoteTempNode(code, index, 3 + extBytes, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); + case 0xFD -> new StoreBytecodes.PopIntoRemoteTempNode(code, index, 3 + extBytes, bytecode[indexWithExt + 1], bytecode[indexWithExt + 2]); case 0xFE, 0xFF -> new MiscellaneousBytecodes.UnknownBytecodeNode(code, index, 3, b); default -> throw SqueakException.create("Not a bytecode:", b); }; From 8ce479bcfed583bf64262c80addda9f8b96a702c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 11:06:31 +0100 Subject: [PATCH 18/40] Simplify Cuis testSuite setup. --- .../src/de/hpi/swa/trufflesqueak/test/runCuisTests.st | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st index eb558afc8..0393fb2a1 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st @@ -1,4 +1,4 @@ -| testSuite testCases nonTerminatingTestCases failingTests result exitCode | +| testSuite nonTerminatingTestCases failingTests result exitCode | StdIOWriteStream stdout nextPutAll: 'Setting author information for testing ...'; newLine; flush. Utilities classPool at: #AuthorName put: 'TruffleSqueak'. @@ -30,10 +30,7 @@ failingTests := OrderedCollection new. assoc value do: [:sel | failingTests add: (testCase selector: sel) ]]. StdIOWriteStream stdout newLine; nextPutAll: 'Passing TestCases:'; newLine; flush. -testSuite := TestSuite new. -testCases := (TestCase allSubclasses reject: [:testCase |testCase isAbstract]) - sorted: [:a :b | a name <= b name]. -testCases do: [:testCase | testCase addToSuiteFromSelectors: testSuite]. +testSuite := TestCase buildSuite. testSuite tests removeAllSuchThat: [:ea | nonTerminatingTestCases anySatisfy: [:t | ea class == t class and: [ ea selector == t selector ]]]. testSuite tests removeAllSuchThat: [:ea | failingTests anySatisfy: [:t | ea class == t class and: [ ea selector == t selector ]]]. result := testSuite run. From 19bae6ffe00b32bb8fb6f5369575898e999314df Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 16:12:33 +0100 Subject: [PATCH 19/40] Retry passing tests after reload to reduce noise in the gate. Also, perform some cleanups. --- .../test/AbstractSqueakTestCaseWithImage.java | 43 +++++++------------ .../trufflesqueak/test/SqueakSUnitTest.java | 14 +++--- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java index 81df43ae3..1f7c3741a 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java @@ -33,6 +33,7 @@ import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectReadNode; +import de.hpi.swa.trufflesqueak.test.SqueakTests.SqueakTest; import de.hpi.swa.trufflesqueak.util.DebugUtils; public class AbstractSqueakTestCaseWithImage extends AbstractSqueakTestCase { @@ -41,6 +42,7 @@ public class AbstractSqueakTestCaseWithImage extends AbstractSqueakTestCase { private static final int TEST_IMAGE_LOAD_TIMEOUT_SECONDS = 45 * (DebugUtils.UNDER_DEBUG ? 1000 : 1); private static final int PRIORITY_10_LIST_INDEX = 9; protected static final String PASSED_VALUE = "passed"; + private static final String TEST_IMAGE_FILE_NAME = "test-64bit.image"; protected static final String[] TRUFFLESQUEAK_TEST_CASE_NAMES = truffleSqueakTestCaseNames(); @@ -123,27 +125,15 @@ protected static final void assumeNotOnMXGate() { } private static String getPathToTestImage() { - final String imagePath64bit = getPathToTestImage("test-64bit.image"); - if (imagePath64bit != null) { - return imagePath64bit; - } - final String imagePath32bit = getPathToTestImage("test-32bit.image"); - if (imagePath32bit != null) { - return imagePath32bit; - } - throw SqueakException.create("Unable to locate test image."); - } - - private static String getPathToTestImage(final String imageName) { Path currentDirectory = Paths.get(System.getProperty("user.dir")).toAbsolutePath(); while (currentDirectory != null) { - final File file = currentDirectory.resolve("images").resolve(imageName).toFile(); + final File file = currentDirectory.resolve("images").resolve(TEST_IMAGE_FILE_NAME).toFile(); if (file.exists()) { return file.getAbsolutePath(); } currentDirectory = currentDirectory.getParent(); } - return null; + throw SqueakException.create("Unable to locate test image."); } /** @@ -171,12 +161,12 @@ protected static void patchMethod(final String className, final String selector, assertNotEquals(NilObject.SINGLETON, patchResult); } - protected static TestResult runTestCase(final TestRequest request) { + protected static TestResult runTestCase(final SqueakTest test) { if (testWithImageIsActive) { throw new IllegalStateException("The previous test case has not finished yet"); } try { - return runWithTimeout(request, AbstractSqueakTestCaseWithImage::extractFailuresAndErrorsFromTestResult, TIMEOUT_SECONDS); + return runWithTimeout(test, AbstractSqueakTestCaseWithImage::extractFailuresAndErrorsFromTestResult, TIMEOUT_SECONDS); } catch (final TimeoutException e) { return TestResult.fromException("did not terminate in " + TIMEOUT_SECONDS + "s", e); } catch (final InterruptedException e) { @@ -211,16 +201,16 @@ protected static R runWithTimeout(final T argument, final Function } } - private static TestResult extractFailuresAndErrorsFromTestResult(final TestRequest request) { - final Object result = evaluate(testCommand(request)); - if (!(result instanceof final NativeObject n) || !n.isByteType()) { + private static TestResult extractFailuresAndErrorsFromTestResult(final SqueakTest test) { + final Object result = evaluate(testCommand(test)); + if (!(result instanceof final NativeObject no) || !no.isByteType()) { return TestResult.failure("did not return a ByteString, got " + result); } - final String testResult = ((NativeObject) result).asStringUnsafe(); + final String testResult = no.asStringUnsafe(); if (PASSED_VALUE.equals(testResult)) { return TestResult.success(); } else { - final boolean shouldPass = (boolean) evaluate(shouldPassCommand(request)); + final boolean shouldPass = (boolean) evaluate(shouldPassCommand(test)); // we cannot estimate or reliably clean up the state of the image after some unknown // exception was thrown if (shouldPass) { @@ -231,16 +221,13 @@ private static TestResult extractFailuresAndErrorsFromTestResult(final TestReque } } - private static String testCommand(final TestRequest request) { + private static String testCommand(final SqueakTest test) { return String.format("[(%s selector: #%s) runCase. '%s'] on: TestFailure, Error do: [:e | (String streamContents: [:s | e printVerboseOn: s]) withUnixLineEndings ]", - request.testCase, request.testSelector, PASSED_VALUE); - } - - private static String shouldPassCommand(final TestRequest request) { - return String.format("[(%s selector: #%s) shouldPass] on: Error do: [:e | false]", request.testCase, request.testSelector); + test.className, test.selector, PASSED_VALUE); } - protected record TestRequest(String testCase, String testSelector) { + private static String shouldPassCommand(final SqueakTest test) { + return String.format("[(%s selector: #%s) shouldPass] on: Error do: [:e | false]", test.className, test.selector); } protected static final class TestResult { diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java index 57e411b44..877f77755 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java @@ -109,9 +109,9 @@ public void runSqueakTest() throws Throwable { loadTruffleSqueakPackages(); } - TestResult result = null; + TestResult result; try { - result = runTestCase(buildRequest()); + result = runTestCase(test); } catch (final RuntimeException e) { e.printStackTrace(); stopRunningSuite = true; @@ -119,9 +119,13 @@ public void runSqueakTest() throws Throwable { } RuntimeException exceptionDuringReload = null; if (!(result.passed && result.message.equals(PASSED_VALUE))) { + printlnErr("Closing current image context and reloading: " + result.message); try { - printlnErr("Closing current image context and reloading: " + result.message); reloadImage(); + if (test.type == TestType.PASSING) { + println("Retrying test that is expected to pass..."); + result = runTestCase(test); + } } catch (final RuntimeException e) { exceptionDuringReload = e; } @@ -144,10 +148,6 @@ private void checkTermination() { } } - private TestRequest buildRequest() { - return new TestRequest(test.className, test.selector); - } - private void checkResult(final TestResult result) throws Throwable { switch (test.type) { case PASSING, SLOWLY_PASSING, EXPECTED_FAILURE -> { From d60a5b724b525b358c828649c53c1787a83118a6 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 17:09:07 +0100 Subject: [PATCH 20/40] Convert `SqueakContextOptions` into a record --- .../hpi/swa/trufflesqueak/SqueakOptions.java | 36 +++++++------------ .../image/SqueakImageContext.java | 22 ++++++------ .../swa/trufflesqueak/io/SqueakDisplay.java | 2 +- .../interrupts/CheckForInterruptsState.java | 4 +-- 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakOptions.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakOptions.java index 6ef56e7a2..b3825ebc1 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakOptions.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakOptions.java @@ -13,7 +13,6 @@ import org.graalvm.options.OptionValues; import com.oracle.truffle.api.Option; -import com.oracle.truffle.api.TruffleLanguage.Env; import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; import de.hpi.swa.trufflesqueak.shared.SqueakLanguageOptions; @@ -59,28 +58,19 @@ public static OptionDescriptors createDescriptors() { return new SqueakOptionsOptionDescriptors(); } - public static final class SqueakContextOptions { - public final String imagePath; - public final String[] imageArguments; - public final boolean printResourceSummary; - public final boolean isHeadless; - public final boolean isQuiet; - public final boolean disableInterruptHandler; - public final boolean disableStartup; - public final boolean isTesting; - public final boolean signalInputSemaphore; - - public SqueakContextOptions(final Env env) { - final OptionValues options = env.getOptions(); - imagePath = options.get(ImagePath).isEmpty() ? null : options.get(ImagePath); - imageArguments = options.get(ImageArguments).isEmpty() ? new String[0] : options.get(ImageArguments).split(","); - printResourceSummary = options.get(ResourceSummary); - isHeadless = options.get(Headless); - isQuiet = options.get(Quiet); - disableInterruptHandler = options.get(Interrupts); - disableStartup = options.get(Startup); - signalInputSemaphore = options.get(SignalInputSemaphore); - isTesting = options.get(Testing); + public record SqueakContextOptions(String imagePath, String[] imageArguments, boolean printResourceSummary, boolean isHeadless, boolean isQuiet, boolean disableInterruptHandler, + boolean disableStartup, boolean isTesting, boolean signalInputSemaphore) { + public static SqueakContextOptions create(final OptionValues options) { + return new SqueakContextOptions( + options.get(ImagePath).isEmpty() ? null : options.get(ImagePath), + options.get(ImageArguments).isEmpty() ? new String[0] : options.get(ImageArguments).split(","), + options.get(ResourceSummary), + options.get(Headless), + options.get(Quiet), + options.get(Interrupts), + options.get(Startup), + options.get(Testing), + options.get(SignalInputSemaphore)); } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java index 6343b6442..6319ebaf6 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java @@ -180,8 +180,8 @@ public final class SqueakImageContext { public SqueakImageContext(final SqueakLanguage squeakLanguage, final SqueakLanguage.Env environment) { language = squeakLanguage; patch(environment); - options = new SqueakContextOptions(env); - isHeadless = options.isHeadless; + options = SqueakContextOptions.create(env.getOptions()); + isHeadless = options.isHeadless(); interrupt = new CheckForInterruptsState(this); allocationReporter = env.lookup(AllocationReporter.class); SqueakMessageInterceptor.enableIfRequested(environment); @@ -189,7 +189,7 @@ public SqueakImageContext(final SqueakLanguage squeakLanguage, final SqueakLangu if (truffleLanguageHome != null) { homePath = env.getInternalTruffleFile(truffleLanguageHome); } else { /* Fall back to image directory if language home is not set. */ - homePath = env.getInternalTruffleFile(options.imagePath).getParent(); + homePath = env.getInternalTruffleFile(options.imagePath()).getParent(); } assert homePath.exists() : "Home directory does not exist: " + homePath; initializeMethodCache(); @@ -208,7 +208,7 @@ public void ensureLoaded() { if (squeakImage == null) { // Load image. SqueakImageReader.load(this); - if (options.disableStartup) { + if (options.disableStartup()) { printToStdOut("Skipping startup routine..."); return; } @@ -669,7 +669,7 @@ public SqueakDisplay getDisplay() { public String getImagePath() { if (imagePath == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - setImagePath(SqueakImageLocator.findImage(options.imagePath)); + setImagePath(SqueakImageLocator.findImage(options.imagePath())); } return imagePath; } @@ -689,8 +689,8 @@ public String getImageDirectory() { } public String[] getImageArguments() { - if (options.imageArguments.length > 0) { - return options.imageArguments; + if (options.imageArguments().length > 0) { + return options.imageArguments(); } else { return env.getApplicationArguments(); } @@ -705,7 +705,7 @@ public Source getLastParseRequestSource() { } public boolean interruptHandlerDisabled() { - return options.disableInterruptHandler; + return options.disableInterruptHandler(); } public boolean isHeadless() { @@ -720,11 +720,11 @@ public void attachDisplayIfNecessary() { } public boolean isTesting() { - return options.isTesting; + return options.isTesting(); } public void finalizeContext() { - if (options.printResourceSummary) { + if (options.printResourceSummary()) { MiscUtils.printResourceSummary(this); } } @@ -982,7 +982,7 @@ public NativeObject toInteropSelector(final Message message) { @TruffleBoundary public void printToStdOut(final String string) { - if (!options.isQuiet) { + if (!options.isQuiet()) { getOutput().println("[trufflesqueak] " + string); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java index 394625634..2eeb58cd6 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java @@ -326,7 +326,7 @@ private void addWindowEvent(final long type) { public void addEvent(final long eventType, final long value3, final long value4, final long value5, final long value6, final long value7) { deferredEvents.add(new long[]{eventType, getEventTime(), value3, value4, value5, value6, value7, HostWindowPlugin.DEFAULT_HOST_WINDOW_ID}); - if (image.options.signalInputSemaphore && inputSemaphoreIndex > 0) { + if (image.options.signalInputSemaphore() && inputSemaphoreIndex > 0) { image.interrupt.signalSemaphoreWithIndex(inputSemaphoreIndex); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java index 9668b16d5..4f7b06dcf 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsState.java @@ -45,14 +45,14 @@ public final class CheckForInterruptsState { public CheckForInterruptsState(final SqueakImageContext image) { this.image = image; - if (image.options.disableInterruptHandler) { + if (image.options.disableInterruptHandler()) { image.printToStdOut("Interrupt handler disabled..."); } } @TruffleBoundary public void start() { - if (image.options.disableInterruptHandler) { + if (image.options.disableInterruptHandler()) { return; } executor = Executors.newSingleThreadScheduledExecutor(r -> { From 386d6814e77f387c6adcffe41d77119f43bf148c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 17:11:14 +0100 Subject: [PATCH 21/40] Improve test code --- .../test/AbstractSqueakTestCaseWithImage.java | 21 ++++-------- .../trufflesqueak/test/SqueakSUnitTest.java | 34 +++++++++---------- .../swa/trufflesqueak/test/SqueakTests.java | 25 +++++--------- 3 files changed, 33 insertions(+), 47 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java index 1f7c3741a..3da4aa140 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java @@ -223,24 +223,16 @@ private static TestResult extractFailuresAndErrorsFromTestResult(final SqueakTes private static String testCommand(final SqueakTest test) { return String.format("[(%s selector: #%s) runCase. '%s'] on: TestFailure, Error do: [:e | (String streamContents: [:s | e printVerboseOn: s]) withUnixLineEndings ]", - test.className, test.selector, PASSED_VALUE); + test.className(), test.selector(), PASSED_VALUE); } private static String shouldPassCommand(final SqueakTest test) { - return String.format("[(%s selector: #%s) shouldPass] on: Error do: [:e | false]", test.className, test.selector); + return String.format("[(%s selector: #%s) shouldPass] on: Error do: [:e | false]", test.className(), test.selector()); } - protected static final class TestResult { - private static final TestResult SUCCESS = new TestResult(true, PASSED_VALUE, null); - protected final boolean passed; - protected final String message; - protected final Throwable reason; + protected record TestResult(boolean passed, String message, Throwable reason) { - private TestResult(final boolean passed, final String message, final Throwable reason) { - this.passed = passed; - this.message = message; - this.reason = reason; - } + private static final TestResult SUCCESS = new TestResult(true, PASSED_VALUE, null); protected static TestResult fromException(final String message, final Throwable reason) { return new TestResult(false, message, reason); @@ -267,7 +259,8 @@ private static String[] truffleSqueakTestCaseNames() { } protected static final String getPathToInImageCode() { - Path currentDirectory = Paths.get(System.getProperty("user.dir")).toAbsolutePath(); + final Path userDir = Paths.get(System.getProperty("user.dir")).toAbsolutePath(); + Path currentDirectory = userDir; while (currentDirectory != null) { final File file = currentDirectory.resolve("src").resolve("image").resolve("src").toFile(); if (file.isDirectory()) { @@ -275,6 +268,6 @@ protected static final String getPathToInImageCode() { } currentDirectory = currentDirectory.getParent(); } - return null; + throw new IllegalStateException("Unable to find in image code in " + userDir + " and its parents"); } } diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java index 877f77755..42b7edf33 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java @@ -118,11 +118,11 @@ public void runSqueakTest() throws Throwable { throw e; } RuntimeException exceptionDuringReload = null; - if (!(result.passed && result.message.equals(PASSED_VALUE))) { - printlnErr("Closing current image context and reloading: " + result.message); + if (!(result.passed() && result.message().equals(PASSED_VALUE))) { + printlnErr("Closing current image context and reloading: " + result.message()); try { reloadImage(); - if (test.type == TestType.PASSING) { + if (test.type() == TestType.PASSING) { println("Retrying test that is expected to pass..."); result = runTestCase(test); } @@ -142,44 +142,44 @@ public void runSqueakTest() throws Throwable { } private void checkTermination() { - Assume.assumeFalse("skipped", stopRunningSuite || test.type == TestType.IGNORED || test.type == TestType.NOT_TERMINATING || test.type == TestType.BROKEN_IN_SQUEAK); - if (test.type == TestType.SLOWLY_FAILING || test.type == TestType.SLOWLY_PASSING) { + Assume.assumeFalse("skipped", stopRunningSuite || test.type() == TestType.IGNORED || test.type() == TestType.NOT_TERMINATING || test.type() == TestType.BROKEN_IN_SQUEAK); + if (test.type() == TestType.SLOWLY_FAILING || test.type() == TestType.SLOWLY_PASSING) { assumeNotOnMXGate(); } } private void checkResult(final TestResult result) throws Throwable { - switch (test.type) { + switch (test.type()) { case PASSING, SLOWLY_PASSING, EXPECTED_FAILURE -> { - if (result.reason != null) { - throw result.reason; + if (result.reason() != null) { + throw result.reason(); } - assertTrue(result.message, result.passed); + assertTrue(result.message(), result.passed()); } case PASSING_WITH_NFI -> checkPassingIf(image.supportsNFI(), result); - case FAILING, SLOWLY_FAILING, BROKEN_IN_SQUEAK -> assertFalse(result.message, result.passed); + case FAILING, SLOWLY_FAILING, BROKEN_IN_SQUEAK -> assertFalse(result.message(), result.passed()); case FLAKY -> { // no verdict possible } case NOT_TERMINATING -> fail("This test unexpectedly terminated"); case IGNORED -> fail("This test should never have been run"); - default -> throw new IllegalArgumentException(test.type.toString()); + default -> throw new IllegalArgumentException(test.type().toString()); } } private static void checkPassingIf(final boolean check, final TestResult result) throws Throwable { if (check) { - if (result.reason != null) { - throw result.reason; + if (result.reason() != null) { + throw result.reason(); } - assertTrue(result.message, result.passed); + assertTrue(result.message(), result.passed()); } else { - assertFalse(result.message, result.passed); + assertFalse(result.message(), result.passed()); } } private static boolean inTruffleSqueakPackage(final SqueakTest test) { - final String className = test.className; + final String className = test.className(); for (final String testCaseName : TRUFFLESQUEAK_TEST_CASE_NAMES) { if (testCaseName.equals(className)) { println("\nLoading TruffleSqueak packages (required by " + test + "). This may take a while..."); @@ -217,7 +217,7 @@ private static void loadTruffleSqueakPackages() { } private static Map countByType(final Collection tests) { - return tests.stream().collect(groupingBy(t -> t.type, counting())); + return tests.stream().collect(groupingBy(SqueakTest::type, counting())); } private static void print(final TestType type, final Map counts, final String color) { diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java index 06e2a2334..9a0ee5723 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java @@ -57,18 +57,7 @@ public String getMessage() { } } - protected static final class SqueakTest { - - protected final TestType type; - protected final String className; - protected final String selector; - - protected SqueakTest(final TestType type, final String className, final String selector) { - this.type = type; - this.className = className; - this.selector = selector; - } - + protected record SqueakTest(TestType type, String className, String selector) { protected String qualifiedName() { return className + ">>#" + selector; } @@ -87,7 +76,7 @@ private SqueakTests() { } protected static Stream getTestsToRun(final String filterExpression) { - final List tests = allTests().filter(getTestFilter(filterExpression)).collect(toList()); + final List tests = allTests().filter(getTestFilter(filterExpression)).toList(); if (tests.isEmpty()) { throw new IllegalArgumentException("No test cases found for filter expression '" + filterExpression + "'"); } @@ -111,7 +100,11 @@ private static Predicate getTestFilter(final String filterExpression } private static List rawTestNames() { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(SqueakTests.class.getResourceAsStream(FILENAME)))) { + final InputStream testMapResource = SqueakTests.class.getResourceAsStream(FILENAME); + if (testMapResource == null) { + throw new IllegalStateException("Unable to find " + FILENAME); + } + try (BufferedReader reader = new BufferedReader(new InputStreamReader(testMapResource))) { return reader.lines().map(TEST_CASE_LINE::matcher).filter(Matcher::find).map(Matcher::group).collect(toList()); } catch (final IOException e) { throw new UncheckedIOException(e); @@ -133,12 +126,12 @@ public static boolean testTestMapConsistency(final List imageTestNames) printError("Image reported duplicate tests"); return false; } - mapTestNameSet.removeAll(imageTestNameList); + imageTestNameList.forEach(mapTestNameSet::remove); if (!mapTestNameSet.isEmpty()) { printError("Additional tests in test.properties:\n" + String.join("\n", mapTestNameSet)); return false; } - imageTestNameSet.removeAll(mapTestNameList); + mapTestNameList.forEach(imageTestNameSet::remove); if (!imageTestNameSet.isEmpty()) { printError("Additional tests in image:\n" + String.join("\n", imageTestNameSet)); return false; From c39285b8cee4ce9f713beac4894291382a2aaa58 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 17:36:27 +0100 Subject: [PATCH 22/40] Do not use `CommandLineToolSet` during testing --- .../de/hpi/swa/trufflesqueak/image/SqueakImageContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java index 6319ebaf6..cd386f948 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageContext.java @@ -218,7 +218,7 @@ public void ensureLoaded() { Processor activeProcess instVarNamed: #suspendedContext put: nil. "Avoid interactive windows and instead exit on errors." - ToolSet default: CommandLineToolSet. + %s ifFalse: [ ToolSet default: CommandLineToolSet ]. "Start up image (see SmalltalkImage>>#snapshot:andQuit:withExitCode:embedded:)." Smalltalk @@ -231,7 +231,7 @@ public void ensureLoaded() { Utilities authorName: 'TruffleSqueak'; setAuthorInitials: 'TruffleSqueak'. - """; + """.formatted(Boolean.toString(options.isTesting())); try { evaluate(prepareHeadlessImageScript); } catch (final Exception e) { From f1a72de694acaea8048f3a8d8abc063093a1b180 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 18:38:42 +0100 Subject: [PATCH 23/40] Remove dead code --- .../de/hpi/swa/trufflesqueak/shared/SqueakLanguageOptions.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.shared/src/de/hpi/swa/trufflesqueak/shared/SqueakLanguageOptions.java b/src/de.hpi.swa.trufflesqueak.shared/src/de/hpi/swa/trufflesqueak/shared/SqueakLanguageOptions.java index 3aef5864d..01752d653 100644 --- a/src/de.hpi.swa.trufflesqueak.shared/src/de/hpi/swa/trufflesqueak/shared/SqueakLanguageOptions.java +++ b/src/de.hpi.swa.trufflesqueak.shared/src/de/hpi/swa/trufflesqueak/shared/SqueakLanguageOptions.java @@ -34,9 +34,6 @@ public final class SqueakLanguageOptions { public static final String RESOURCE_SUMMARY_HELP = "Print resource summary on context exit"; public static final String SIGNAL_INPUT_SEMAPHORE = "signal-input-semaphore"; public static final String SIGNAL_INPUT_SEMAPHORE_HELP = "Signal the input semaphore"; - public static final String STACK_DEPTH_PROTECTION = "stack-depth-protection"; - public static final String STACK_DEPTH_PROTECTION_FLAG = "--" + STACK_DEPTH_PROTECTION; - public static final String STACK_DEPTH_PROTECTION_HELP = "Enable stack depth protection"; public static final String STARTUP = "disable-startup"; public static final String STARTUP_HELP = "Disable image startup routine in headless mode"; public static final String TESTING = "testing"; From 48caa3fa9bd712604cc2900fb7d9894bc67822b3 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 19:46:38 +0100 Subject: [PATCH 24/40] Minor test code cleanups --- .../test/AbstractSqueakTestCaseWithImage.java | 6 +++--- .../swa/trufflesqueak/test/SqueakSUnitTest.java | 14 +++++++------- .../de/hpi/swa/trufflesqueak/test/SqueakTests.java | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java index 3da4aa140..b6d08c59b 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/AbstractSqueakTestCaseWithImage.java @@ -234,15 +234,15 @@ protected record TestResult(boolean passed, String message, Throwable reason) { private static final TestResult SUCCESS = new TestResult(true, PASSED_VALUE, null); - protected static TestResult fromException(final String message, final Throwable reason) { + private static TestResult fromException(final String message, final Throwable reason) { return new TestResult(false, message, reason); } - protected static TestResult failure(final String message) { + private static TestResult failure(final String message) { return new TestResult(false, message, null); } - protected static TestResult success() { + private static TestResult success() { return SUCCESS; } } diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java index 42b7edf33..b215d5d5d 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakSUnitTest.java @@ -64,7 +64,7 @@ public final class SqueakSUnitTest extends AbstractSqueakTestCaseWithImage { private static final String TEST_CLASS_PROPERTY = "squeakTests"; - protected static final List TESTS = selectTestsToRun().collect(toList()); + private static final List TESTS = selectTestsToRun().collect(toList()); @Parameter public SqueakTest test; @@ -231,11 +231,11 @@ private static void print(final TestType type, final Map counts, } protected static final class AnsiCodes { - protected static final String BOLD = "\033[1m"; - protected static final String RED = "\033[31;1m"; - protected static final String GREEN = "\033[32;1m"; - protected static final String BLUE = "\033[34;1m"; - protected static final String YELLOW = "\033[33;1m"; - protected static final String RESET = "\033[0m"; + private static final String BOLD = "\033[1m"; + private static final String RED = "\033[31;1m"; + private static final String GREEN = "\033[32;1m"; + private static final String BLUE = "\033[34;1m"; + private static final String YELLOW = "\033[33;1m"; + private static final String RESET = "\033[0m"; } } diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java index 9a0ee5723..e06761fae 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakTests.java @@ -27,7 +27,7 @@ public final class SqueakTests { - protected static final Pattern TEST_CASE = Pattern.compile("(\\w+)>>(\\w+)"); + private static final Pattern TEST_CASE = Pattern.compile("(\\w+)>>(\\w+)"); private static final Pattern TEST_CASE_LINE = Pattern.compile("^" + TEST_CASE.pattern()); private static final String FILENAME = "tests.properties"; private static final String TEST_TYPE_PREFIX_LINUX = "LINUX_"; @@ -58,7 +58,7 @@ public String getMessage() { } protected record SqueakTest(TestType type, String className, String selector) { - protected String qualifiedName() { + private String qualifiedName() { return className + ">>#" + selector; } @@ -67,7 +67,7 @@ public String toString() { return (type == null ? "" : type.getMessage() + ": ") + className + ">>" + selector; } - protected boolean nameEquals(final SqueakTest test) { + private boolean nameEquals(final SqueakTest test) { return className.equals(test.className) && selector.equals(test.selector); } } @@ -75,7 +75,7 @@ protected boolean nameEquals(final SqueakTest test) { private SqueakTests() { } - protected static Stream getTestsToRun(final String filterExpression) { + public static Stream getTestsToRun(final String filterExpression) { final List tests = allTests().filter(getTestFilter(filterExpression)).toList(); if (tests.isEmpty()) { throw new IllegalArgumentException("No test cases found for filter expression '" + filterExpression + "'"); @@ -140,14 +140,14 @@ public static boolean testTestMapConsistency(final List imageTestNames) } // Checkstyle: stop - protected static void printError(final String value) { + private static void printError(final String value) { System.err.println(value); System.err.flush(); } // Checkstyle: resume // Checkstyle: stop - protected static Stream allTests() { + public static Stream allTests() { final Properties properties = loadProperties(); return properties.stringPropertyNames().stream() // .map(test -> parseTest(test, properties.getProperty(test))) // From 60de9571516aa012bc83784f7dc172bb4581eb9a Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 20:10:01 +0100 Subject: [PATCH 25/40] Use `List.of()` instead of `Arrays.asList()` --- .../launcher/TruffleSqueakLauncher.java | 3 +-- .../swa/trufflesqueak/test/SqueakBytecodeTest.java | 13 ++++++------- .../swa/trufflesqueak/nodes/plugins/FilePlugin.java | 3 +-- .../swa/trufflesqueak/nodes/plugins/NullPlugin.java | 3 +-- .../nodes/plugins/SSLContextInitializer.java | 8 +++----- .../trufflesqueak/nodes/plugins/SecurityPlugin.java | 3 +-- .../nodes/primitives/impl/ControlPrimitives.java | 3 +-- .../primitives/impl/MiscellaneousPrimitives.java | 2 +- .../nodes/primitives/impl/StoragePrimitives.java | 3 +-- 9 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.launcher/src/de/hpi/swa/trufflesqueak/launcher/TruffleSqueakLauncher.java b/src/de.hpi.swa.trufflesqueak.launcher/src/de/hpi/swa/trufflesqueak/launcher/TruffleSqueakLauncher.java index c284eaf9b..2d7c26f25 100644 --- a/src/de.hpi.swa.trufflesqueak.launcher/src/de/hpi/swa/trufflesqueak/launcher/TruffleSqueakLauncher.java +++ b/src/de.hpi.swa.trufflesqueak.launcher/src/de/hpi/swa/trufflesqueak/launcher/TruffleSqueakLauncher.java @@ -12,7 +12,6 @@ import java.nio.file.InvalidPathException; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; @@ -177,7 +176,7 @@ protected void printHelp(final OptionCategory maxCategory) { @Override protected void collectArguments(final Set options) { - options.addAll(Arrays.asList(SqueakLanguageOptions.CODE_FLAG, SqueakLanguageOptions.CODE_FLAG_SHORT, SqueakLanguageOptions.HEADLESS_FLAG, + options.addAll(List.of(SqueakLanguageOptions.CODE_FLAG, SqueakLanguageOptions.CODE_FLAG_SHORT, SqueakLanguageOptions.HEADLESS_FLAG, SqueakLanguageOptions.QUIET_FLAG, SqueakLanguageOptions.PRINT_IMAGE_PATH_FLAG, SqueakLanguageOptions.RESOURCE_SUMMARY_FLAG, SqueakLanguageOptions.TRANSCRIPT_FORWARDING_FLAG)); } diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakBytecodeTest.java b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakBytecodeTest.java index 460071f5b..315ff4cf9 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakBytecodeTest.java +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/SqueakBytecodeTest.java @@ -12,7 +12,6 @@ import static org.junit.Assert.fail; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -76,7 +75,7 @@ public void testPushLiteralConstants() { final int bytecodeStart = 32; final Object[] expectedResults = getTestObjects(32); final List literalsList = new ArrayList<>(Collections.singletonList(68419598L)); - literalsList.addAll(Arrays.asList(expectedResults)); + literalsList.addAll(List.of(expectedResults)); final AbstractSqueakObject rcvr = image.specialObjectsArray; for (int i = 0; i < expectedResults.length; i++) { final CompiledCodeObject method = makeMethod(literalsList.toArray(), bytecodeStart + i, 124); @@ -95,7 +94,7 @@ public void testPushLiteralVariables() { final int bytecodeStart = 64; final Object[] expectedResults = getTestObjects(32); final List literalsList = new ArrayList<>(Collections.singletonList(68419598L)); - literalsList.addAll(Arrays.asList(expectedResults)); + literalsList.addAll(List.of(expectedResults)); final AbstractSqueakObject rcvr = image.specialObjectsArray; for (int i = 0; i < 32; i++) { final CompiledCodeObject method = makeMethod(literalsList.toArray(), bytecodeStart + i, 124); @@ -202,7 +201,7 @@ public void testExtendedPushTemporaryVariables() { public void testExtendedPushLiteralConstants() { final Object[] expectedResults = getTestObjects(64); final List literalsList = new ArrayList<>(Collections.singletonList(68419598L)); - literalsList.addAll(Arrays.asList(expectedResults)); + literalsList.addAll(List.of(expectedResults)); final AbstractSqueakObject rcvr = image.specialObjectsArray; for (int i = 0; i < expectedResults.length; i++) { final CompiledCodeObject method = makeMethod(literalsList.toArray(), 128, 128 + i, 124); @@ -220,7 +219,7 @@ public void testExtendedPushLiteralConstants() { public void testExtendedPushLiteralVariables() { final Object[] expectedResults = getTestObjects(64); final List literalsList = new ArrayList<>(Collections.singletonList(68419598L)); - literalsList.addAll(Arrays.asList(expectedResults)); + literalsList.addAll(List.of(expectedResults)); final AbstractSqueakObject rcvr = image.specialObjectsArray; for (int i = 0; i < expectedResults.length; i++) { final CompiledCodeObject method = makeMethod(literalsList.toArray(), 128, 192 + i, 124); @@ -361,7 +360,7 @@ public void testDoubleExtendedPushReceiverVariables() { public void testDoubleExtendedPushLiteralConstants() { final Object[] expectedResults = getTestObjects(255); final List literalsList = new ArrayList<>(Collections.singletonList(68419598L)); - literalsList.addAll(Arrays.asList(expectedResults)); + literalsList.addAll(List.of(expectedResults)); final AbstractSqueakObject rcvr = image.specialObjectsArray; for (int i = 0; i < expectedResults.length; i++) { final CompiledCodeObject method = makeMethod(literalsList.toArray(), 132, 96, i, 124); @@ -379,7 +378,7 @@ public void testDoubleExtendedPushLiteralConstants() { public void testDoubleExtendedPushLiteralVariables() { final Object[] expectedResults = getTestObjects(255); final List literalsList = new ArrayList<>(Collections.singletonList(68419598L)); - literalsList.addAll(Arrays.asList(expectedResults)); + literalsList.addAll(List.of(expectedResults)); final AbstractSqueakObject rcvr = image.specialObjectsArray; for (int i = 0; i < expectedResults.length; i++) { final CompiledCodeObject method = makeMethod(literalsList.toArray(), 132, 128, i, 124); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java index 03bb43793..09ea23617 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java @@ -16,7 +16,6 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.concurrent.TimeUnit; @@ -54,7 +53,7 @@ import de.hpi.swa.trufflesqueak.util.VarHandleUtils; public final class FilePlugin extends AbstractPrimitiveFactoryHolder { - private static final List>> ENTRY_ATTRIBUTES = Arrays.asList( + private static final List>> ENTRY_ATTRIBUTES = List.of( TruffleFile.LAST_MODIFIED_TIME, TruffleFile.CREATION_TIME, TruffleFile.IS_DIRECTORY, TruffleFile.SIZE); private static final EnumSet OPTIONS_DEFAULT = EnumSet.of(StandardOpenOption.READ); private static final EnumSet OPTIONS_WRITEABLE = EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/NullPlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/NullPlugin.java index c85cea569..950e8938b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/NullPlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/NullPlugin.java @@ -7,7 +7,6 @@ package de.hpi.swa.trufflesqueak.nodes.plugins; import java.time.ZonedDateTime; -import java.util.Arrays; import java.util.List; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -120,6 +119,6 @@ public List> getFactories @Override public List> getSingletonPrimitives() { - return Arrays.asList(PrimScreenScaleFactorNode.class, PrimHighResClockNode.class, PrimMultipleBytecodeSetsActive0Node.class, PrimUtcWithOffset1Node.class); + return List.of(PrimScreenScaleFactorNode.class, PrimHighResClockNode.class, PrimMultipleBytecodeSetsActive0Node.class, PrimUtcWithOffset1Node.class); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SSLContextInitializer.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SSLContextInitializer.java index 8e40b220b..f324b1703 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SSLContextInitializer.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SSLContextInitializer.java @@ -6,8 +6,6 @@ */ package de.hpi.swa.trufflesqueak.nodes.plugins; -import static java.util.Arrays.asList; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Files; @@ -135,8 +133,8 @@ private static TrustManager[] collectTrustManagers(final KeyStore store) final TrustManagerFactory systemFactory = prepareSystemTrustMangerFactory(); final List trustManagers = new ArrayList<>( - asList(customFactory.getTrustManagers())); - trustManagers.addAll(asList(systemFactory.getTrustManagers())); + List.of(customFactory.getTrustManagers())); + trustManagers.addAll(List.of(systemFactory.getTrustManagers())); return new TrustManager[]{new CompositeTrustManager(trustManagers)}; } @@ -233,7 +231,7 @@ public void checkServerTrusted(final X509Certificate[] chain, final String authT public X509Certificate[] getAcceptedIssuers() { final List certificates = new ArrayList<>(); for (final X509TrustManager manager : managers) { - certificates.addAll(asList(manager.getAcceptedIssuers())); + certificates.addAll(List.of(manager.getAcceptedIssuers())); } return certificates.toArray(new X509Certificate[0]); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SecurityPlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SecurityPlugin.java index fcbbb2056..9e4bccd67 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SecurityPlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SecurityPlugin.java @@ -6,7 +6,6 @@ */ package de.hpi.swa.trufflesqueak.nodes.plugins; -import java.util.Arrays; import java.util.List; import com.oracle.truffle.api.dsl.GenerateNodeFactory; @@ -66,6 +65,6 @@ public List> getFactories @Override public List> getSingletonPrimitives() { - return Arrays.asList(PrimCanWriteImageNode.class, PrimGetUntrustedUserDirectoryNode.class); + return List.of(PrimCanWriteImageNode.class, PrimGetUntrustedUserDirectoryNode.class); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java index 446e07b44..d8cea2bc7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java @@ -9,7 +9,6 @@ import java.lang.management.ManagementFactory; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; -import java.util.Arrays; import java.util.List; import java.util.logging.Level; @@ -1391,7 +1390,7 @@ public List> getFactories() { @Override public List> getSingletonPrimitives() { - return Arrays.asList( + return List.of( PrimQuickReturnTrueNode.class, PrimQuickReturnFalseNode.class, PrimQuickReturnNilNode.class, diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java index dea2c8944..f9ac71918 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java @@ -1114,7 +1114,7 @@ public List> getFactories() { @Override public List> getSingletonPrimitives() { - return Arrays.asList( + return List.of( PrimSecondClockNode.class, PrimVMPathNode.class, PrimMaxIdentityHashNode.class, diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java index a0232d31d..d97b241b4 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java @@ -6,7 +6,6 @@ */ package de.hpi.swa.trufflesqueak.nodes.primitives.impl; -import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -715,6 +714,6 @@ public List> getFactories() { @Override public List> getSingletonPrimitives() { - return Arrays.asList(PrimSpecialObjectsArrayNode.class, PrimSomeObjectNode.class); + return List.of(PrimSpecialObjectsArrayNode.class, PrimSomeObjectNode.class); } } From 12e98512a5f7dfb0b5cf6338f5e7cfc740953d2e Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 20:56:53 +0100 Subject: [PATCH 26/40] Use instanceof pattern matching consistently --- .../image/SqueakImageWriter.java | 20 +++++----- .../model/BlockClosureObject.java | 8 ++-- .../swa/trufflesqueak/model/ClassObject.java | 6 +-- .../model/CompiledCodeObject.java | 8 ++-- .../model/layout/SlotLocation.java | 8 ++-- .../swa/trufflesqueak/nodes/DoItRootNode.java | 2 +- .../swa/trufflesqueak/nodes/plugins/B2D.java | 4 +- .../trufflesqueak/nodes/plugins/BitBlt.java | 38 +++++++++---------- .../nodes/plugins/CroquetPlugin.java | 1 + .../trufflesqueak/nodes/plugins/DSAPrims.java | 15 ++++++-- .../nodes/plugins/FilePlugin.java | 8 +--- .../nodes/plugins/Float64ArrayPlugin.java | 2 +- .../nodes/plugins/FloatArrayPlugin.java | 2 +- .../nodes/plugins/JPEGReader.java | 5 ++- .../nodes/plugins/Matrix2x3Plugin.java | 8 ++-- .../nodes/plugins/TruffleSqueakPlugin.java | 6 +-- .../swa/trufflesqueak/nodes/plugins/Zip.java | 4 +- .../nodes/plugins/network/SqueakSocket.java | 4 +- .../swa/trufflesqueak/util/FrameAccess.java | 12 +++--- 19 files changed, 82 insertions(+), 79 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageWriter.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageWriter.java index ba520261b..c9b6ac3f1 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageWriter.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageWriter.java @@ -232,17 +232,17 @@ public long toWord(final Object object) { assert object != null; if (object == NilObject.SINGLETON) { return nilOop; - } else if (object instanceof Boolean) { - return (boolean) object ? trueOop : falseOop; - } else if (object instanceof Character) { - return toTaggedCharacter((char) object); + } else if (object instanceof final Boolean b) { + return b ? trueOop : falseOop; + } else if (object instanceof final Character c) { + return toTaggedCharacter(c); } else if (object instanceof final CharacterObject o) { return toTaggedCharacter(o.getValue()); - } else if (object instanceof Long) { - return toTaggedSmallInteger((long) object); - } else if (object instanceof Double) { - return toTaggedSmallFloat((double) object); - } else if (object instanceof AbstractSqueakObjectWithClassAndHash aso) { + } else if (object instanceof final Long l) { + return toTaggedSmallInteger(l); + } else if (object instanceof final Double d) { + return toTaggedSmallFloat(d); + } else if (object instanceof final AbstractSqueakObjectWithClassAndHash aso) { final Long oop = oopMap.get(aso); if (oop != null) { return oop; @@ -385,7 +385,7 @@ public void writeObjects(final Object[] objects) { } public void writeObjectIfTracedElseNil(final Object object) { - writeLong(toWord(object instanceof AbstractSqueakObjectWithClassAndHash aso && oopMap.containsKey(aso) ? object : NilObject.SINGLETON)); + writeLong(toWord(object instanceof final AbstractSqueakObjectWithClassAndHash aso && oopMap.containsKey(aso) ? object : NilObject.SINGLETON)); } private static long toTaggedCharacter(final long value) { diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/BlockClosureObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/BlockClosureObject.java index 0384c2384..598812c88 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/BlockClosureObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/BlockClosureObject.java @@ -279,11 +279,11 @@ public void pointersBecomeOneWay(final Object[] from, final Object[] to) { if (receiver == fromPointer) { receiver = to[i]; } - if (block == fromPointer && to[i] instanceof CompiledCodeObject) { - block = (CompiledCodeObject) to[i]; + if (block == fromPointer && to[i] instanceof final CompiledCodeObject b) { + block = b; } - if (outerContext == fromPointer && fromPointer != to[i] && to[i] instanceof ContextObject) { - setOuterContext((ContextObject) to[i]); + if (outerContext == fromPointer && fromPointer != to[i] && to[i] instanceof final ContextObject c) { + setOuterContext(c); } for (int j = 0; j < copiedValues.length; j++) { final Object copiedValue = copiedValues[j]; diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java index 961fa2563..a8ddfe3ea 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ClassObject.java @@ -240,8 +240,8 @@ private boolean includesBehavior(final ClassObject squeakClass) { public boolean includesExternalFunctionBehavior(final SqueakImageContext i) { final Object externalFunctionClass = i.getSpecialObject(SPECIAL_OBJECT.CLASS_EXTERNAL_FUNCTION); - if (externalFunctionClass instanceof ClassObject) { - return includesBehavior((ClassObject) i.getSpecialObject(SPECIAL_OBJECT.CLASS_EXTERNAL_FUNCTION)); + if (externalFunctionClass instanceof final ClassObject efc) { + return includesBehavior(efc); } else { return false; } @@ -431,7 +431,7 @@ public boolean pointsTo(final Object thang) { if (methodDict == thang) { return true; } - if (thang instanceof Long && format == (long) thang) { + if (thang instanceof final Long l && format == l) { return true; } if (instanceVariables == thang) { diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java index 882ca214a..3ab734af7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java @@ -383,10 +383,10 @@ public void atput0(final long longIndex, final Object obj) { } else { final int realIndex = index - getBytecodeOffset(); assert realIndex < bytes.length; - if (obj instanceof Integer) { - bytes[realIndex] = (byte) (int) obj; - } else if (obj instanceof Long) { - bytes[realIndex] = (byte) (long) obj; + if (obj instanceof final Integer i) { + bytes[realIndex] = i.byteValue(); + } else if (obj instanceof final Long l) { + bytes[realIndex] = l.byteValue(); } else { bytes[realIndex] = (byte) obj; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/layout/SlotLocation.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/layout/SlotLocation.java index c8eab4f9b..29766d0a4 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/layout/SlotLocation.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/layout/SlotLocation.java @@ -440,9 +440,9 @@ public Object read(final AbstractPointersObject object) { @Override public void writeProfiled(final AbstractPointersObject object, final Object value, final IntValueProfile primitiveUsedMapProfile) throws IllegalWriteException { - if (value instanceof Boolean) { + if (value instanceof final Boolean v) { setMask(object, primitiveUsedMapProfile); - UnsafeUtils.putBoolAt(object, address, (boolean) value); + UnsafeUtils.putBoolAt(object, address, v); } else { transferToInterpreterAndThrowIllegalWriteException(); } @@ -451,9 +451,9 @@ public void writeProfiled(final AbstractPointersObject object, final Object valu @Override public void write(final AbstractPointersObject object, final Object value) throws IllegalWriteException { CompilerAsserts.neverPartOfCompilation(); - if (value instanceof Boolean) { + if (value instanceof final Boolean v) { setMask(object); - UnsafeUtils.putBoolAt(object, address, (boolean) value); + UnsafeUtils.putBoolAt(object, address, v); } else { transferToInterpreterAndThrowIllegalWriteException(); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/DoItRootNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/DoItRootNode.java index 299866fd6..02ba8174b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/DoItRootNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/DoItRootNode.java @@ -38,7 +38,7 @@ public static DoItRootNode create(final SqueakImageContext image, final SqueakLa protected final Object doIt(final VirtualFrame frame, @Bind("this") final Node node, @Cached final WrapToSqueakNode wrapNode) { - if (!(maybeClosure instanceof BlockClosureObject closure)) { + if (!(maybeClosure instanceof final BlockClosureObject closure)) { return NilObject.SINGLETON; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java index 5094937d7..5d984ecb8 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/B2D.java @@ -7214,9 +7214,9 @@ private static int shr(final int a, final int b) { } private static int toInt(final Object value) { - if (value instanceof Long longValue) { + if (value instanceof final Long longValue) { return longValue.intValue(); - } else if (value instanceof Double doubleValue) { + } else if (value instanceof final Double doubleValue) { return doubleValue.intValue(); } else if (value instanceof final FloatObject floatValue) { return (int) floatValue.getValue(); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java index b391b18e9..9188a1a31 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java @@ -1436,16 +1436,16 @@ private static long expensiveDither32To16threshold(final long srcWord, final lon /* BitBltSimulation>>#fetchIntOrFloat:ofObject: */ private static int fetchIntOrFloatofObject(final int fieldIndex, final PointersObject objectPointer) { final Object fieldOop = fetchPointerofObject(fieldIndex, objectPointer); - if (fieldOop instanceof Long) { - final long longValue = (long) fieldOop; - if (Integer.MIN_VALUE <= longValue && longValue <= Integer.MAX_VALUE) { - return (int) longValue; + if (fieldOop instanceof final Long longValue) { + final int intValue = longValue.intValue(); + if (intValue == longValue) { + return intValue; } throw PrimitiveFailed.andTransferToInterpreter(); // Fail because value is too big. } else if (fieldOop instanceof final FloatObject o) { return floatToLong(o.getValue()); - } else if (fieldOop instanceof Double) { - return floatToLong((double) fieldOop); + } else if (fieldOop instanceof final Double d) { + return floatToLong(d); } /* Fail if the value is not an int or float (e.g. Fraction). */ throw PrimitiveFailed.andTransferToInterpreter(); @@ -1467,10 +1467,10 @@ private static int floatToLong(final double floatValue) { /* BitBltSimulation>>#fetchIntOrFloat:ofObject:ifNil: */ private static int fetchIntOrFloatofObjectifNil(final int fieldIndex, final PointersObject objectPointer, final long defaultValue) { final Object fieldOop = fetchPointerofObject(fieldIndex, objectPointer); - if (fieldOop instanceof Long) { - final long longValue = (long) fieldOop; - if ((int) longValue == longValue) { - return (int) longValue; + if (fieldOop instanceof final Long longValue) { + final int intValue = longValue.intValue(); + if (intValue == longValue) { + return intValue; } else { throw PrimitiveFailed.andTransferToInterpreter(); // Fail because longValue is too // big. @@ -1478,8 +1478,8 @@ private static int fetchIntOrFloatofObjectifNil(final int fieldIndex, final Poin } if (fieldOop == NilObject.SINGLETON) { return (int) defaultValue; - } else if (fieldOop instanceof Double) { - return floatToLong((double) fieldOop); + } else if (fieldOop instanceof final Double d) { + return floatToLong(d); } else if (fieldOop instanceof final FloatObject o) { return floatToLong(o.getValue()); } @@ -1616,7 +1616,7 @@ private boolean loadBitBltDestForm() { destDepth = -destDepth; } final Object destBitsValue = fetchPointerofObject(FORM.BITS, destForm); - if (!(destBitsValue instanceof NativeObject destBitsNative && (isWords(destBitsNative) || isBytes(destBitsNative)))) { + if (!(destBitsValue instanceof final NativeObject destBitsNative && (isWords(destBitsNative) || isBytes(destBitsNative)))) { if (destBitsValue instanceof Long) { throw SqueakException.create("Not supported: Query for actual surface dimensions"); } else { @@ -1742,7 +1742,7 @@ private boolean loadBitBltSourceForm() { sourceDepth = -sourceDepth; } final Object sourceBitsValue = fetchPointerofObject(FORM.BITS, sourceForm); - if (!(sourceBitsValue instanceof NativeObject sourceBitsNative && (isWords(sourceBitsNative) || isBytes(sourceBitsNative)))) { + if (!(sourceBitsValue instanceof final NativeObject sourceBitsNative && (isWords(sourceBitsNative) || isBytes(sourceBitsNative)))) { if (sourceBitsValue instanceof Long) { throw SqueakException.create("Not supported: Query for actual surface dimensions"); } else { @@ -1797,7 +1797,7 @@ private boolean loadColorMap() { oldStyle = true; } else { /* A new-style color map (fully qualified) */ - if (!(cmOop instanceof PointersObject cmOopPointers && slotSizeOf(cmOopPointers) >= 3)) { + if (!(cmOop instanceof final PointersObject cmOopPointers && slotSizeOf(cmOopPointers) >= 3)) { return false; } cmShiftTable = loadColorMapShiftOrMaskFrom(fetchNativeofObjectOrNull(0, cmOopPointers)); @@ -1867,7 +1867,7 @@ private boolean loadHalftoneForm() { return true; } final NativeObject halftoneBitsValue; - if (halftoneForm instanceof VariablePointersObject hfvpo && slotSizeOf(hfvpo) >= 4) { + if (halftoneForm instanceof final VariablePointersObject hfvpo && slotSizeOf(hfvpo) >= 4) { /* Old-style 32xN monochrome halftone Forms */ halftoneBitsValue = fetchNativeofObjectOrNull(FORM.BITS, hfvpo); halftoneHeight = fetchIntegerofObject(FORM.HEIGHT, hfvpo); @@ -1878,7 +1878,7 @@ private boolean loadHalftoneForm() { } } else { /* New spec accepts, basically, a word array */ - if (!(halftoneForm instanceof NativeObject hfno && isWords(hfno))) { + if (!(halftoneForm instanceof final NativeObject hfno && isWords(hfno))) { return false; } halftoneBitsValue = hfno; @@ -3759,8 +3759,8 @@ private long warpPickSourcePixelsxDeltahyDeltahxDeltavyDeltavdstShiftIncflags(fi private static int fetchIntegerofObject(final int index, final AbstractPointersObject object) { final Object value = fetchPointerofObject(index, object); - if (value instanceof Long) { - return MiscUtils.toIntExact((long) value); + if (value instanceof final Long l) { + return MiscUtils.toIntExact(l); } else { throw PrimitiveFailed.andTransferToInterpreter(); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/CroquetPlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/CroquetPlugin.java index 569e733be..c4f912e9a 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/CroquetPlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/CroquetPlugin.java @@ -42,6 +42,7 @@ protected abstract static class PrimMD5TransformNode extends AbstractPrimitiveNo protected static final NativeObject doMD5(@SuppressWarnings("unused") final Object receiver, final NativeObject buffer, final NativeObject hash) { final int[] in = buffer.getIntStorage(); final int[] hashInts = hash.getIntStorage(); + int a = hashInts[0]; int b = hashInts[1]; int c = hashInts[2]; diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/DSAPrims.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/DSAPrims.java index 8a7d10142..14c499ab0 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/DSAPrims.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/DSAPrims.java @@ -11,11 +11,13 @@ import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.DenyReplace; import de.hpi.swa.trufflesqueak.model.BooleanObject; import de.hpi.swa.trufflesqueak.model.NativeObject; import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; +import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractSingletonPrimitiveNode; import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveFallbacks.TernaryPrimitiveFallback; import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; import de.hpi.swa.trufflesqueak.util.VarHandleUtils; @@ -38,11 +40,11 @@ protected static final Object doExpand(final Object receiver, final NativeObject } } - @GenerateNodeFactory + @DenyReplace @SqueakPrimitive(names = "primitiveHasSecureHashPrimitive") - protected abstract static class PrimHasSecureHashPrimitiveNode extends AbstractPrimitiveNode { - @Specialization - protected static final boolean doHas(@SuppressWarnings("unused") final Object receiver) { + public static final class PrimHasSecureHashPrimitiveNode extends AbstractSingletonPrimitiveNode { + @Override + public Object execute() { return BooleanObject.TRUE; } } @@ -117,4 +119,9 @@ private static int leftRotateBy5(final int value) { public List> getFactories() { return DSAPrimsFactory.getFactories(); } + + @Override + public List> getSingletonPrimitives() { + return List.of(PrimHasSecureHashPrimitiveNode.class); + } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java index 09ea23617..bd8eb02b9 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FilePlugin.java @@ -705,14 +705,8 @@ private static void writeToOutputStream(final OutputStream outputStream, final b @SqueakPrimitive(names = "primitiveHasFileAccess") protected abstract static class PrimHasFileAccessNode extends AbstractPrimitiveNode { @Specialization - @TruffleBoundary protected final boolean hasFileAccess(@SuppressWarnings("unused") final Object receiver) { - try { - getContext().env.getCurrentWorkingDirectory(); - return BooleanObject.TRUE; - } catch (final SecurityException e) { - return BooleanObject.FALSE; - } + return BooleanObject.wrap(getContext().env.isFileIOAllowed()); } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Float64ArrayPlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Float64ArrayPlugin.java index 7dfcd87f7..d732f6940 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Float64ArrayPlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Float64ArrayPlugin.java @@ -69,7 +69,7 @@ public abstract static class PrimFloat64ArrayAtNode extends AbstractPrimitiveNod @Specialization(guards = {"receiver.isLongType()", "index <= receiver.getLongLength()"}) protected static final double doAt(final NativeObject receiver, final long index) { - return Double.longBitsToDouble(receiver.getLong((int) index - 1)); + return Double.longBitsToDouble(receiver.getLong(index - 1)); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FloatArrayPlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FloatArrayPlugin.java index ea74fae66..797898fe5 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FloatArrayPlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/FloatArrayPlugin.java @@ -70,7 +70,7 @@ public abstract static class PrimFloatArrayAtNode extends AbstractPrimitiveNode @Specialization(guards = {"receiver.isIntType()", "index <= receiver.getIntLength()"}) protected static final double doAt(final NativeObject receiver, final long index) { - return Float.intBitsToFloat(receiver.getInt((int) index - 1)); + return Float.intBitsToFloat(receiver.getInt(index - 1)); } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java index a7714e6db..99aeb1cec 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java @@ -14,6 +14,7 @@ import de.hpi.swa.trufflesqueak.model.NativeObject; import de.hpi.swa.trufflesqueak.model.PointersObject; import de.hpi.swa.trufflesqueak.nodes.SqueakGuards; +import de.hpi.swa.trufflesqueak.util.MiscUtils; /* Automatically generated by VMPluginCodeGenerator * VMMaker.oscog-eem.2480 uuid: bb3ffda7-8241-4dea-b886-d656e474b6c1 @@ -699,8 +700,8 @@ private static Object fetchPointerofObject(final int index, final PointersObject private int fetchIntegerofObject(final int index, final PointersObject arrayOop) { final Object value = fetchPointerofObject(index, arrayOop); - if (value instanceof Long) { - return ((Long) value).intValue(); + if (value instanceof final Long l) { + return MiscUtils.toIntExact(l); } else { failed = true; return 0; diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Matrix2x3Plugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Matrix2x3Plugin.java index c3c668455..0c3b1e839 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Matrix2x3Plugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Matrix2x3Plugin.java @@ -75,10 +75,10 @@ protected final double loadArgumentPointY(final PointersObject point, final Abst private double loadArgumentPointAt(final PointersObject point, final int index, final AbstractPointersObjectReadNode readNode, final InlinedBranchProfile errorProfile, final Node node) { if (isPoint(point)) { final Object value = readNode.execute(node, point, index); - if (value instanceof Long) { - return (long) value; - } else if (value instanceof Double) { - return (double) value; + if (value instanceof final Long longValue) { + return longValue; + } else if (value instanceof final Double doubleValue) { + return doubleValue; } } errorProfile.enter(node); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/TruffleSqueakPlugin.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/TruffleSqueakPlugin.java index f2d50022d..017342fd4 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/TruffleSqueakPlugin.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/TruffleSqueakPlugin.java @@ -90,11 +90,11 @@ protected abstract static class PrimGetDirectCallNodesNode extends AbstractPrimi @CompilerDirectives.TruffleBoundary protected static final Object doGet(@SuppressWarnings("unused") final Object receiver, final JavaObjectWrapper target) { final Object wrappedObject = target.unwrap(); - if (wrappedObject instanceof RootNode rootNode) { + if (wrappedObject instanceof final RootNode rootNode) { final List callNodes = new ArrayList<>(); rootNode.accept(node -> { - if (node instanceof DirectCallNode) { - callNodes.add((DirectCallNode) node); + if (node instanceof final DirectCallNode dcn) { + callNodes.add(dcn); } return true; }); diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Zip.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Zip.java index 1a95ce398..4f47c782b 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Zip.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Zip.java @@ -868,8 +868,8 @@ private static int[] fetchNativePointerOfObjectWithExpectedLength(final Pointers private static int fetchIntegerofObject(final int index, final PointersObject arrayOop) { final Object value = fetchPointerofObject(index, arrayOop); - if (value instanceof Long) { - return MiscUtils.toIntExact((long) value); + if (value instanceof final Long l) { + return MiscUtils.toIntExact(l); } else { throw PrimitiveFailed.GENERIC_ERROR; } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/SqueakSocket.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/SqueakSocket.java index dd10d81db..5e6bae14f 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/SqueakSocket.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/SqueakSocket.java @@ -129,8 +129,8 @@ protected final boolean supportsOption(final String name) { protected final String getOption(final String name) throws IOException { final SocketOption option = socketOptionFromString(name); final Object value = asNetworkChannel().getOption(option); - if (value instanceof Boolean) { - return (boolean) value ? "1" : "0"; + if (value instanceof final Boolean b) { + return b ? "1" : "0"; } return String.valueOf(value); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/FrameAccess.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/FrameAccess.java index e34f6e0a1..75c66ec35 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/FrameAccess.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/FrameAccess.java @@ -279,15 +279,15 @@ public static void setSlot(final Frame frame, final int slotIndex, final Object if (slotIndex < numberOfSlots) { final FrameSlotKind frameSlotKind = frameDescriptor.getSlotKind(slotIndex); final boolean isIllegal = frameSlotKind == FrameSlotKind.Illegal; - if (value instanceof Boolean && (isIllegal || frameSlotKind == FrameSlotKind.Boolean)) { + if (value instanceof final Boolean b && (isIllegal || frameSlotKind == FrameSlotKind.Boolean)) { frameDescriptor.setSlotKind(slotIndex, FrameSlotKind.Boolean); - frame.setBoolean(slotIndex, (boolean) value); - } else if (value instanceof Long && (isIllegal || frameSlotKind == FrameSlotKind.Long)) { + frame.setBoolean(slotIndex, b); + } else if (value instanceof final Long l && (isIllegal || frameSlotKind == FrameSlotKind.Long)) { frameDescriptor.setSlotKind(slotIndex, FrameSlotKind.Long); - frame.setLong(slotIndex, (long) value); - } else if (value instanceof Double && (isIllegal || frameSlotKind == FrameSlotKind.Double)) { + frame.setLong(slotIndex, l); + } else if (value instanceof final Double d && (isIllegal || frameSlotKind == FrameSlotKind.Double)) { frameDescriptor.setSlotKind(slotIndex, FrameSlotKind.Double); - frame.setDouble(slotIndex, (double) value); + frame.setDouble(slotIndex, d); } else { frameDescriptor.setSlotKind(slotIndex, FrameSlotKind.Object); frame.setObject(slotIndex, value); From 6c018f3cb04104f120b73ef798556814800185f6 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 21:09:05 +0100 Subject: [PATCH 27/40] Deduplicate code in `JPEGReader` --- .../nodes/plugins/JPEGReader.java | 92 +++++-------------- 1 file changed, 22 insertions(+), 70 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java index 99aeb1cec..1f655abba 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/JPEGReader.java @@ -310,68 +310,40 @@ private boolean loadJPEGStreamFrom(final PointersObject streamOop) { /* JPEGReaderPlugin>>#nextSampleCb */ private int nextSampleCb() { - final int blockIndex; - int curX; - int dx; - int dy; - final int sample; - final int sampleIndex; - final int sx; - final int sy; - - dx = curX = cbComponent[CurrentXIndex]; - dy = cbComponent[CurrentYIndex]; - sx = cbComponent[HScaleIndex]; - sy = cbComponent[VScaleIndex]; - if (!(sx == 0 && sy == 0)) { - dx = dx / sx; - dy = dy / sy; - } - blockIndex = (int) ((Integer.toUnsignedLong(dy) >> 3) * cbComponent[BlockWidthIndex] + (Integer.toUnsignedLong(dx) >> 3)); - sampleIndex = (int) ((Integer.toUnsignedLong(dy & 7) << 3) + (dx & 7)); - sample = cbBlocks[blockIndex][sampleIndex]; - curX += 1; - if (curX < cbComponent[MCUWidthIndex] * 8) { - cbComponent[CurrentXIndex] = curX; - } else { - cbComponent[CurrentXIndex] = 0; - cbComponent[CurrentYIndex] = cbComponent[CurrentYIndex] + 1; - } - return sample; + return nextSample(cbComponent, cbBlocks); } - /** JPEGReaderPlugin>>#nextSampleCr inlined. */ + /* JPEGReaderPlugin>>#nextSampleCr */ + private int nextSampleCr() { + return nextSample(crComponent, crBlocks); + } /** JPEGReaderPlugin>>#nextSampleFrom:blocks: has no sender. */ /* JPEGReaderPlugin>>#nextSampleY */ private int nextSampleY() { - final int blockIndex; - int curX; - int dx; - int dy; - final int sample; - final int sampleIndex; - final int sx; - final int sy; - - dx = curX = yComponent[CurrentXIndex]; - dy = yComponent[CurrentYIndex]; - sx = yComponent[HScaleIndex]; - sy = yComponent[VScaleIndex]; + return nextSample(yComponent, yBlocks); + } + + private static int nextSample(final int[] component, final int[][] blocks) { + int dx = component[CurrentXIndex]; + int curX = dx; + int dy = component[CurrentYIndex]; + final int sx = component[HScaleIndex]; + final int sy = component[VScaleIndex]; if (!(sx == 0 && sy == 0)) { dx = dx / sx; dy = dy / sy; } - blockIndex = (int) ((Integer.toUnsignedLong(dy) >> 3) * yComponent[BlockWidthIndex] + (Integer.toUnsignedLong(dx) >> 3)); - sampleIndex = (int) ((Integer.toUnsignedLong(dy & 7) << 3) + (dx & 7)); - sample = yBlocks[blockIndex][sampleIndex]; + final int blockIndex = (int) ((Integer.toUnsignedLong(dy) >> 3) * component[BlockWidthIndex] + (Integer.toUnsignedLong(dx) >> 3)); + final int sampleIndex = (int) ((Integer.toUnsignedLong(dy & 7) << 3) + (dx & 7)); + final int sample = blocks[blockIndex][sampleIndex]; curX += 1; - if (curX < yComponent[MCUWidthIndex] * 8) { - yComponent[CurrentXIndex] = curX; + if (curX < component[MCUWidthIndex] * 8) { + component[CurrentXIndex] = curX; } else { - yComponent[CurrentXIndex] = 0; - yComponent[CurrentYIndex] = yComponent[CurrentYIndex] + 1; + component[CurrentXIndex] = 0; + component[CurrentYIndex] = component[CurrentYIndex] + 1; } return sample; } @@ -437,27 +409,7 @@ public void primitiveColorConvertMCU(final PointersObject componentArray, final final int y = nextSampleY(); int cb = nextSampleCb(); cb -= SampleOffset; - /* begin nextSampleCr */ - int dx = crComponent[CurrentXIndex]; - int curX = dx; - int dy = crComponent[CurrentYIndex]; - final int sx = crComponent[HScaleIndex]; - final int sy = crComponent[VScaleIndex]; - if (!(sx == 0 && sy == 0)) { - dx = dx / sx; - dy = dy / sy; - } - final int blockIndex = (int) ((Integer.toUnsignedLong(dy) >> 3) * crComponent[BlockWidthIndex] + (Integer.toUnsignedLong(dx) >> 3)); - final int sampleIndex = (int) ((Integer.toUnsignedLong(dy & 7) << 3) + (dx & 7)); - final int sample = crBlocks[blockIndex][sampleIndex]; - curX += 1; - if (curX < crComponent[MCUWidthIndex] * 8) { - crComponent[CurrentXIndex] = curX; - } else { - crComponent[CurrentXIndex] = 0; - crComponent[CurrentYIndex] = crComponent[CurrentYIndex] + 1; - } - int cr = sample; + int cr = nextSampleCr(); cr -= SampleOffset; int red = y + FIXn1n40200 * cr / 65536 + residuals[RedIndex]; red = Math.min(red, MaxSample); From 8bf50c2f258bdf4603ac1f919f449ce90589f6a1 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 21:40:35 +0100 Subject: [PATCH 28/40] Deduplicate code in `LargeIntegerObject` --- .../model/LargeIntegerObject.java | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/LargeIntegerObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/LargeIntegerObject.java index 5dcd3bffb..57e104dcc 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/LargeIntegerObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/LargeIntegerObject.java @@ -145,17 +145,8 @@ public void setBytes(final SqueakImageContext image, final byte[] bytes) { @TruffleBoundary public void setBytes(final SqueakImageContext image, final LargeIntegerObject src, final int srcPos, final int destPos, final int length) { - final byte[] bytes; final byte[] srcBytes = toBigEndianBytes(src.integer); - final byte[] bigIntegerBytes = toBigEndianBytes(integer); - final int offset = bigIntegerBytes[0] != 0 ? 0 : 1; - final int bigIntegerBytesActualLength = bigIntegerBytes.length - offset; - if (bigIntegerBytesActualLength < destPos + length) { - bytes = new byte[size()]; - System.arraycopy(bigIntegerBytes, offset, bytes, 0, bigIntegerBytesActualLength); - } else { - bytes = bigIntegerBytes; - } + final byte[] bytes = getBigIntegerBytes(destPos, length); System.arraycopy(srcBytes, srcBytes.length - length - srcPos, bytes, bytes.length - length - destPos, length); integer = new BigInteger(isPositive(image) ? 1 : -1, bytes); bitLength = integer.bitLength(); @@ -163,22 +154,27 @@ public void setBytes(final SqueakImageContext image, final LargeIntegerObject sr @TruffleBoundary public void setBytes(final SqueakImageContext image, final byte[] srcBytes, final int srcPos, final int destPos, final int length) { + final byte[] bytes = getBigIntegerBytes(destPos, length); // destination bytes are big-endian, source bytes are not - final byte[] bytes; + for (int i = 0; i < length; i++) { + bytes[bytes.length - 1 - (destPos + i)] = srcBytes[srcPos + i]; + } + integer = new BigInteger(isPositive(image) ? 1 : -1, bytes); + bitLength = integer.bitLength(); + } + + private byte[] getBigIntegerBytes(final int destPos, final int length) { final byte[] bigIntegerBytes = toBigEndianBytes(integer); final int offset = bigIntegerBytes[0] != 0 ? 0 : 1; final int bigIntegerBytesActualLength = bigIntegerBytes.length - offset; + final byte[] bytes; if (bigIntegerBytesActualLength < destPos + length) { bytes = new byte[size()]; System.arraycopy(bigIntegerBytes, offset, bytes, 0, bigIntegerBytesActualLength); } else { bytes = bigIntegerBytes; } - for (int i = 0; i < length; i++) { - bytes[bytes.length - 1 - (destPos + i)] = srcBytes[srcPos + i]; - } - integer = new BigInteger(isPositive(image) ? 1 : -1, bytes); - bitLength = integer.bitLength(); + return bytes; } @Override From eb70ddf571bc375edca40a573d50cbdeeabd170c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 21:40:44 +0100 Subject: [PATCH 29/40] Minor BitBlt improvement --- .../de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java index 9188a1a31..8d4809842 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BitBlt.java @@ -1310,8 +1310,8 @@ private void drawLoopXY(final long xDelta, final long yDelta) { dy1 = -1; } } - final long px = Math.abs(yDelta); - final long py = Math.abs(xDelta); + final int px = Math.abs(MiscUtils.toIntExact(yDelta)); + final int py = Math.abs(MiscUtils.toIntExact(xDelta)); /* init null rectangle */ int affL = 9999; int affR = -9999; @@ -1319,7 +1319,7 @@ private void drawLoopXY(final long xDelta, final long yDelta) { int affB = -9999; if (py > px) { /* more horizontal */ - long p = py / 2; + int p = py / 2; for (int i = 1; i <= py; i++) { destX += dx1; if ((p -= px) < 0) { @@ -1353,7 +1353,7 @@ private void drawLoopXY(final long xDelta, final long yDelta) { } } else { /* more vertical */ - long p = px / 2; + int p = px / 2; for (int i = 1; i <= px; i++) { destY += dy1; if ((p -= py) < 0) { From ba9039f90dfb0966fa89531a6ca525842fda4f30 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 22:43:43 +0100 Subject: [PATCH 30/40] Fix parameters of showDisplayRect --- .../src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java | 2 +- .../swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java index 2eeb58cd6..bfbad8c59 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakDisplay.java @@ -162,7 +162,7 @@ private void setSqueakDisplay(final PointersObject squeakDisplay) { } @TruffleBoundary - public void showDisplayRect(final int left, final int right, final int top, final int bottom) { + public void showDisplayRect(final int left, final int top, final int right, final int bottom) { assert left <= right && top <= bottom; canvas.paintImmediately(left, top, right, bottom); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java index 4b6b3b7ce..3cae74210 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/IOPrimitives.java @@ -862,7 +862,7 @@ protected abstract static class PrimShowDisplayRectNode extends AbstractPrimitiv protected final PointersObject doShow(final PointersObject receiver, final long left, final long right, final long top, final long bottom) { final SqueakImageContext image = getContext(); if (image.hasDisplay() && left < right && top < bottom) { - image.getDisplay().showDisplayRect((int) left, (int) right, (int) top, (int) bottom); + image.getDisplay().showDisplayRect((int) left, (int) top, (int) right, (int) bottom); } return receiver; } From 1c46c0ae54568bff008ddebd55830dd74c902cd9 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 22:44:27 +0100 Subject: [PATCH 31/40] Avoid interrupts while calling back into the image --- .../trufflesqueak/nodes/SendSelectorNode.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SendSelectorNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SendSelectorNode.java index f5ceb5f97..938344b51 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SendSelectorNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SendSelectorNode.java @@ -13,6 +13,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.ClassObject; import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; import de.hpi.swa.trufflesqueak.model.NativeObject; @@ -23,7 +24,7 @@ * Performs a send to receiver with arguments. For use in other node. Selector must resolve to a * {@link CompiledCodeObject}, object-as-method is not allowed. */ -public abstract class SendSelectorNode extends Node { +public abstract class SendSelectorNode extends AbstractNode { private final NativeObject selector; protected SendSelectorNode(final NativeObject selector) { @@ -45,9 +46,18 @@ protected final Object doSend(final VirtualFrame frame, final Object[] receiverA @Cached final DispatchEagerlyNode dispatchNode) { final ClassObject rcvrClass = lookupClassNode.executeLookup(node, receiverAndArguments[0]); final CompiledCodeObject method = (CompiledCodeObject) lookupMethodNode.executeLookup(node, rcvrClass, selector); - final Object result = dispatchNode.executeDispatch(frame, method, receiverAndArguments); - assert result != null : "Result of a message send should not be null"; - return result; + final SqueakImageContext image = getContext(); + final boolean wasActive = image.interrupt.isActive(); + image.interrupt.deactivate(); // avoid interrupts while calling back into the image + try { + final Object result = dispatchNode.executeDispatch(frame, method, receiverAndArguments); + assert result != null : "Result of a message send should not be null"; + return result; + } finally { + if (wasActive) { + image.interrupt.activate(); + } + } } @Override From 6a78a82cf62ed1f9ab02c604191f87a9ce186a5d Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Fri, 22 Dec 2023 23:24:36 +0100 Subject: [PATCH 32/40] Minor edits --- .../src/de/hpi/swa/trufflesqueak/model/ContextObject.java | 2 +- .../swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java | 3 ++- .../nodes/context/TemporaryWriteMarkContextsNode.java | 2 ++ .../trufflesqueak/nodes/context/frame/FrameStackReadNode.java | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java index ee2970c1e..8c52f66e6 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java @@ -403,7 +403,7 @@ public boolean isDead() { } public boolean canBeReturnedTo() { - return getInstructionPointerForBytecodeLoop() >= 0 && getFrameSender() != NilObject.SINGLETON; + return !isDead() && getFrameSender() != NilObject.SINGLETON; } public ContextObject shallowCopy() { diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java index 4e0034e84..9c1bc6d7e 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java @@ -166,7 +166,8 @@ private ContextObject commonReturn(final ContextObject startContext, final Conte } final ContextObject context = (ContextObject) contextOrNil; assert !context.isPrimitiveContext(); - if (!context.hasClosure() && context.getCodeObject().isUnwindMarked()) { + if (context.getCodeObject().isUnwindMarked()) { + assert !context.hasClosure(); /* "context is marked; break out" */ return sendAboutToReturn(startContext, returnValue, context); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/TemporaryWriteMarkContextsNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/TemporaryWriteMarkContextsNode.java index 939f116c4..be15c36b2 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/TemporaryWriteMarkContextsNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/TemporaryWriteMarkContextsNode.java @@ -6,6 +6,7 @@ */ package de.hpi.swa.trufflesqueak.nodes.context; +import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; @@ -24,6 +25,7 @@ protected TemporaryWriteMarkContextsNode(final FrameStackWriteNode writeNode) { this.writeNode = writeNode; } + @NeverDefault public static TemporaryWriteMarkContextsNode create(final VirtualFrame frame, final int tempIndex) { return new TemporaryWriteMarkContextsNode(FrameStackWriteNode.create(frame, tempIndex)); } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/frame/FrameStackReadNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/frame/FrameStackReadNode.java index 93dbdd5c4..65469c3ba 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/frame/FrameStackReadNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/frame/FrameStackReadNode.java @@ -55,6 +55,7 @@ public static final FrameStackReadNode create(final Frame frame, final int index } } + @NeverDefault public static final FrameStackReadNode createTemporaryReadNode(final Frame frame, final int index) { final int numArgs = FrameAccess.getNumArguments(frame); if (index < numArgs) { From 1f43c1dc3598c6a8390c5edf5307d30b4553adb4 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Sat, 23 Dec 2023 00:26:42 +0100 Subject: [PATCH 33/40] Mark more Cuis tests as passing --- .../src/de/hpi/swa/trufflesqueak/test/runCuisTests.st | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st index 0393fb2a1..84fc86cee 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st @@ -8,8 +8,6 @@ SmallInteger initMinValAndMaxVal. "resize SmallInteger range" nonTerminatingTestCases := OrderedCollection new. { #JpegTest -> #(#test16bpp61 #test16bpp63 #test16bppLE #test16bppLE61 #test16bppLE62 #test16bppLE63 #test32bpp #test32bpp63 #test32bppLE63 #testBA32bpp #testBA32bpp63 "all previous tests pass on TruffleSqueak in JVM mode, the rest is not yet supported" #test16bpp #test16bpp62 #testBA16bpp #testBA16bpp61 #testBA16bpp62 #testBA16bpp63 #testBA16bppLE #testBA16bppLE61 #testBA16bppLE62 #testBA16bppLE63 #testGray #testGray61 #testGray62 #testGray63 #testGrayBA #testGrayBA61 #testGrayBA62 #testGrayBA63). - #ProcessTest -> #(#testTerminateInEnsure #testValueEnsured). - #TestValueWithinFix -> #(#testValueWithinNonLocalReturnFixReal #testValueWithinNonLocalReturnFixSimply). } collect: [:assoc | | testCase | testCase := Smalltalk at: assoc key. assoc value do: [:sel | nonTerminatingTestCases add: (testCase selector: sel) ]]. @@ -23,7 +21,6 @@ failingTests := OrderedCollection new. #ProcessorTest -> #("flaky" #testGrabProcessor #testGrabProcessorOnlyForNoTimeout #testGrabProcessorOnlyForTimeout #testValueUnpreemptively). #ProcessTerminateUnwindNonLocalReturn -> #(test1ATerminate #test1BTerminate #test2ATerminate #test2BTerminate #test3ATerminate #test3BTerminate #test4ATerminate #test4BTerminate #test5ATerminate #test5BTerminate "flaky" #test5DTerminate #test6ATerminate #test6BTerminate "flaky" #test6DTerminate #test7ATerminate #test7BTerminate #test8ATerminate #test8BTerminate). #SmallIntegerTest -> #(#testMaxVal #testMinVal #testPrintString). - #TestValueWithinFix -> #("flaky" #testValueWithinTimingRepeat). #WeakIdentitySetTest -> #(#test). "Failing (or flaky?) on TruffleSqueak Native" } collect: [:assoc | | testCase | testCase := Smalltalk at: assoc key. From 91be31d97dad9e10644cbf348b1721624c0475af Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Sat, 23 Dec 2023 00:41:03 +0100 Subject: [PATCH 34/40] Use aboutToReturnNode unconditionally --- .../hpi/swa/trufflesqueak/nodes/HandleNonLocalReturnNode.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/HandleNonLocalReturnNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/HandleNonLocalReturnNode.java index dc31bd42a..ae3e37bb9 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/HandleNonLocalReturnNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/HandleNonLocalReturnNode.java @@ -36,8 +36,8 @@ public static HandleNonLocalReturnNode create(final CompiledCodeObject code) { protected final Object doHandle(final VirtualFrame frame, final NonLocalReturn nlr, @Bind("this") final Node node, @Cached final InlinedConditionProfile hasModifiedSenderProfile) { + aboutToReturnNode.executeAboutToReturn(frame, nlr); // handle ensure: or ifCurtailed: if (hasModifiedSenderProfile.profile(node, FrameAccess.hasModifiedSender(frame))) { - aboutToReturnNode.executeAboutToReturn(frame, nlr); // handle ensure: or ifCurtailed: // Sender might have changed. final ContextObject newSender = FrameAccess.getSenderContext(frame); final ContextObject target = (ContextObject) nlr.getTargetContextOrMarker(); @@ -45,7 +45,6 @@ protected final Object doHandle(final VirtualFrame frame, final NonLocalReturn n // TODO: `target == newSender` may could use special handling? throw new NonVirtualReturn(nlr.getReturnValue(), target, newSender); } else { - aboutToReturnNode.executeAboutToReturn(frame, nlr); // handle ensure: or ifCurtailed: FrameAccess.terminate(frame); throw nlr; } From cc9a61eeeca0ead6e5f83c6407805fc35cf4d859 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Sat, 23 Dec 2023 00:07:00 +0100 Subject: [PATCH 35/40] Do not mark context as escaped when unwinding --- .../src/de/hpi/swa/trufflesqueak/nodes/AboutToReturnNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/AboutToReturnNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/AboutToReturnNode.java index f16cbaef3..b80ad5130 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/AboutToReturnNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/AboutToReturnNode.java @@ -22,8 +22,8 @@ import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; import de.hpi.swa.trufflesqueak.model.ContextObject; import de.hpi.swa.trufflesqueak.nodes.AboutToReturnNodeFactory.AboutToReturnImplNodeGen; -import de.hpi.swa.trufflesqueak.nodes.context.TemporaryWriteMarkContextsNode; import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackReadNode; +import de.hpi.swa.trufflesqueak.nodes.context.frame.FrameStackWriteNode; import de.hpi.swa.trufflesqueak.nodes.context.frame.GetContextOrMarkerNode; import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchClosureNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; @@ -55,7 +55,7 @@ protected static final void doAboutToReturnVirtualized(final VirtualFrame frame, @Bind("this") final Node node, @Cached("createTemporaryReadNode(frame, 0)") final FrameStackReadNode blockArgumentNode, @SuppressWarnings("unused") @Cached("createTemporaryReadNode(frame, 1)") final FrameStackReadNode completeTempReadNode, - @Cached("create(frame, 1)") final TemporaryWriteMarkContextsNode completeTempWriteNode, + @Cached("create(frame, 1)") final FrameStackWriteNode completeTempWriteNode, @Cached final GetContextOrMarkerNode getContextOrMarkerNode, @Cached final DispatchClosureNode dispatchNode) { completeTempWriteNode.executeWrite(frame, BooleanObject.TRUE); From 038683f62752124fd0087197b9626fe39d5c4ce2 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 26 Dec 2023 11:47:49 +0100 Subject: [PATCH 36/40] Introduce `TransferToNode` and align `WakeHighestPriorityNode` with SqueakJS. --- .../trufflesqueak/model/ContextObject.java | 23 ------ .../nodes/process/ResumeProcessNode.java | 55 +++++-------- .../nodes/process/TransferToNode.java | 79 +++++++++++++++++++ .../process/WakeHighestPriorityNode.java | 32 +++----- 4 files changed, 111 insertions(+), 78 deletions(-) create mode 100644 src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/TransferToNode.java diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java index 8c52f66e6..c2fec29ae 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/ContextObject.java @@ -19,16 +19,12 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; -import de.hpi.swa.trufflesqueak.exceptions.ProcessSwitch; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; import de.hpi.swa.trufflesqueak.image.SqueakImageChunk; import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.image.SqueakImageReader; import de.hpi.swa.trufflesqueak.image.SqueakImageWriter; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.CONTEXT; -import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; -import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; -import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; import de.hpi.swa.trufflesqueak.util.FrameAccess; import de.hpi.swa.trufflesqueak.util.MiscUtils; import de.hpi.swa.trufflesqueak.util.ObjectGraphUtils.ObjectTracer; @@ -505,25 +501,6 @@ private Object[] getReceiverAndNArguments(final int numArgs) { return arguments; } - public void transferTo(final SqueakImageContext image, final PointersObject newProcess, final PointersObject activeProcess, final ContextObject newActiveContext, - final AbstractPointersObjectWriteNode writeNode, final Node inlineTarget) { - // Record a process to be awakened on the next interpreter cycle. - final PointersObject scheduler = image.getScheduler(); - assert newProcess != activeProcess : "trying to switch to already active process"; - // overwritten in next line. - final PointersObject oldProcess = activeProcess; - writeNode.execute(inlineTarget, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS, newProcess); - writeNode.execute(inlineTarget, oldProcess, PROCESS.SUSPENDED_CONTEXT, this); - writeNode.executeNil(inlineTarget, newProcess, PROCESS.LIST); - writeNode.executeNil(inlineTarget, newProcess, PROCESS.SUSPENDED_CONTEXT); - if (CompilerDirectives.isPartialEvaluationConstant(newActiveContext)) { - throw ProcessSwitch.create(newActiveContext); - } else { - // Avoid further PE if newActiveContext is not a PE constant. - throw ProcessSwitch.createWithBoundary(newActiveContext); - } - } - /** * Since {@link MaterializedFrame} is an interface, the Graal compiler needs help to find the * concrete class, and which concrete implementation is used depends on the GraalVM edition (CE diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java index 27b278ac5..612d5f3a8 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java @@ -6,9 +6,7 @@ */ package de.hpi.swa.trufflesqueak.nodes.process; -import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; @@ -16,26 +14,23 @@ import com.oracle.truffle.api.nodes.Node; import de.hpi.swa.trufflesqueak.image.SqueakImageContext; -import de.hpi.swa.trufflesqueak.model.ContextObject; import de.hpi.swa.trufflesqueak.model.PointersObject; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; import de.hpi.swa.trufflesqueak.nodes.AbstractNode; import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; -import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; -import de.hpi.swa.trufflesqueak.nodes.context.frame.GetOrCreateContextNode; @GenerateInline @GenerateCached(false) public abstract class ResumeProcessNode extends AbstractNode { - public static void executeUncached(final VirtualFrame frame, final SqueakImageContext image, final PointersObject newProcess) { - final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); + public static final void executeUncached(final VirtualFrame frame, final SqueakImageContext image, final PointersObject newProcess) { final PointersObject activeProcess = image.getActiveProcessSlow(); - if (hasHigherPriority(newProcess, activeProcess, readNode, null)) { + final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); + final long activePriority = readNode.executeLong(null, activeProcess, PROCESS.PRIORITY); + final long newPriority = readNode.executeLong(null, newProcess, PROCESS.PRIORITY); + if (newPriority > activePriority) { PutToSleepNode.executeUncached(image, activeProcess); - final ContextObject newActiveContext = (ContextObject) readNode.execute(null, newProcess, PROCESS.SUSPENDED_CONTEXT); - final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); - GetOrCreateContextNode.getOrCreateUncached(frame).transferTo(image, newProcess, activeProcess, newActiveContext, writeNode, null); + throw TransferToNode.executeUncached(frame, newProcess); } else { PutToSleepNode.executeUncached(image, newProcess); } @@ -43,28 +38,20 @@ public static void executeUncached(final VirtualFrame frame, final SqueakImageCo public abstract void executeResume(VirtualFrame frame, Node node, PointersObject newProcess); - @Specialization(guards = "hasHigherPriority(newProcess, activeProcess, pointersReadNode, node)") - protected static final void doTransferTo(final VirtualFrame frame, final Node node, final PointersObject newProcess, - @Shared("putToSleepNode") @Cached final PutToSleepNode putToSleepNode, - @Shared("pointersReadNode") @Cached final AbstractPointersObjectReadNode pointersReadNode, - @SuppressWarnings("unused") @Shared("getActiveProcessNode") @Cached final GetActiveProcessNode getActiveProcessNode, - @Bind("getActiveProcessNode.execute(node)") final PointersObject activeProcess, - @Cached final AbstractPointersObjectWriteNode pointersWriteNode, - @Cached final GetOrCreateContextNode contextNode) { - putToSleepNode.executePutToSleep(node, activeProcess); - final ContextObject newActiveContext = (ContextObject) pointersReadNode.execute(node, newProcess, PROCESS.SUSPENDED_CONTEXT); - contextNode.executeGet(frame, node).transferTo(getContext(node), newProcess, activeProcess, newActiveContext, pointersWriteNode, node); - } - - @Specialization(guards = "!hasHigherPriority(newProcess, getActiveProcessNode.execute(node), pointersReadNode, node)") - protected static final void doSleep(final Node node, final PointersObject newProcess, - @SuppressWarnings("unused") @Shared("pointersReadNode") @Cached final AbstractPointersObjectReadNode pointersReadNode, - @SuppressWarnings("unused") @Shared("getActiveProcessNode") @Cached final GetActiveProcessNode getActiveProcessNode, - @Shared("putToSleepNode") @Cached final PutToSleepNode putToSleepNode) { - putToSleepNode.executePutToSleep(node, newProcess); - } - - protected static final boolean hasHigherPriority(final PointersObject newProcess, final PointersObject activeProcess, final AbstractPointersObjectReadNode readNode, final Node inlineTarget) { - return readNode.executeLong(inlineTarget, newProcess, PROCESS.PRIORITY) > readNode.executeLong(inlineTarget, activeProcess, PROCESS.PRIORITY); + @Specialization + protected static final void resumeProcess(final VirtualFrame frame, final Node node, final PointersObject newProcess, + @Cached final AbstractPointersObjectReadNode readNode, + @Cached final GetActiveProcessNode getActiveProcessNode, + @Cached final PutToSleepNode putToSleepNode, + @Cached final TransferToNode transferToNode) { + final PointersObject activeProcess = getActiveProcessNode.execute(node); + final long activePriority = readNode.executeLong(node, activeProcess, PROCESS.PRIORITY); + final long newPriority = readNode.executeLong(node, newProcess, PROCESS.PRIORITY); + if (newPriority > activePriority) { + putToSleepNode.executePutToSleep(node, activeProcess); + throw transferToNode.execute(frame, node, newProcess); + } else { + putToSleepNode.executePutToSleep(node, newProcess); + } } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/TransferToNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/TransferToNode.java new file mode 100644 index 000000000..6cfb11073 --- /dev/null +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/TransferToNode.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Software Architecture Group, Hasso Plattner Institute + * Copyright (c) 2023 Oracle and/or its affiliates + * + * Licensed under the MIT License. + */ +package de.hpi.swa.trufflesqueak.nodes.process; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateCached; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; + +import de.hpi.swa.trufflesqueak.exceptions.ProcessSwitch; +import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; +import de.hpi.swa.trufflesqueak.model.ContextObject; +import de.hpi.swa.trufflesqueak.model.PointersObject; +import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; +import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; +import de.hpi.swa.trufflesqueak.nodes.AbstractNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; +import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; +import de.hpi.swa.trufflesqueak.nodes.context.frame.GetOrCreateContextNode; + +@GenerateInline +@GenerateCached(false) +public abstract class TransferToNode extends AbstractNode { + + public abstract ProcessSwitch execute(VirtualFrame frame, Node node, PointersObject newProcess); + + public static final ProcessSwitch executeUncached(final VirtualFrame frame, final PointersObject newProcess) { + // Record a process to be awakened on the next interpreter cycle. + final PointersObject scheduler = getContext(null).getScheduler(); + final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); + final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); + final PointersObject oldProcess = readNode.executePointers(null, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS); + writeNode.execute(null, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS, newProcess); + final ContextObject activeContext = GetOrCreateContextNode.getOrCreateUncached(frame); + writeNode.execute(null, oldProcess, PROCESS.SUSPENDED_CONTEXT, activeContext); + final Object newActiveContext = readNode.execute(null, newProcess, PROCESS.SUSPENDED_CONTEXT); + writeNode.executeNil(null, newProcess, PROCESS.SUSPENDED_CONTEXT); + writeNode.executeNil(null, newProcess, PROCESS.LIST); + if (!(newActiveContext instanceof final ContextObject newActiveContextObject)) { + throw SqueakException.create("new process not runnable"); + } + throw ProcessSwitch.createWithBoundary(newActiveContextObject); + } + + @Specialization + protected static final ProcessSwitch transferTo(final VirtualFrame frame, final Node node, final PointersObject newProcess, + @Cached final GetOrCreateContextNode contextNode, + @Cached final AbstractPointersObjectReadNode readOldProcessNode, + @Cached final AbstractPointersObjectReadNode readNewActiveContextNode, + @Cached final AbstractPointersObjectWriteNode writeActiveProcessNode, + @Cached final AbstractPointersObjectWriteNode writeSuspendedContextNode, + @Cached final AbstractPointersObjectWriteNode writeNilContextNode, + @Cached final AbstractPointersObjectWriteNode writeListNode) { + // Record a process to be awakened on the next interpreter cycle. + final PointersObject scheduler = getContext(node).getScheduler(); + final PointersObject oldProcess = readOldProcessNode.executePointers(node, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS); + writeActiveProcessNode.execute(node, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS, newProcess); + writeSuspendedContextNode.execute(node, oldProcess, PROCESS.SUSPENDED_CONTEXT, contextNode.executeGet(frame, node)); + final Object newActiveContext = readNewActiveContextNode.execute(node, newProcess, PROCESS.SUSPENDED_CONTEXT); + writeNilContextNode.executeNil(node, newProcess, PROCESS.SUSPENDED_CONTEXT); + writeListNode.executeNil(node, newProcess, PROCESS.LIST); + if (!(newActiveContext instanceof final ContextObject newActiveContextObject)) { + throw SqueakException.create("new process not runnable"); + } + if (CompilerDirectives.isPartialEvaluationConstant(newActiveContextObject)) { + throw ProcessSwitch.create(newActiveContextObject); + } else { + // Avoid further PE if newActiveContext is not a PE constant. + throw ProcessSwitch.createWithBoundary(newActiveContextObject); + } + } +} diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java index f7e5998a7..00d14c47f 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/WakeHighestPriorityNode.java @@ -15,18 +15,14 @@ import de.hpi.swa.trufflesqueak.exceptions.ProcessSwitch; import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; -import de.hpi.swa.trufflesqueak.image.SqueakImageContext; import de.hpi.swa.trufflesqueak.model.ArrayObject; -import de.hpi.swa.trufflesqueak.model.ContextObject; import de.hpi.swa.trufflesqueak.model.PointersObject; -import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; import de.hpi.swa.trufflesqueak.nodes.AbstractNode; import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectReadNode; import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectSizeNode; -import de.hpi.swa.trufflesqueak.nodes.context.frame.GetOrCreateContextNode; @GenerateInline @GenerateCached(false) @@ -40,25 +36,19 @@ protected static final ProcessSwitch doWake(final VirtualFrame frame, final Node @Cached final ArrayObjectSizeNode arraySizeNode, @Cached final AbstractPointersObjectReadNode pointersReadNode, @Cached final AbstractPointersObjectWriteNode pointersWriteNode, - @Cached final GetOrCreateContextNode contextNode, - @Cached final GetActiveProcessNode getActiveProcessNode) { - final SqueakImageContext image = getContext(node); + @Cached final TransferToNode transferToNode) { // Return the highest priority process that is ready to run. // Note: It is a fatal VM error if there is no runnable process. - final ArrayObject schedLists = pointersReadNode.executeArray(node, image.getScheduler(), PROCESS_SCHEDULER.PROCESS_LISTS); - for (long p = arraySizeNode.execute(node, schedLists) - 1; p >= 0; p--) { - final PointersObject processList = (PointersObject) arrayReadNode.execute(node, schedLists, p); - while (!processList.isEmptyList(pointersReadNode, node)) { - final PointersObject newProcess = processList.removeFirstLinkOfList(pointersReadNode, pointersWriteNode, node); - final Object newContext = pointersReadNode.execute(node, newProcess, PROCESS.SUSPENDED_CONTEXT); - if (newContext instanceof final ContextObject newActiveContext) { - contextNode.executeGet(frame, node).transferTo(image, newProcess, getActiveProcessNode.execute(node), newActiveContext, pointersWriteNode, node); - throw SqueakException.create("Should not be reached"); - } else { - assert false : "evicted zombie process from run queue"; - } + final ArrayObject schedLists = pointersReadNode.executeArray(node, getContext(node).getScheduler(), PROCESS_SCHEDULER.PROCESS_LISTS); + long p = arraySizeNode.execute(node, schedLists) - 1; // index of last indexable field + PointersObject processList; + do { + if (p < 0) { + throw SqueakException.create("scheduler could not find a runnable process"); } - } - throw SqueakException.create("scheduler could not find a runnable process"); + processList = (PointersObject) arrayReadNode.execute(node, schedLists, p--); + } while (processList.isEmptyList(pointersReadNode, node)); + final PointersObject newProcess = processList.removeFirstLinkOfList(pointersReadNode, pointersWriteNode, node); + throw transferToNode.execute(frame, node, newProcess); } } From aa239d4af7f15d65f91cbac333cf5de8b5a6433f Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 26 Dec 2023 13:31:01 +0100 Subject: [PATCH 37/40] Minor edit --- .../nodes/primitives/impl/ControlPrimitives.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java index d8cea2bc7..798413a10 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/ControlPrimitives.java @@ -455,11 +455,11 @@ protected static final PointersObject doSuspendOtherProcess(final PointersObject @Cached final AbstractPointersObjectReadNode readNode, @Cached final AbstractPointersObjectWriteNode writeNode) { final Object myListOrNil = readNode.execute(node, receiver, PROCESS.LIST); - if (myListOrNil == NilObject.SINGLETON) { + if (!(myListOrNil instanceof final PointersObject myList)) { CompilerDirectives.transferToInterpreter(); + assert myListOrNil == NilObject.SINGLETON; throw PrimitiveFailed.BAD_RECEIVER; } - final PointersObject myList = (PointersObject) myListOrNil; removeProcessNode.executeRemove(receiver, myList, readNode, writeNode, node); writeNode.execute(node, receiver, PROCESS.LIST, NilObject.SINGLETON); return myList; From 876d77e25ddb8100aebfa183dd5957dc89be14f8 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 26 Dec 2023 21:36:16 +0100 Subject: [PATCH 38/40] Refactor `ExecuteTopLevelContextNode` --- .../nodes/ExecuteTopLevelContextNode.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java index 9c1bc6d7e..6ab0a8da3 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java @@ -109,15 +109,15 @@ private void executeLoop() { @TruffleBoundary private static ContextObject returnTo(final ContextObject activeContext, final AbstractSqueakObject sender, final Object returnValue) { - if (sender == NilObject.SINGLETON) { + if (!(sender instanceof final ContextObject senderContext)) { + assert sender == NilObject.SINGLETON; throw returnToTopLevel(activeContext, returnValue); } - final ContextObject targetContext = (ContextObject) sender; final ContextObject context; - if (targetContext.isPrimitiveContext()) { - context = (ContextObject) targetContext.getFrameSender(); // skip primitive contexts. + if (senderContext.isPrimitiveContext()) { + context = (ContextObject) senderContext.getFrameSender(); // skip primitive contexts. } else { - context = targetContext; + context = senderContext; } context.push(returnValue); return context; @@ -125,10 +125,11 @@ private static ContextObject returnTo(final ContextObject activeContext, final A @TruffleBoundary private ContextObject commonNLReturn(final AbstractSqueakObject sender, final ContextObject targetContext, final Object returnValue) { - if (sender == NilObject.SINGLETON) { + if (!(sender instanceof final ContextObject senderContext)) { + assert sender == NilObject.SINGLETON; throw returnToTopLevel(targetContext, returnValue); } - ContextObject context = (ContextObject) sender; + ContextObject context = senderContext; while (context != targetContext) { final AbstractSqueakObject currentSender = context.getSender(); if (currentSender instanceof final ContextObject o) { @@ -160,11 +161,11 @@ private ContextObject commonReturn(final ContextObject startContext, final Conte */ AbstractSqueakObject contextOrNil = startContext; while (contextOrNil != targetContext) { - if (contextOrNil == NilObject.SINGLETON) { + if (!(contextOrNil instanceof final ContextObject context)) { /* "error: sender's instruction pointer or context is nil; cannot return" */ + assert contextOrNil == NilObject.SINGLETON; return sendCannotReturn(startContext, returnValue); } - final ContextObject context = (ContextObject) contextOrNil; assert !context.isPrimitiveContext(); if (context.getCodeObject().isUnwindMarked()) { assert !context.hasClosure(); From db6c96842f4e05b30fead670c3a4aa37f019560c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 27 Dec 2023 16:40:28 +0100 Subject: [PATCH 39/40] Handle aboutToReturn in commonNLReturn --- .../swa/trufflesqueak/test/runCuisTests.st | 1 - .../nodes/ExecuteTopLevelContextNode.java | 21 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st index 84fc86cee..6bc9f6871 100644 --- a/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st +++ b/src/de.hpi.swa.trufflesqueak.test/src/de/hpi/swa/trufflesqueak/test/runCuisTests.st @@ -19,7 +19,6 @@ failingTests := OrderedCollection new. { #FloatTest -> #(#testIsDenormalized #testPrimTruncated). #ProcessorTest -> #("flaky" #testGrabProcessor #testGrabProcessorOnlyForNoTimeout #testGrabProcessorOnlyForTimeout #testValueUnpreemptively). - #ProcessTerminateUnwindNonLocalReturn -> #(test1ATerminate #test1BTerminate #test2ATerminate #test2BTerminate #test3ATerminate #test3BTerminate #test4ATerminate #test4BTerminate #test5ATerminate #test5BTerminate "flaky" #test5DTerminate #test6ATerminate #test6BTerminate "flaky" #test6DTerminate #test7ATerminate #test7BTerminate #test8ATerminate #test8BTerminate). #SmallIntegerTest -> #(#testMaxVal #testMinVal #testPrintString). #WeakIdentitySetTest -> #(#test). "Failing (or flaky?) on TruffleSqueak Native" } collect: [:assoc | | testCase | diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java index 6ab0a8da3..6ba25a0da 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ExecuteTopLevelContextNode.java @@ -98,7 +98,7 @@ private void executeLoop() { activeContext = ps.getNewContext(); LogUtils.SCHEDULING.log(Level.FINE, "Process Switch: {0}", activeContext); } catch (final NonLocalReturn nlr) { - activeContext = commonNLReturn(sender, nlr.getTargetContext(), nlr.getReturnValue()); + activeContext = commonNLReturn(sender, nlr); LogUtils.SCHEDULING.log(Level.FINE, "Non Local Return on top-level: {0}", activeContext); } catch (final NonVirtualReturn nvr) { activeContext = commonReturn(nvr.getCurrentContext(), nvr.getTargetContext(), nvr.getReturnValue()); @@ -124,12 +124,29 @@ private static ContextObject returnTo(final ContextObject activeContext, final A } @TruffleBoundary - private ContextObject commonNLReturn(final AbstractSqueakObject sender, final ContextObject targetContext, final Object returnValue) { + private ContextObject commonNLReturn(final AbstractSqueakObject sender, final NonLocalReturn nlr) { + final ContextObject targetContext = nlr.getTargetContext(); + final Object returnValue = nlr.getReturnValue(); if (!(sender instanceof final ContextObject senderContext)) { assert sender == NilObject.SINGLETON; throw returnToTopLevel(targetContext, returnValue); } ContextObject context = senderContext; + while (context != targetContext) { + if (context.getCodeObject().isUnwindMarked()) { + try { + // TODO: make this better + AboutToReturnNode.create(context.getCodeObject()).executeAboutToReturn(context.getTruffleFrame(), nlr); + } catch (NonVirtualReturn nvr) { + return commonReturn(nvr.getCurrentContext(), nvr.getTargetContext(), nvr.getReturnValue()); + } + } + final AbstractSqueakObject currentSender = context.getSender(); + if (currentSender instanceof final ContextObject o) { + context = o; + } + } + context = senderContext; while (context != targetContext) { final AbstractSqueakObject currentSender = context.getSender(); if (currentSender instanceof final ContextObject o) { From 6e11884baa1d1a52a1707aa11ae90fcb2383334c Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Wed, 3 Jan 2024 14:27:18 +0100 Subject: [PATCH 40/40] Update "Getting Started" section [ci skip] --- README.md | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index ef3c89218..020409dd4 100644 --- a/README.md +++ b/README.md @@ -7,20 +7,11 @@ A [Squeak/Smalltalk][squeak] VM and Polyglot Programming Environment for the [Gr ## Getting Started -1. Download the latest [GraalVM distribution][graalvm_download] for your platform. -2. Use the [GraalVM Updater][graalvm_updater] to install the TruffleSqueak - component for your platform: +1. Download and extract the latest [TruffleSqueak standalone][ts_latest] for your platform. +2. Run the following in a terminal to start TruffleSqueak: ```bash - $GRAALVM_HOME/bin/gu \ - -C https://raw.githubusercontent.com/hpi-swa/trufflesqueak/main/gu-catalog.properties \ - install smalltalk - ``` - -3. You should now be able to run TruffleSqueak: - - ```bash - $GRAALVM_HOME/bin/trufflesqueak + bin/trufflesqueak [