diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageChunk.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageChunk.java index 083635497..46be77df1 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageChunk.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/image/SqueakImageChunk.java @@ -184,11 +184,11 @@ public Object[] getPointers() { return pointers; } - public Object[] getPointers(final int end) { + public Object[] getPointers(final int start, final int count) { if (pointers == null) { - pointers = new Object[end]; - for (int i = 0; i < end; i++) { - pointers[i] = decodePointer(getWord(i)); + pointers = new Object[count]; + for (int i = 0; i < count; i++) { + pointers[i] = decodePointer(getWord(start + i)); } } return pointers; diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java index 2c15755ba..0ff5f5bc7 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/model/CompiledCodeObject.java @@ -47,7 +47,6 @@ import de.hpi.swa.trufflesqueak.shared.SqueakLanguageConfig; import de.hpi.swa.trufflesqueak.util.ArrayUtils; import de.hpi.swa.trufflesqueak.util.FrameAccess; -import de.hpi.swa.trufflesqueak.util.MiscUtils; import de.hpi.swa.trufflesqueak.util.ObjectGraphUtils.ObjectTracer; import de.hpi.swa.trufflesqueak.util.UnsafeUtils; @@ -66,11 +65,9 @@ public final class CompiledCodeObject extends AbstractSqueakObjectWithClassAndHa * Literals are cached in the AST and bytes are represented by nodes, so this should not affect * performance. Find out why it does affect performance. */ + @CompilationFinal private long header; @CompilationFinal(dimensions = 1) private Object[] literals; @CompilationFinal(dimensions = 1) private byte[] bytes; - @CompilationFinal private int numArgs; - @CompilationFinal private int numLiterals; - @CompilationFinal private int numTemps; /* * With FullBlockClosure support, CompiledMethods store CompiledBlocks in their literals and @@ -97,13 +94,13 @@ public CompiledCodeObject(final long header, final ClassObject classObject) { public CompiledCodeObject(final SqueakImageContext image, final byte[] bc, final Object[] lits, final ClassObject classObject) { super(image, classObject); literals = lits; - decodeHeader(); bytes = bc; } private CompiledCodeObject(final CompiledCodeObject original) { super(original); frameDescriptor = original.frameDescriptor; + this.header = original.header; setLiteralsAndBytes(original.literals.clone(), original.bytes.clone()); } @@ -120,11 +117,9 @@ private CompiledCodeObject(final CompiledCodeObject outerCode, final int startPC outerMethod = currentOuterCode; // header info and data + header = outerCode.header; literals = outerCode.literals; bytes = outerCode.bytes; - numArgs = outerCode.numArgs; - numLiterals = outerCode.numLiterals; - numTemps = outerCode.numTemps; } private CompiledCodeObject(final int size, final SqueakImageContext image, final ClassObject classObject) { @@ -161,7 +156,6 @@ public CompiledCodeObject getOuterMethod() { private void setLiteralsAndBytes(final Object[] literals, final byte[] bytes) { CompilerDirectives.transferToInterpreterAndInvalidate(); this.literals = literals; - decodeHeader(); this.bytes = bytes; renewCallTarget(); } @@ -280,15 +274,15 @@ public FrameDescriptor getFrameDescriptor() { @Idempotent public int getNumArgs() { - return numArgs; + return CompiledCodeHeaderDecoder.getNumArguments(getHeader()); } public int getNumTemps() { - return numTemps; + return CompiledCodeHeaderDecoder.getNumTemps(getHeader()); } public int getNumLiterals() { - return numLiterals; + return literals.length; } public int getSqueakContextSize() { @@ -312,13 +306,10 @@ private AbstractSqueakBytecodeDecoder getDecoder() { public void fillin(final SqueakImageChunk chunk) { CompilerDirectives.transferToInterpreterAndInvalidate(); // header is a tagged small integer - final long header = chunk.getWord(0) >> SqueakImageConstants.NUM_TAG_BITS; - numLiterals = CompiledCodeHeaderDecoder.getNumLiterals(header); - assert literals == null; - literals = chunk.getPointers(1 + numLiterals); - decodeHeader(); - assert bytes == null; - bytes = Arrays.copyOfRange(chunk.getBytes(), literals.length * SqueakImageConstants.WORD_SIZE, chunk.getBytes().length); + header = chunk.getWord(0) >> SqueakImageConstants.NUM_TAG_BITS; + assert literals == null && bytes == null; + literals = chunk.getPointers(1, CompiledCodeHeaderDecoder.getNumLiterals(header)); + bytes = Arrays.copyOfRange(chunk.getBytes(), getBytecodeOffset(), chunk.getBytes().length); } public AbstractBytecodeNode[] asBytecodeNodesEmpty() { @@ -333,24 +324,19 @@ public int findLineNumber(final int index) { return getDecoder().findLineNumber(this, index); } - private void decodeHeader() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - final long header = getHeader(); - numLiterals = CompiledCodeHeaderDecoder.getNumLiterals(header); - numTemps = CompiledCodeHeaderDecoder.getNumTemps(header); - numArgs = CompiledCodeHeaderDecoder.getNumArguments(header); - } - public void become(final CompiledCodeObject other) { CompilerDirectives.transferToInterpreterAndInvalidate(); + final long header2 = other.header; final Object[] literals2 = other.literals; final byte[] bytes2 = other.bytes; final EconomicMap shadowBlocks2 = other.shadowBlocks; final CompiledCodeObject outerMethod2 = other.outerMethod; + other.header = header; other.setLiteralsAndBytes(literals, bytes); other.shadowBlocks = shadowBlocks; other.outerMethod = outerMethod; other.callTargetStable().invalidate(); + header = header2; setLiteralsAndBytes(literals2, bytes2); shadowBlocks = shadowBlocks2; outerMethod = outerMethod2; @@ -358,7 +344,7 @@ public void become(final CompiledCodeObject other) { } public int getBytecodeOffset() { - return (1 + numLiterals) * SqueakImageConstants.WORD_SIZE; // header plus numLiterals + return (1 + getNumLiterals()) * SqueakImageConstants.WORD_SIZE; // header plus numLiterals } public long at0(final long index) { @@ -393,22 +379,13 @@ public void atput0(final long longIndex, final Object obj) { } } - public Object getLiteral(final long longIndex) { - return literals[(int) (1 + longIndex)]; // +1 for skipping header. + public Object getLiteral(final long index) { + return literals[(int) index]; } - public void setLiteral(final long longIndex, final Object obj) { - final int index = (int) longIndex; + public void setLiteral(final long index, final Object obj) { CompilerDirectives.transferToInterpreterAndInvalidate(); - if (index == 0) { - assert obj instanceof Long; - final int oldNumLiterals = numLiterals; - literals[0] = obj; - decodeHeader(); - assert numLiterals == oldNumLiterals; - } else { - literals[index] = obj; - } + literals[(int) index] = obj; invalidateCallTarget(); } @@ -524,6 +501,7 @@ public void write(final SqueakImageWriter writer) { assert 0 <= formatOffset && formatOffset <= 7 : "too many odd bits (see instSpec)"; if (writeHeader(writer, formatOffset)) { assert SqueakImageConstants.SMALL_INTEGER_MIN_VAL <= getHeader() && getHeader() <= SqueakImageConstants.SMALL_INTEGER_MAX_VAL : "Method header out of SmallInteger range"; + writer.writeLong(getHeader()); writer.writeObjects(literals); writer.writeBytes(getBytes()); final int byteOffset = getBytes().length % SqueakImageConstants.WORD_SIZE; @@ -606,16 +584,18 @@ public ClassObject getMethodClass(final AbstractPointersObjectReadNode readNode) return (ClassObject) readNode.execute((AbstractPointersObject) getMethodClassAssociation(), CLASS_BINDING.VALUE); } - private long getHeader() { - return (long) literals[0]; + public long getHeader() { + return header; } public void setHeader(final long header) { - numLiterals = CompiledCodeHeaderDecoder.getNumLiterals(header); - literals = ArrayUtils.withAll(1 + numLiterals, NilObject.SINGLETON); // keep negative method headers in SmallInteger range - literals[0] = header | (header < 0 ? NEGATIVE_METHOD_HEADER_MASK : 0); - decodeHeader(); + this.header = header | (header < 0 ? NEGATIVE_METHOD_HEADER_MASK : 0); + assert literals == null || getNumLiterals() == literals.length; + } + + public void initalizeLiterals() { + literals = ArrayUtils.withAll(getNumLiterals(), NilObject.SINGLETON); } public boolean hasStoreIntoTemp1AfterCallPrimitive() { @@ -663,29 +643,26 @@ public CompiledCodeObject getMethodUnsafe() { * sign bit: 1 bit: selects the instruction set, >= 0 Primary, < 0 Secondary (#signFlag) * */ - private static final class CompiledCodeHeaderDecoder { - private static final int NUM_LITERALS_SIZE = 1 << 15; - private static final int NUM_TEMPS_TEMPS_SIZE = 1 << 6; - private static final int NUM_ARGUMENTS_SIZE = 1 << 4; + public static final class CompiledCodeHeaderDecoder { - private static int getNumLiterals(final long headerWord) { - return MiscUtils.bitSplit(headerWord, 0, NUM_LITERALS_SIZE); + public static int getNumLiterals(final long headerWord) { + return (int) headerWord & 0x7FFF; } private static boolean getHasPrimitive(final long headerWord) { - return (headerWord & 1 << 16) != 0; + return (headerWord & 0x10000) != 0; } private static boolean getNeedsLargeFrame(final long headerWord) { - return (headerWord & 1 << 17) != 0; + return (headerWord & 0x20000) != 0; } private static int getNumTemps(final long headerWord) { - return MiscUtils.bitSplit(headerWord, 18, NUM_TEMPS_TEMPS_SIZE); + return (int) (headerWord >> 18) & 0x3F; } private static int getNumArguments(final long headerWord) { - return MiscUtils.bitSplit(headerWord, 24, NUM_ARGUMENTS_SIZE); + return (int) (headerWord >> 24) & 0x0F; } private static boolean getSignFlag(final long headerWord) { diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java index c5366f4cd..9f0cc7210 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/MiscellaneousPrimitives.java @@ -128,9 +128,9 @@ public abstract static class AbstractPrimCalloutToFFINode extends AbstractFFIPri public final boolean acceptsMethod(final CompiledCodeObject method) { CompilerAsserts.neverPartOfCompilation(); if (method.getNumLiterals() > 0) { - final Object literal1 = method.getLiterals()[1]; - if (literal1 instanceof final PointersObject l1 && l1.getSqueakClass().includesExternalFunctionBehavior(getContext())) { - externalFunction = l1; + final Object literal0 = method.getLiteral(0); + if (literal0 instanceof final PointersObject l0 && l0.getSqueakClass().includesExternalFunctionBehavior(getContext())) { + externalFunction = l0; return true; } } diff --git a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java index 09a4c171f..f47431dce 100644 --- a/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java +++ b/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/nodes/primitives/impl/StoragePrimitives.java @@ -164,19 +164,33 @@ private static void patchTruffleFrames(final Object[] fromPointers, final Object @NodeInfo(cost = NodeCost.NONE) @SqueakPrimitive(indices = 68) protected abstract static class PrimCompiledMethodObjectAtNode extends AbstractPrimitiveNode implements BinaryPrimitiveFallback { - @Specialization(guards = "to0(index) < receiver.getLiterals().length") - protected static final Object literalAt(final CompiledCodeObject receiver, final long index) { - // Use getLiterals() instead of getLiteral(i), the latter skips the header. - return receiver.getLiterals()[(int) index - 1]; + @Specialization(guards = "index == 1") + protected static final Object getHeader(final CompiledCodeObject receiver, @SuppressWarnings("unused") final long index) { + return receiver.getHeader(); + } + + @Specialization(guards = {"index > 1", "to0(index) <= receiver.getNumLiterals()"}) + protected static final Object getLiteral(final CompiledCodeObject receiver, final long index) { + return receiver.getLiteral(index - 2); } } @GenerateNodeFactory @SqueakPrimitive(indices = 69) protected abstract static class PrimCompiledMethodObjectAtPutNode extends AbstractPrimitiveNode implements TernaryPrimitiveFallback { - @Specialization(guards = "to0(index) < receiver.getLiterals().length") + @Specialization(guards = "index == 1") + protected static final Object setHeader(final CompiledCodeObject receiver, @SuppressWarnings("unused") final long index, final long value) { + if (receiver.getHeader() != CompiledCodeObject.CompiledCodeHeaderDecoder.getNumLiterals(value)) { + CompilerDirectives.transferToInterpreter(); + throw PrimitiveFailed.BAD_ARGUMENT; + } + receiver.setHeader(value); + return value; + } + + @Specialization(guards = {"index > 1", "to0(index) <= receiver.getNumLiterals()"}) protected static final Object setLiteral(final CompiledCodeObject receiver, final long index, final Object value) { - receiver.setLiteral(index - 1, value); + receiver.setLiteral(index - 2, value); return value; } } @@ -372,6 +386,7 @@ protected final CompiledCodeObject newMethod(final ClassObject receiver, final l assert receiver.getSuperclassOrNull() == image.compiledMethodClass.getSuperclassOrNull() : "Receiver must be subclass of CompiledCode"; final CompiledCodeObject newMethod = CompiledCodeObject.newOfSize(image, (int) bytecodeCount, receiver); newMethod.setHeader(header); + newMethod.initalizeLiterals(); return newMethod; } }