Skip to content

Commit

Permalink
Refactor CompiledCodeObject
Browse files Browse the repository at this point in the history
- Extract header field from literal array
- Drop numArgs, numLiterals, numTemps to reduce size of objects
  • Loading branch information
fniephaus committed Dec 7, 2023
1 parent c06fcd1 commit 6fc2faa
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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());
}

Expand All @@ -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) {
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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() {
Expand All @@ -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() {
Expand All @@ -333,32 +324,27 @@ 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<Integer, CompiledCodeObject> 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;
callTargetStable().invalidate();
}

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) {
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -663,29 +643,26 @@ public CompiledCodeObject getMethodUnsafe() {
* sign bit: 1 bit: selects the instruction set, >= 0 Primary, < 0 Secondary (#signFlag)
* </pre>
*/
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
}
Expand Down

0 comments on commit 6fc2faa

Please sign in to comment.