├── .gitmodules ├── mx.trufflesqueak ├── trufflesqueak-jvm ├── copyrights │ ├── oracle.copyright.hash │ ├── oracle.copyright.star │ ├── oracle.copyright.regex.hash │ └── oracle.copyright.regex.star ├── trufflesqueak-native ├── eclipse-settings │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.jdt.ui.prefs ├── graalvm-25.0.1.patch ├── mvn-settings.xml.template └── mx_trufflesqueak.py ├── src ├── de.hpi.swa.trufflesqueak.tck │ ├── src │ │ └── META-INF │ │ │ └── services │ │ │ └── org.graalvm.polyglot.tck.LanguageProvider │ └── .checkstyle ├── de.hpi.swa.trufflesqueak │ ├── src │ │ ├── META-INF │ │ │ └── native-image │ │ │ │ ├── serialization-config.json │ │ │ │ ├── resource-config.json │ │ │ │ └── native-image.properties │ │ └── de │ │ │ └── hpi │ │ │ └── swa │ │ │ └── trufflesqueak │ │ │ ├── nodes │ │ │ ├── plugins │ │ │ │ ├── package-info.java │ │ │ │ ├── network │ │ │ │ │ ├── package-info.java │ │ │ │ │ ├── Resolver.java │ │ │ │ │ └── SqueakUDPSocket.java │ │ │ │ ├── ffi │ │ │ │ │ └── wrappers │ │ │ │ │ │ ├── IntStorage.java │ │ │ │ │ │ ├── ByteStorage.java │ │ │ │ │ │ ├── LongStorage.java │ │ │ │ │ │ ├── ShortStorage.java │ │ │ │ │ │ └── NativeObjectStorage.java │ │ │ │ ├── SoundCodecPrims.java │ │ │ │ ├── UUIDPlugin.java │ │ │ │ ├── DropPlugin.java │ │ │ │ ├── Win32OSProcessPlugin.java │ │ │ │ ├── SecurityPlugin.java │ │ │ │ └── BMPReadWriterPlugin.java │ │ │ ├── primitives │ │ │ │ ├── impl │ │ │ │ │ └── package-info.java │ │ │ │ ├── SqueakPrimitive.java │ │ │ │ ├── AbstractPrimitiveFactoryHolder.java │ │ │ │ ├── AbstractSingletonPrimitiveNode.java │ │ │ │ └── AbstractPrimitiveNode.java │ │ │ ├── dispatch │ │ │ │ ├── DispatchSelectorNode.java │ │ │ │ ├── AbstractDispatchNode.java │ │ │ │ ├── AbstractDispatchDirectNode.java │ │ │ │ ├── HandlePrimitiveFailedNode.java │ │ │ │ └── CreateDoesNotUnderstandMessageNode.java │ │ │ ├── CacheLimits.java │ │ │ ├── SqueakTypes.java │ │ │ ├── interpreter │ │ │ │ ├── AbstractInterpreterInstrumentableNode.java │ │ │ │ ├── PushToStackNode.java │ │ │ │ └── BytecodeUtils.java │ │ │ ├── process │ │ │ │ ├── GetActiveProcessNode.java │ │ │ │ ├── AddLastLinkToListNode.java │ │ │ │ ├── GetNextActiveContextNode.java │ │ │ │ ├── PutToSleepNode.java │ │ │ │ ├── ResumeProcessNode.java │ │ │ │ ├── TransferToNode.java │ │ │ │ ├── AddLinkToListNode.java │ │ │ │ ├── SignalSemaphoreNode.java │ │ │ │ └── RemoveProcessFromListNode.java │ │ │ ├── accessing │ │ │ │ ├── FloatObjectNodes.java │ │ │ │ ├── SqueakObjectInstSizeNode.java │ │ │ │ ├── ClassObjectNodes.java │ │ │ │ └── SqueakObjectShallowCopyNode.java │ │ │ ├── context │ │ │ │ ├── GetOrCreateContextWithoutFrameNode.java │ │ │ │ └── GetOrCreateContextWithFrameNode.java │ │ │ ├── AbstractRootNode.java │ │ │ ├── DoItRootNode.java │ │ │ ├── AbstractNode.java │ │ │ ├── InheritsFromNode.java │ │ │ ├── LookupMethodNode.java │ │ │ ├── interrupts │ │ │ │ └── CheckForInterruptsFullNode.java │ │ │ └── ResumeContextRootNode.java │ │ │ ├── exceptions │ │ │ ├── ProcessSwitch.java │ │ │ ├── RespecializeException.java │ │ │ └── PrimitiveFailed.java │ │ │ ├── interop │ │ │ ├── SqueakFileDetector.java │ │ │ ├── InteropArray.java │ │ │ ├── ConvertToSqueakNode.java │ │ │ ├── LookupMethodByStringNode.java │ │ │ └── SqueakLanguageView.java │ │ │ ├── model │ │ │ ├── BooleanObject.java │ │ │ ├── EmptyObject.java │ │ │ ├── NilObject.java │ │ │ ├── VariablePointersObject.java │ │ │ ├── CharacterObject.java │ │ │ └── AbstractVariablePointersObject.java │ │ │ ├── util │ │ │ ├── MethodCacheEntry.java │ │ │ ├── OS.java │ │ │ ├── LogUtils.java │ │ │ └── ReflectionUtils.java │ │ │ ├── io │ │ │ ├── SqueakMouse.java │ │ │ ├── SqueakKeyboard.java │ │ │ └── SqueakIOConstants.java │ │ │ ├── SqueakImage.java │ │ │ ├── SqueakLanguage.java │ │ │ └── tools │ │ │ └── SqueakMessageInterceptor.java │ ├── resources │ │ └── trufflesqueak-icon.png │ └── .checkstyle ├── de.hpi.swa.trufflesqueak.ffi.native │ ├── include │ │ ├── sqPlatformSpecific.h │ │ ├── vmCallback.h │ │ └── sqMemoryAccess.h │ └── CMakeLists.txt ├── de.hpi.swa.trufflesqueak.launcher │ ├── .checkstyle │ └── src │ │ └── de │ │ └── hpi │ │ └── swa │ │ └── trufflesqueak │ │ └── launcher │ │ └── SqueakTranscriptForwarder.java ├── de.hpi.swa.trufflesqueak.shared │ ├── .checkstyle │ └── src │ │ └── de │ │ └── hpi │ │ └── swa │ │ └── trufflesqueak │ │ └── shared │ │ ├── SqueakLanguageConfig.java │ │ └── SqueakLanguageOptions.java ├── de.hpi.swa.trufflesqueak.test │ └── .checkstyle └── image-tests │ └── runCuisTests.st ├── docs ├── README.md ├── images.md └── polyglot-api.md ├── .gitignore ├── LICENSE └── CITATION.bib /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/image"] 2 | path = src/image 3 | url = https://github.com/hpi-swa/trufflesqueak.git 4 | branch = image 5 | -------------------------------------------------------------------------------- /mx.trufflesqueak/trufflesqueak-jvm: -------------------------------------------------------------------------------- 1 | DYNAMIC_IMPORTS=/tools 2 | BUILD_TARGETS=TRUFFLESQUEAK_JVM_STANDALONE 3 | GRAALVM_SKIP_ARCHIVE=true 4 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.tck/src/META-INF/services/org.graalvm.polyglot.tck.LanguageProvider: -------------------------------------------------------------------------------- 1 | de.hpi.swa.trufflesqueak.tck.SqueakTCKLanguageProvider -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/META-INF/native-image/serialization-config.json: -------------------------------------------------------------------------------- 1 | { "types": [{ "name": "java.lang.String" }], "lambdaCapturingTypes": [ ] } -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/resources/trufflesqueak-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpi-swa/trufflesqueak/HEAD/src/de.hpi.swa.trufflesqueak/resources/trufflesqueak-icon.png -------------------------------------------------------------------------------- /mx.trufflesqueak/copyrights/oracle.copyright.hash: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | # Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | # 5 | # Licensed under the MIT License. 6 | # 7 | 8 | -------------------------------------------------------------------------------- /mx.trufflesqueak/copyrights/oracle.copyright.star: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | -------------------------------------------------------------------------------- /mx.trufflesqueak/trufflesqueak-native: -------------------------------------------------------------------------------- 1 | COMPONENTS=SubstrateVM 2 | DYNAMIC_IMPORTS=/compiler,/substratevm,/tools 3 | NATIVE_IMAGES=lib:smalltalkvm 4 | GENERATE_DEBUGINFO=false 5 | BUILD_TARGETS=TRUFFLESQUEAK_NATIVE_STANDALONE 6 | GRAALVM_SKIP_ARCHIVE=true 7 | -------------------------------------------------------------------------------- /mx.trufflesqueak/copyrights/oracle.copyright.regex.hash: -------------------------------------------------------------------------------- 1 | #(?:!.*)? 2 | # Copyright \(c\) (\d\d\d\d-)?(\d\d\d\d) Software Architecture Group, Hasso Plattner Institute(?: 3 | # Copyright \(c\) (?:\d\d\d\d-)?\d\d\d\d Oracle and/or its affiliates)* 4 | # 5 | # Licensed under the MIT License\. 6 | # 7 | 8 | .* -------------------------------------------------------------------------------- /mx.trufflesqueak/copyrights/oracle.copyright.regex.star: -------------------------------------------------------------------------------- 1 | \/\* 2 | \* Copyright \(c\) (\d\d\d\d-)?(\d\d\d\d) Software Architecture Group, Hasso Plattner Institute(?: 3 | \* Copyright \(c\) (?:\d\d\d\d-)?\d\d\d\d Oracle and\/or its affiliates)* 4 | \* 5 | \* Licensed under the MIT License\. 6 | \*\/ 7 | .* -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # TruffleSqueak Documentation 2 | 3 | - [Development](development.md) 4 | - [Polyglot API Reference](polyglot-api.md) 5 | - [Image Creation](images.md) 6 | 7 | Please feel free to open a [pull request][pull_request] if you'd like to 8 | contribute. 9 | 10 | [pull_request]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request 11 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.ffi.native/include/sqPlatformSpecific.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | #ifdef _WIN32 9 | # define EXPORT(returnType) extern __declspec(dllexport) returnType 10 | #else 11 | # define EXPORT(returnType) extern returnType 12 | #endif 13 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2024-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | @SuppressPackageWarnings({"truffle-inlining"}) 8 | package de.hpi.swa.trufflesqueak.nodes.plugins; 9 | 10 | import com.oracle.truffle.api.dsl.SuppressPackageWarnings; 11 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2024-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | @SuppressPackageWarnings({"truffle-inlining"}) 8 | package de.hpi.swa.trufflesqueak.nodes.plugins.network; 9 | 10 | import com.oracle.truffle.api.dsl.SuppressPackageWarnings; 11 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2024-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | @SuppressPackageWarnings({"truffle-inlining"}) 8 | package de.hpi.swa.trufflesqueak.nodes.primitives.impl; 9 | 10 | import com.oracle.truffle.api.dsl.SuppressPackageWarnings; 11 | -------------------------------------------------------------------------------- /mx.trufflesqueak/eclipse-settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow=4 2 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon=4 3 | org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow=4 4 | org.eclipse.jdt.core.formatter.alignment_for_assertion_message=4 5 | 6 | # ignore unused imports (minor bugs in code generated by Truffle) 7 | org.eclipse.jdt.core.compiler.problem.unusedImport=ignore -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/SqueakPrimitive.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.primitives; 8 | 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.RetentionPolicy; 11 | 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface SqueakPrimitive { 14 | int[] indices() default {}; 15 | 16 | String[] names() default {}; 17 | } 18 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/exceptions/ProcessSwitch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.exceptions; 8 | 9 | import com.oracle.truffle.api.nodes.ControlFlowException; 10 | 11 | public final class ProcessSwitch extends ControlFlowException { 12 | public static final ProcessSwitch SINGLETON = new ProcessSwitch(); 13 | private static final long serialVersionUID = 1L; 14 | 15 | private ProcessSwitch() { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/META-INF/native-image/resource-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "includes": [ 4 | { 5 | "pattern": "\\QMETA-INF/services/com.oracle.truffle.api.TruffleLanguage$Provider\\E" 6 | }, 7 | { 8 | "pattern": "\\QMETA-INF/services/com.oracle.truffle.api.instrumentation.TruffleInstrument$Provider\\E" 9 | }, 10 | { "pattern": "\\QMETA-INF/services/java.nio.file.spi.FileSystemProvider\\E" }, 11 | { "pattern": "\\Qcom/oracle/truffle/nfi/backend/libffi/LibFFILanguage.class\\E" } 12 | ] 13 | }, 14 | "bundles": [{ "name": "sun.awt.resources.awt", "classNames": ["sun.awt.resources.awt"] }] 15 | } -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.tck/.checkstyle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/.checkstyle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/DispatchSelectorNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.dispatch; 8 | 9 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 10 | 11 | public abstract class DispatchSelectorNode { 12 | protected static final boolean checkArgumentCount(final CompiledCodeObject method, final int expectedNumArgs) { 13 | assert method.getNumArgs() == expectedNumArgs : "Unexpected number of arguments: " + method.getNumArgs(); 14 | return true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.launcher/.checkstyle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.shared/.checkstyle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.test/.checkstyle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/META-INF/native-image/native-image.properties: -------------------------------------------------------------------------------- 1 | # This file contains native-image arguments needed to build TruffleSqueak 2 | # 3 | 4 | Requires = language:nfi 5 | 6 | JavaArgs = -Djava.awt.headless=false 7 | 8 | Args = --initialize-at-build-time=de.hpi.swa.trufflesqueak \ 9 | --initialize-at-run-time=com.sun.imageio.plugins,com.sun.java.swing,java.applet,java.awt,javax.accessibility,com.sun.java.accessibility,javax.imageio,javax.swing,sun.awt,sun.datatransfer,sun.font,sun.java2d,sun.swing,com.sun.beans.util \ 10 | --add-exports=java.base/jdk.internal.module=de.hpi.swa.trufflesqueak \ 11 | -H:MaxRuntimeCompileMethods=5000 \ 12 | --link-at-build-time \ 13 | -Dorg.graalvm.launcher.relative.smalltalk.home\=.. \ 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | .DS_Store 3 | 4 | # Editors 5 | *~ 6 | 7 | # Eclipse 8 | .classpath 9 | .project 10 | .settings 11 | .factorypath 12 | workingsets.xml 13 | 14 | # NetBeans 15 | nbproject 16 | build.xml 17 | 18 | # IntelliJ 19 | .idea 20 | *.iml 21 | 22 | # Python 23 | *.pyc 24 | 25 | # mx 26 | /.mx 27 | /mx.trufflesqueak/.pydevproject 28 | /mx.trufflesqueak/env 29 | /mx.trufflesqueak/eclipse-launches 30 | /mx.trufflesqueak/mvn-settings.xml 31 | /mxbuild 32 | /TRUFFLESQUEAK*.dist 33 | /coverage 34 | jacoco.exec 35 | 36 | # Diagnostic output directory 37 | dumps/ 38 | graal_dumps/ 39 | 40 | # Profile output directory 41 | profiles/ 42 | 43 | # TruffleSqueak 44 | images 45 | lib/**/*.dll 46 | lib/**/*.dylib 47 | lib/**/*.so 48 | trufflesqueak*.zip 49 | trufflesqueak*.jar 50 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/AbstractPrimitiveFactoryHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.primitives; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | import com.oracle.truffle.api.dsl.NodeFactory; 13 | 14 | public abstract class AbstractPrimitiveFactoryHolder { 15 | public abstract List> getFactories(); 16 | 17 | public List getSingletonPrimitives() { 18 | return Collections.emptyList(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/AbstractDispatchNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.dispatch; 8 | 9 | import de.hpi.swa.trufflesqueak.model.NativeObject; 10 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 11 | 12 | public abstract class AbstractDispatchNode extends AbstractNode { 13 | protected final NativeObject selector; 14 | 15 | AbstractDispatchNode(final NativeObject selector) { 16 | this.selector = selector; 17 | } 18 | 19 | @Override 20 | public final String toString() { 21 | return "send: " + selector.toString(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/CacheLimits.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | public final class CacheLimits { 10 | public static final int EXECUTE_METHOD_CACHE_LIMIT = 4; 11 | public static final int INDIRECT_PRIMITIVE_CACHE_LIMIT = 2; 12 | public static final int INLINE_BLOCK_CACHE_LIMIT = 4; 13 | public static final int INLINE_METHOD_CACHE_LIMIT = 4; 14 | public static final int NEW_CACHE_LIMIT = 3; 15 | public static final int PERFORM_SELECTOR_CACHE_LIMIT = 4; 16 | public static final int POINTERS_LAYOUT_CACHE_LIMIT = 4; 17 | public static final int POINTERS_VARIABLE_PART_CACHE_LIMIT = 3; 18 | } 19 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/AbstractSingletonPrimitiveNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.primitives; 8 | 9 | import com.oracle.truffle.api.nodes.Node; 10 | import com.oracle.truffle.api.nodes.UnadoptableNode; 11 | 12 | public abstract class AbstractSingletonPrimitiveNode extends AbstractPrimitiveNode implements UnadoptableNode { 13 | @Override 14 | public final Node copy() { 15 | return this; 16 | } 17 | 18 | @Override 19 | public final Node deepCopy() { 20 | return this; 21 | } 22 | 23 | @Override 24 | public final boolean needsFrame() { 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/AbstractDispatchDirectNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.dispatch; 8 | 9 | import com.oracle.truffle.api.Assumption; 10 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; 11 | 12 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 13 | 14 | abstract class AbstractDispatchDirectNode extends AbstractNode { 15 | @CompilationFinal(dimensions = 1) private final Assumption[] assumptions; 16 | 17 | AbstractDispatchDirectNode(final Assumption[] assumptions) { 18 | this.assumptions = assumptions; 19 | } 20 | 21 | public final Assumption[] getAssumptions() { 22 | return assumptions; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/SqueakTypes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | import com.oracle.truffle.api.dsl.TypeCast; 10 | import com.oracle.truffle.api.dsl.TypeCheck; 11 | import com.oracle.truffle.api.dsl.TypeSystem; 12 | 13 | import de.hpi.swa.trufflesqueak.model.NilObject; 14 | 15 | @TypeSystem 16 | public class SqueakTypes { 17 | @TypeCheck(NilObject.class) 18 | public static final boolean isNilObject(final Object value) { 19 | return value == NilObject.SINGLETON; 20 | } 21 | 22 | @TypeCast(NilObject.class) 23 | public static final NilObject asNilObject(final Object value) { 24 | assert isNilObject(value); 25 | return NilObject.SINGLETON; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.ffi.native/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | # Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | # 5 | # Licensed under the MIT License. 6 | # 7 | 8 | cmake_minimum_required(VERSION 3.22) 9 | project(de.hpi.swa.trufflesqueak.ffi.native) 10 | 11 | if(NOT DEFINED SRC_DIR) 12 | set(SRC_DIR "${CMAKE_SOURCE_DIR}") 13 | endif() 14 | 15 | set(CMAKE_C_STANDARD 11) 16 | 17 | # don't install into the system but into the MX project's output dir 18 | set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}) 19 | 20 | set(CAPI_SRC "${SRC_DIR}/src") 21 | 22 | function(build_library LIB_NAME SOURCE_FILE) 23 | add_library(${LIB_NAME} SHARED ${SOURCE_FILE}) 24 | target_include_directories(${LIB_NAME} PUBLIC include) 25 | endfunction() 26 | 27 | 28 | build_library(InterpreterProxy "${CAPI_SRC}/InterpreterProxy.c") 29 | build_library(SqueakFFIPrims "${CAPI_SRC}/SqueakFFIPrims.c") -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/exceptions/RespecializeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.exceptions; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives; 10 | import com.oracle.truffle.api.nodes.SlowPathException; 11 | 12 | public final class RespecializeException extends SlowPathException { 13 | public static final RespecializeException SINGLETON = new RespecializeException(); 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | private RespecializeException() { 18 | } 19 | 20 | public static RespecializeException transferToInterpreterInvalidateAndThrow() throws RespecializeException { 21 | CompilerDirectives.transferToInterpreterAndInvalidate(); 22 | throw SINGLETON; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/wrappers/IntStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.ffi.wrappers; 8 | 9 | import de.hpi.swa.trufflesqueak.util.UnsafeUtils; 10 | 11 | final class IntStorage extends NativeObjectStorage { 12 | private final int[] storage; 13 | 14 | IntStorage(final int[] storage) { 15 | this.storage = storage; 16 | } 17 | 18 | @Override 19 | public int byteSizeOf() { 20 | return storage.length * Integer.BYTES; 21 | } 22 | 23 | @Override 24 | protected long allocate() { 25 | return UnsafeUtils.allocateNativeInts(storage); 26 | } 27 | 28 | @Override 29 | public void cleanup() { 30 | UnsafeUtils.copyNativeIntsBackAndFree(nativeAddress, storage); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/wrappers/ByteStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.ffi.wrappers; 8 | 9 | import de.hpi.swa.trufflesqueak.util.UnsafeUtils; 10 | 11 | final class ByteStorage extends NativeObjectStorage { 12 | private final byte[] storage; 13 | 14 | ByteStorage(final byte[] storage) { 15 | this.storage = storage; 16 | } 17 | 18 | @Override 19 | public int byteSizeOf() { 20 | return storage.length * Byte.BYTES; 21 | } 22 | 23 | @Override 24 | protected long allocate() { 25 | return UnsafeUtils.allocateNativeBytes(storage); 26 | } 27 | 28 | @Override 29 | public void cleanup() { 30 | UnsafeUtils.copyNativeBytesBackAndFree(nativeAddress, storage); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/wrappers/LongStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.ffi.wrappers; 8 | 9 | import de.hpi.swa.trufflesqueak.util.UnsafeUtils; 10 | 11 | final class LongStorage extends NativeObjectStorage { 12 | private final long[] storage; 13 | 14 | LongStorage(final long[] storage) { 15 | this.storage = storage; 16 | } 17 | 18 | @Override 19 | public int byteSizeOf() { 20 | return storage.length * Long.BYTES; 21 | } 22 | 23 | @Override 24 | protected long allocate() { 25 | return UnsafeUtils.allocateNativeLongs(storage); 26 | } 27 | 28 | @Override 29 | public void cleanup() { 30 | UnsafeUtils.copyNativeLongsBackAndFree(nativeAddress, storage); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/wrappers/ShortStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.ffi.wrappers; 8 | 9 | import de.hpi.swa.trufflesqueak.util.UnsafeUtils; 10 | 11 | final class ShortStorage extends NativeObjectStorage { 12 | private final short[] storage; 13 | 14 | ShortStorage(final short[] storage) { 15 | this.storage = storage; 16 | } 17 | 18 | @Override 19 | public int byteSizeOf() { 20 | return storage.length * Short.BYTES; 21 | } 22 | 23 | @Override 24 | protected long allocate() { 25 | return UnsafeUtils.allocateNativeShorts(storage); 26 | } 27 | 28 | @Override 29 | public void cleanup() { 30 | UnsafeUtils.copyNativeShortsBackAndFree(nativeAddress, storage); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/AbstractPrimitiveNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.primitives; 8 | 9 | import com.oracle.truffle.api.CompilerAsserts; 10 | 11 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 12 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 13 | 14 | public abstract class AbstractPrimitiveNode extends AbstractNode implements Primitive { 15 | public boolean acceptsMethod(@SuppressWarnings("unused") final CompiledCodeObject method) { 16 | CompilerAsserts.neverPartOfCompilation(); 17 | return true; 18 | } 19 | 20 | public boolean needsFrame() { 21 | return false; 22 | } 23 | 24 | public abstract static class AbstractPrimitiveWithFrameNode extends AbstractPrimitiveNode { 25 | @Override 26 | public final boolean needsFrame() { 27 | return true; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/interop/SqueakFileDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.interop; 8 | 9 | import java.nio.charset.Charset; 10 | 11 | import com.oracle.truffle.api.TruffleFile; 12 | 13 | import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; 14 | 15 | public final class SqueakFileDetector implements TruffleFile.FileTypeDetector { 16 | 17 | @Override 18 | public String findMimeType(final TruffleFile file) { 19 | final String fileName = file.getName(); 20 | if (fileName == null) { 21 | return null; 22 | } else if (fileName.endsWith(".image")) { 23 | return SqueakLanguageConfig.MIME_TYPE; 24 | } else if (fileName.endsWith(".st")) { 25 | return SqueakLanguageConfig.ST_MIME_TYPE; 26 | } else { 27 | return null; 28 | } 29 | } 30 | 31 | @Override 32 | public Charset findEncoding(final TruffleFile file) { 33 | return null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interpreter/AbstractInterpreterInstrumentableNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.interpreter; 8 | 9 | import com.oracle.truffle.api.frame.VirtualFrame; 10 | import com.oracle.truffle.api.instrumentation.GenerateWrapper; 11 | import com.oracle.truffle.api.instrumentation.InstrumentableNode; 12 | import com.oracle.truffle.api.instrumentation.ProbeNode; 13 | 14 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 15 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 16 | 17 | @GenerateWrapper 18 | public abstract class AbstractInterpreterInstrumentableNode extends AbstractNode implements InstrumentableNode { 19 | 20 | public abstract Object execute(VirtualFrame frame, int startPC, int startSP); 21 | 22 | public abstract CompiledCodeObject getCodeObject(); 23 | 24 | @Override 25 | public WrapperNode createWrapper(final ProbeNode probeNode) { 26 | return new AbstractInterpreterInstrumentableNodeWrapper(this, probeNode); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 4 | Copyright (c) 2021-2025 Oracle and/or its affiliates 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /mx.trufflesqueak/eclipse-settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | sp_cleanup.add_missing_annotations=true 2 | sp_cleanup.add_missing_override_annotations=true 3 | sp_cleanup.add_missing_override_annotations_interface_methods=true 4 | sp_cleanup.convert_functional_interfaces=true 5 | sp_cleanup.format_source_code=true 6 | sp_cleanup.make_local_variable_final=true 7 | sp_cleanup.make_parameters_final=true 8 | sp_cleanup.make_variable_declarations_final=true 9 | sp_cleanup.never_use_parentheses_in_expressions=true 10 | sp_cleanup.on_save_use_additional_actions=true 11 | sp_cleanup.organize_imports=true 12 | sp_cleanup.remove_redundant_semicolons=true 13 | sp_cleanup.remove_redundant_type_arguments=true 14 | sp_cleanup.remove_trailing_whitespaces=true 15 | sp_cleanup.remove_trailing_whitespaces_all=true 16 | sp_cleanup.remove_trailing_whitespaces_ignore_empty=false 17 | sp_cleanup.remove_unnecessary_casts=true 18 | sp_cleanup.remove_unused_imports=true 19 | sp_cleanup.use_lambda=true 20 | sp_cleanup.use_parentheses_in_expressions=true 21 | sp_cleanup.use_this_for_non_static_field_access=true 22 | sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true 23 | sp_cleanup.use_this_for_non_static_method_access=true 24 | sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true -------------------------------------------------------------------------------- /mx.trufflesqueak/graalvm-25.0.1.patch: -------------------------------------------------------------------------------- 1 | diff --git a/sdk/mx.sdk/suite.py b/sdk/mx.sdk/suite.py 2 | index 79c97354020..9518d41f5db 100644 3 | --- a/sdk/mx.sdk/suite.py 4 | +++ b/sdk/mx.sdk/suite.py 5 | @@ -520,6 +520,8 @@ suite = { 6 | "javaCompliance" : "17+", 7 | "workingSets" : "Truffle,Tools", 8 | "checkstyle" : "org.graalvm.word", 9 | + # disable SpotBugs due to incorrect lazy initialization 10 | + "spotbugs" : "false", 11 | "graalCompilerSourceEdition": "ignore", 12 | }, 13 | "org.graalvm.launcher.test" : { 14 | diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java 15 | index 10b976c323e..18e3fd6a8a8 100644 16 | --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java 17 | +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java 18 | @@ -175,7 +175,7 @@ public final class NodeUtil { 19 | current = current.getParent(); 20 | } while (current != null); 21 | 22 | - if (!(prev instanceof ExecutableNode)) { 23 | + if (prev.isAdoptable() && !(prev instanceof ExecutableNode)) { 24 | failNotAdopted(node, prev); 25 | } 26 | return true; 27 | -------------------------------------------------------------------------------- /mx.trufflesqueak/mvn-settings.xml.template: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | github 10 | 11 | 12 | 13 | 14 | github 15 | 16 | 17 | central 18 | https://repo1.maven.org/maven2 19 | 20 | 21 | github 22 | https://maven.pkg.github.com/hpi-swa/trufflesqueak 23 | 24 | true 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | github 34 | {USERNAME} 35 | {TOKEN} 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/BooleanObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.model; 8 | 9 | import de.hpi.swa.trufflesqueak.image.SqueakImageConstants; 10 | import de.hpi.swa.trufflesqueak.image.SqueakImageWriter; 11 | 12 | public final class BooleanObject { 13 | public static final boolean FALSE = false; 14 | public static final boolean TRUE = true; 15 | public static final long FALSE_SQUEAK_HASH = 2L; 16 | public static final long TRUE_SQUEAK_HASH = 3L; 17 | 18 | private BooleanObject() { 19 | } 20 | 21 | public static boolean wrap(final boolean object) { 22 | return object; /** avoid check since true->true and false->false. */ 23 | } 24 | 25 | public static void write(final SqueakImageWriter writer, final boolean value) { 26 | if (value) { 27 | writer.writeObjectHeader(0, TRUE_SQUEAK_HASH, writer.getImage().trueClass, 0); 28 | } else { 29 | writer.writeObjectHeader(0, FALSE_SQUEAK_HASH, writer.getImage().falseClass, 0); 30 | } 31 | writer.writePadding(SqueakImageConstants.WORD_SIZE); /* Write alignment word. */ 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/GetActiveProcessNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.nodes.Node; 14 | 15 | import de.hpi.swa.trufflesqueak.model.PointersObject; 16 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; 17 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 18 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 19 | 20 | @GenerateInline 21 | @GenerateCached(false) 22 | public abstract class GetActiveProcessNode extends AbstractNode { 23 | public abstract PointersObject execute(Node node); 24 | 25 | @Specialization 26 | protected static final PointersObject getActiveProcess(final Node node, 27 | @Cached final AbstractPointersObjectReadNode readNode) { 28 | return readNode.executePointers(node, getContext(node).getScheduler(), PROCESS_SCHEDULER.ACTIVE_PROCESS); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.ffi.native/include/vmCallback.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | #include 8 | #include "sqMemoryAccess.h" 9 | 10 | //////////// from here on: copied from 11 | //////////// https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/ec421b99cf41fc5f2f5fb734b536d6233cdde809/src/spur64.cog/vmCallback.h 12 | 13 | /* Automatically generated by 14 | CCodeGeneratorGlobalStructure VMMaker.oscog-eem.3150 uuid: 832f44e4-6d22-4545-ae94-d8453b49d54f 15 | */ 16 | 17 | #define VM_CALLBACK_INC 1 18 | 19 | typedef struct _VMCallbackContext { 20 | void *thunkp; 21 | sqIntptr_t *stackp; 22 | sqIntptr_t *intregargsp; 23 | double *floatregargsp; 24 | void *savedCStackPointer; 25 | void *savedCFramePointer; 26 | union { 27 | sqIntptr_t valword; 28 | struct { int low, high; } valleint64; 29 | struct { int high, low; } valbeint64; 30 | double valflt64; 31 | struct { void *addr; sqIntptr_t size; } valstruct; 32 | }rvs; 33 | void *savedMostRecentCallbackContext; 34 | jmp_buf trampoline; 35 | jmp_buf savedReenterInterpreter; 36 | } VMCallbackContext; 37 | 38 | /* The callback return type codes */ 39 | #define retword 1 40 | #define retword64 2 41 | #define retdouble 3 42 | #define retstruct 4 -------------------------------------------------------------------------------- /docs/images.md: -------------------------------------------------------------------------------- 1 | # Images for TruffleSqueak 2 | 3 | ## TruffleSqueak Image Creation 4 | 5 | Run the following in a workspace, then save and quit the image: 6 | 7 | ```smalltalk 8 | Metacello new 9 | baseline: 'TruffleSqueak'; 10 | repository: 'github://hpi-swa/trufflesqueak:image/src'; 11 | load: #('tests'). 12 | Metacello new 13 | baseline: 'AWFYBenchmarks'; 14 | repository: 'github://hpi-swa/trufflesqueak:image-awfy/src'; 15 | load. 16 | (Smalltalk at: #TruffleSqueakUtilities) setUpImage. 17 | ``` 18 | 19 | ## TruffleSqueak Test Image Creation 20 | 21 | Run the following in a workspace, then save and quit the image: 22 | 23 | ```smalltalk 24 | Metacello new 25 | baseline: 'TruffleSqueak'; 26 | repository: 'github://hpi-swa/trufflesqueak:image/src'; 27 | load: #('tests'). 28 | (Smalltalk at: #TruffleSqueakUtilities) setUpTestImage. 29 | ``` 30 | 31 | ## Cuis Test Image Creation 32 | 33 | Run the following in a [Cuis-Smalltalk-Dev](https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev) checkout: 34 | 35 | ```bash 36 | ./CuisVM.app/Contents/MacOS/Squeak CuisImage/Cuis?.?-????.image -d "\ 37 | Utilities classPool at: #AuthorName put: 'TruffleSqueak'. 38 | Utilities classPool at: #AuthorInitials put: 'TS'. 39 | ChangeSet installNewUpdates. 40 | CodePackageFile installPackage: DirectoryEntry currentDirectory // 'Packages/BaseImageTests.pck.st'. 41 | ChangeSet fileIn: DirectoryEntry currentDirectory // '.ContinuousIntegrationScripts/TestResultConsolePrinter.st'. 42 | Smalltalk saveAndQuit. 43 | " 44 | ``` 45 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/HandlePrimitiveFailedNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.dispatch; 8 | 9 | import com.oracle.truffle.api.dsl.NeverDefault; 10 | import com.oracle.truffle.api.nodes.UnadoptableNode; 11 | 12 | import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; 13 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 14 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 15 | 16 | abstract class HandlePrimitiveFailedNode extends AbstractNode implements UnadoptableNode { 17 | private static final HandlePrimitiveFailedNode STORE_INSTANCE = new HandlePrimitiveFailedNode() { 18 | @Override 19 | protected void execute(final PrimitiveFailed pf) { 20 | getContext().setPrimFailCode(pf); 21 | } 22 | }; 23 | 24 | private static final HandlePrimitiveFailedNode NOP_INSTANCE = new HandlePrimitiveFailedNode() { 25 | @Override 26 | protected void execute(final PrimitiveFailed pf) { 27 | // Nothing to do 28 | } 29 | }; 30 | 31 | @NeverDefault 32 | public static final HandlePrimitiveFailedNode create(final CompiledCodeObject method) { 33 | return method.hasStoreIntoTemp1AfterCallPrimitive() ? STORE_INSTANCE : NOP_INSTANCE; 34 | } 35 | 36 | protected abstract void execute(PrimitiveFailed pf); 37 | } 38 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/EmptyObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.model; 8 | 9 | import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; 10 | import de.hpi.swa.trufflesqueak.image.SqueakImageChunk; 11 | import de.hpi.swa.trufflesqueak.image.SqueakImageWriter; 12 | 13 | public final class EmptyObject extends AbstractSqueakObjectWithClassAndHash { 14 | 15 | public EmptyObject(final SqueakImageChunk chunk) { 16 | super(chunk); 17 | } 18 | 19 | public EmptyObject(final ClassObject classObject) { 20 | super(classObject); 21 | } 22 | 23 | public EmptyObject(final EmptyObject original) { 24 | super(original); 25 | } 26 | 27 | @Override 28 | public void fillin(final SqueakImageChunk chunk) { 29 | // Nothing to do. 30 | } 31 | 32 | @Override 33 | public int instsize() { 34 | return 0; 35 | } 36 | 37 | @Override 38 | public int size() { 39 | return 0; 40 | } 41 | 42 | public void become(final EmptyObject other) { 43 | becomeOtherClass(other); 44 | } 45 | 46 | @Override 47 | public void write(final SqueakImageWriter writer) { 48 | if (writeHeader(writer)) { 49 | throw SqueakException.create("Empty objects should not have any slots:", this); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SoundCodecPrims.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins; 8 | 9 | import java.util.List; 10 | 11 | import com.oracle.truffle.api.dsl.GenerateNodeFactory; 12 | import com.oracle.truffle.api.dsl.NodeFactory; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | 15 | import de.hpi.swa.trufflesqueak.model.NilObject; 16 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; 17 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; 18 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive0; 19 | import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; 20 | 21 | public final class SoundCodecPrims extends AbstractPrimitiveFactoryHolder { 22 | 23 | @GenerateNodeFactory 24 | @SqueakPrimitive(names = "primitiveGSMNewState") 25 | protected abstract static class PrimGSMNewStateNode extends AbstractPrimitiveNode implements Primitive0 { 26 | @Specialization 27 | protected static final Object doFakeNewState(@SuppressWarnings("unused") final Object receiver) { 28 | return NilObject.SINGLETON; 29 | } 30 | } 31 | 32 | @Override 33 | public List> getFactories() { 34 | return SoundCodecPrimsFactory.getFactories(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interpreter/PushToStackNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.interpreter; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives; 10 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; 11 | import com.oracle.truffle.api.dsl.NeverDefault; 12 | import com.oracle.truffle.api.frame.VirtualFrame; 13 | 14 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.CONTEXT; 15 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 16 | import de.hpi.swa.trufflesqueak.util.FrameAccess; 17 | 18 | public final class PushToStackNode extends AbstractNode { 19 | @CompilationFinal private int stackPointer = -1; 20 | @CompilationFinal private int stackSlot = -1; 21 | 22 | @NeverDefault 23 | public static PushToStackNode create() { 24 | return new PushToStackNode(); 25 | } 26 | 27 | public void execute(final VirtualFrame frame, final Object value) { 28 | if (stackPointer == -1) { 29 | CompilerDirectives.transferToInterpreterAndInvalidate(); 30 | stackPointer = FrameAccess.getStackPointer(frame) + 1; 31 | assert stackPointer <= CONTEXT.MAX_STACK_SIZE : "Bad stack pointer"; 32 | stackSlot = FrameAccess.toStackSlotIndex(frame, stackPointer - 1); 33 | } 34 | FrameAccess.setStackPointer(frame, stackPointer); 35 | FrameAccess.setSlotValue(frame, stackSlot, value); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/MethodCacheEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.util; 8 | 9 | import com.oracle.truffle.api.CompilerAsserts; 10 | 11 | import de.hpi.swa.trufflesqueak.model.ClassObject; 12 | import de.hpi.swa.trufflesqueak.model.NativeObject; 13 | 14 | public final class MethodCacheEntry { 15 | private ClassObject classObject; 16 | private NativeObject selector; 17 | private Object result; 18 | 19 | public ClassObject getClassObject() { 20 | return classObject; 21 | } 22 | 23 | public Object getSelector() { 24 | return selector; 25 | } 26 | 27 | public Object getResult() { 28 | return result; 29 | } 30 | 31 | public void setResult(final Object object) { 32 | result = object; 33 | } 34 | 35 | public void freeAndRelease() { 36 | selector = null; /* Mark it free. */ 37 | result = null; /* Release the method. */ 38 | } 39 | 40 | public MethodCacheEntry reuseFor(final ClassObject lookupClass, final NativeObject lookupSelector) { 41 | classObject = lookupClass; 42 | selector = lookupSelector; 43 | result = null; 44 | return this; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | CompilerAsserts.neverPartOfCompilation(); 50 | return "MethodCache[" + classObject + "/" + selector + "/" + result + "]" + " @" + Integer.toHexString(hashCode()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /CITATION.bib: -------------------------------------------------------------------------------- 1 | @inproceedings{10.1145/3357390.3361024, 2 | author = {Niephaus, Fabio and Felgentreff, Tim and Hirschfeld, Robert}, 3 | title = {GraalSqueak: Toward a Smalltalk-Based Tooling Platform for Polyglot Programming}, 4 | year = {2019}, 5 | isbn = {9781450369770}, 6 | publisher = {Association for Computing Machinery}, 7 | address = {New York, NY, USA}, 8 | url = {https://doi.org/10.1145/3357390.3361024}, 9 | doi = {10.1145/3357390.3361024}, 10 | abstract = {Polyglot programming provides software developers with a broader choice in terms of 11 | software libraries and frameworks available for building applications. Previous research 12 | and engineering activities have focused on language interoperability and the design 13 | and implementation of fast polyglot runtimes. To make polyglot programming more approachable 14 | for developers, novel software development tools are needed that help them build polyglot 15 | applications. We believe a suitable prototyping platform helps to more quickly evaluate 16 | new ideas for such tools. In this paper we present GraalSqueak, a Squeak/Smalltalk 17 | virtual machine implementation for the GraalVM. We report our experience implementing 18 | GraalSqueak, evaluate the performance of the language and the programming environment, 19 | and discuss how the system can be used as a tooling platform for polyglot programming.}, 20 | booktitle = {Proceedings of the 16th ACM SIGPLAN International Conference on Managed Programming Languages and Runtimes}, 21 | pages = {14–26}, 22 | numpages = {13}, 23 | keywords = {virtual machines, GraalVM, Squeak/Smalltalk, polyglot programming, tools, Truffle, live development}, 24 | location = {Athens, Greece}, 25 | series = {MPLR 2019} 26 | } 27 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/interop/InteropArray.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.interop; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; 10 | import com.oracle.truffle.api.interop.InteropLibrary; 11 | import com.oracle.truffle.api.interop.InvalidArrayIndexException; 12 | import com.oracle.truffle.api.interop.TruffleObject; 13 | import com.oracle.truffle.api.library.ExportLibrary; 14 | import com.oracle.truffle.api.library.ExportMessage; 15 | 16 | @ExportLibrary(InteropLibrary.class) 17 | public final class InteropArray implements TruffleObject { 18 | @CompilationFinal(dimensions = 1) private final Object[] keys; 19 | 20 | public InteropArray(final Object[] keys) { 21 | this.keys = keys; 22 | } 23 | 24 | @SuppressWarnings("static-method") 25 | @ExportMessage 26 | public boolean hasArrayElements() { 27 | return true; 28 | } 29 | 30 | @ExportMessage 31 | protected boolean isArrayElementReadable(final long index) { 32 | return index >= 0 && index < keys.length; 33 | } 34 | 35 | @ExportMessage 36 | protected long getArraySize() { 37 | return keys.length; 38 | } 39 | 40 | @ExportMessage 41 | protected Object readArrayElement(final long index) throws InvalidArrayIndexException { 42 | if (!isArrayElementReadable(index)) { 43 | throw InvalidArrayIndexException.create(index); 44 | } 45 | return keys[(int) index]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/accessing/FloatObjectNodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.accessing; 8 | 9 | import com.oracle.truffle.api.dsl.GenerateCached; 10 | import com.oracle.truffle.api.dsl.GenerateInline; 11 | import com.oracle.truffle.api.dsl.GenerateUncached; 12 | import com.oracle.truffle.api.dsl.ImportStatic; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.model.FloatObject; 17 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 18 | import de.hpi.swa.trufflesqueak.nodes.accessing.FloatObjectNodesFactory.FloatObjectNormalizeNodeGen; 19 | 20 | public final class FloatObjectNodes { 21 | 22 | @GenerateInline 23 | @GenerateUncached 24 | @GenerateCached(false) 25 | @ImportStatic(Double.class) 26 | public abstract static class FloatObjectNormalizeNode extends AbstractNode { 27 | 28 | public static FloatObjectNormalizeNode getUncached() { 29 | return FloatObjectNormalizeNodeGen.getUncached(); 30 | } 31 | 32 | public abstract Object execute(Node node, double value); 33 | 34 | @Specialization(guards = "isFinite(value)") 35 | protected static final double doFinite(final double value) { 36 | return value; 37 | } 38 | 39 | @Specialization(guards = "!isFinite(value)") 40 | protected static final FloatObject doNaNOrInfinite(final double value) { 41 | return new FloatObject(value); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/OS.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.util; 8 | 9 | import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; 10 | 11 | public enum OS { 12 | Linux, 13 | macOS, 14 | Windows; 15 | 16 | private static final OS THE_OS = findOS(); 17 | 18 | private static OS findOS() { 19 | final String name = System.getProperty("os.name"); 20 | if (name.equals("Linux")) { 21 | return Linux; 22 | } 23 | if (name.equals("Mac OS X") || name.equals("Darwin")) { 24 | return macOS; 25 | } 26 | if (name.startsWith("Windows")) { 27 | return Windows; 28 | } 29 | throw SqueakException.create("Unsupported Platform: " + name); 30 | } 31 | 32 | public static String findSqueakOSName() { 33 | return switch (THE_OS) { 34 | case macOS -> "Mac OS"; 35 | case Windows -> "Win32"; 36 | case Linux -> "unix"; 37 | }; 38 | } 39 | 40 | public static String findWindowSystemName() { 41 | return switch (THE_OS) { 42 | case macOS -> "Aqua"; 43 | case Windows -> "Windows"; 44 | case Linux -> "X11"; 45 | }; 46 | } 47 | 48 | public static boolean isLinux() { 49 | return THE_OS == Linux; 50 | } 51 | 52 | public static boolean isMacOS() { 53 | return THE_OS == macOS; 54 | } 55 | 56 | public static boolean isWindows() { 57 | return THE_OS == Windows; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/dispatch/CreateDoesNotUnderstandMessageNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.dispatch; 8 | 9 | import com.oracle.truffle.api.dsl.Bind; 10 | import com.oracle.truffle.api.dsl.Cached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.nodes.Node; 14 | 15 | import de.hpi.swa.trufflesqueak.model.ClassObject; 16 | import de.hpi.swa.trufflesqueak.model.NativeObject; 17 | import de.hpi.swa.trufflesqueak.model.PointersObject; 18 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 19 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 20 | import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectClassNode; 21 | 22 | @GenerateInline(false) 23 | abstract class CreateDoesNotUnderstandMessageNode extends AbstractNode { 24 | public abstract PointersObject execute(NativeObject selector, Object receiver, Object[] arguments); 25 | 26 | @Specialization 27 | protected static final PointersObject doCreate(final NativeObject selector, final Object receiver, final Object[] arguments, 28 | @Bind final Node node, 29 | @Cached(inline = true) final AbstractPointersObjectWriteNode writeNode, 30 | @Cached(inline = true) final SqueakObjectClassNode classNode) { 31 | final ClassObject receiverClass = classNode.executeLookup(node, receiver); 32 | return getContext(node).newMessage(writeNode, node, selector, receiverClass, arguments); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.shared/src/de/hpi/swa/trufflesqueak/shared/SqueakLanguageConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.shared; 8 | 9 | public final class SqueakLanguageConfig { 10 | public static final String ID = "smalltalk"; 11 | public static final String IMAGE_SOURCE_NAME = ""; 12 | public static final String IMPLEMENTATION_NAME = "TruffleSqueak"; 13 | public static final String MIME_TYPE = "application/x-smalltalk"; 14 | public static final String NAME = "Squeak/Smalltalk"; 15 | public static final String ST_MIME_TYPE = "text/x-smalltalk"; 16 | public static final String VERSION = "25.0.1"; // sync with Truffle import 17 | public static final String WEBSITE = "https://github.com/hpi-swa/trufflesqueak"; 18 | private static final String IMAGE_VERSION = VERSION; // on release: `VERSION;` 19 | 20 | public static final String[][] SUPPORTED_IMAGES = { 21 | {"TruffleSqueak image (" + IMAGE_VERSION + ") (recommended)", 22 | "https://github.com/hpi-swa/trufflesqueak/releases/download/" + IMAGE_VERSION + "/TruffleSqueakImage-" + IMAGE_VERSION + ".zip"}, 23 | {"Squeak/Smalltalk (6.0-22148)", "https://files.squeak.org/6.0/Squeak6.0-22148-64bit/Squeak6.0-22148-64bit.zip"}, 24 | {"TruffleSqueak test image (6.0-22104)", "https://github.com/hpi-swa/trufflesqueak/releases/download/22.3.0/TruffleSqueakTestImage-6.0-22104-64bit.zip"}, 25 | {"Cuis Smalltalk test image (7.3-7036)", "https://github.com/hpi-swa/trufflesqueak/releases/download/24.1.2/CuisTestImage-7.3-7036.zip"}}; 26 | 27 | private SqueakLanguageConfig() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/UUIDPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins; 8 | 9 | import java.util.List; 10 | 11 | import com.oracle.truffle.api.dsl.GenerateNodeFactory; 12 | import com.oracle.truffle.api.dsl.NodeFactory; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | 15 | import de.hpi.swa.trufflesqueak.model.NativeObject; 16 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; 17 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; 18 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive0WithFallback; 19 | import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; 20 | import de.hpi.swa.trufflesqueak.util.ArrayUtils; 21 | 22 | public final class UUIDPlugin extends AbstractPrimitiveFactoryHolder { 23 | 24 | @Override 25 | public List> getFactories() { 26 | return UUIDPluginFactory.getFactories(); 27 | } 28 | 29 | @GenerateNodeFactory 30 | @SqueakPrimitive(names = "primitiveMakeUUID") 31 | protected abstract static class PrimMakeUUIDNode extends AbstractPrimitiveNode implements Primitive0WithFallback { 32 | @Specialization(guards = {"receiver.isByteType()", "receiver.getByteLength() == 16"}) 33 | protected static final Object doUUID(final NativeObject receiver) { 34 | ArrayUtils.fillRandomly(receiver.getByteStorage()); 35 | // Version 4 36 | receiver.setByte(6, receiver.getByte(6) & 0x0F | 0x40); 37 | // Fixed 8..b value 38 | receiver.setByte(8, receiver.getByte(8) & 0x3F | 0x80); 39 | return receiver; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/GetOrCreateContextWithoutFrameNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.context; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.NeverDefault; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.frame.VirtualFrame; 15 | import com.oracle.truffle.api.nodes.Node; 16 | import com.oracle.truffle.api.profiles.InlinedConditionProfile; 17 | 18 | import de.hpi.swa.trufflesqueak.model.ContextObject; 19 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 20 | import de.hpi.swa.trufflesqueak.util.FrameAccess; 21 | 22 | /* Gets context or lazily initializes one if necessary. */ 23 | @GenerateInline 24 | @GenerateCached(true) 25 | public abstract class GetOrCreateContextWithoutFrameNode extends AbstractNode { 26 | @NeverDefault 27 | public static GetOrCreateContextWithoutFrameNode create() { 28 | return GetOrCreateContextWithoutFrameNodeGen.create(); 29 | } 30 | 31 | public abstract ContextObject execute(VirtualFrame frame, Node node); 32 | 33 | public final ContextObject execute(final VirtualFrame frame) { 34 | return execute(frame, this); 35 | } 36 | 37 | @Specialization 38 | public static ContextObject getContext(final VirtualFrame frame, final Node node, 39 | @Cached final InlinedConditionProfile hasContextProfile) { 40 | final ContextObject context = FrameAccess.getContext(frame); 41 | if (hasContextProfile.profile(node, context != null)) { 42 | return context; 43 | } else { 44 | return new ContextObject(frame); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/ffi/wrappers/NativeObjectStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.ffi.wrappers; 8 | 9 | import com.oracle.truffle.api.interop.InteropLibrary; 10 | import com.oracle.truffle.api.interop.TruffleObject; 11 | import com.oracle.truffle.api.library.ExportLibrary; 12 | import com.oracle.truffle.api.library.ExportMessage; 13 | 14 | import de.hpi.swa.trufflesqueak.model.NativeObject; 15 | 16 | @ExportLibrary(InteropLibrary.class) 17 | public abstract class NativeObjectStorage implements TruffleObject { 18 | protected long nativeAddress; 19 | private boolean isAllocated; 20 | 21 | public static NativeObjectStorage from(final NativeObject object) { 22 | if (object.isByteType()) { 23 | return new ByteStorage(object.getByteStorage()); 24 | } else if (object.isIntType()) { 25 | return new IntStorage(object.getIntStorage()); 26 | } else if (object.isLongType()) { 27 | return new LongStorage(object.getLongStorage()); 28 | } else if (object.isShortType()) { 29 | return new ShortStorage(object.getShortStorage()); 30 | } else { 31 | throw new IllegalArgumentException("Object storage type is not supported."); 32 | } 33 | } 34 | 35 | @ExportMessage 36 | public boolean isPointer() { 37 | return isAllocated; 38 | } 39 | 40 | @ExportMessage 41 | public long asPointer() { 42 | return nativeAddress; 43 | } 44 | 45 | @ExportMessage 46 | public void toNative() { 47 | if (isAllocated) { 48 | return; 49 | } 50 | nativeAddress = allocate(); 51 | isAllocated = true; 52 | } 53 | 54 | public abstract int byteSizeOf(); 55 | 56 | protected abstract long allocate(); 57 | 58 | public abstract void cleanup(); 59 | } 60 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/NilObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.model; 8 | 9 | import com.oracle.truffle.api.nodes.Node; 10 | import com.oracle.truffle.api.profiles.InlinedConditionProfile; 11 | 12 | import de.hpi.swa.trufflesqueak.image.SqueakImageConstants; 13 | import de.hpi.swa.trufflesqueak.image.SqueakImageWriter; 14 | 15 | public final class NilObject extends AbstractSqueakObject { 16 | public static final NilObject SINGLETON = new NilObject(); 17 | public static final long SQUEAK_HASH = 1L; 18 | 19 | private NilObject() { 20 | } 21 | 22 | public static AbstractSqueakObject nullToNil(final AbstractSqueakObject object) { 23 | return object == null ? SINGLETON : object; 24 | } 25 | 26 | public static AbstractSqueakObject nullToNil(final AbstractSqueakObject object, final InlinedConditionProfile profile, final Node node) { 27 | return profile.profile(node, object == null) ? SINGLETON : object; 28 | } 29 | 30 | public static Object nullToNil(final Object object) { 31 | return object == null ? SINGLETON : object; 32 | } 33 | 34 | public static Object nilToNull(final Object object) { 35 | return object == SINGLETON ? null : object; 36 | } 37 | 38 | @Override 39 | public long getOrCreateSqueakHash() { 40 | return SQUEAK_HASH; 41 | } 42 | 43 | @Override 44 | public int getNumSlots() { 45 | return 0; 46 | } 47 | 48 | @Override 49 | public int instsize() { 50 | return 0; 51 | } 52 | 53 | @Override 54 | public int size() { 55 | return 0; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "nil"; 61 | } 62 | 63 | public void write(final SqueakImageWriter writer) { 64 | writer.writeObjectHeader(instsize() + size(), getOrCreateSqueakHash(), writer.getImage().nilClass, 0); 65 | writer.writePadding(SqueakImageConstants.WORD_SIZE); /* Write alignment word. */ 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/VariablePointersObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.model; 8 | 9 | import org.graalvm.collections.UnmodifiableEconomicMap; 10 | 11 | import de.hpi.swa.trufflesqueak.image.SqueakImageChunk; 12 | import de.hpi.swa.trufflesqueak.image.SqueakImageWriter; 13 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayout; 14 | import de.hpi.swa.trufflesqueak.util.ArrayUtils; 15 | import de.hpi.swa.trufflesqueak.util.ObjectGraphUtils.ObjectTracer; 16 | 17 | public final class VariablePointersObject extends AbstractVariablePointersObject { 18 | 19 | public VariablePointersObject(final SqueakImageChunk chunk) { 20 | super(chunk); 21 | } 22 | 23 | public VariablePointersObject(final ClassObject classObject, final ObjectLayout layout, final int variableSize) { 24 | super(classObject, layout, variableSize); 25 | } 26 | 27 | public VariablePointersObject(final VariablePointersObject original) { 28 | super(original); 29 | } 30 | 31 | public Object getFromVariablePart(final long index) { 32 | return getObjectFromVariablePart(index); 33 | } 34 | 35 | public void putIntoVariablePart(final long index, final Object value) { 36 | putObjectFromVariablePart(index, value); 37 | } 38 | 39 | @Override 40 | public void pointersBecomeOneWay(final UnmodifiableEconomicMap fromToMap) { 41 | super.pointersBecomeOneWay(fromToMap); 42 | ArrayUtils.replaceAll(variablePart, fromToMap); 43 | } 44 | 45 | @Override 46 | protected void traceVariablePart(final ObjectTracer tracer) { 47 | tracer.addAllIfUnmarked(variablePart); 48 | } 49 | 50 | @Override 51 | protected void traceVariablePart(final SqueakImageWriter writer) { 52 | writer.traceAllIfNecessary(variablePart); 53 | } 54 | 55 | @Override 56 | protected void writeVariablePart(final SqueakImageWriter writer) { 57 | writer.writeObjects(variablePart); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/exceptions/PrimitiveFailed.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.exceptions; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives; 10 | import com.oracle.truffle.api.nodes.ControlFlowException; 11 | 12 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.ERROR_TABLE; 13 | 14 | public final class PrimitiveFailed extends ControlFlowException { 15 | private static final long serialVersionUID = 1L; 16 | 17 | public static final PrimitiveFailed GENERIC_ERROR = new PrimitiveFailed(ERROR_TABLE.GENERIC_ERROR.ordinal()); 18 | public static final PrimitiveFailed BAD_RECEIVER = new PrimitiveFailed(ERROR_TABLE.BAD_RECEIVER.ordinal()); 19 | public static final PrimitiveFailed BAD_ARGUMENT = new PrimitiveFailed(ERROR_TABLE.BAD_ARGUMENT.ordinal()); 20 | public static final PrimitiveFailed BAD_INDEX = new PrimitiveFailed(ERROR_TABLE.BAD_INDEX.ordinal()); 21 | public static final PrimitiveFailed BAD_NUMBER_OF_ARGUMENTS = new PrimitiveFailed(ERROR_TABLE.BAD_NUMBER_OF_ARGUMENTS.ordinal()); 22 | public static final PrimitiveFailed INSUFFICIENT_OBJECT_MEMORY = new PrimitiveFailed(ERROR_TABLE.INSUFFICIENT_OBJECT_MEMORY.ordinal()); 23 | 24 | private final int primFailCode; 25 | 26 | private PrimitiveFailed(final int primFailCode) { 27 | this.primFailCode = primFailCode; 28 | } 29 | 30 | public int getPrimFailCode() { 31 | return primFailCode; 32 | } 33 | 34 | public static PrimitiveFailed andTransferToInterpreter() { 35 | CompilerDirectives.transferToInterpreter(); 36 | throw GENERIC_ERROR; 37 | } 38 | 39 | public static PrimitiveFailed andTransferToInterpreter(final int primFailCode) { 40 | CompilerDirectives.transferToInterpreter(); 41 | throw new PrimitiveFailed(primFailCode); 42 | } 43 | 44 | public static PrimitiveFailed andTransferToInterpreterWithError(final Throwable t) { 45 | CompilerDirectives.transferToInterpreter(); 46 | t.printStackTrace(); 47 | throw GENERIC_ERROR; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/AbstractRootNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | package de.hpi.swa.trufflesqueak.nodes; 9 | 10 | import com.oracle.truffle.api.CompilerDirectives; 11 | import com.oracle.truffle.api.nodes.RootNode; 12 | 13 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 14 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 15 | import de.hpi.swa.trufflesqueak.nodes.interpreter.AbstractInterpreterInstrumentableNode; 16 | import de.hpi.swa.trufflesqueak.nodes.interpreter.InterpreterSistaV1Node; 17 | import de.hpi.swa.trufflesqueak.nodes.interpreter.InterpreterV3PlusClosuresNode; 18 | 19 | public abstract class AbstractRootNode extends RootNode { 20 | @Child protected AbstractInterpreterInstrumentableNode interpreterNode; 21 | 22 | protected AbstractRootNode(final SqueakImageContext image, final CompiledCodeObject code) { 23 | super(image.getLanguage(), code.getFrameDescriptor()); 24 | interpreterNode = code.getSignFlag() ? new InterpreterV3PlusClosuresNode(code) : new InterpreterSistaV1Node(code); 25 | } 26 | 27 | protected AbstractRootNode(final AbstractRootNode original) { 28 | super(SqueakImageContext.get(original).getLanguage(), original.getFrameDescriptor()); 29 | interpreterNode = switch (original.interpreterNode) { 30 | case InterpreterSistaV1Node n -> new InterpreterSistaV1Node(n); 31 | case InterpreterV3PlusClosuresNode n -> new InterpreterV3PlusClosuresNode(n); 32 | default -> throw CompilerDirectives.shouldNotReachHere("Unknown node " + original); 33 | }; 34 | } 35 | 36 | public final CompiledCodeObject getCode() { 37 | return interpreterNode.getCodeObject(); 38 | } 39 | 40 | @Override 41 | public final String getName() { 42 | return toString(); 43 | } 44 | 45 | @Override 46 | public final boolean isCloningAllowed() { 47 | return true; 48 | } 49 | 50 | @Override 51 | protected final boolean isCloneUninitializedSupported() { 52 | return true; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CharacterObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.model; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives.ValueType; 10 | import com.oracle.truffle.api.nodes.Node; 11 | import com.oracle.truffle.api.profiles.InlinedConditionProfile; 12 | 13 | import de.hpi.swa.trufflesqueak.exceptions.RespecializeException; 14 | 15 | @ValueType 16 | public final class CharacterObject extends AbstractSqueakObject { 17 | private final int value; 18 | 19 | private CharacterObject(final int value) { 20 | assert value > Character.MAX_VALUE : "CharacterObject should only be used for non-primitive chars."; 21 | this.value = value; 22 | } 23 | 24 | public CharacterObject(final CharacterObject original) { 25 | this.value = original.value; 26 | } 27 | 28 | @Override 29 | public int getNumSlots() { 30 | return 0; 31 | } 32 | 33 | @Override 34 | public int instsize() { 35 | return 0; 36 | } 37 | 38 | @Override 39 | public int size() { 40 | return 0; 41 | } 42 | 43 | public static Object valueOf(final int value) { 44 | if (value <= Character.MAX_VALUE) { 45 | return (char) value; 46 | } else { 47 | return new CharacterObject(value); 48 | } 49 | } 50 | 51 | public static char valueExactOf(final long value) throws RespecializeException { 52 | if (value <= Character.MAX_VALUE) { 53 | return (char) value; 54 | } else { 55 | throw RespecializeException.transferToInterpreterInvalidateAndThrow(); 56 | } 57 | } 58 | 59 | public static Object valueOf(final int value, final InlinedConditionProfile isImmediateProfile, final Node node) { 60 | if (isImmediateProfile.profile(node, value <= Character.MAX_VALUE)) { 61 | return (char) value; 62 | } else { 63 | return new CharacterObject(value); 64 | } 65 | } 66 | 67 | @Override 68 | public long getOrCreateSqueakHash() { 69 | return getValue(); 70 | } 71 | 72 | public long getValue() { 73 | return value; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.launcher/src/de/hpi/swa/trufflesqueak/launcher/SqueakTranscriptForwarder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.launcher; 8 | 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | import java.io.PrintStream; 12 | import java.nio.ByteBuffer; 13 | import java.nio.charset.StandardCharsets; 14 | import java.util.Arrays; 15 | 16 | import org.graalvm.polyglot.Context; 17 | import org.graalvm.polyglot.Source; 18 | import org.graalvm.polyglot.Value; 19 | 20 | import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; 21 | 22 | public final class SqueakTranscriptForwarder extends PrintStream { 23 | private static final String TRANSCRIPT_BLOCK_CODE = "[ :s | Transcript nextPutAll: s; flush ]"; 24 | private static final String TRANSCRIPT_BLOCK_CODE_NAME = ""; 25 | 26 | private Value transcriptBlock; 27 | 28 | public SqueakTranscriptForwarder(final OutputStream out, final boolean autoFlush) { 29 | super(out, autoFlush); 30 | } 31 | 32 | public void setUp(final Context context) throws IOException { 33 | transcriptBlock = context.eval(Source.newBuilder(SqueakLanguageConfig.ID, TRANSCRIPT_BLOCK_CODE, TRANSCRIPT_BLOCK_CODE_NAME).build()); 34 | } 35 | 36 | @Override 37 | public void write(final byte[] b) throws IOException { 38 | try { 39 | if (transcriptBlock != null) { 40 | transcriptBlock.execute(bytesToString(b)); 41 | } 42 | } catch (final Exception e) { 43 | e.printStackTrace(); 44 | } finally { 45 | super.write(b); 46 | } 47 | } 48 | 49 | @Override 50 | public void write(final byte[] b, final int off, final int len) { 51 | try { 52 | if (transcriptBlock != null) { 53 | transcriptBlock.execute(bytesToString(Arrays.copyOfRange(b, off, off + len))); 54 | } 55 | } catch (final Exception e) { 56 | e.printStackTrace(); 57 | } finally { 58 | super.write(b, off, len); 59 | } 60 | } 61 | 62 | private static String bytesToString(final byte[] b) { 63 | return StandardCharsets.UTF_8.decode(ByteBuffer.wrap(b)).toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interpreter/BytecodeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.interpreter; 8 | 9 | import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; 10 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 11 | 12 | public class BytecodeUtils { 13 | public static final int trailerPosition(final CompiledCodeObject code) { 14 | return code.isCompiledBlock() ? code.getBytes().length : trailerPosition(code.getBytes()); 15 | } 16 | 17 | private static int trailerPosition(final byte[] bytecode) { 18 | final int bytecodeLength = bytecode.length; 19 | final int flagByte = Byte.toUnsignedInt(bytecode[bytecodeLength - 1]); 20 | final int index = (flagByte >> 2) + 1; 21 | return switch (index) { 22 | // #decodeNoTrailer and #decodeSourceBySelector 23 | case 1, 5 -> bytecodeLength - 1; 24 | // #decodeClearedTrailer, #decodeTempsNamesQCompress, #decodeTempsNamesZip, 25 | // #decodeSourceByStringIdentifier, #decodeEmbeddedSourceQCompress, and 26 | // #decodeEmbeddedSourceZip 27 | case 2, 3, 4, 6, 7, 8 -> decodeLengthField(bytecode, bytecodeLength, flagByte); 28 | // #decodeVarLengthSourcePointer 29 | case 9 -> { 30 | int pos = bytecodeLength - 2; 31 | while (bytecode[pos] < 0) { 32 | pos--; 33 | } 34 | yield pos; 35 | } 36 | // #decodeSourcePointer 37 | case 64 -> bytecodeLength - 4; 38 | default -> throw SqueakException.create("Undefined method encoding (see CompiledMethodTrailer)."); 39 | }; 40 | } 41 | 42 | private static int decodeLengthField(final byte[] bytecode, final int bytecodeLength, final int flagByte) { 43 | final int numBytes = (flagByte & 3) + 1; 44 | int length = 0; 45 | final int firstLengthValueIndex = bytecodeLength - 2; 46 | for (int i = 0; i < numBytes; i++) { 47 | length = (length << 8) + Byte.toUnsignedInt(bytecode[firstLengthValueIndex - i]); 48 | } 49 | return bytecodeLength - (1 + numBytes + length); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/DoItRootNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | import com.oracle.truffle.api.TruffleLanguage; 10 | import com.oracle.truffle.api.dsl.Bind; 11 | import com.oracle.truffle.api.dsl.Cached; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.frame.VirtualFrame; 14 | import com.oracle.truffle.api.nodes.Node; 15 | import com.oracle.truffle.api.nodes.RootNode; 16 | 17 | import de.hpi.swa.trufflesqueak.SqueakLanguage; 18 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 19 | import de.hpi.swa.trufflesqueak.interop.WrapToSqueakNode; 20 | import de.hpi.swa.trufflesqueak.model.BlockClosureObject; 21 | import de.hpi.swa.trufflesqueak.model.NilObject; 22 | import de.hpi.swa.trufflesqueak.nodes.primitives.impl.BlockClosurePrimitives.PrimFullClosureValueWithArgsNode; 23 | 24 | public abstract class DoItRootNode extends RootNode { 25 | private final SqueakImageContext image; 26 | private final BlockClosureObject blockClosure; 27 | 28 | protected DoItRootNode(final SqueakImageContext image, final TruffleLanguage language, final BlockClosureObject closure) { 29 | super(language); 30 | this.image = image; 31 | blockClosure = closure; 32 | } 33 | 34 | public static DoItRootNode create(final SqueakImageContext image, final SqueakLanguage language, final BlockClosureObject closure) { 35 | return DoItRootNodeGen.create(image, (TruffleLanguage) language, closure); 36 | } 37 | 38 | @Specialization 39 | protected final Object doIt(final VirtualFrame frame, 40 | @Bind final Node node, 41 | @Cached final WrapToSqueakNode wrapNode, 42 | @Cached final PrimFullClosureValueWithArgsNode primitiveNode) { 43 | if (blockClosure.getNumArgs() != frame.getArguments().length) { 44 | return NilObject.SINGLETON; 45 | } 46 | final boolean wasActive = image.interrupt.deactivate(); 47 | try { 48 | return primitiveNode.execute(image.externalSenderFrame, blockClosure, wrapNode.executeWrap(node, frame.getArguments())); 49 | } finally { 50 | image.interrupt.reactivate(wasActive); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/LogUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.util; 8 | 9 | import java.util.logging.Level; 10 | 11 | import com.oracle.truffle.api.TruffleLogger; 12 | 13 | import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; 14 | 15 | /** 16 | * Logging infrastructure for TruffleSqueak. All loggers are consistently defined here, so that it 17 | * is clear which loggers are available. 18 | */ 19 | public final class LogUtils { 20 | 21 | public static final TruffleLogger MAIN = TruffleLogger.getLogger(SqueakLanguageConfig.ID); 22 | 23 | public static final TruffleLogger ARRAY_STATEGIES = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "array-strategies"); 24 | public static final TruffleLogger DEBUG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "debug"); 25 | public static final TruffleLogger GC = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "gc"); 26 | public static final TruffleLogger IMAGE = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "image"); 27 | public static final TruffleLogger INTEROP = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "interop"); 28 | public static final TruffleLogger INTERPRETER_PROXY = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "interpreter-proxy"); 29 | public static final TruffleLogger INTERRUPTS = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "interrupts"); 30 | public static final TruffleLogger IO = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "io"); 31 | public static final TruffleLogger ITERATE_FRAMES = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "iterate-frames"); 32 | public static final TruffleLogger OBJECT_GRAPH = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "object-graph"); 33 | public static final TruffleLogger PRIMITIVES = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "primitives"); 34 | public static final TruffleLogger READER = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "reader"); 35 | public static final TruffleLogger SCHEDULING = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "scheduling"); 36 | public static final TruffleLogger SOCKET = TruffleLogger.getLogger(SqueakLanguageConfig.ID, "socket"); 37 | 38 | public static final boolean GC_IS_LOGGABLE_FINE = GC.isLoggable(Level.FINE); 39 | } 40 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/AbstractNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | import com.oracle.truffle.api.dsl.Idempotent; 10 | import com.oracle.truffle.api.dsl.ImportStatic; 11 | import com.oracle.truffle.api.dsl.TypeSystemReference; 12 | import com.oracle.truffle.api.nodes.Node; 13 | import com.oracle.truffle.api.nodes.NodeInfo; 14 | 15 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 16 | import de.hpi.swa.trufflesqueak.model.BooleanObject; 17 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 18 | import de.hpi.swa.trufflesqueak.model.NativeObject; 19 | import de.hpi.swa.trufflesqueak.model.PointersObject; 20 | import de.hpi.swa.trufflesqueak.nodes.plugins.LargeIntegers; 21 | import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; 22 | import de.hpi.swa.trufflesqueak.util.FrameAccess; 23 | 24 | @ImportStatic({BooleanObject.class, CacheLimits.class, FrameAccess.class, SqueakGuards.class, LargeIntegers.class}) 25 | @TypeSystemReference(SqueakTypes.class) 26 | @NodeInfo(language = SqueakLanguageConfig.ID) 27 | public abstract class AbstractNode extends Node { 28 | 29 | public static SqueakImageContext getContext(final Node node) { 30 | return SqueakImageContext.get(node); 31 | } 32 | 33 | public final SqueakImageContext getContext() { 34 | return getContext(this); 35 | } 36 | 37 | protected final CompiledCodeObject getCode() { 38 | return ((AbstractRootNode) getRootNode()).getCode(); 39 | } 40 | 41 | protected final boolean isBitmap(final NativeObject object) { 42 | return getContext().isBitmapClass(object.getSqueakClass()); 43 | } 44 | 45 | protected final boolean isPoint(final PointersObject object) { 46 | return getContext().isPoint(object); 47 | } 48 | 49 | @Idempotent 50 | protected final boolean numericPrimsMixArithmetic() { 51 | return getContext().flags.numericPrimsMixArithmetic(); 52 | } 53 | 54 | @Idempotent 55 | protected final boolean numericPrimsMixComparison() { 56 | return getContext().flags.numericPrimsMixComparison(); 57 | } 58 | 59 | protected final boolean isSemaphore(final PointersObject object) { 60 | return getContext().isSemaphoreClass(object.getSqueakClass()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/context/GetOrCreateContextWithFrameNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.context; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.NeverDefault; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.frame.VirtualFrame; 15 | import com.oracle.truffle.api.nodes.Node; 16 | import com.oracle.truffle.api.profiles.InlinedBranchProfile; 17 | import com.oracle.truffle.api.profiles.InlinedConditionProfile; 18 | 19 | import de.hpi.swa.trufflesqueak.model.ContextObject; 20 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 21 | import de.hpi.swa.trufflesqueak.util.FrameAccess; 22 | 23 | @GenerateInline 24 | @GenerateCached(true) 25 | public abstract class GetOrCreateContextWithFrameNode extends AbstractNode { 26 | 27 | @NeverDefault 28 | public static GetOrCreateContextWithFrameNode create() { 29 | return GetOrCreateContextWithFrameNodeGen.create(); 30 | } 31 | 32 | public static final ContextObject executeUncached(final VirtualFrame frame) { 33 | return doGetOrCreate(frame, null, InlinedConditionProfile.getUncached(), InlinedBranchProfile.getUncached()); 34 | } 35 | 36 | public abstract ContextObject executeGet(VirtualFrame frame, Node node); 37 | 38 | public final ContextObject executeGet(final VirtualFrame frame) { 39 | return executeGet(frame, this); 40 | } 41 | 42 | @Specialization 43 | protected static final ContextObject doGetOrCreate(final VirtualFrame frame, final Node node, 44 | @Cached final InlinedConditionProfile hasContextProfile, 45 | @Cached final InlinedBranchProfile hasFrameProfile) { 46 | final ContextObject context = FrameAccess.getContext(frame); 47 | if (hasContextProfile.profile(node, context != null)) { 48 | if (!context.hasTruffleFrame()) { 49 | hasFrameProfile.enter(node); 50 | context.setTruffleFrame(frame.materialize()); 51 | } 52 | return context; 53 | } else { 54 | return new ContextObject(frame.materialize()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/AddLastLinkToListNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.nodes.Node; 14 | 15 | import de.hpi.swa.trufflesqueak.model.PointersObject; 16 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.LINKED_LIST; 17 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 18 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 19 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 20 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 21 | 22 | /* 23 | * Add the given process to the given linked list and set the backpointer of process to its new list. 24 | */ 25 | @GenerateInline 26 | @GenerateCached(false) 27 | public abstract class AddLastLinkToListNode extends AbstractNode { 28 | 29 | public abstract void execute(Node node, PointersObject process, PointersObject list); 30 | 31 | @Specialization 32 | protected static final void addLastLinkToList(final Node node, final PointersObject process, final PointersObject list, 33 | @Cached final AbstractPointersObjectReadNode readEmptyNode, 34 | @Cached final AbstractPointersObjectReadNode readNode, 35 | @Cached final AbstractPointersObjectWriteNode writeNode, 36 | @Cached final AbstractPointersObjectWriteNode writeLastLinkNode, 37 | @Cached final AbstractPointersObjectWriteNode writeListNode) { 38 | if (list.isEmptyList(readEmptyNode, node)) { 39 | writeNode.execute(node, list, LINKED_LIST.FIRST_LINK, process); 40 | } else { 41 | final PointersObject lastLink = readNode.executePointers(node, list, LINKED_LIST.LAST_LINK); 42 | writeNode.execute(node, lastLink, PROCESS.NEXT_LINK, process); 43 | } 44 | writeLastLinkNode.execute(node, list, LINKED_LIST.LAST_LINK, process); 45 | writeListNode.execute(node, process, PROCESS.LIST, list); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/InheritsFromNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.GenerateUncached; 13 | import com.oracle.truffle.api.dsl.ReportPolymorphism; 14 | import com.oracle.truffle.api.dsl.Specialization; 15 | import com.oracle.truffle.api.nodes.Node; 16 | 17 | import de.hpi.swa.trufflesqueak.model.ClassObject; 18 | import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectClassNode; 19 | 20 | @GenerateInline 21 | @GenerateUncached 22 | @GenerateCached(false) 23 | public abstract class InheritsFromNode extends AbstractNode { 24 | protected static final int CACHE_SIZE = 3; 25 | 26 | public abstract boolean execute(Node node, Object object, ClassObject classObject); 27 | 28 | @SuppressWarnings("unused") 29 | @Specialization(limit = "CACHE_SIZE", guards = {"object == cachedObject", "classObject == cachedClass"}, assumptions = {"cachedClass.getClassHierarchyAndMethodDictStable()"}) 30 | protected static final boolean doCached(final Object object, final ClassObject classObject, 31 | @Cached("object") final Object cachedObject, 32 | @Cached("classObject") final ClassObject cachedClass, 33 | @Cached("doUncached(object, cachedClass)") final boolean inInheritanceChain) { 34 | return inInheritanceChain; 35 | } 36 | 37 | protected static final boolean doUncached(final Object receiver, final ClassObject superClass) { 38 | return doUncached(null, receiver, superClass, SqueakObjectClassNode.getUncached()); 39 | } 40 | 41 | @ReportPolymorphism.Megamorphic 42 | @Specialization(replaces = "doCached") 43 | protected static final boolean doUncached(final Node node, final Object receiver, final ClassObject superClass, 44 | @Cached final SqueakObjectClassNode classNode) { 45 | ClassObject classObject = classNode.executeLookup(node, receiver); 46 | while (classObject != superClass) { 47 | classObject = classObject.getSuperclassOrNull(); 48 | if (classObject == null) { 49 | return false; 50 | } 51 | } 52 | return true; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/LookupMethodNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.GenerateUncached; 13 | import com.oracle.truffle.api.dsl.ReportPolymorphism; 14 | import com.oracle.truffle.api.dsl.Specialization; 15 | import com.oracle.truffle.api.nodes.Node; 16 | 17 | import de.hpi.swa.trufflesqueak.model.ClassObject; 18 | import de.hpi.swa.trufflesqueak.model.NativeObject; 19 | import de.hpi.swa.trufflesqueak.util.MethodCacheEntry; 20 | 21 | @GenerateInline 22 | @GenerateUncached 23 | @GenerateCached(false) 24 | public abstract class LookupMethodNode extends AbstractNode { 25 | protected static final int LOOKUP_CACHE_SIZE = 6; 26 | 27 | public abstract Object executeLookup(Node node, ClassObject sqClass, NativeObject selector); 28 | 29 | public static final Object executeUncached(final ClassObject sqClass, final NativeObject selector) { 30 | return LookupMethodNodeGen.getUncached().executeLookup(null, sqClass, selector); 31 | } 32 | 33 | @SuppressWarnings("unused") 34 | @Specialization(limit = "LOOKUP_CACHE_SIZE", guards = {"classObject == cachedClass", "selector == cachedSelector"}, // 35 | assumptions = {"cachedClass.getClassHierarchyAndMethodDictStable()"}) 36 | protected static final Object doCached(final ClassObject classObject, final NativeObject selector, 37 | @Cached("classObject") final ClassObject cachedClass, 38 | @Cached("selector") final NativeObject cachedSelector, 39 | @Cached("classObject.lookupInMethodDictSlow(selector)") final Object cachedMethod) { 40 | return cachedMethod; 41 | } 42 | 43 | @ReportPolymorphism.Megamorphic 44 | @Specialization(replaces = "doCached") 45 | protected final Object doUncached(final ClassObject classObject, final NativeObject selector) { 46 | final MethodCacheEntry cachedEntry = getContext().findMethodCacheEntry(classObject, selector); 47 | if (cachedEntry.getResult() == null) { 48 | cachedEntry.setResult(classObject.lookupInMethodDictSlow(selector)); 49 | } 50 | return cachedEntry.getResult(); /* `null` return signals a doesNotUnderstand. */ 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/GetNextActiveContextNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Bind; 10 | import com.oracle.truffle.api.dsl.Cached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.nodes.Node; 14 | 15 | import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; 16 | import de.hpi.swa.trufflesqueak.model.ContextObject; 17 | import de.hpi.swa.trufflesqueak.model.PointersObject; 18 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 19 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 20 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 21 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 22 | 23 | @GenerateInline(false) 24 | public abstract class GetNextActiveContextNode extends AbstractNode { 25 | 26 | public static GetNextActiveContextNode create() { 27 | return GetNextActiveContextNodeGen.create(); 28 | } 29 | 30 | public abstract ContextObject execute(); 31 | 32 | @Specialization 33 | protected static final ContextObject doHandle( 34 | @Bind final Node node, 35 | @Cached final GetActiveProcessNode getActiveProcessNode, 36 | @Cached(inline = true) final AbstractPointersObjectReadNode readNode, 37 | @Cached(inline = true) final AbstractPointersObjectWriteNode writeSuspendedContextNode, 38 | @Cached(inline = true) final AbstractPointersObjectWriteNode writeListNode) { 39 | final PointersObject activeProcess = getActiveProcessNode.execute(node); 40 | final Object newActiveContextObject = readNode.execute(node, activeProcess, PROCESS.SUSPENDED_CONTEXT); 41 | if (!(newActiveContextObject instanceof final ContextObject newActiveContext)) { 42 | throw SqueakException.create("new process not runnable"); 43 | } 44 | writeSuspendedContextNode.executeNil(node, activeProcess, PROCESS.SUSPENDED_CONTEXT); 45 | writeListNode.executeNil(node, activeProcess, PROCESS.LIST); 46 | assert !newActiveContext.isDead() : "Cannot switch to terminated context"; 47 | return newActiveContext; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/image-tests/runCuisTests.st: -------------------------------------------------------------------------------- 1 | | testSuite nonTerminatingTestCases failingTests result retries exitCode | 2 | 3 | StdIOWriteStream stdout nextPutAll: 'Setting author information for testing ...'; newLine; flush. 4 | Utilities classPool at: #AuthorName put: 'TruffleSqueak'. 5 | Utilities classPool at: #AuthorInitials put: 'TS'. 6 | 7 | nonTerminatingTestCases := OrderedCollection new. 8 | { 9 | #ProcessTest -> #(#testResumeWithEnsureAfterBCR). 10 | } collect: [:assoc | | testCase | 11 | testCase := Smalltalk at: assoc key. 12 | assoc value do: [:sel | nonTerminatingTestCases add: (testCase selector: sel) ]]. 13 | StdIOWriteStream stdout newLine; nextPutAll: 'Non-terminating TestCases:'; newLine; flush. 14 | nonTerminatingTestCases do: [:ea | StdIOWriteStream stdout nextPutAll: '- ', ea asString; newLine; flush ]. 15 | StdIOWriteStream stdout newLine; flush. 16 | 17 | failingTests := OrderedCollection new. 18 | { 19 | #FloatTest -> #(#testHashWithSmallishLargeNegativeInteger #testHashWithSmallishLargePositiveInteger #testIsDenormalized #testPrimTruncated). 20 | #IntegerTest -> #(#testRange). 21 | #StringTest -> #("flaky" #testFindSelector). 22 | #SmallIntegerTest -> #(#testDivideMayOverflow). 23 | } collect: [:assoc | | testCase | 24 | testCase := Smalltalk at: assoc key. 25 | assoc value do: [:sel | failingTests add: (testCase selector: sel) ]]. 26 | 27 | StdIOWriteStream stdout newLine; nextPutAll: 'Passing TestCases:'; newLine; flush. 28 | testSuite := TestCase buildSuite. 29 | testSuite tests removeAllSuchThat: [:ea | nonTerminatingTestCases anySatisfy: [:t | ea class == t class and: [ ea selector == t selector ]]]. 30 | testSuite tests removeAllSuchThat: [:ea | failingTests anySatisfy: [:t | ea class == t class and: [ ea selector == t selector ]]]. 31 | result := testSuite run. 32 | result printReport. 33 | 34 | exitCode := result hasPassed ifTrue: [ 0 ] ifFalse: [ 1 ]. 35 | 36 | retries := 3. 37 | [ exitCode == 1 and: [ retries > 0 ] ] whileTrue: [ 38 | StdIOWriteStream stdout newLine; nextPutAll: 'Retry failures or errors:'; newLine; flush. 39 | testSuite := TestSuite new. 40 | testSuite tests addAll: result failures. 41 | testSuite tests addAll: result errors. 42 | result := testSuite run. 43 | result printReport. 44 | exitCode := result hasPassed ifTrue: [ 0 ] ifFalse: [ 1 ]. 45 | retries := retries - 1. 46 | ]. 47 | 48 | StdIOWriteStream stdout newLine; nextPutAll: 'Failing and Flaky TestCases:'; newLine; flush. 49 | testSuite := TestSuite new. 50 | testSuite tests addAll: failingTests. 51 | testSuite run printReport. 52 | 53 | Smalltalk quitPrimitive: exitCode 54 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakMouse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.io; 8 | 9 | import java.awt.event.MouseEvent; 10 | import java.awt.event.MouseWheelEvent; 11 | 12 | import javax.swing.event.MouseInputAdapter; 13 | 14 | import de.hpi.swa.trufflesqueak.io.SqueakIOConstants.EVENT_TYPE; 15 | import de.hpi.swa.trufflesqueak.io.SqueakIOConstants.MOUSE; 16 | import de.hpi.swa.trufflesqueak.io.SqueakIOConstants.MOUSE_EVENT; 17 | import de.hpi.swa.trufflesqueak.util.LogUtils; 18 | 19 | public final class SqueakMouse extends MouseInputAdapter { 20 | private final SqueakDisplay display; 21 | 22 | public SqueakMouse(final SqueakDisplay display) { 23 | this.display = display; 24 | } 25 | 26 | @Override 27 | public void mouseDragged(final MouseEvent e) { 28 | recordMouseEvent(MOUSE_EVENT.MOVE, e); 29 | } 30 | 31 | @Override 32 | public void mouseMoved(final MouseEvent e) { 33 | recordMouseEvent(MOUSE_EVENT.MOVE, e); 34 | } 35 | 36 | @Override 37 | public void mousePressed(final MouseEvent e) { 38 | recordMouseEvent(MOUSE_EVENT.DOWN, e); 39 | } 40 | 41 | @Override 42 | public void mouseReleased(final MouseEvent e) { 43 | recordMouseEvent(MOUSE_EVENT.UP, e); 44 | } 45 | 46 | @Override 47 | public void mouseWheelMoved(final MouseWheelEvent e) { 48 | display.addEvent(EVENT_TYPE.MOUSE_WHEEL, 0L /* X-Axis Scrolling is not supported */, (long) (e.getPreciseWheelRotation() * MOUSE.WHEEL_DELTA_FACTOR), display.buttons >> 3, 0L); 49 | } 50 | 51 | private void recordMouseEvent(final MOUSE_EVENT type, final MouseEvent e) { 52 | final int buttons = switch (type) { 53 | case DOWN -> mapButton(e); 54 | case MOVE -> display.buttons & MOUSE.ALL; 55 | case UP -> 0; 56 | }; 57 | display.buttons = buttons | display.recordModifiers(e); 58 | display.addEvent(EVENT_TYPE.MOUSE, e.getX(), e.getY(), display.buttons & MOUSE.ALL, display.buttons >> 3); 59 | } 60 | 61 | private static int mapButton(final MouseEvent e) { 62 | return switch (e.getButton()) { 63 | case MouseEvent.BUTTON1 -> e.isAltDown() ? MOUSE.YELLOW : MOUSE.RED; // left 64 | case MouseEvent.BUTTON2 -> MOUSE.YELLOW; // middle 65 | case MouseEvent.BUTTON3 -> MOUSE.BLUE; // right 66 | case MouseEvent.NOBUTTON -> 0; 67 | default -> { 68 | LogUtils.IO.warning("Unknown mouse button in event: " + e); 69 | yield 0; 70 | } 71 | }; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/PutToSleepNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.nodes.Node; 14 | 15 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 16 | import de.hpi.swa.trufflesqueak.model.ArrayObject; 17 | import de.hpi.swa.trufflesqueak.model.PointersObject; 18 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 19 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; 20 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 21 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 22 | import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectReadNode; 23 | 24 | /* 25 | * Save the given process on the scheduler process list for its priority. 26 | */ 27 | @GenerateInline 28 | @GenerateCached(false) 29 | public abstract class PutToSleepNode extends AbstractNode { 30 | 31 | public static final void executeUncached(final SqueakImageContext image, final PointersObject process, final boolean addLast) { 32 | final long priority = (Long) process.instVarAt0Slow(PROCESS.PRIORITY); 33 | final ArrayObject processLists = (ArrayObject) image.getScheduler().instVarAt0Slow(PROCESS_SCHEDULER.PROCESS_LISTS); 34 | final PointersObject processList = (PointersObject) processLists.getObject(priority - 1); 35 | AddLinkToListNode.executeUncached(process, processList, addLast); 36 | } 37 | 38 | public abstract void executePutToSleep(Node node, PointersObject process, boolean addLast); 39 | 40 | @Specialization 41 | protected static final void putToSleep(final Node node, final PointersObject process, final boolean addLast, 42 | @Cached final ArrayObjectReadNode arrayReadNode, 43 | @Cached final AbstractPointersObjectReadNode pointersReadNode, 44 | @Cached final AddLinkToListNode addLinkToListNode) { 45 | final long priority = pointersReadNode.executeLong(node, process, PROCESS.PRIORITY); 46 | final ArrayObject processLists = pointersReadNode.executeArray(node, getContext(node).getScheduler(), PROCESS_SCHEDULER.PROCESS_LISTS); 47 | final PointersObject processList = (PointersObject) arrayReadNode.execute(node, processLists, priority - 1); 48 | addLinkToListNode.execute(node, process, processList, addLast); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakKeyboard.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.io; 8 | 9 | import java.awt.event.KeyEvent; 10 | import java.awt.event.KeyListener; 11 | 12 | import de.hpi.swa.trufflesqueak.io.SqueakIOConstants.EVENT_TYPE; 13 | import de.hpi.swa.trufflesqueak.io.SqueakIOConstants.KEYBOARD_EVENT; 14 | 15 | public final class SqueakKeyboard implements KeyListener { 16 | private final SqueakDisplay display; 17 | 18 | public SqueakKeyboard(final SqueakDisplay display) { 19 | this.display = display; 20 | } 21 | 22 | @Override 23 | public void keyPressed(final KeyEvent e) { 24 | display.recordModifiers(e); 25 | final int keyChar = toKeyChar(e); 26 | addKeyboardEvent(KEYBOARD_EVENT.DOWN, keyChar != KeyEvent.CHAR_UNDEFINED ? keyChar : e.getKeyCode()); 27 | if (keyChar != KeyEvent.CHAR_UNDEFINED) { 28 | addKeyboardEvent(KEYBOARD_EVENT.CHAR, keyChar); 29 | } 30 | if ((e.isAltDown() || e.isMetaDown()) && keyChar == '.') { 31 | display.image.interrupt.setInterruptPending(); 32 | } 33 | } 34 | 35 | @Override 36 | public void keyTyped(final KeyEvent e) { 37 | /** Keyboard char events handled in keyPressed(KeyEvent). */ 38 | } 39 | 40 | @Override 41 | public void keyReleased(final KeyEvent e) { 42 | display.recordModifiers(e); 43 | final int keyChar = toKeyChar(e); 44 | addKeyboardEvent(KEYBOARD_EVENT.UP, keyChar != KeyEvent.CHAR_UNDEFINED ? keyChar : e.getKeyCode()); 45 | } 46 | 47 | private void addKeyboardEvent(final long eventType, final int keyCharOrCode) { 48 | display.addEvent(EVENT_TYPE.KEYBOARD, keyCharOrCode, eventType, display.buttons >> 3, keyCharOrCode); 49 | } 50 | 51 | private static int toKeyChar(final KeyEvent e) { 52 | return switch (e.getKeyCode()) { // Handle special keys. 53 | case KeyEvent.VK_BACK_SPACE -> 8; 54 | case KeyEvent.VK_TAB -> 9; 55 | case KeyEvent.VK_ENTER -> 13; 56 | case KeyEvent.VK_ESCAPE -> 27; 57 | case KeyEvent.VK_SPACE -> 32; 58 | case KeyEvent.VK_PAGE_UP -> 11; 59 | case KeyEvent.VK_PAGE_DOWN -> 12; 60 | case KeyEvent.VK_END -> 4; 61 | case KeyEvent.VK_HOME -> 1; 62 | case KeyEvent.VK_LEFT -> 28; 63 | case KeyEvent.VK_UP -> 30; 64 | case KeyEvent.VK_RIGHT -> 29; 65 | case KeyEvent.VK_DOWN -> 31; 66 | case KeyEvent.VK_INSERT -> 5; 67 | case KeyEvent.VK_DELETE -> 127; 68 | default -> e.getKeyChar(); 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/AbstractVariablePointersObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.model; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; 10 | import com.oracle.truffle.api.nodes.Node; 11 | 12 | import de.hpi.swa.trufflesqueak.image.SqueakImageChunk; 13 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayout; 14 | import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectIdentityNode; 15 | import de.hpi.swa.trufflesqueak.util.ArrayUtils; 16 | import de.hpi.swa.trufflesqueak.util.UnsafeUtils; 17 | 18 | public abstract class AbstractVariablePointersObject extends AbstractPointersObject { 19 | @CompilationFinal(dimensions = 0) protected Object[] variablePart; 20 | 21 | public AbstractVariablePointersObject(final SqueakImageChunk chunk) { 22 | super(chunk); 23 | } 24 | 25 | public AbstractVariablePointersObject(final ClassObject classObject, final ObjectLayout layout, final int variableSize) { 26 | super(classObject, layout); 27 | variablePart = ArrayUtils.withAll(variableSize, NilObject.SINGLETON); 28 | } 29 | 30 | protected AbstractVariablePointersObject(final AbstractVariablePointersObject original) { 31 | super(original); 32 | variablePart = original.variablePart.clone(); 33 | } 34 | 35 | @Override 36 | protected void fillInVariablePart(final SqueakImageChunk chunk, final int instSize) { 37 | variablePart = chunk.getPointers(instSize); 38 | } 39 | 40 | public final void become(final AbstractVariablePointersObject other) { 41 | becomeLayout(other); 42 | final Object[] otherVariablePart = other.variablePart; 43 | other.variablePart = variablePart; 44 | variablePart = otherVariablePart; 45 | } 46 | 47 | @Override 48 | public final int size() { 49 | return instsize() + variablePart.length; 50 | } 51 | 52 | public boolean pointsTo(final SqueakObjectIdentityNode identityNode, final Node inlineTarget, final Object thang) { 53 | return layoutValuesPointTo(identityNode, inlineTarget, thang) || ArrayUtils.contains(variablePart, thang); 54 | } 55 | 56 | public final Object[] getVariablePart() { 57 | return variablePart; 58 | } 59 | 60 | public final int getVariablePartSize() { 61 | return variablePart.length; 62 | } 63 | 64 | protected final Object getObjectFromVariablePart(final long index) { 65 | return UnsafeUtils.getObject(variablePart, index); 66 | } 67 | 68 | protected final void putObjectFromVariablePart(final long index, final Object value) { 69 | UnsafeUtils.putObject(variablePart, index, value); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /mx.trufflesqueak/mx_trufflesqueak.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | # Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | # 5 | # Licensed under the MIT License. 6 | # 7 | 8 | import os 9 | import mx 10 | import mx_gate 11 | import mx_truffle 12 | import mx_unittest 13 | 14 | # re-export custom mx project classes so they can be used from suite.py 15 | from mx_cmake import CMakeNinjaProject # pylint: disable=unused-import 16 | from mx_sdk_vm_ng import ( # pylint: disable=unused-import 17 | StandaloneLicenses, 18 | ThinLauncherProject, 19 | LanguageLibraryProject, 20 | DynamicPOMDistribution, 21 | ) 22 | 23 | _SUITE = mx.suite("trufflesqueak") 24 | 25 | 26 | # Called from suite.py 27 | def trufflesqueak_standalone_deps(): 28 | return mx_truffle.resolve_truffle_dist_names(use_optimized_runtime=True) 29 | 30 | 31 | # Called from suite.py 32 | def libsmalltalkvm_build_args(): 33 | build_args = [] 34 | selected_march = ( 35 | "x86-64-v2" 36 | if mx.get_arch() == "amd64" 37 | else ("armv8.1-a" if mx.get_arch() == "aarch64" else "compatibility") 38 | ) 39 | build_args.append(f"-march={selected_march}") 40 | is_oracle_graalvm = "-community" not in os.getenv("JAVA_HOME") 41 | if is_oracle_graalvm and mx.get_os() == "linux": 42 | build_args.append("--gc=G1") 43 | return build_args 44 | 45 | 46 | def _trufflesqueak_gate_runner(args, tasks): 47 | with mx_gate.Task("Check Copyrights", tasks, tags=[mx_gate.Tags.style]) as t: 48 | if t: 49 | if mx.checkcopyrights(["--primary"]) != 0: 50 | t.abort( 51 | 'Copyright errors found. Please run "mx ' 52 | 'checkcopyrights --primary -- --fix" to fix them.' 53 | ) 54 | with mx_gate.Task("TruffleSqueak JUnit and SUnit tests", tasks, tags=["test"]) as t: 55 | if t: 56 | mx_unittest.unittest( 57 | [ 58 | "--suite", 59 | "trufflesqueak", 60 | "--very-verbose", 61 | "--color", 62 | "--enable-timing", 63 | ] 64 | ) 65 | 66 | 67 | def _unittest_config_participant(config): 68 | (vmArgs, mainClass, mainClassArgs) = config 69 | vmArgs += ["-Dpolyglotimpl.DisableClassPathIsolation=true"] 70 | vmArgs += ["--add-exports=java.base/jdk.internal.module=de.hpi.swa.trufflesqueak"] 71 | mainClassArgs += [ 72 | "-JUnitOpenPackages", 73 | "de.hpi.swa.trufflesqueak/*=de.hpi.swa.trufflesqueak.test", 74 | ] 75 | mainClassArgs += ["-JUnitOpenPackages", "de.hpi.swa.trufflesqueak/*=ALL-UNNAMED"] 76 | return (vmArgs, mainClass, mainClassArgs) 77 | 78 | 79 | mx_gate.add_gate_runner(_SUITE, _trufflesqueak_gate_runner) 80 | mx_unittest.add_config_participant(_unittest_config_participant) 81 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakImage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 10 | import com.oracle.truffle.api.RootCallTarget; 11 | import com.oracle.truffle.api.frame.VirtualFrame; 12 | import com.oracle.truffle.api.interop.InteropLibrary; 13 | import com.oracle.truffle.api.interop.TruffleObject; 14 | import com.oracle.truffle.api.library.ExportLibrary; 15 | import com.oracle.truffle.api.library.ExportMessage; 16 | import com.oracle.truffle.api.nodes.RootNode; 17 | 18 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 19 | import de.hpi.swa.trufflesqueak.image.SqueakImageReader; 20 | import de.hpi.swa.trufflesqueak.model.NilObject; 21 | 22 | @ExportLibrary(InteropLibrary.class) 23 | public final class SqueakImage implements TruffleObject { 24 | private final SqueakImageContext image; 25 | 26 | public SqueakImage(final SqueakImageContext image) { 27 | this.image = image; 28 | } 29 | 30 | private static class SqueakImageNode extends RootNode { 31 | private final SqueakImage squeakImage; 32 | 33 | protected SqueakImageNode(final SqueakImage squeakImage) { 34 | super(squeakImage.image.getLanguage()); 35 | this.squeakImage = squeakImage; 36 | } 37 | 38 | @Override 39 | public Object execute(final VirtualFrame frame) { 40 | SqueakImageReader.load(squeakImage.image); 41 | return squeakImage; 42 | } 43 | } 44 | 45 | public RootCallTarget asCallTarget() { 46 | return new SqueakImageNode(this).getCallTarget(); 47 | } 48 | 49 | public String getName() { 50 | return image.getImagePath(); 51 | } 52 | 53 | @SuppressWarnings("static-method") 54 | @ExportMessage 55 | public boolean isExecutable() { 56 | return true; 57 | } 58 | 59 | @ExportMessage 60 | @TruffleBoundary 61 | public Object execute(final Object... arguments) { 62 | assert arguments.length == 0; 63 | image.interrupt.start(); 64 | image.attachDisplayIfNecessary(); 65 | return image.getActiveContextNode().getCallTarget().call(); 66 | } 67 | 68 | @SuppressWarnings("static-method") 69 | @ExportMessage 70 | public boolean hasMembers() { 71 | return true; 72 | } 73 | 74 | @SuppressWarnings("static-method") 75 | @ExportMessage 76 | public boolean isMemberReadable(@SuppressWarnings("unused") final String member) { 77 | return image.lookup(member) != NilObject.SINGLETON; 78 | } 79 | 80 | @ExportMessage 81 | public Object getMembers(@SuppressWarnings("unused") final boolean includeInternal) { 82 | return image.evaluateUninterruptably("Smalltalk globals keys collect: [:ea | ea asString]"); 83 | } 84 | 85 | @ExportMessage 86 | public Object readMember(final String member) { 87 | return image.lookup(member); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/DropPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins; 8 | 9 | import java.util.List; 10 | 11 | import com.oracle.truffle.api.dsl.GenerateNodeFactory; 12 | import com.oracle.truffle.api.dsl.ImportStatic; 13 | import com.oracle.truffle.api.dsl.NodeFactory; 14 | import com.oracle.truffle.api.dsl.Specialization; 15 | 16 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 17 | import de.hpi.swa.trufflesqueak.model.NativeObject; 18 | import de.hpi.swa.trufflesqueak.model.PointersObject; 19 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; 20 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; 21 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive1WithFallback; 22 | import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; 23 | 24 | public final class DropPlugin extends AbstractPrimitiveFactoryHolder { 25 | 26 | @Override 27 | public List> getFactories() { 28 | return DropPluginFactory.getFactories(); 29 | } 30 | 31 | @ImportStatic(DropPlugin.class) 32 | @GenerateNodeFactory 33 | @SqueakPrimitive(names = "primitiveDropRequestFileHandle") 34 | protected abstract static class PrimDropRequestFileHandleNode extends AbstractPrimitiveNode implements Primitive1WithFallback { 35 | 36 | @Specialization(guards = "dropIndex <= getFileList(getContext()).length") 37 | protected final PointersObject doRequest(@SuppressWarnings("unused") final Object receiver, final long dropIndex) { 38 | final SqueakImageContext image = getContext(); 39 | return FilePlugin.createFileHandleOrPrimFail(image, 40 | image.env.getPublicTruffleFile(getFileList(image)[(int) dropIndex - 1]), false); 41 | } 42 | 43 | @SuppressWarnings("static-method") // Work around code generation problems. 44 | protected final String[] getFileList(final SqueakImageContext image) { 45 | return image.dropPluginFileList; 46 | } 47 | } 48 | 49 | @ImportStatic(DropPlugin.class) 50 | @GenerateNodeFactory 51 | @SqueakPrimitive(names = "primitiveDropRequestFileName") 52 | protected abstract static class PrimDropRequestFileNameNode extends AbstractPrimitiveNode implements Primitive1WithFallback { 53 | 54 | @Specialization(guards = "dropIndex <= getFileList(getContext()).length") 55 | protected final NativeObject doRequest(@SuppressWarnings("unused") final Object receiver, final long dropIndex) { 56 | final SqueakImageContext image = getContext(); 57 | return image.asByteString(getFileList(image)[(int) dropIndex - 1]); 58 | } 59 | 60 | @SuppressWarnings("static-method") // Work around code generation problems. 61 | protected final String[] getFileList(final SqueakImageContext image) { 62 | return image.dropPluginFileList; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/util/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2022-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.util; 8 | 9 | import java.lang.reflect.Constructor; 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | 13 | import jdk.internal.module.Modules; 14 | 15 | public final class ReflectionUtils { 16 | public static Constructor lookupConstructor(final Class declaringClass, final Class... parameterTypes) { 17 | try { 18 | final Constructor result = declaringClass.getDeclaredConstructor(parameterTypes); 19 | openModule(declaringClass); 20 | result.setAccessible(true); 21 | return result; 22 | } catch (final ReflectiveOperationException e) { 23 | throw new RuntimeException(e); 24 | } 25 | } 26 | 27 | public static Field lookupField(final Class declaringClass, final String fieldName) { 28 | try { 29 | final Field result = declaringClass.getDeclaredField(fieldName); 30 | openModule(declaringClass); 31 | result.setAccessible(true); 32 | return result; 33 | } catch (final ReflectiveOperationException e) { 34 | throw new RuntimeException(e); 35 | } 36 | } 37 | 38 | public static Method lookupMethod(final Class declaringClass, final String methodName, final Class... parameterTypes) { 39 | try { 40 | final Method result = declaringClass.getDeclaredMethod(methodName, parameterTypes); 41 | openModule(declaringClass); 42 | result.setAccessible(true); 43 | return result; 44 | } catch (final ReflectiveOperationException e) { 45 | throw new RuntimeException(e); 46 | } 47 | } 48 | 49 | /** 50 | * Ensure that this class is allowed to call setAccessible for an element of the provided 51 | * declaring class. 52 | */ 53 | private static void openModule(final Class declaringClass) { 54 | openModuleByClass(declaringClass, ReflectionUtils.class); 55 | } 56 | 57 | public static void openModuleByClass(final Class declaringClass, final Class accessingClass) { 58 | final Module declaringModule = declaringClass.getModule(); 59 | final String packageName = declaringClass.getPackageName(); 60 | Module namedAccessingModule = null; 61 | if (accessingClass != null) { 62 | final Module accessingModule = accessingClass.getModule(); 63 | if (accessingModule.isNamed()) { 64 | namedAccessingModule = accessingModule; 65 | } 66 | } 67 | if (namedAccessingModule != null ? declaringModule.isOpen(packageName, namedAccessingModule) : declaringModule.isOpen(packageName)) { 68 | return; 69 | } 70 | if (namedAccessingModule != null) { 71 | Modules.addOpens(declaringModule, packageName, namedAccessingModule); 72 | } else { 73 | Modules.addOpensToAllUnnamed(declaringModule, packageName); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/Resolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.network; 8 | 9 | import java.net.InetAddress; 10 | import java.net.InetSocketAddress; 11 | import java.net.UnknownHostException; 12 | 13 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 14 | 15 | final class Resolver { 16 | 17 | enum Status { 18 | Uninitialized(0), 19 | Ready(1), 20 | Busy(2), 21 | Error(3); 22 | 23 | private final long id; 24 | 25 | Status(final long id) { 26 | this.id = id; 27 | } 28 | 29 | long id() { 30 | return id; 31 | } 32 | } 33 | 34 | private static InetAddress anyLocalAddress; 35 | private static InetAddress loopbackAddress; 36 | 37 | private static byte[] lastNameLookup; 38 | private static String lastAddressLookup; 39 | 40 | private Resolver() { 41 | } 42 | 43 | protected static byte[] getAnyLocalAddress() { 44 | if (anyLocalAddress == null) { 45 | anyLocalAddress = new InetSocketAddress(0).getAddress(); 46 | } 47 | return anyLocalAddress.getAddress(); 48 | } 49 | 50 | @TruffleBoundary 51 | protected static byte[] getLoopbackAddress() { 52 | if (loopbackAddress == null) { 53 | loopbackAddress = InetAddress.getLoopbackAddress(); 54 | } 55 | return loopbackAddress.getAddress(); 56 | } 57 | 58 | @TruffleBoundary 59 | protected static void startHostNameLookUp(final String hostName) throws UnknownHostException { 60 | try { 61 | if ("localhost".equals(hostName)) { 62 | lastNameLookup = Resolver.getLoopbackAddress(); 63 | return; 64 | } 65 | 66 | final InetAddress address = InetAddress.getByName(hostName); 67 | lastNameLookup = address.getAddress(); 68 | } catch (final UnknownHostException e) { 69 | lastNameLookup = null; 70 | throw e; 71 | } 72 | } 73 | 74 | protected static byte[] lastHostNameLookupResult() { 75 | return lastNameLookup; 76 | } 77 | 78 | @TruffleBoundary 79 | protected static void startAddressLookUp(final byte[] address) throws UnknownHostException { 80 | try { 81 | lastAddressLookup = InetAddress.getByAddress(address).getHostName(); 82 | } catch (final UnknownHostException e) { 83 | lastAddressLookup = null; 84 | throw e; 85 | } 86 | } 87 | 88 | protected static String lastAddressLookUpResult() { 89 | return lastAddressLookup; 90 | } 91 | 92 | @TruffleBoundary 93 | protected static String addressBytesToString(final byte[] address) { 94 | try { 95 | return InetAddress.getByAddress(address).getHostAddress(); 96 | } catch (final UnknownHostException e) { 97 | return null; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.shared/src/de/hpi/swa/trufflesqueak/shared/SqueakLanguageOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.shared; 8 | 9 | public final class SqueakLanguageOptions { 10 | public static final String CODE_FLAG = "--code"; 11 | public static final String CODE_FLAG_SHORT = "-c"; 12 | public static final String CODE_HELP = "Smalltalk code to be executed without display"; 13 | public static final String CONTEXT_STACK_DEPTH = "context-stack-depth"; 14 | public static final String CONTEXT_STACK_DEPTH_FLAG = "--" + CONTEXT_STACK_DEPTH; 15 | public static final String CONTEXT_STACK_DEPTH_HELP = "Flush context stack when it reaches this depth (0 = disabled)"; 16 | public static final String HEADLESS = "headless"; 17 | public static final String HEADLESS_FLAG = "--" + HEADLESS; 18 | public static final String HEADLESS_HELP = "Run without a display"; 19 | public static final String IMAGE_ARGUMENTS = "image-arguments"; 20 | public static final String IMAGE_ARGUMENTS_FLAG = "--" + IMAGE_ARGUMENTS; 21 | public static final String IMAGE_ARGUMENTS_HELP = "Comma-separated list of image arguments"; 22 | public static final String IMAGE_PATH = "image-path"; 23 | public static final String IMAGE_PATH_FLAG = "--" + IMAGE_PATH; 24 | public static final String IMAGE_PATH_HELP = "Path to image"; 25 | public static final String INTERCEPT_MESSAGES = "intercept-messages"; 26 | public static final String INTERCEPT_MESSAGES_HELP = "Comma-separated list of messages to intercept with an instrument"; 27 | public static final String INTERRUPTS = "disable-interrupts"; 28 | public static final String INTERRUPTS_FLAG = "--" + INTERRUPTS; 29 | public static final String INTERRUPTS_HELP = "Disable interrupt handler"; 30 | public static final String PRINT_IMAGE_PATH_FLAG = "--print-image-path"; 31 | public static final String PRINT_IMAGE_PATH_HELP = "Print the path to default Squeak/Smalltalk image"; 32 | public static final String QUIET = "quiet"; 33 | public static final String QUIET_FLAG = "--" + QUIET; 34 | public static final String QUIET_HELP = "Operate quietly"; 35 | public static final String RESOURCE_SUMMARY = "resource-summary"; 36 | public static final String RESOURCE_SUMMARY_FLAG = "--" + RESOURCE_SUMMARY; 37 | public static final String RESOURCE_SUMMARY_HELP = "Print resource summary on context exit"; 38 | public static final String SIGNAL_INPUT_SEMAPHORE = "signal-input-semaphore"; 39 | public static final String SIGNAL_INPUT_SEMAPHORE_HELP = "Signal the input semaphore"; 40 | public static final String STARTUP = "disable-startup"; 41 | public static final String STARTUP_HELP = "Disable image startup routine in headless mode"; 42 | public static final String TESTING = "testing"; 43 | public static final String TESTING_HELP = "For internal testing purposes only"; 44 | public static final String TRANSCRIPT_FORWARDING_FLAG = "--enable-transcript-forwarding"; 45 | public static final String TRANSCRIPT_FORWARDING_HELP = "Forward stdio to Smalltalk transcript"; 46 | 47 | private SqueakLanguageOptions() { 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/accessing/SqueakObjectInstSizeNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.accessing; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.nodes.Node; 14 | 15 | import de.hpi.swa.trufflesqueak.model.AbstractPointersObject; 16 | import de.hpi.swa.trufflesqueak.model.ArrayObject; 17 | import de.hpi.swa.trufflesqueak.model.BlockClosureObject; 18 | import de.hpi.swa.trufflesqueak.model.CharacterObject; 19 | import de.hpi.swa.trufflesqueak.model.ClassObject; 20 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 21 | import de.hpi.swa.trufflesqueak.model.ContextObject; 22 | import de.hpi.swa.trufflesqueak.model.EmptyObject; 23 | import de.hpi.swa.trufflesqueak.model.FloatObject; 24 | import de.hpi.swa.trufflesqueak.model.NativeObject; 25 | import de.hpi.swa.trufflesqueak.model.NilObject; 26 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 27 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectInstSizeNode; 28 | 29 | @GenerateInline 30 | @GenerateCached(false) 31 | public abstract class SqueakObjectInstSizeNode extends AbstractNode { 32 | 33 | public abstract int execute(Node node, Object obj); 34 | 35 | @Specialization 36 | protected static final int doArray(final ArrayObject obj) { 37 | return obj.instsize(); 38 | } 39 | 40 | @Specialization 41 | protected static final int doNative(final NativeObject obj) { 42 | return obj.instsize(); 43 | } 44 | 45 | @Specialization 46 | protected static final int doAbstractPointersObject(final Node node, final AbstractPointersObject obj, 47 | @Cached final AbstractPointersObjectInstSizeNode instSizeNode) { 48 | return instSizeNode.execute(node, obj); 49 | } 50 | 51 | @Specialization 52 | protected static final int doCode(final CompiledCodeObject obj) { 53 | return obj.instsize(); 54 | } 55 | 56 | @Specialization 57 | protected static final int doClosure(final BlockClosureObject obj) { 58 | return obj.instsize(); 59 | } 60 | 61 | @Specialization 62 | protected static final int doClass(final ClassObject obj) { 63 | return obj.instsize(); 64 | } 65 | 66 | @Specialization 67 | protected static final int doNil(final NilObject obj) { 68 | return obj.instsize(); 69 | } 70 | 71 | @Specialization 72 | protected static final int doEmpty(final EmptyObject obj) { 73 | return obj.instsize(); 74 | } 75 | 76 | @Specialization 77 | protected static final int doContext(final ContextObject obj) { 78 | return obj.instsize(); 79 | } 80 | 81 | @Specialization 82 | protected static final int doFloat(final FloatObject obj) { 83 | return obj.instsize(); 84 | } 85 | 86 | @Specialization 87 | protected static final int doCharacterObject(final CharacterObject obj) { 88 | return obj.instsize(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/interrupts/CheckForInterruptsFullNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.interrupts; 8 | 9 | import com.oracle.truffle.api.dsl.NeverDefault; 10 | import com.oracle.truffle.api.frame.VirtualFrame; 11 | import com.oracle.truffle.api.nodes.Node; 12 | 13 | import de.hpi.swa.trufflesqueak.exceptions.ProcessSwitch; 14 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 15 | import de.hpi.swa.trufflesqueak.model.ArrayObject; 16 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.SPECIAL_OBJECT; 17 | import de.hpi.swa.trufflesqueak.nodes.process.SignalSemaphoreNode; 18 | 19 | public final class CheckForInterruptsFullNode extends Node { 20 | @Child private SignalSemaphoreNode signalSemaporeNode; 21 | 22 | private final Object[] specialObjects; 23 | private final CheckForInterruptsState istate; 24 | 25 | private CheckForInterruptsFullNode(final SqueakImageContext image) { 26 | specialObjects = image.specialObjectsArray.getObjectStorage(); 27 | istate = image.interrupt; 28 | signalSemaporeNode = SignalSemaphoreNode.create(); 29 | } 30 | 31 | @NeverDefault 32 | public static CheckForInterruptsFullNode create() { 33 | return new CheckForInterruptsFullNode(SqueakImageContext.getSlow()); 34 | } 35 | 36 | public void execute(final VirtualFrame frame) { 37 | if (istate.shouldSkip()) { 38 | return; 39 | } 40 | boolean switchToNewProcess = false; 41 | if (istate.tryInterruptPending()) { 42 | switchToNewProcess |= signalSemaporeNode.executeSignal(frame, this, specialObjects[SPECIAL_OBJECT.THE_INTERRUPT_SEMAPHORE]); 43 | } 44 | if (istate.tryWakeUpTickTrigger()) { 45 | switchToNewProcess |= signalSemaporeNode.executeSignal(frame, this, specialObjects[SPECIAL_OBJECT.THE_TIMER_SEMAPHORE]); 46 | } 47 | if (istate.tryPendingFinalizations()) { 48 | switchToNewProcess |= signalSemaporeNode.executeSignal(frame, this, specialObjects[SPECIAL_OBJECT.THE_FINALIZATION_SEMAPHORE]); 49 | } 50 | if (istate.trySemaphoresToSignal()) { 51 | final ArrayObject externalObjects = (ArrayObject) specialObjects[SPECIAL_OBJECT.EXTERNAL_OBJECTS_ARRAY]; 52 | if (!externalObjects.isEmptyType()) { // signal external semaphores 53 | final Object[] semaphores = externalObjects.getObjectStorage(); 54 | Integer semaIndex; 55 | while ((semaIndex = istate.nextSemaphoreToSignal()) != null) { 56 | switchToNewProcess |= signalSemaporeNode.executeSignal(frame, this, semaphores[semaIndex - 1]); 57 | } 58 | } 59 | } 60 | /* 61 | * OpenSmalltalk VM signals all semaphores and switches to the highest priority process. If 62 | * we do not do this, small Delays in a loop in the image will prevent the code after the 63 | * wake-up-tick handler from getting executed (finalizations, for example). 64 | */ 65 | if (switchToNewProcess) { 66 | throw ProcessSwitch.SINGLETON; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/Win32OSProcessPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 14 | import com.oracle.truffle.api.dsl.GenerateNodeFactory; 15 | import com.oracle.truffle.api.dsl.NodeFactory; 16 | import com.oracle.truffle.api.dsl.Specialization; 17 | import com.oracle.truffle.api.interop.InteropLibrary; 18 | import com.oracle.truffle.api.library.CachedLibrary; 19 | 20 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 21 | import de.hpi.swa.trufflesqueak.model.NativeObject; 22 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; 23 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive0; 24 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive0WithFallback; 25 | import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; 26 | 27 | public final class Win32OSProcessPlugin extends AbstractOSProcessPlugin { 28 | 29 | @Override 30 | public List> getFactories() { 31 | final List> factories = new ArrayList<>(); 32 | factories.addAll(Win32OSProcessPluginFactory.getFactories()); 33 | factories.addAll(AbstractOSProcessPluginFactory.getFactories()); 34 | return factories; 35 | } 36 | 37 | @GenerateNodeFactory 38 | @SqueakPrimitive(names = "primitiveGetEnvironmentStrings") 39 | protected abstract static class PrimGetEnvironmentStringNode extends AbstractPrimitiveNode implements Primitive0 { 40 | @Specialization 41 | protected final NativeObject doGet(@SuppressWarnings("unused") final Object receiver) { 42 | final SqueakImageContext image = getContext(); 43 | return image.asByteString(getEnvironmentString(image)); 44 | } 45 | 46 | @TruffleBoundary 47 | private static String getEnvironmentString(final SqueakImageContext image) { 48 | final Map envMap = image.env.getEnvironment(); 49 | final List strings = new ArrayList<>(); 50 | for (final Map.Entry entry : envMap.entrySet()) { 51 | strings.add(entry.getKey() + "=" + entry.getValue()); 52 | } 53 | return String.join("\n", strings); 54 | } 55 | } 56 | 57 | @GenerateNodeFactory 58 | @SqueakPrimitive(names = "primitiveGetMainThreadID") 59 | protected abstract static class PrimGetMainThreadIDNode extends AbstractSysCallPrimitiveNode implements Primitive0WithFallback { 60 | @Specialization(guards = "supportsNFI") 61 | protected final long doGetMainThreadID(@SuppressWarnings("unused") final Object receiver, 62 | @CachedLibrary("getSysCallObject()") final InteropLibrary lib) { 63 | return getValue(lib); 64 | } 65 | 66 | @Override 67 | protected final String getFunctionName() { 68 | return "GetCurrentThreadId"; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/SecurityPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins; 8 | 9 | import java.util.List; 10 | 11 | import com.oracle.truffle.api.dsl.GenerateNodeFactory; 12 | import com.oracle.truffle.api.dsl.NodeFactory; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.frame.VirtualFrame; 15 | import com.oracle.truffle.api.nodes.DenyReplace; 16 | 17 | import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; 18 | import de.hpi.swa.trufflesqueak.model.BooleanObject; 19 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; 20 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; 21 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractSingletonPrimitiveNode; 22 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive0; 23 | import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; 24 | 25 | public final class SecurityPlugin extends AbstractPrimitiveFactoryHolder { 26 | 27 | @DenyReplace 28 | @SqueakPrimitive(names = "primitiveCanWriteImage") 29 | public static final class PrimCanWriteImageNode extends AbstractSingletonPrimitiveNode implements Primitive0 { 30 | @Override 31 | public Object execute(final VirtualFrame frame, final Object receiver) { 32 | return BooleanObject.wrap(getContext().env.getCurrentWorkingDirectory().isWritable()); 33 | } 34 | } 35 | 36 | @GenerateNodeFactory 37 | @SqueakPrimitive(names = "primitiveDisableImageWrite") 38 | protected abstract static class PrimDisableImageWriteNode extends AbstractPrimitiveNode implements Primitive0 { 39 | @Specialization 40 | protected static final Object doDisable(@SuppressWarnings("unused") final Object receiver) { 41 | throw PrimitiveFailed.GENERIC_ERROR; // TODO: implement primitive 42 | } 43 | } 44 | 45 | @GenerateNodeFactory 46 | @SqueakPrimitive(names = "primitiveGetSecureUserDirectory") 47 | protected abstract static class PrimGetSecureUserDirectoryNode extends AbstractPrimitiveNode implements Primitive0 { 48 | @Specialization 49 | protected static final Object doGet(@SuppressWarnings("unused") final Object receiver) { 50 | throw PrimitiveFailed.GENERIC_ERROR; // TODO: implement primitive 51 | } 52 | } 53 | 54 | @DenyReplace 55 | @SqueakPrimitive(names = "primitiveGetUntrustedUserDirectory") 56 | public static final class PrimGetUntrustedUserDirectoryNode extends AbstractSingletonPrimitiveNode implements Primitive0 { 57 | @Override 58 | public Object execute(final VirtualFrame frame, final Object receiver) { 59 | return getContext().getResourcesDirectory(); 60 | } 61 | } 62 | 63 | @Override 64 | public List> getFactories() { 65 | return SecurityPluginFactory.getFactories(); 66 | } 67 | 68 | @Override 69 | public List getSingletonPrimitives() { 70 | return List.of(new PrimCanWriteImageNode(), new PrimGetUntrustedUserDirectoryNode()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/ResumeProcessNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.frame.VirtualFrame; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 17 | import de.hpi.swa.trufflesqueak.model.PointersObject; 18 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 19 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 20 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 21 | 22 | /** 23 | * Returns the new active Context or null if the current active Context has not been preempted. 24 | */ 25 | @GenerateInline 26 | @GenerateCached(false) 27 | public abstract class ResumeProcessNode extends AbstractNode { 28 | 29 | public static final boolean executeUncached(final VirtualFrame frame, final SqueakImageContext image, final PointersObject newProcess) { 30 | final PointersObject activeProcess = image.getActiveProcessSlow(); 31 | final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); 32 | final long activePriority = readNode.executeLong(null, activeProcess, PROCESS.PRIORITY); 33 | final long newPriority = readNode.executeLong(null, newProcess, PROCESS.PRIORITY); 34 | if (newPriority > activePriority) { 35 | PutToSleepNode.executeUncached(image, activeProcess, image.flags.preemptionYields()); 36 | TransferToNode.executeUncached(frame, newProcess); 37 | return true; 38 | } else { 39 | PutToSleepNode.executeUncached(image, newProcess, true); 40 | return false; 41 | } 42 | } 43 | 44 | public abstract boolean executeResume(VirtualFrame frame, Node node, PointersObject newProcess); 45 | 46 | @Specialization 47 | protected static final boolean resumeProcess(final VirtualFrame frame, final Node node, final PointersObject newProcess, 48 | @Cached final AbstractPointersObjectReadNode readNode, 49 | @Cached final GetActiveProcessNode getActiveProcessNode, 50 | @Cached final PutToSleepNode putToSleepNode, 51 | @Cached final TransferToNode transferToNode) { 52 | final PointersObject activeProcess = getActiveProcessNode.execute(node); 53 | final long activePriority = readNode.executeLong(node, activeProcess, PROCESS.PRIORITY); 54 | final long newPriority = readNode.executeLong(node, newProcess, PROCESS.PRIORITY); 55 | if (newPriority > activePriority) { 56 | putToSleepNode.executePutToSleep(node, activeProcess, getContext(node).flags.preemptionYields()); 57 | transferToNode.execute(frame, node, newProcess); 58 | return true; 59 | } else { 60 | putToSleepNode.executePutToSleep(node, newProcess, true); 61 | return false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/ResumeContextRootNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes; 8 | 9 | import com.oracle.truffle.api.CompilerAsserts; 10 | import com.oracle.truffle.api.CompilerDirectives; 11 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 12 | import com.oracle.truffle.api.frame.VirtualFrame; 13 | import com.oracle.truffle.api.nodes.RootNode; 14 | import com.oracle.truffle.api.profiles.IntValueProfile; 15 | 16 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 17 | import de.hpi.swa.trufflesqueak.model.ContextObject; 18 | 19 | public final class ResumeContextRootNode extends AbstractRootNode { 20 | private ContextObject activeContext; 21 | private final IntValueProfile instructionPointerProfile = IntValueProfile.createIdentityProfile(); 22 | private final IntValueProfile stackPointerProfile = IntValueProfile.createIdentityProfile(); 23 | 24 | public ResumeContextRootNode(final SqueakImageContext image, final ContextObject context) { 25 | super(image, context.getMethodOrBlock()); 26 | activeContext = context; 27 | assert !activeContext.isDead() : "Terminated contexts cannot be resumed"; 28 | } 29 | 30 | public ResumeContextRootNode(final ResumeContextRootNode original) { 31 | super(original); 32 | activeContext = original.activeContext; 33 | assert !activeContext.isDead() : "Terminated contexts cannot be resumed"; 34 | } 35 | 36 | @Override 37 | public Object execute(final VirtualFrame frame) { 38 | assert !activeContext.isDead() : "Terminated contexts cannot be resumed"; 39 | activeContext.clearModifiedSender(); 40 | final int pc = instructionPointerProfile.profile(activeContext.getInstructionPointerForBytecodeLoop()); 41 | final int sp = stackPointerProfile.profile(activeContext.getStackPointer()); 42 | if (CompilerDirectives.isPartialEvaluationConstant(pc) && CompilerDirectives.isPartialEvaluationConstant(sp)) { 43 | return interpreterNode.execute(activeContext.getTruffleFrame(), pc, sp); 44 | } else { 45 | return interpretBytecodeWithBoundary(pc, sp); 46 | } 47 | } 48 | 49 | @TruffleBoundary 50 | private Object interpretBytecodeWithBoundary(final int pc, final int sp) { 51 | return interpreterNode.execute(activeContext.getTruffleFrame(), pc, sp); 52 | } 53 | 54 | public ContextObject getActiveContext() { 55 | return activeContext; 56 | } 57 | 58 | public void setActiveContext(final ContextObject newActiveContext) { 59 | assert activeContext.getCodeObject() == newActiveContext.getCodeObject(); 60 | assert getFrameDescriptor() == newActiveContext.getMethodOrBlock().getFrameDescriptor(); 61 | activeContext = newActiveContext; 62 | } 63 | 64 | @Override 65 | protected boolean isInstrumentable() { 66 | return false; 67 | } 68 | 69 | @Override 70 | protected RootNode cloneUninitialized() { 71 | return new ResumeContextRootNode(this); 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | CompilerAsserts.neverPartOfCompilation(); 77 | return activeContext.toString(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/TransferToNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.GenerateCached; 11 | import com.oracle.truffle.api.dsl.GenerateInline; 12 | import com.oracle.truffle.api.dsl.Specialization; 13 | import com.oracle.truffle.api.frame.VirtualFrame; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.model.ContextObject; 17 | import de.hpi.swa.trufflesqueak.model.PointersObject; 18 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 19 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS_SCHEDULER; 20 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 21 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 22 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 23 | import de.hpi.swa.trufflesqueak.nodes.context.GetOrCreateContextWithFrameNode; 24 | 25 | /** 26 | * Record a Process to be awakened on the next interpreter cycle. Suspends the active Context and 27 | * returns the new active Context. 28 | */ 29 | @GenerateInline 30 | @GenerateCached(false) 31 | public abstract class TransferToNode extends AbstractNode { 32 | private static final AbstractPointersObjectReadNode READ_NODE = AbstractPointersObjectReadNode.getUncached(); 33 | private static final AbstractPointersObjectWriteNode WRITE_NODE = AbstractPointersObjectWriteNode.getUncached(); 34 | 35 | public abstract void execute(VirtualFrame frame, Node node, PointersObject newProcess); 36 | 37 | public static final void executeUncached(final VirtualFrame frame, final PointersObject newProcess) { 38 | final PointersObject scheduler = getContext(null).getScheduler(); 39 | final PointersObject oldProcess = READ_NODE.executePointers(null, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS); 40 | WRITE_NODE.execute(null, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS, newProcess); 41 | final ContextObject activeContext = GetOrCreateContextWithFrameNode.executeUncached(frame); 42 | WRITE_NODE.execute(null, oldProcess, PROCESS.SUSPENDED_CONTEXT, activeContext); 43 | } 44 | 45 | @Specialization 46 | protected static final void transferTo(final VirtualFrame frame, final Node node, final PointersObject newProcess, 47 | @Cached final GetOrCreateContextWithFrameNode contextNode, 48 | @Cached final AbstractPointersObjectReadNode readOldProcessNode, 49 | @Cached final AbstractPointersObjectWriteNode writeActiveProcessNode, 50 | @Cached final AbstractPointersObjectWriteNode writeSuspendedContextNode) { 51 | final PointersObject scheduler = getContext(node).getScheduler(); 52 | final PointersObject oldProcess = readOldProcessNode.executePointers(node, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS); 53 | writeActiveProcessNode.execute(node, scheduler, PROCESS_SCHEDULER.ACTIVE_PROCESS, newProcess); 54 | writeSuspendedContextNode.execute(node, oldProcess, PROCESS.SUSPENDED_CONTEXT, contextNode.executeGet(frame, node)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak.ffi.native/include/sqMemoryAccess.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2023-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | #define SIZEOF_VOID_P 8 8 | 9 | //////////// from here on: copied from 10 | //////////// https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/ec421b99cf41fc5f2f5fb734b536d6233cdde809/platforms/Cross/vm/sqMemoryAccess.h 11 | 12 | #ifndef SIZEOF_LONG 13 | # if LLP64 14 | # define SIZEOF_LONG 4 15 | # else 16 | # define SIZEOF_LONG SIZEOF_VOID_P /* default is sizeof(long)==sizeof(void *) */ 17 | # endif 18 | #endif 19 | 20 | #if (SQ_VI_BYTES_PER_WORD == 4) 21 | # define SQ_IMAGE32 1 22 | # define SQ_IMAGE64 0 23 | #else 24 | # define SQ_IMAGE64 1 25 | # define SQ_IMAGE32 0 26 | #endif 27 | 28 | #if (SQ_IMAGE64 || SPURVM) 29 | # define OBJECTS_64BIT_ALIGNED 1 30 | # define OBJECTS_32BIT_ALIGNED 0 31 | #else 32 | # define OBJECTS_32BIT_ALIGNED 1 33 | # define OBJECTS_64BIT_ALIGNED 0 34 | #endif 35 | 36 | #if (SIZEOF_VOID_P == 4) 37 | # define SQ_HOST32 1 38 | #elif (SIZEOF_VOID_P == 8) 39 | # define SQ_HOST64 1 40 | #else 41 | # error host is neither 32- nor 64-bit? 42 | #endif 43 | 44 | /* sqInt is a signed integer with size adequate for holding an Object Oriented Pointer (or immediate value) 45 | - that is 32bits long on a 32bits image or 64bits long on a 64bits image 46 | we could use C99 int32_t and int64_t once retiring legacy compiler support this time has not yet come 47 | usqInt is the unsigned flavour 48 | SQABS is a macro for taking absolute value of an sqInt */ 49 | #if SQ_IMAGE32 50 | typedef int sqInt; 51 | typedef unsigned int usqInt; 52 | #define PRIdSQINT "d" 53 | #define PRIuSQINT "u" 54 | #define PRIxSQINT "x" 55 | #define PRIXSQINT "X" 56 | # define SQABS abs 57 | #elif SQ_HOST64 && (SIZEOF_LONG == 8) 58 | typedef long sqInt; 59 | typedef unsigned long usqInt; 60 | #define PRIdSQINT "ld" 61 | #define PRIuSQINT "lu" 62 | #define PRIxSQINT "lx" 63 | #define PRIXSQINT "lX" 64 | # define SQABS labs 65 | #elif (SIZEOF_LONG_LONG != 8) 66 | # error long long integers are not 64-bits wide? 67 | #else 68 | typedef long long sqInt; 69 | typedef unsigned long long usqInt; 70 | #define PRIdSQINT "lld" 71 | #define PRIuSQINT "llu" 72 | #define PRIxSQINT "llx" 73 | #define PRIXSQINT "llX" 74 | # define SQABS llabs 75 | #endif 76 | 77 | /* sqLong is a signed integer with at least 64bits on both 32 and 64 bits images 78 | usqLong is the unsigned flavour 79 | SQLABS is a macro for taking absolute value of a sqLong */ 80 | #if !defined(sqLong) 81 | # if SIZEOF_LONG == 8 82 | # define sqLong long 83 | # define usqLong unsigned long 84 | # define SQLABS labs 85 | # elif _MSC_VER 86 | # define sqLong __int64 87 | # define usqLong unsigned __int64 88 | # define SQLABS llabs 89 | # else 90 | # define sqLong long long 91 | # define usqLong unsigned long long 92 | # define SQLABS llabs 93 | # endif 94 | #endif /* !defined(sqLong) */ 95 | 96 | /* sqIntptr_t is a signed integer with enough bits to hold a pointer 97 | usqIntptr_t is the unsigned flavour 98 | this is essentially C99 intptr_t and uintptr_t but we support legacy compilers 99 | the C99 printf formats macros are also defined with SQ prefix */ 100 | #if SIZEOF_LONG == SIZEOF_VOID_P 101 | typedef long sqIntptr_t; 102 | typedef unsigned long usqIntptr_t; 103 | #define PRIdSQPTR "ld" 104 | #define PRIuSQPTR "lu" 105 | #define PRIxSQPTR "lx" 106 | #define PRIXSQPTR "lX" 107 | #else 108 | typedef long long sqIntptr_t; 109 | typedef unsigned long long usqIntptr_t; 110 | #define PRIdSQPTR "lld" 111 | #define PRIuSQPTR "llu" 112 | #define PRIxSQPTR "llx" 113 | #define PRIXSQPTR "llX" 114 | #endif 115 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/BMPReadWriterPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins; 8 | 9 | import java.util.List; 10 | 11 | import com.oracle.truffle.api.dsl.GenerateNodeFactory; 12 | import com.oracle.truffle.api.dsl.NodeFactory; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | 15 | import de.hpi.swa.trufflesqueak.model.NativeObject; 16 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder; 17 | import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode; 18 | import de.hpi.swa.trufflesqueak.nodes.primitives.Primitive.Primitive4WithFallback; 19 | import de.hpi.swa.trufflesqueak.nodes.primitives.SqueakPrimitive; 20 | 21 | public final class BMPReadWriterPlugin extends AbstractPrimitiveFactoryHolder { 22 | 23 | protected abstract static class AbstractBMPPluginNode extends AbstractPrimitiveNode { 24 | protected static final boolean inBounds(final long formBitsIndex, final long width, final NativeObject formBits, final NativeObject pixelLine) { 25 | return formBitsIndex + width <= formBits.getIntLength() && width * 3 <= pixelLine.getByteLength(); 26 | } 27 | } 28 | 29 | @GenerateNodeFactory 30 | @SqueakPrimitive(names = "primitiveRead24BmpLine") 31 | protected abstract static class PrimRead24BmpLineNode extends AbstractBMPPluginNode implements Primitive4WithFallback { 32 | @Specialization(guards = {"pixelLine.isByteType()", "formBits.isIntType()", "inBounds(formBitsIndex, width, formBits, pixelLine)"}) 33 | protected static final Object doRead(final Object receiver, final NativeObject pixelLine, final NativeObject formBits, final long formBitsIndex, final long width) { 34 | final byte[] bytes = pixelLine.getByteStorage(); 35 | final int[] ints = formBits.getIntStorage(); 36 | final int bitsStartIndex = (int) formBitsIndex - 1; 37 | for (int i = 0; i < width; i++) { 38 | final int pixelIndex = i * 3; 39 | final int rgb = bytes[pixelIndex] & 0xFF | (bytes[pixelIndex + 1] & 0xFF) << 8 | (bytes[pixelIndex + 2] & 0xFF) << 16; 40 | ints[bitsStartIndex + i] = rgb == 0 ? 0xFF000001 : rgb | 0xFF000000; 41 | } 42 | return receiver; 43 | } 44 | } 45 | 46 | @GenerateNodeFactory 47 | @SqueakPrimitive(names = "primitiveWrite24BmpLine") 48 | protected abstract static class PrimWrite24BmpLineNode extends AbstractBMPPluginNode implements Primitive4WithFallback { 49 | @Specialization(guards = {"pixelLine.isByteType()", "formBits.isIntType()", "inBounds(formBitsIndex, width, formBits, pixelLine)"}) 50 | protected static final Object doWrite(final Object receiver, final NativeObject pixelLine, final NativeObject formBits, final long formBitsIndex, final long width) { 51 | final byte[] bytes = pixelLine.getByteStorage(); 52 | final int[] ints = formBits.getIntStorage(); 53 | final int bitsStartIndex = (int) formBitsIndex - 1; 54 | for (int i = 0; i < width; i++) { 55 | final int rgb = ints[bitsStartIndex + i] & 0xFFFFFF; 56 | final int pixelIndex = i * 3; 57 | bytes[pixelIndex] = (byte) (rgb & 0xFF); 58 | bytes[pixelIndex + 1] = (byte) (rgb >> 8 & 0xFF); 59 | bytes[pixelIndex + 2] = (byte) (rgb >> 16 & 0xFF); 60 | } 61 | return receiver; 62 | } 63 | } 64 | 65 | @Override 66 | public List> getFactories() { 67 | return BMPReadWriterPluginFactory.getFactories(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/AddLinkToListNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.Cached.Shared; 11 | import com.oracle.truffle.api.dsl.GenerateCached; 12 | import com.oracle.truffle.api.dsl.GenerateInline; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.model.PointersObject; 17 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.LINKED_LIST; 18 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 19 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 20 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 21 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 22 | 23 | /* 24 | * Add the given process to the given end of the given linked list. 25 | */ 26 | @GenerateInline 27 | @GenerateCached(false) 28 | public abstract class AddLinkToListNode extends AbstractNode { 29 | 30 | public static void executeUncached(final PointersObject process, final PointersObject list, final boolean addLast) { 31 | final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); 32 | final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); 33 | addLinkToList(null, process, list, addLast, readNode, readNode, readNode, writeNode, writeNode, writeNode, writeNode); 34 | } 35 | 36 | public abstract void execute(Node node, PointersObject process, PointersObject list, boolean addLast); 37 | 38 | /** 39 | *
40 |      * Adding as the firstLink versus the lastLink differ in two ways.
41 |      * 1. LAST_LINK and FIRST_LINK are interchanged
42 |      * 2. process.nextLink = firstLink versus lastLink.nextLink = process
43 |      * 
44 | */ 45 | @Specialization 46 | protected static final void addLinkToList(final Node node, final PointersObject process, final PointersObject list, final boolean addLast, 47 | @Cached final AbstractPointersObjectReadNode readEmptyNode, 48 | @Cached final AbstractPointersObjectReadNode readFirstLinkNode, 49 | @Cached final AbstractPointersObjectReadNode readLastLinkNode, 50 | @Cached final AbstractPointersObjectWriteNode writeFirstLinkNode, 51 | @Cached final AbstractPointersObjectWriteNode writeLastLinkNode, 52 | @Cached final AbstractPointersObjectWriteNode writeNextLinkNode, 53 | @Cached final AbstractPointersObjectWriteNode writeListNode) { 54 | writeListNode.execute(node, process, PROCESS.LIST, list); 55 | if (list.isEmptyList(readEmptyNode, node)) { 56 | writeFirstLinkNode.execute(node, list, LINKED_LIST.FIRST_LINK, process); 57 | writeLastLinkNode.execute(node, list, LINKED_LIST.LAST_LINK, process); 58 | } else if (addLast) { 59 | final PointersObject lastLink = readLastLinkNode.executePointers(node, list, LINKED_LIST.LAST_LINK); 60 | writeLastLinkNode.execute(node, list, LINKED_LIST.LAST_LINK, process); 61 | writeNextLinkNode.execute(node, lastLink, PROCESS.NEXT_LINK, process); 62 | } else { 63 | final PointersObject firstLink = readFirstLinkNode.executePointers(node, list, LINKED_LIST.FIRST_LINK); 64 | writeFirstLinkNode.execute(node, list, LINKED_LIST.FIRST_LINK, process); 65 | writeNextLinkNode.execute(node, process, PROCESS.NEXT_LINK, firstLink); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/accessing/ClassObjectNodes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.accessing; 8 | 9 | import com.oracle.truffle.api.dsl.GenerateCached; 10 | import com.oracle.truffle.api.dsl.GenerateInline; 11 | import com.oracle.truffle.api.dsl.GenerateUncached; 12 | import com.oracle.truffle.api.dsl.ImportStatic; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.model.AbstractSqueakObject; 17 | import de.hpi.swa.trufflesqueak.model.ClassObject; 18 | import de.hpi.swa.trufflesqueak.model.NilObject; 19 | import de.hpi.swa.trufflesqueak.model.VariablePointersObject; 20 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 21 | 22 | public final class ClassObjectNodes { 23 | @GenerateInline 24 | @GenerateUncached 25 | @GenerateCached(false) 26 | @ImportStatic(ClassObject.class) 27 | public abstract static class ClassObjectReadNode extends AbstractNode { 28 | public abstract Object execute(Node node, ClassObject obj, long index); 29 | 30 | @Specialization(guards = "isSuperclassIndex(index)") 31 | protected static final AbstractSqueakObject doClassSuperclass(final ClassObject obj, @SuppressWarnings("unused") final long index) { 32 | return obj.getSuperclass(); 33 | } 34 | 35 | @Specialization(guards = {"isMethodDictIndex(index)"}) 36 | protected static final VariablePointersObject doClassMethodDict(final ClassObject obj, @SuppressWarnings("unused") final long index) { 37 | return obj.getMethodDict(); 38 | } 39 | 40 | @Specialization(guards = {"isFormatIndex(index)"}) 41 | protected static final long doClassFormat(final ClassObject obj, @SuppressWarnings("unused") final long index) { 42 | return obj.getFormat(); 43 | } 44 | 45 | @Specialization(guards = "isOtherIndex(index)") 46 | protected static final Object doClass(final ClassObject obj, final long index) { 47 | return obj.getOtherPointer((int) index); 48 | } 49 | } 50 | 51 | @GenerateInline 52 | @GenerateUncached 53 | @GenerateCached(false) 54 | @ImportStatic(ClassObject.class) 55 | public abstract static class ClassObjectWriteNode extends AbstractNode { 56 | 57 | public abstract void execute(Node node, ClassObject obj, long index, Object value); 58 | 59 | @Specialization(guards = "isSuperclassIndex(index)") 60 | protected static final void doClassSuperclass(final ClassObject obj, @SuppressWarnings("unused") final long index, final ClassObject value) { 61 | obj.setSuperclass(value); 62 | } 63 | 64 | @Specialization(guards = "isSuperclassIndex(index)") 65 | protected static final void doClassSuperclass(final ClassObject obj, @SuppressWarnings("unused") final long index, @SuppressWarnings("unused") final NilObject value) { 66 | obj.setSuperclass(null); 67 | } 68 | 69 | @Specialization(guards = "isMethodDictIndex(index)") 70 | protected static final void doClassMethodDict(final ClassObject obj, @SuppressWarnings("unused") final long index, final VariablePointersObject value) { 71 | obj.setMethodDict(value); 72 | } 73 | 74 | @Specialization(guards = "isFormatIndex(index)") 75 | protected static final void doClassFormat(final ClassObject obj, @SuppressWarnings("unused") final long index, final long value) { 76 | obj.setFormat(value); 77 | } 78 | 79 | @Specialization(guards = "isOtherIndex(index)") 80 | protected static final void doClass(final ClassObject obj, final long index, final Object value) { 81 | obj.setOtherPointer((int) index, value); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/interop/ConvertToSqueakNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.interop; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives; 10 | import com.oracle.truffle.api.dsl.Fallback; 11 | import com.oracle.truffle.api.dsl.GenerateCached; 12 | import com.oracle.truffle.api.dsl.GenerateInline; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.interop.InteropLibrary; 15 | import com.oracle.truffle.api.interop.UnsupportedMessageException; 16 | import com.oracle.truffle.api.library.CachedLibrary; 17 | import com.oracle.truffle.api.nodes.Node; 18 | 19 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 20 | import de.hpi.swa.trufflesqueak.model.NativeObject; 21 | import de.hpi.swa.trufflesqueak.model.NilObject; 22 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 23 | import de.hpi.swa.trufflesqueak.util.LogUtils; 24 | 25 | /** 26 | * Converts an object to a TruffleSqueak object, returns `nil` if conversion is not possible. 27 | */ 28 | @GenerateInline 29 | @GenerateCached(false) 30 | public abstract class ConvertToSqueakNode extends AbstractNode { 31 | 32 | public abstract Object executeConvert(Node node, Object value); 33 | 34 | @Specialization(guards = "lib.isBoolean(value)", limit = "1") 35 | protected static final boolean doBoolean(final Object value, 36 | @CachedLibrary("value") final InteropLibrary lib) { 37 | try { 38 | return lib.asBoolean(value); 39 | } catch (final UnsupportedMessageException e) { 40 | CompilerDirectives.transferToInterpreter(); 41 | LogUtils.INTEROP.warning(e.toString()); 42 | return false; 43 | } 44 | } 45 | 46 | @Specialization(guards = "lib.isString(value)", limit = "1") 47 | protected final NativeObject doString(final Object value, 48 | @CachedLibrary("value") final InteropLibrary lib) { 49 | final SqueakImageContext image = getContext(); 50 | try { 51 | return image.asByteString(lib.asString(value)); 52 | } catch (final UnsupportedMessageException e) { 53 | CompilerDirectives.transferToInterpreter(); 54 | LogUtils.INTEROP.warning(e.toString()); 55 | return image.asByteString(""); 56 | } 57 | } 58 | 59 | @SuppressWarnings("unused") 60 | @Specialization(guards = "lib.isNull(value)", limit = "1") 61 | protected static final NilObject doNull(final Object value, 62 | @CachedLibrary("value") final InteropLibrary lib) { 63 | return NilObject.SINGLETON; 64 | } 65 | 66 | @Specialization(guards = "lib.fitsInLong(value)", limit = "1") 67 | protected static final long doLong(final Object value, 68 | @CachedLibrary("value") final InteropLibrary lib) { 69 | try { 70 | return lib.asLong(value); 71 | } catch (final UnsupportedMessageException e) { 72 | CompilerDirectives.transferToInterpreter(); 73 | LogUtils.INTEROP.warning(e.toString()); 74 | return 0L; 75 | } 76 | } 77 | 78 | @Specialization(guards = {"lib.fitsInDouble(value)", "!lib.fitsInLong(value)"}, limit = "1") 79 | protected static final double doDouble(final Object value, 80 | @CachedLibrary("value") final InteropLibrary lib) { 81 | try { 82 | return lib.asDouble(value); 83 | } catch (final UnsupportedMessageException e) { 84 | CompilerDirectives.transferToInterpreter(); 85 | LogUtils.INTEROP.warning(e.toString()); 86 | return 0D; 87 | } 88 | } 89 | 90 | @Fallback 91 | protected static final NilObject doFail(@SuppressWarnings("unused") final Object value) { 92 | return NilObject.SINGLETON; /* Return nil if conversion fails. */ 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/SqueakLanguage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak; 8 | 9 | import org.graalvm.options.OptionDescriptors; 10 | 11 | import com.oracle.truffle.api.CallTarget; 12 | import com.oracle.truffle.api.TruffleLanguage; 13 | import com.oracle.truffle.api.debug.DebuggerTags; 14 | import com.oracle.truffle.api.instrumentation.ProvidedTags; 15 | import com.oracle.truffle.api.instrumentation.StandardTags; 16 | import com.oracle.truffle.api.source.Source; 17 | 18 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 19 | import de.hpi.swa.trufflesqueak.interop.SqueakFileDetector; 20 | import de.hpi.swa.trufflesqueak.interop.SqueakLanguageView; 21 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 22 | import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; 23 | 24 | @TruffleLanguage.Registration(// 25 | characterMimeTypes = {SqueakLanguageConfig.MIME_TYPE, SqueakLanguageConfig.ST_MIME_TYPE}, // 26 | defaultMimeType = SqueakLanguageConfig.ST_MIME_TYPE, // 27 | dependentLanguages = {"nfi"}, // 28 | fileTypeDetectors = SqueakFileDetector.class, // 29 | id = SqueakLanguageConfig.ID, // 30 | implementationName = SqueakLanguageConfig.IMPLEMENTATION_NAME, // 31 | interactive = true, // 32 | internal = false, // 33 | name = SqueakLanguageConfig.NAME, // 34 | version = SqueakLanguageConfig.VERSION, // 35 | website = SqueakLanguageConfig.WEBSITE) 36 | @ProvidedTags({StandardTags.StatementTag.class, StandardTags.CallTag.class, StandardTags.RootTag.class, DebuggerTags.AlwaysHalt.class}) 37 | public final class SqueakLanguage extends TruffleLanguage { 38 | private static final LanguageReference REFERENCE = LanguageReference.create(SqueakLanguage.class); 39 | 40 | public static SqueakLanguage get(final AbstractNode node) { 41 | return REFERENCE.get(node); 42 | } 43 | 44 | @Override 45 | protected SqueakImageContext createContext(final Env env) { 46 | return new SqueakImageContext(this, env); 47 | } 48 | 49 | @Override 50 | protected void finalizeContext(final SqueakImageContext context) { 51 | context.finalizeContext(); 52 | } 53 | 54 | @Override 55 | protected CallTarget parse(final ParsingRequest request) { 56 | final SqueakImageContext image = SqueakImageContext.getSlow(); 57 | final Source source = request.getSource(); 58 | final String imageOrSourcePath = source.getCharacters().toString(); 59 | if (SqueakLanguageConfig.IMAGE_SOURCE_NAME.equals(source.getName())) { 60 | image.setImagePath(imageOrSourcePath); 61 | return image.getSqueakImage().asCallTarget(); 62 | } else { 63 | image.ensureLoaded(); 64 | return image.getDoItContextNode(request).getCallTarget(); 65 | } 66 | } 67 | 68 | @Override 69 | protected boolean isThreadAccessAllowed(final Thread thread, final boolean singleThreaded) { 70 | return true; // TODO: Experimental, make TruffleSqueak work in multiple threads. 71 | } 72 | 73 | @Override 74 | protected Object getScope(final SqueakImageContext context) { 75 | return context.getScope(); 76 | } 77 | 78 | public String getTruffleLanguageHome() { 79 | return getLanguageHome(); 80 | } 81 | 82 | @Override 83 | protected OptionDescriptors getOptionDescriptors() { 84 | return SqueakOptions.createDescriptors(); 85 | } 86 | 87 | @Override 88 | protected boolean patchContext(final SqueakImageContext context, final Env newEnv) { 89 | return context.patch(newEnv); 90 | } 91 | 92 | @Override 93 | protected Object getLanguageView(final SqueakImageContext context, final Object value) { 94 | return SqueakLanguageView.create(value); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/plugins/network/SqueakUDPSocket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.plugins.network; 8 | 9 | import java.io.IOException; 10 | import java.net.InetSocketAddress; 11 | import java.net.SocketAddress; 12 | import java.nio.ByteBuffer; 13 | import java.nio.channels.DatagramChannel; 14 | import java.nio.channels.NetworkChannel; 15 | import java.nio.channels.SelectionKey; 16 | 17 | final class SqueakUDPSocket extends SqueakSocket { 18 | 19 | private final DatagramChannel channel; 20 | 21 | SqueakUDPSocket() throws IOException { 22 | super(); 23 | channel = DatagramChannel.open(); 24 | channel.configureBlocking(false); 25 | } 26 | 27 | @Override 28 | protected NetworkChannel asNetworkChannel() { 29 | return channel; 30 | } 31 | 32 | @Override 33 | protected byte[] getLocalAddress() throws IOException { 34 | if (listening) { 35 | return Resolver.getLoopbackAddress(); 36 | } 37 | 38 | return castAddress(channel.getLocalAddress()).getAddress().getAddress(); 39 | } 40 | 41 | @Override 42 | protected long getLocalPort() throws IOException { 43 | final SocketAddress address = channel.getLocalAddress(); 44 | return castAddress(address).getPort(); 45 | } 46 | 47 | @Override 48 | protected byte[] getRemoteAddress() throws IOException { 49 | final SocketAddress address = channel.getRemoteAddress(); 50 | if (channel.isConnected()) { 51 | return castAddress(address).getAddress().getAddress(); 52 | } 53 | return Resolver.getAnyLocalAddress(); 54 | } 55 | 56 | @Override 57 | protected long getRemotePort() throws IOException { 58 | if (listening) { 59 | return 0L; 60 | } 61 | 62 | if (channel.isConnected()) { 63 | return castAddress(channel.getRemoteAddress()).getPort(); 64 | } 65 | 66 | return 0L; 67 | } 68 | 69 | @Override 70 | protected Status getStatus() { 71 | if (listening) { 72 | return Status.WaitingForConnection; 73 | } 74 | 75 | if (channel.isConnected()) { 76 | return Status.Connected; 77 | } 78 | 79 | return Status.Unconnected; 80 | } 81 | 82 | @Override 83 | protected void connectTo(final String address, final long port) throws IOException { 84 | channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); 85 | channel.connect(new InetSocketAddress(address, (int) port)); 86 | } 87 | 88 | @Override 89 | protected void listenOn(final long port, final long backlogSize) throws IOException { 90 | listening = true; 91 | channel.bind(new InetSocketAddress((int) port)); 92 | channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); 93 | } 94 | 95 | @Override 96 | protected SqueakSocket accept() { 97 | throw new UnsupportedOperationException("accept() on UDP socket"); 98 | } 99 | 100 | @Override 101 | protected boolean isSendDone() { 102 | return true; 103 | } 104 | 105 | @Override 106 | protected long sendDataTo(final ByteBuffer data, final SelectionKey key) throws IOException { 107 | final DatagramChannel to = (DatagramChannel) key.channel(); 108 | return to.send(data, to.getRemoteAddress()); 109 | } 110 | 111 | @Override 112 | protected long receiveDataFrom(final SelectionKey key, final ByteBuffer data) throws IOException { 113 | final DatagramChannel from = (DatagramChannel) key.channel(); 114 | from.receive(data); 115 | return data.position(); 116 | } 117 | 118 | @Override 119 | protected void close() throws IOException { 120 | super.close(); 121 | channel.close(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/SignalSemaphoreNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.Cached.Exclusive; 11 | import com.oracle.truffle.api.dsl.GenerateCached; 12 | import com.oracle.truffle.api.dsl.GenerateInline; 13 | import com.oracle.truffle.api.dsl.NeverDefault; 14 | import com.oracle.truffle.api.dsl.Specialization; 15 | import com.oracle.truffle.api.frame.VirtualFrame; 16 | import com.oracle.truffle.api.nodes.Node; 17 | 18 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 19 | import de.hpi.swa.trufflesqueak.model.NilObject; 20 | import de.hpi.swa.trufflesqueak.model.PointersObject; 21 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.SEMAPHORE; 22 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 23 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 24 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 25 | 26 | /** 27 | * Returns the new active Context or null if the current active Context has not been preempted. 28 | */ 29 | @GenerateInline 30 | @GenerateCached(true) 31 | public abstract class SignalSemaphoreNode extends AbstractNode { 32 | 33 | @NeverDefault 34 | public static SignalSemaphoreNode create() { 35 | return SignalSemaphoreNodeGen.create(); 36 | } 37 | 38 | public static final boolean executeUncached(final VirtualFrame frame, final SqueakImageContext image, final Object semaphoreOrNil) { 39 | if (!(semaphoreOrNil instanceof final PointersObject semaphore) || !image.isSemaphoreClass(semaphore.getSqueakClass())) { 40 | return false; 41 | } 42 | final AbstractPointersObjectWriteNode writeNode = AbstractPointersObjectWriteNode.getUncached(); 43 | final AbstractPointersObjectReadNode readNode = AbstractPointersObjectReadNode.getUncached(); 44 | if (semaphore.isEmptyList(AbstractPointersObjectReadNode.getUncached(), null)) { 45 | writeNode.execute(null, semaphore, SEMAPHORE.EXCESS_SIGNALS, 46 | readNode.executeLong(null, semaphore, SEMAPHORE.EXCESS_SIGNALS) + 1); 47 | return false; 48 | } else { 49 | return ResumeProcessNode.executeUncached(frame, image, semaphore.removeFirstLinkOfList(readNode, writeNode, null)); 50 | } 51 | } 52 | 53 | public abstract boolean executeSignal(VirtualFrame frame, Node node, Object semaphoreOrNil); 54 | 55 | @Specialization(guards = {"isSemaphore(semaphore)", "semaphore.isEmptyList(readNode, node)"}, limit = "1") 56 | protected static final boolean doSignalEmpty(final Node node, final PointersObject semaphore, 57 | @Exclusive @Cached final AbstractPointersObjectReadNode readNode, 58 | @Exclusive @Cached final AbstractPointersObjectWriteNode writeNode) { 59 | writeNode.execute(node, semaphore, SEMAPHORE.EXCESS_SIGNALS, readNode.executeLong(node, semaphore, SEMAPHORE.EXCESS_SIGNALS) + 1); 60 | return false; 61 | } 62 | 63 | @Specialization(guards = {"isSemaphore(semaphore)", "!semaphore.isEmptyList(readNode, node)"}, limit = "1") 64 | protected static final boolean doSignal(final VirtualFrame frame, final Node node, final PointersObject semaphore, 65 | @Exclusive @Cached final AbstractPointersObjectReadNode readNode, 66 | @Exclusive @Cached final AbstractPointersObjectWriteNode writeNode, 67 | @Cached final ResumeProcessNode resumeProcessNode) { 68 | return resumeProcessNode.executeResume(frame, node, semaphore.removeFirstLinkOfList(readNode, writeNode, node)); 69 | } 70 | 71 | @Specialization 72 | protected static final boolean doNothing(@SuppressWarnings("unused") final NilObject nil) { 73 | // nothing to do 74 | return false; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/polyglot-api.md: -------------------------------------------------------------------------------- 1 | # Polyglot API Reference 2 | 3 | TruffleSqueak provides access to all languages supported by GraalVM through its 4 | Polyglot API. 5 | This document describes how this API can be used to interact with different 6 | languages from Smalltalk. 7 | 8 | ## Evaluating code written in foreign languages 9 | 10 | ```smalltalk 11 | Polyglot eval: 'id' file: 'path'. "Evaluates a file with code of a language, identified by its ID." 12 | Polyglot eval: 'id' string: 'code'. "Evaluates code of a language, identified by its ID." 13 | ``` 14 | 15 | ## Sharing objects between languages 16 | 17 | ```smalltalk 18 | Polyglot import: 'name'. "Imports and returns a value with a given name" 19 | Polyglot export: 'name' value: aValue. "Exports a value with a given name" 20 | Polyglot bindings. "Returns the polyglot bindings object" 21 | ``` 22 | 23 | ## Accessing language information 24 | 25 | ```smalltalk 26 | Polyglot availableLanguages. "Returns a list of supported language IDs" 27 | Polyglot languageDefaultMimeTypeOf: 'id'. "Returns the default mime type for a given language ID" 28 | Polyglot languageMimeTypesOf: 'id'. "Returns all mime types for a given language ID" 29 | Polyglot languageNameOf: 'id'. "Returns the language name for a given language ID" 30 | Polyglot languageVersionOf: 'id'. "Returns the language version for a given language ID" 31 | ``` 32 | 33 | ## Accessing Java 34 | 35 | ```smalltalk 36 | Java type: 'name'. "Looks up and returns a Java class object" 37 | 38 | "Examples" 39 | (Java type: 'int[]') new: 2. "Equivalent to `new int[2]`" 40 | (Java type: 'java.lang.System') exit: 0. "Equivalent to `System.exit(0)`" 41 | ``` 42 | 43 | ## Interacting with Smalltalk from other languages 44 | 45 | Smalltalk images can be opened and accessed from other languages with an 46 | appropriate polyglot evaluate file request. 47 | As an example, here is how to interact with an image from Python: 48 | 49 | ```python 50 | import polyglot 51 | image = polyglot.eval( # Load an image file 52 | language='smalltalk', path='/path/to/trufflesqueak.image') 53 | dir(image) # Returns a list of all Smalltalk globals 54 | image.Compiler # Returns the `Compiler` class object 55 | image.Compiler.evaluate_('1 + 2 * 3') # Equivalent to `Compiler evaluate: ''` 56 | image.Array.with_with_(True, None) # Equivalent to `Array with: true with: nil` 57 | image() # Opens the image 58 | ``` 59 | 60 | To be able to evaluate Smalltalk code with a polyglot evaluation request, 61 | `smalltalk.ImagePath` must be specified. 62 | The polyglot shell, for example, can be started with the following options: 63 | ```bash 64 | polyglot --shell --jvm --smalltalk.ImagePath=/path/to/trufflesqueak.image 65 | ``` 66 | 67 | Then, it is possible to directly evaluate Smalltalk code, the provided image 68 | file will be loaded automatically as part of the first evaluation request. 69 | Here is an example for evaluating Smalltalk code from Javascript: 70 | 71 | ```javascript 72 | Polyglot.eval('smalltalk', '1 + 2 * 3') // Returns `9`` 73 | ``` 74 | 75 | ## Internal API 76 | 77 | [`Polyglot`][polyglot_class] exposes additional methods for internal use that 78 | provide further functionality. It is not recommended to rely on them as they may 79 | change without notice. 80 | All foreign objects are represented by the 81 | [`TruffleObject`][truffle_object_class] class. 82 | The [`Interop`][interop_class] class exposes the underlying [Truffle API for 83 | language interoperability][truffle_interop_library]. 84 | 85 | *Please note that the Polyglot API may change with newer releases of 86 | TruffleSqueak.* 87 | 88 | [interop_class]: https://github.com/hpi-swa/trufflesqueak/tree/image/src/TruffleSqueak-Core.package/Interop.class 89 | [polyglot_class]: https://github.com/hpi-swa/trufflesqueak/tree/image/src/TruffleSqueak-Core.package/Polyglot.class 90 | [truffle_interop_library]: https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/interop/InteropLibrary.html 91 | [truffle_object_class]: https://github.com/hpi-swa/trufflesqueak/tree/image/src/TruffleSqueak-Core.package/TruffleObject.class 92 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/interop/LookupMethodByStringNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.interop; 8 | 9 | import java.util.Arrays; 10 | 11 | import com.oracle.truffle.api.dsl.Cached; 12 | import com.oracle.truffle.api.dsl.GenerateCached; 13 | import com.oracle.truffle.api.dsl.GenerateInline; 14 | import com.oracle.truffle.api.dsl.GenerateUncached; 15 | import com.oracle.truffle.api.dsl.ReportPolymorphism; 16 | import com.oracle.truffle.api.dsl.Specialization; 17 | import com.oracle.truffle.api.nodes.Node; 18 | 19 | import de.hpi.swa.trufflesqueak.model.ClassObject; 20 | import de.hpi.swa.trufflesqueak.model.NativeObject; 21 | import de.hpi.swa.trufflesqueak.model.VariablePointersObject; 22 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.METHOD_DICT; 23 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 24 | import de.hpi.swa.trufflesqueak.nodes.LookupMethodNode; 25 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 26 | import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectReadNode; 27 | import de.hpi.swa.trufflesqueak.util.MiscUtils; 28 | 29 | /** Similar to {@link LookupMethodNode}, but for interop. */ 30 | @GenerateInline 31 | @GenerateUncached 32 | @GenerateCached(false) 33 | public abstract class LookupMethodByStringNode extends AbstractNode { 34 | protected static final int LOOKUP_CACHE_SIZE = 3; 35 | 36 | public abstract Object executeLookup(Node node, ClassObject sqClass, String selectorBytes); 37 | 38 | public static final Object executeUncached(final ClassObject sqClass, final String selectorBytes) { 39 | return LookupMethodByStringNodeGen.getUncached().executeLookup(null, sqClass, selectorBytes); 40 | } 41 | 42 | @SuppressWarnings("unused") 43 | @Specialization(limit = "LOOKUP_CACHE_SIZE", guards = {"classObject == cachedClass", "selector.equals(cachedSelector)"}, assumptions = {"cachedClass.getClassHierarchyAndMethodDictStable()"}) 44 | protected static final Object doCached(final Node node, final ClassObject classObject, final String selector, 45 | @Cached("classObject") final ClassObject cachedClass, 46 | @Cached("selector") final String cachedSelector, 47 | @Cached("doUncachedSlow(node, cachedClass, cachedSelector)") final Object cachedMethod) { 48 | return cachedMethod; 49 | } 50 | 51 | protected static final Object doUncachedSlow(final Node node, final ClassObject classObject, final String selector) { 52 | return doUncached(node, classObject, selector, AbstractPointersObjectReadNode.getUncached(), ArrayObjectReadNode.getUncached()); 53 | } 54 | 55 | @ReportPolymorphism.Megamorphic 56 | @Specialization(replaces = "doCached") 57 | protected static final Object doUncached(final Node node, final ClassObject classObject, final String selector, 58 | /* 59 | * An AbstractPointersObjectReadNode is sufficient for accessing `values` 60 | * instance variable here. 61 | */ 62 | @Cached final AbstractPointersObjectReadNode pointersReadValuesNode, 63 | @Cached final ArrayObjectReadNode arrayReadNode) { 64 | final byte[] selectorBytes = MiscUtils.toBytes(selector); 65 | ClassObject lookupClass = classObject; 66 | while (lookupClass != null) { 67 | final VariablePointersObject methodDict = lookupClass.getMethodDict(); 68 | final Object[] methodDictVariablePart = methodDict.getVariablePart(); 69 | for (int i = 0; i < methodDictVariablePart.length; i++) { 70 | final Object methodSelector = methodDictVariablePart[i]; 71 | if (methodSelector instanceof final NativeObject m && Arrays.equals(selectorBytes, m.getByteStorage())) { 72 | return arrayReadNode.execute(node, pointersReadValuesNode.executeArray(node, methodDict, METHOD_DICT.VALUES), i); 73 | } 74 | } 75 | lookupClass = lookupClass.getSuperclassOrNull(); 76 | } 77 | return null; // Signals a doesNotUnderstand. 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/interop/SqueakLanguageView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.interop; 8 | 9 | import static com.oracle.truffle.api.CompilerDirectives.shouldNotReachHere; 10 | 11 | import com.oracle.truffle.api.TruffleLanguage; 12 | import com.oracle.truffle.api.dsl.Bind; 13 | import com.oracle.truffle.api.dsl.Cached; 14 | import com.oracle.truffle.api.dsl.Specialization; 15 | import com.oracle.truffle.api.interop.InteropLibrary; 16 | import com.oracle.truffle.api.interop.TruffleObject; 17 | import com.oracle.truffle.api.interop.UnsupportedMessageException; 18 | import com.oracle.truffle.api.library.ExportLibrary; 19 | import com.oracle.truffle.api.library.ExportMessage; 20 | import com.oracle.truffle.api.nodes.Node; 21 | 22 | import de.hpi.swa.trufflesqueak.SqueakLanguage; 23 | import de.hpi.swa.trufflesqueak.exceptions.SqueakExceptions.SqueakException; 24 | import de.hpi.swa.trufflesqueak.image.SqueakImageContext; 25 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 26 | import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectClassNode; 27 | import de.hpi.swa.trufflesqueak.nodes.dispatch.DispatchSelector0Node.DispatchDirect0Node; 28 | import de.hpi.swa.trufflesqueak.nodes.dispatch.LookupClassGuard; 29 | 30 | @SuppressWarnings("static-method") 31 | @ExportLibrary(value = InteropLibrary.class, delegateTo = "delegate") 32 | public final class SqueakLanguageView implements TruffleObject { 33 | protected final Object delegate; 34 | 35 | public SqueakLanguageView(final Object delegate) { 36 | this.delegate = delegate; 37 | } 38 | 39 | @ExportMessage 40 | protected boolean hasLanguage() { 41 | return true; 42 | } 43 | 44 | @ExportMessage 45 | protected Class> getLanguage() { 46 | return SqueakLanguage.class; 47 | } 48 | 49 | @ExportMessage 50 | protected boolean hasMetaObject() { 51 | return true; 52 | } 53 | 54 | @ExportMessage 55 | protected Object getMetaObject(@Bind final Node node, @Cached(inline = true) final SqueakObjectClassNode classNode) { 56 | return classNode.executeLookup(node, delegate); 57 | } 58 | 59 | @ExportMessage 60 | protected abstract static class ToDisplayString { 61 | @SuppressWarnings("unused") 62 | @Specialization(guards = "guard.check(view.delegate)", assumptions = "dispatchNode.getAssumptions()", limit = "1") 63 | protected static final Object toDisplayString(final SqueakLanguageView view, final boolean allowSideEffects, 64 | @Cached(value = "create(view.delegate)", allowUncached = true) final LookupClassGuard guard, 65 | @Bind final Node node, 66 | @Cached(value = "create(guard)", allowUncached = true) final DispatchDirect0Node dispatchNode) { 67 | return dispatchNode.execute(SqueakImageContext.get(node).externalSenderFrame, view.delegate); 68 | } 69 | 70 | protected static final DispatchDirect0Node create(final LookupClassGuard guard) { 71 | final Object lookupResult = LookupMethodByStringNode.executeUncached(guard.getSqueakClass(null), "asString"); 72 | if (lookupResult instanceof CompiledCodeObject method) { 73 | return DispatchDirect0Node.create(method, guard); 74 | } else { 75 | throw SqueakException.create("Failed to lookup asString"); 76 | } 77 | } 78 | } 79 | 80 | public static Object create(final Object value) { 81 | assert isPrimitiveOrFromOtherLanguage(value); 82 | return new SqueakLanguageView(value); 83 | } 84 | 85 | /* 86 | * Language views are intended to be used only for primitives and other language values. 87 | */ 88 | private static boolean isPrimitiveOrFromOtherLanguage(final Object value) { 89 | final InteropLibrary interop = InteropLibrary.getFactory().getUncached(value); 90 | try { 91 | return !interop.hasLanguage(value) || interop.getLanguage(value) != SqueakLanguage.class; 92 | } catch (final UnsupportedMessageException e) { 93 | throw shouldNotReachHere(e); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/tools/SqueakMessageInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.tools; 8 | 9 | import org.graalvm.polyglot.Context; 10 | 11 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 12 | import com.oracle.truffle.api.frame.VirtualFrame; 13 | import com.oracle.truffle.api.instrumentation.EventContext; 14 | import com.oracle.truffle.api.instrumentation.ExecutionEventListener; 15 | import com.oracle.truffle.api.instrumentation.SourceSectionFilter; 16 | import com.oracle.truffle.api.instrumentation.StandardTags.CallTag; 17 | import com.oracle.truffle.api.instrumentation.TruffleInstrument; 18 | 19 | import de.hpi.swa.trufflesqueak.SqueakLanguage; 20 | import de.hpi.swa.trufflesqueak.SqueakOptions; 21 | 22 | @TruffleInstrument.Registration(id = SqueakMessageInterceptor.ID, services = SqueakMessageInterceptor.class) 23 | public final class SqueakMessageInterceptor extends TruffleInstrument { 24 | protected static final String ID = "squeak-message-interceptor"; 25 | private static final String DEFAULTS = "TestCase>>runCase,TestCase>>logFailure:,TestCase>>signalFailure:,Object>>halt,Object>>inform:," + // 26 | "SmalltalkImage>>logSqueakError:inContext:,UnhandledError>>defaultAction,SyntaxErrorNotification>>setClass:code:doitFlag:errorMessage:location:"; 27 | 28 | private static String[] breakpoints; 29 | 30 | public static void enableIfRequested(final SqueakLanguage.Env env) { 31 | if (env.getOptions().hasBeenSet(SqueakOptions.InterceptMessages)) { 32 | /* Looking up instrument to activate it. */ 33 | breakpoints = (DEFAULTS + "," + env.getOptions().get(SqueakOptions.InterceptMessages)).split(","); 34 | Context.getCurrent().getEngine().getInstruments().get(ID).lookup(SqueakMessageInterceptor.class); 35 | } 36 | } 37 | 38 | @Override 39 | protected void onCreate(final Env env) { 40 | assert breakpoints != null; 41 | env.registerService(this); 42 | env.getInstrumenter().attachExecutionEventListener( 43 | SourceSectionFilter.newBuilder().tagIs(CallTag.class).rootNameIs(s -> { 44 | if (s == null) { 45 | return false; 46 | } 47 | for (final String breakpoint : breakpoints) { 48 | if (s.contains(breakpoint)) { 49 | return true; 50 | } 51 | } 52 | return false; 53 | }).build(), 54 | new ExecutionEventListener() { 55 | 56 | /* 57 | * This is the "halt" method - put a breakpoint in your IDE on the print 58 | * statement within. 59 | */ 60 | @Override 61 | public void onEnter(final EventContext context, final VirtualFrame frame) { 62 | printToStdOut(context); 63 | } 64 | 65 | @TruffleBoundary 66 | private static void printToStdOut(final EventContext context) { 67 | // Checkstyle: stop 68 | System.out.println("Entering " + context.getInstrumentedSourceSection().getSource().getName() + "..."); 69 | // Checkstyle: resume 70 | } 71 | 72 | @Override 73 | public void onReturnValue(final EventContext context, final VirtualFrame frame, final Object result) { 74 | /* Nothing to do. */ 75 | } 76 | 77 | @Override 78 | public void onReturnExceptional(final EventContext context, final VirtualFrame frame, final Throwable exception) { 79 | /* Nothing to do. */ 80 | } 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/io/SqueakIOConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.io; 8 | 9 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; 10 | 11 | public final class SqueakIOConstants { 12 | 13 | public static final int CURSOR_WIDTH = 16; 14 | public static final int CURSOR_HEIGHT = 16; 15 | 16 | public static final int EVENT_SIZE = 8; 17 | 18 | /* 19 | * All zeros. Since it does not escape EventSensor>>#fetchMoreEvents, there is no need to 20 | * allocate individual `long[]` arrays to signal no event (reduces memory pressure). 21 | */ 22 | @CompilationFinal(dimensions = 1) public static final long[] NONE_EVENT = new long[EVENT_SIZE]; 23 | 24 | public enum MOUSE_EVENT { 25 | DOWN, 26 | MOVE, 27 | UP 28 | } 29 | 30 | public static final class DRAG { 31 | public static final long ENTER = 1; 32 | public static final long MOVE = 2; 33 | public static final long LEAVE = 3; 34 | public static final long DROP = 4; 35 | } 36 | 37 | public static final class KEYBOARD_EVENT { 38 | public static final long CHAR = 0; 39 | public static final long DOWN = 1; 40 | public static final long UP = 2; 41 | } 42 | 43 | public static final class KEYBOARD { 44 | public static final int SHIFT = 8; 45 | public static final int CTRL = 16; 46 | public static final int ALT = 32; 47 | public static final int CMD = 64; 48 | public static final int ALL = SHIFT + CTRL + ALT + CMD; 49 | } 50 | 51 | public static final class KEY { 52 | public static final int DOWN = 31; 53 | public static final int LEFT = 28; 54 | public static final int RIGHT = 29; 55 | public static final int UP = 30; 56 | public static final int HOME = 1; 57 | public static final int END = 4; 58 | public static final int INSERT = 5; 59 | public static final int BACKSPACE = 8; 60 | public static final int PAGEUP = 11; 61 | public static final int PAGEDOWN = 12; 62 | public static final int RETURN = 13; 63 | public static final int SHIFT = 16; 64 | public static final int CTRL = 17; 65 | public static final int COMMAND = 18; 66 | public static final int BREAK = 19; 67 | public static final int CAPSLOCK = 20; 68 | public static final int ESCAPE = 27; 69 | public static final int PRINT = 44; 70 | public static final int DELETE = 127; 71 | public static final int NUMLOCK = 184; 72 | public static final int SCROLLLOCK = 212; 73 | 74 | public static final int SHIFT_BIT = 1; 75 | public static final int CTRL_BIT = 2; 76 | public static final int OPTION_BIT = 4; 77 | public static final int COMMAND_BIT = 8; 78 | } 79 | 80 | public static final class MOUSE { 81 | public static final int BLUE = 1; 82 | public static final int YELLOW = 2; 83 | public static final int RED = 4; 84 | public static final int ALL = BLUE + YELLOW + RED; 85 | /* See HandMorph>>#generateMouseWheelEvent:direction: */ 86 | public static final long WHEEL_DELTA_FACTOR = -120; 87 | } 88 | 89 | public static final class EVENT_TYPE { 90 | public static final long NONE = 0; 91 | public static final long MOUSE = 1; 92 | public static final long KEYBOARD = 2; 93 | public static final long DRAG_DROP_FILES = 3; 94 | public static final long MENU = 4; 95 | public static final long WINDOW = 5; 96 | public static final long COMPLEX = 6; 97 | public static final long MOUSE_WHEEL = 7; 98 | } 99 | 100 | public static final class WINDOW { 101 | public static final long METRIC_CHANGE = 1; 102 | public static final long CLOSE = 2; 103 | public static final long ICONISE = 3; 104 | public static final long ACTIVATED = 4; 105 | public static final long PAINT = 5; 106 | public static final long CHANGED_SCREEN = 6; 107 | public static final long DEACTIVATED = 7; 108 | } 109 | 110 | private SqueakIOConstants() { 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/accessing/SqueakObjectShallowCopyNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.accessing; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.Cached.Exclusive; 11 | import com.oracle.truffle.api.dsl.GenerateCached; 12 | import com.oracle.truffle.api.dsl.GenerateInline; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.model.ArrayObject; 17 | import de.hpi.swa.trufflesqueak.model.BlockClosureObject; 18 | import de.hpi.swa.trufflesqueak.model.CharacterObject; 19 | import de.hpi.swa.trufflesqueak.model.ClassObject; 20 | import de.hpi.swa.trufflesqueak.model.CompiledCodeObject; 21 | import de.hpi.swa.trufflesqueak.model.ContextObject; 22 | import de.hpi.swa.trufflesqueak.model.EmptyObject; 23 | import de.hpi.swa.trufflesqueak.model.EphemeronObject; 24 | import de.hpi.swa.trufflesqueak.model.FloatObject; 25 | import de.hpi.swa.trufflesqueak.model.NativeObject; 26 | import de.hpi.swa.trufflesqueak.model.PointersObject; 27 | import de.hpi.swa.trufflesqueak.model.VariablePointersObject; 28 | import de.hpi.swa.trufflesqueak.model.WeakVariablePointersObject; 29 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 30 | import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectShallowCopyNode; 31 | import de.hpi.swa.trufflesqueak.nodes.accessing.NativeObjectNodes.NativeObjectShallowCopyNode; 32 | 33 | @GenerateInline 34 | @GenerateCached(false) 35 | public abstract class SqueakObjectShallowCopyNode extends AbstractNode { 36 | 37 | public abstract Object execute(Node node, Object object); 38 | 39 | @Specialization 40 | protected static final PointersObject doPointers(final PointersObject receiver) { 41 | return new PointersObject(receiver); 42 | } 43 | 44 | @Specialization 45 | protected static final ArrayObject doArray(final Node node, final ArrayObject receiver, 46 | @Exclusive @Cached final ArrayObjectShallowCopyNode copyNode) { 47 | return copyNode.execute(node, receiver); 48 | } 49 | 50 | @Specialization 51 | protected static final NativeObject doNative(final Node node, final NativeObject receiver, 52 | @Cached final NativeObjectShallowCopyNode copyNode) { 53 | return copyNode.execute(node, receiver); 54 | } 55 | 56 | @Specialization 57 | protected static final VariablePointersObject doVariablePointers(final VariablePointersObject receiver) { 58 | return new VariablePointersObject(receiver); 59 | } 60 | 61 | @Specialization 62 | protected static final ContextObject doContext(final ContextObject receiver) { 63 | return new ContextObject(receiver); 64 | } 65 | 66 | @Specialization 67 | protected static final WeakVariablePointersObject doWeakPointers(final WeakVariablePointersObject receiver) { 68 | return new WeakVariablePointersObject(receiver); 69 | } 70 | 71 | @Specialization 72 | protected static final EphemeronObject doEphemeron(final EphemeronObject receiver) { 73 | return new EphemeronObject(receiver); 74 | } 75 | 76 | @Specialization 77 | protected static final BlockClosureObject doClosure(final BlockClosureObject receiver) { 78 | return new BlockClosureObject(receiver); 79 | } 80 | 81 | @Specialization 82 | protected static final CompiledCodeObject doCode(final CompiledCodeObject receiver) { 83 | return new CompiledCodeObject(receiver); 84 | } 85 | 86 | @Specialization 87 | protected static final ClassObject doClass(final ClassObject receiver) { 88 | return new ClassObject(receiver); 89 | } 90 | 91 | @Specialization 92 | protected static final EmptyObject doEmpty(final EmptyObject receiver) { 93 | return new EmptyObject(receiver); 94 | } 95 | 96 | @Specialization 97 | protected static final FloatObject doFloat(final FloatObject receiver) { 98 | return new FloatObject(receiver); 99 | } 100 | 101 | @Specialization 102 | protected static final CharacterObject doCharacterObject(final CharacterObject obj) { 103 | return new CharacterObject(obj); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/process/RemoveProcessFromListNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2025 Software Architecture Group, Hasso Plattner Institute 3 | * Copyright (c) 2021-2025 Oracle and/or its affiliates 4 | * 5 | * Licensed under the MIT License. 6 | */ 7 | package de.hpi.swa.trufflesqueak.nodes.process; 8 | 9 | import com.oracle.truffle.api.dsl.Cached; 10 | import com.oracle.truffle.api.dsl.Cached.Shared; 11 | import com.oracle.truffle.api.dsl.GenerateCached; 12 | import com.oracle.truffle.api.dsl.GenerateInline; 13 | import com.oracle.truffle.api.dsl.Specialization; 14 | import com.oracle.truffle.api.nodes.Node; 15 | 16 | import de.hpi.swa.trufflesqueak.exceptions.PrimitiveFailed; 17 | import de.hpi.swa.trufflesqueak.model.AbstractSqueakObject; 18 | import de.hpi.swa.trufflesqueak.model.NilObject; 19 | import de.hpi.swa.trufflesqueak.model.PointersObject; 20 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.LINKED_LIST; 21 | import de.hpi.swa.trufflesqueak.model.layout.ObjectLayouts.PROCESS; 22 | import de.hpi.swa.trufflesqueak.nodes.AbstractNode; 23 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode; 24 | import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectWriteNode; 25 | 26 | @GenerateInline 27 | @GenerateCached(false) 28 | public abstract class RemoveProcessFromListNode extends AbstractNode { 29 | 30 | public final void executeRemove(final PointersObject process, final PointersObject list, 31 | final AbstractPointersObjectReadNode readNode, 32 | final AbstractPointersObjectWriteNode writeNode, 33 | final Node inlineTarget) { 34 | final Object first = readNode.execute(inlineTarget, list, LINKED_LIST.FIRST_LINK); 35 | final Object last = readNode.execute(inlineTarget, list, LINKED_LIST.LAST_LINK); 36 | executeRemove(inlineTarget, process, list, first, last); 37 | writeNode.executeNil(inlineTarget, process, PROCESS.NEXT_LINK); 38 | } 39 | 40 | protected abstract void executeRemove(Node node, PointersObject process, PointersObject list, Object first, Object last); 41 | 42 | @Specialization(guards = "process == first") 43 | protected static final void doRemoveEqual(final Node node, final PointersObject process, final PointersObject list, @SuppressWarnings("unused") final PointersObject first, 44 | final AbstractSqueakObject last, 45 | @Shared("readNode") @Cached final AbstractPointersObjectReadNode readNode, 46 | @Shared("writeNode") @Cached final AbstractPointersObjectWriteNode writeNode) { 47 | final Object next = readNode.execute(node, process, PROCESS.NEXT_LINK); 48 | writeNode.execute(node, list, LINKED_LIST.FIRST_LINK, next); 49 | if (process == last) { 50 | writeNode.executeNil(node, list, LINKED_LIST.LAST_LINK); 51 | } 52 | } 53 | 54 | @Specialization(guards = "process != first") 55 | protected static final void doRemoveNotEqual(final Node node, final PointersObject process, final PointersObject list, final PointersObject first, final AbstractSqueakObject last, 56 | @Shared("readNode") @Cached final AbstractPointersObjectReadNode readNode, 57 | @Shared("writeNode") @Cached final AbstractPointersObjectWriteNode writeNode) { 58 | PointersObject temp = first; 59 | Object next; 60 | while (true) { 61 | next = readNode.execute(node, temp, PROCESS.NEXT_LINK); 62 | if (next == process) { 63 | break; 64 | } else if (next == NilObject.SINGLETON) { 65 | throw PrimitiveFailed.andTransferToInterpreter(); // TODO: make this better. 66 | } else { 67 | temp = (PointersObject) next; 68 | } 69 | } 70 | next = readNode.execute(node, process, PROCESS.NEXT_LINK); 71 | writeNode.execute(node, temp, PROCESS.NEXT_LINK, next); 72 | if (process == last) { 73 | writeNode.execute(node, list, LINKED_LIST.LAST_LINK, temp); 74 | } 75 | } 76 | 77 | @SuppressWarnings("unused") 78 | @Specialization 79 | protected static final void doRemoveNotEqual(final PointersObject process, final PointersObject list, final NilObject first, final AbstractSqueakObject last) { 80 | throw PrimitiveFailed.GENERIC_ERROR; // TODO: make sure this is needed (and make it better). 81 | } 82 | } 83 | --------------------------------------------------------------------------------