Skip to content

Commit

Permalink
Run test closures with ExecuteTopLevelContextNode
Browse files Browse the repository at this point in the history
  • Loading branch information
fniephaus committed Dec 21, 2023
1 parent 6bacc80 commit cc09aba
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,25 @@
import org.junit.Assume;
import org.junit.BeforeClass;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.MaterializedFrame;

import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException;
import de.hpi.swa.trufflesqueak.interop.LookupMethodByStringNode;
import de.hpi.swa.trufflesqueak.model.ArrayObject;
import de.hpi.swa.trufflesqueak.model.BlockClosureObject;
import de.hpi.swa.trufflesqueak.model.CompiledCodeObject;
import de.hpi.swa.trufflesqueak.model.ContextObject;
import de.hpi.swa.trufflesqueak.model.NativeObject;
import de.hpi.swa.trufflesqueak.model.NilObject;
import de.hpi.swa.trufflesqueak.model.PointersObject;
import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.LINKED_LIST;
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.ExecuteTopLevelContextNode;
import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectReadNode;
import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchUneagerlyNode;
import de.hpi.swa.trufflesqueak.util.DebugUtils;
import de.hpi.swa.trufflesqueak.util.FrameAccess;

public class AbstractSqueakTestCaseWithImage extends AbstractSqueakTestCase {
private static final int SQUEAK_TIMEOUT_SECONDS = 90 * (DebugUtils.UNDER_DEBUG ? 1000 : 1);
Expand Down Expand Up @@ -119,12 +124,9 @@ private static void patchImageForTesting() {
patchMethod("TestCase", "performTest", "performTest [self perform: testSelector asSymbol] on: Error do: [:e | e printVerboseOn: FileStream stderr. e signal]");
}
println("Image ready for testing...");
String testClosureCode = """
final String testClosureCode = """
[:testClass :testSelector |
[ | test |
test := ((Smalltalk at: testClass asSymbol) selector: testSelector asSymbol).
[ test setUp. test performTest ] ensure: [ test tearDown ].
'%s' ]
[ ((Smalltalk at: testClass asSymbol) selector: testSelector asSymbol) runCase. '%s' ]
on: TestFailure, Error
do: [:e | (String streamContents: [:s | e printVerboseOn: s]) withUnixLineEndings ] ]""";
testClosure = (BlockClosureObject) evaluate(String.format(testClosureCode, PASSED_VALUE));
Expand Down Expand Up @@ -251,24 +253,31 @@ private static TestResult extractFailuresAndErrorsFromTestResult(final TestReque
}

private static Object run(final TestRequest request) {
return evaluateClosure(testClosure, request);
return closureValueValue(testClosure, request);
}

private static boolean shouldPass(final TestRequest request) {
return (boolean) evaluateClosure(shouldPassClosure, request);
return (boolean) closureValueValue(shouldPassClosure, request);
}

private static Object evaluateClosure(final BlockClosureObject closure, final TestRequest request) {
private static Object closureValueValue(final BlockClosureObject closure, final TestRequest request) {
context.enter();
try {
return DispatchUneagerlyNode.executeUncached(closureValueValueMethod,
new Object[]{closure, image.asByteString(request.testCase), image.asByteString(request.testSelector)},
NilObject.SINGLETON);
return getDispatchContextNode(closureValueValueMethod, closure, image.asByteString(request.testCase), image.asByteString(request.testSelector)).getCallTarget().call();
} finally {
context.leave();
}
}

private static ExecuteTopLevelContextNode getDispatchContextNode(final CompiledCodeObject method, final Object... receiverAndArguments) {
final Object[] frameArguments = FrameAccess.newWith(NilObject.SINGLETON, null, receiverAndArguments);
final MaterializedFrame frame = Truffle.getRuntime().createMaterializedFrame(frameArguments, method.getFrameDescriptor());
final ContextObject doItContext = ContextObject.create(image, frame, method);
doItContext.setInstructionPointer(method.getInitialPC());
doItContext.setStackPointer(method.getNumTemps());
return ExecuteTopLevelContextNode.create(image, image.getLanguage(), doItContext, false);
}

protected record TestRequest(String testCase, String testSelector) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -231,7 +231,7 @@ public void ensureLoaded() {
Utilities
authorName: 'TruffleSqueak';
setAuthorInitials: 'TruffleSqueak'.
""";
""".formatted(Boolean.toString(options.isTesting));
try {
evaluate(prepareHeadlessImageScript);
} catch (final Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ private static ContextObject returnTo(final ContextObject activeContext, final A
final ContextObject targetContext = (ContextObject) sender;
final ContextObject context;
if (targetContext.isPrimitiveContext()) {
context = (ContextObject) targetContext.getFrameSender(); // skip primitive contexts.
final Object targetContextSender = targetContext.getFrameSender();
if (targetContextSender == NilObject.SINGLETON) {
throw returnToTopLevel(activeContext, returnValue);
}
context = (ContextObject) targetContextSender; // skip primitive contexts.
} else {
context = targetContext;
}
Expand Down Expand Up @@ -187,10 +191,15 @@ private ContextObject commonReturn(final ContextObject startContext, final Conte
}

private static TopLevelReturn returnToTopLevel(final ContextObject targetContext, final Object returnValue) {
assert "DoIt".equals(targetContext.getCodeObject().getCompiledInSelector().asStringUnsafe());
assert isDoItOrTestContext(targetContext);
throw new TopLevelReturn(returnValue);
}

private static boolean isDoItOrTestContext(final ContextObject targetContext) {
final String methodName = targetContext.getCodeObject().toString();
return methodName.endsWith("#DoIt") || methodName.endsWith("#value:value:");
}

private ContextObject sendCannotReturn(final ContextObject startContext, final Object returnValue) {
try {
sendCannotReturnNode.executeSend(startContext.getTruffleFrame(), new Object[]{startContext, returnValue});
Expand Down

0 comments on commit cc09aba

Please sign in to comment.