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 extends NodeFactory extends AbstractPrimitiveNode>> getFactories() {
65 | return SecurityPluginFactory.getFactories();
66 | }
67 |
68 | @Override
69 | public List extends AbstractSingletonPrimitiveNode> 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 extends NodeFactory extends AbstractPrimitiveNode>> 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 extends TruffleLanguage>> 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 |
--------------------------------------------------------------------------------