mirror of
https://github.com/Qortal/AT.git
synced 2025-01-30 19:02:14 +00:00
Try to reduce byte arrays being created/copied wherever possible. Also bump to v1.3.7 due to interface changes.
This commit is contained in:
parent
facb9c213f
commit
2884b586d6
@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.ciyam</groupId>
|
<groupId>org.ciyam</groupId>
|
||||||
<artifactId>AT</artifactId>
|
<artifactId>AT</artifactId>
|
||||||
<version>1.3.6</version>
|
<version>1.3.7</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<properties>
|
<properties>
|
||||||
<skipTests>true</skipTests>
|
<skipTests>true</skipTests>
|
||||||
|
@ -3,7 +3,6 @@ package org.ciyam.at;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -65,8 +64,6 @@ public class MachineState {
|
|||||||
public final short numUserStackPages;
|
public final short numUserStackPages;
|
||||||
public final long minActivationAmount;
|
public final long minActivationAmount;
|
||||||
|
|
||||||
private final byte[] headerBytes;
|
|
||||||
|
|
||||||
/** Constants set in effect */
|
/** Constants set in effect */
|
||||||
private final VersionedConstants constants;
|
private final VersionedConstants constants;
|
||||||
|
|
||||||
@ -137,15 +134,10 @@ public class MachineState {
|
|||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
/** For internal use when recreating a machine state */
|
/** For internal use when recreating a machine state. Leaves ByteBuffer position immediately after header. */
|
||||||
private MachineState(byte[] headerBytes, API api, AtLoggerFactory loggerFactory) {
|
private MachineState(ByteBuffer byteBuffer) {
|
||||||
if (headerBytes.length != HEADER_LENGTH)
|
if (byteBuffer.remaining() < HEADER_LENGTH)
|
||||||
throw new IllegalArgumentException("headerBytes length " + headerBytes.length + " incorrect, expected " + HEADER_LENGTH);
|
throw new IllegalArgumentException("ByteBuffer too small (" + byteBuffer.remaining() + "), minimum " + HEADER_LENGTH);
|
||||||
|
|
||||||
this.headerBytes = headerBytes;
|
|
||||||
|
|
||||||
// Parsing header bytes
|
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(this.headerBytes);
|
|
||||||
|
|
||||||
this.version = byteBuffer.getShort();
|
this.version = byteBuffer.getShort();
|
||||||
if (this.version < 1)
|
if (this.version < 1)
|
||||||
@ -174,8 +166,13 @@ public class MachineState {
|
|||||||
throw new IllegalArgumentException("Number of user stack pages must be >= 0");
|
throw new IllegalArgumentException("Number of user stack pages must be >= 0");
|
||||||
|
|
||||||
this.minActivationAmount = byteBuffer.getLong();
|
this.minActivationAmount = byteBuffer.getLong();
|
||||||
|
if (this.minActivationAmount < 0)
|
||||||
|
throw new IllegalArgumentException("Minimum activation amount must be >= 0");
|
||||||
|
|
||||||
// Header OK - set up code and data buffers
|
// Header OK
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSegmentsAndStacks() {
|
||||||
this.codeByteBuffer = ByteBuffer.allocate(this.numCodePages * this.constants.CODE_PAGE_SIZE);
|
this.codeByteBuffer = ByteBuffer.allocate(this.numCodePages * this.constants.CODE_PAGE_SIZE);
|
||||||
this.dataByteBuffer = ByteBuffer.allocate(this.numDataPages * this.constants.DATA_PAGE_SIZE);
|
this.dataByteBuffer = ByteBuffer.allocate(this.numDataPages * this.constants.DATA_PAGE_SIZE);
|
||||||
|
|
||||||
@ -185,35 +182,29 @@ public class MachineState {
|
|||||||
|
|
||||||
this.userStackByteBuffer = ByteBuffer.allocate(this.numUserStackPages * this.constants.USER_STACK_PAGE_SIZE);
|
this.userStackByteBuffer = ByteBuffer.allocate(this.numUserStackPages * this.constants.USER_STACK_PAGE_SIZE);
|
||||||
this.userStackByteBuffer.position(this.userStackByteBuffer.limit()); // Downward-growing stack, so start at the end
|
this.userStackByteBuffer.position(this.userStackByteBuffer.limit()); // Downward-growing stack, so start at the end
|
||||||
|
|
||||||
this.api = api;
|
|
||||||
this.currentBlockHeight = 0;
|
|
||||||
this.currentBalance = 0;
|
|
||||||
this.previousBalance = 0;
|
|
||||||
this.steps = 0;
|
|
||||||
this.loggerFactory = loggerFactory;
|
|
||||||
this.logger = loggerFactory.create(MachineState.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** For creating a new machine state */
|
/** For creating a new machine state */
|
||||||
public MachineState(API api, AtLoggerFactory loggerFactory, byte[] creationBytes) {
|
public MachineState(API api, AtLoggerFactory loggerFactory, byte[] creationBytes) {
|
||||||
this(Arrays.copyOfRange(creationBytes, 0, HEADER_LENGTH), api, loggerFactory);
|
this(ByteBuffer.wrap(creationBytes));
|
||||||
|
|
||||||
int expectedLength = HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE + this.numDataPages * this.constants.DATA_PAGE_SIZE;
|
int expectedLength = HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE + this.numDataPages * this.constants.DATA_PAGE_SIZE;
|
||||||
if (creationBytes.length != expectedLength)
|
if (creationBytes.length != expectedLength)
|
||||||
throw new IllegalArgumentException("Creation bytes length does not match header values");
|
throw new IllegalArgumentException("Creation bytes length does not match header values");
|
||||||
|
|
||||||
|
setupSegmentsAndStacks();
|
||||||
|
|
||||||
System.arraycopy(creationBytes, HEADER_LENGTH, this.codeByteBuffer.array(), 0, this.numCodePages * this.constants.CODE_PAGE_SIZE);
|
System.arraycopy(creationBytes, HEADER_LENGTH, this.codeByteBuffer.array(), 0, this.numCodePages * this.constants.CODE_PAGE_SIZE);
|
||||||
|
|
||||||
System.arraycopy(creationBytes, HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE, this.dataByteBuffer.array(), 0,
|
System.arraycopy(creationBytes, HEADER_LENGTH + this.numCodePages * this.constants.CODE_PAGE_SIZE, this.dataByteBuffer.array(), 0,
|
||||||
this.numDataPages * this.constants.DATA_PAGE_SIZE);
|
this.numDataPages * this.constants.DATA_PAGE_SIZE);
|
||||||
|
|
||||||
commonFinalConstruction();
|
commonFinalConstruction(api, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** For creating a new machine state - used in tests */
|
/** For creating a new machine state - used in tests */
|
||||||
public MachineState(API api, AtLoggerFactory loggerFactory, byte[] headerBytes, byte[] codeBytes, byte[] dataBytes) {
|
public MachineState(API api, AtLoggerFactory loggerFactory, byte[] headerBytes, byte[] codeBytes, byte[] dataBytes) {
|
||||||
this(headerBytes, api, loggerFactory);
|
this(ByteBuffer.wrap(headerBytes));
|
||||||
|
|
||||||
if (codeBytes.length > this.numCodePages * this.constants.CODE_PAGE_SIZE)
|
if (codeBytes.length > this.numCodePages * this.constants.CODE_PAGE_SIZE)
|
||||||
throw new IllegalArgumentException("Number of code pages too small to hold code bytes");
|
throw new IllegalArgumentException("Number of code pages too small to hold code bytes");
|
||||||
@ -221,14 +212,25 @@ public class MachineState {
|
|||||||
if (dataBytes.length > this.numDataPages * this.constants.DATA_PAGE_SIZE)
|
if (dataBytes.length > this.numDataPages * this.constants.DATA_PAGE_SIZE)
|
||||||
throw new IllegalArgumentException("Number of data pages too small to hold data bytes");
|
throw new IllegalArgumentException("Number of data pages too small to hold data bytes");
|
||||||
|
|
||||||
|
setupSegmentsAndStacks();
|
||||||
|
|
||||||
System.arraycopy(codeBytes, 0, this.codeByteBuffer.array(), 0, codeBytes.length);
|
System.arraycopy(codeBytes, 0, this.codeByteBuffer.array(), 0, codeBytes.length);
|
||||||
|
|
||||||
System.arraycopy(dataBytes, 0, this.dataByteBuffer.array(), 0, dataBytes.length);
|
System.arraycopy(dataBytes, 0, this.dataByteBuffer.array(), 0, dataBytes.length);
|
||||||
|
|
||||||
commonFinalConstruction();
|
commonFinalConstruction(api, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commonFinalConstruction() {
|
private void commonFinalConstruction(API api, AtLoggerFactory loggerFactory) {
|
||||||
|
this.api = api;
|
||||||
|
this.loggerFactory = loggerFactory;
|
||||||
|
this.logger = loggerFactory.create(MachineState.class);
|
||||||
|
|
||||||
|
this.currentBlockHeight = 0;
|
||||||
|
this.currentBalance = 0;
|
||||||
|
this.previousBalance = 0;
|
||||||
|
this.steps = 0;
|
||||||
|
|
||||||
this.programCounter = 0;
|
this.programCounter = 0;
|
||||||
this.onStopAddress = 0;
|
this.onStopAddress = 0;
|
||||||
this.onErrorAddress = null;
|
this.onErrorAddress = null;
|
||||||
@ -443,33 +445,89 @@ public class MachineState {
|
|||||||
return this.codeByteBuffer.array();
|
return this.codeByteBuffer.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class NumericByteArrayOutputStream extends ByteArrayOutputStream {
|
||||||
|
public NumericByteArrayOutputStream(int capacity) {
|
||||||
|
super(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeShort(short value) {
|
||||||
|
this.write((byte) (value >> 8));
|
||||||
|
this.write((byte) (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeInt(int value) {
|
||||||
|
this.write((byte) (value >> 24));
|
||||||
|
this.write((byte) (value >> 16));
|
||||||
|
this.write((byte) (value >> 8));
|
||||||
|
this.write((byte) (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeLong(long value) {
|
||||||
|
this.write((byte) (value >> 56));
|
||||||
|
this.write((byte) (value >> 48));
|
||||||
|
this.write((byte) (value >> 40));
|
||||||
|
this.write((byte) (value >> 32));
|
||||||
|
this.write((byte) (value >> 24));
|
||||||
|
this.write((byte) (value >> 16));
|
||||||
|
this.write((byte) (value >> 8));
|
||||||
|
this.write((byte) (value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** For serializing a machine state */
|
/** For serializing a machine state */
|
||||||
public byte[] toBytes() {
|
public byte[] toBytes() {
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
int capacity = HEADER_LENGTH
|
||||||
|
+ this.dataByteBuffer.capacity()
|
||||||
|
+ this.callStackByteBuffer.capacity()
|
||||||
|
+ this.userStackByteBuffer.capacity()
|
||||||
|
+ 7 * 4 // Misc ints like stack lengths, PC, PCS, flags, etc.
|
||||||
|
+ 10 * 8; // Misc longs like previous balance, frozen balance, A, B, etc.
|
||||||
|
|
||||||
|
NumericByteArrayOutputStream bytes = new NumericByteArrayOutputStream(capacity);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Header first
|
// Header first
|
||||||
bytes.write(this.headerBytes);
|
|
||||||
|
// Version
|
||||||
|
bytes.writeShort(version);
|
||||||
|
|
||||||
|
// Reserved
|
||||||
|
bytes.writeShort((short) 0);
|
||||||
|
|
||||||
|
// Code length
|
||||||
|
bytes.writeShort(numCodePages);
|
||||||
|
|
||||||
|
// Data length
|
||||||
|
bytes.writeShort(numDataPages);
|
||||||
|
|
||||||
|
// Call stack length
|
||||||
|
bytes.writeShort(numCallStackPages);
|
||||||
|
|
||||||
|
// User stack length
|
||||||
|
bytes.writeShort(numUserStackPages);
|
||||||
|
|
||||||
|
// Minimum activation amount
|
||||||
|
bytes.writeLong(minActivationAmount);
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
bytes.write(this.dataByteBuffer.array());
|
bytes.write(this.dataByteBuffer.array());
|
||||||
|
|
||||||
// Call stack length (32bit unsigned int)
|
// Call stack length (32bit unsigned int)
|
||||||
int callStackLength = this.callStackByteBuffer.limit() - this.callStackByteBuffer.position();
|
int callStackLength = this.callStackByteBuffer.limit() - this.callStackByteBuffer.position();
|
||||||
bytes.write(toByteArray(callStackLength));
|
bytes.writeInt(callStackLength);
|
||||||
// Call stack (only the bytes actually in use)
|
// Call stack (only the bytes actually in use)
|
||||||
bytes.write(this.callStackByteBuffer.array(), this.callStackByteBuffer.position(), callStackLength);
|
bytes.write(this.callStackByteBuffer.array(), this.callStackByteBuffer.position(), callStackLength);
|
||||||
|
|
||||||
// User stack length (32bit unsigned int)
|
// User stack length (32bit unsigned int)
|
||||||
int userStackLength = this.userStackByteBuffer.limit() - this.userStackByteBuffer.position();
|
int userStackLength = this.userStackByteBuffer.limit() - this.userStackByteBuffer.position();
|
||||||
bytes.write(toByteArray(userStackLength));
|
bytes.writeInt(userStackLength);
|
||||||
// User stack (only the bytes actually in use)
|
// User stack (only the bytes actually in use)
|
||||||
bytes.write(this.userStackByteBuffer.array(), this.userStackByteBuffer.position(), userStackLength);
|
bytes.write(this.userStackByteBuffer.array(), this.userStackByteBuffer.position(), userStackLength);
|
||||||
|
|
||||||
// Actual state
|
// Actual state
|
||||||
bytes.write(toByteArray(this.programCounter));
|
bytes.writeInt(this.programCounter);
|
||||||
bytes.write(toByteArray(this.onStopAddress));
|
bytes.writeInt(this.onStopAddress);
|
||||||
bytes.write(toByteArray(this.previousBalance));
|
bytes.writeLong(this.previousBalance);
|
||||||
|
|
||||||
// Various flags
|
// Various flags
|
||||||
Flags flags = new Flags();
|
Flags flags = new Flags();
|
||||||
@ -489,30 +547,30 @@ public class MachineState {
|
|||||||
boolean hasNonZeroB = this.b1 != 0 || this.b2 != 0 || this.b3 != 0 || this.b4 != 0;
|
boolean hasNonZeroB = this.b1 != 0 || this.b2 != 0 || this.b3 != 0 || this.b4 != 0;
|
||||||
flags.push(hasNonZeroB);
|
flags.push(hasNonZeroB);
|
||||||
|
|
||||||
bytes.write(toByteArray(flags.intValue()));
|
bytes.writeInt(flags.intValue());
|
||||||
|
|
||||||
// Optional flag-indicated extra info in same order as above
|
// Optional flag-indicated extra info in same order as above
|
||||||
if (this.onErrorAddress != null)
|
if (this.onErrorAddress != null)
|
||||||
bytes.write(toByteArray(this.onErrorAddress));
|
bytes.writeInt(this.onErrorAddress);
|
||||||
|
|
||||||
if (this.sleepUntilHeight != null)
|
if (this.sleepUntilHeight != null)
|
||||||
bytes.write(toByteArray(this.sleepUntilHeight));
|
bytes.writeInt(this.sleepUntilHeight);
|
||||||
|
|
||||||
if (this.frozenBalance != null)
|
if (this.frozenBalance != null)
|
||||||
bytes.write(toByteArray(this.frozenBalance));
|
bytes.writeLong(this.frozenBalance);
|
||||||
|
|
||||||
if (hasNonZeroA) {
|
if (hasNonZeroA) {
|
||||||
bytes.write(toByteArray(this.a1));
|
bytes.writeLong(this.a1);
|
||||||
bytes.write(toByteArray(this.a2));
|
bytes.writeLong(this.a2);
|
||||||
bytes.write(toByteArray(this.a3));
|
bytes.writeLong(this.a3);
|
||||||
bytes.write(toByteArray(this.a4));
|
bytes.writeLong(this.a4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasNonZeroB) {
|
if (hasNonZeroB) {
|
||||||
bytes.write(toByteArray(this.b1));
|
bytes.writeLong(this.b1);
|
||||||
bytes.write(toByteArray(this.b2));
|
bytes.writeLong(this.b2);
|
||||||
bytes.write(toByteArray(this.b3));
|
bytes.writeLong(this.b3);
|
||||||
bytes.write(toByteArray(this.b4));
|
bytes.writeLong(this.b4);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return null;
|
return null;
|
||||||
@ -525,14 +583,22 @@ public class MachineState {
|
|||||||
public static MachineState fromBytes(API api, AtLoggerFactory loggerFactory, byte[] stateBytes, byte[] codeBytes) {
|
public static MachineState fromBytes(API api, AtLoggerFactory loggerFactory, byte[] stateBytes, byte[] codeBytes) {
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(stateBytes);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(stateBytes);
|
||||||
|
|
||||||
byte[] headerBytes = new byte[HEADER_LENGTH];
|
MachineState state = new MachineState(byteBuffer);
|
||||||
byteBuffer.get(headerBytes);
|
|
||||||
|
|
||||||
MachineState state = new MachineState(headerBytes, api, loggerFactory);
|
if (codeBytes.length != state.numCodePages * state.constants.CODE_PAGE_SIZE)
|
||||||
|
|
||||||
if (codeBytes.length != state.codeByteBuffer.capacity())
|
|
||||||
throw new IllegalStateException("Passed codeBytes does not match length in header");
|
throw new IllegalStateException("Passed codeBytes does not match length in header");
|
||||||
|
|
||||||
|
state.api = api;
|
||||||
|
state.loggerFactory = loggerFactory;
|
||||||
|
state.logger = loggerFactory.create(MachineState.class);
|
||||||
|
|
||||||
|
state.currentBlockHeight = 0;
|
||||||
|
state.currentBalance = 0;
|
||||||
|
state.previousBalance = 0;
|
||||||
|
state.steps = 0;
|
||||||
|
|
||||||
|
state.setupSegmentsAndStacks();
|
||||||
|
|
||||||
// Pull in code bytes
|
// Pull in code bytes
|
||||||
System.arraycopy(codeBytes, 0, state.codeByteBuffer.array(), 0, codeBytes.length);
|
System.arraycopy(codeBytes, 0, state.codeByteBuffer.array(), 0, codeBytes.length);
|
||||||
|
|
||||||
@ -557,6 +623,34 @@ public class MachineState {
|
|||||||
System.arraycopy(stateBytes, byteBuffer.position(), state.userStackByteBuffer.array(), state.userStackByteBuffer.position(), userStackLength);
|
System.arraycopy(stateBytes, byteBuffer.position(), state.userStackByteBuffer.array(), state.userStackByteBuffer.position(), userStackLength);
|
||||||
byteBuffer.position(byteBuffer.position() + userStackLength);
|
byteBuffer.position(byteBuffer.position() + userStackLength);
|
||||||
|
|
||||||
|
extractMisc(byteBuffer, state);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For restoring only flags from a previously serialized machine state */
|
||||||
|
public static MachineState flagsOnlyfromBytes(byte[] stateBytes) {
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(stateBytes);
|
||||||
|
|
||||||
|
MachineState state = new MachineState(byteBuffer);
|
||||||
|
|
||||||
|
// Skip data segment
|
||||||
|
byteBuffer.position(byteBuffer.position() + state.numDataPages * state.constants.DATA_PAGE_SIZE);
|
||||||
|
|
||||||
|
// Skip call stack
|
||||||
|
int callStackLength = byteBuffer.getInt();
|
||||||
|
byteBuffer.position(byteBuffer.position() + callStackLength);
|
||||||
|
|
||||||
|
// Skip user stack
|
||||||
|
int userStackLength = byteBuffer.getInt();
|
||||||
|
byteBuffer.position(byteBuffer.position() + userStackLength);
|
||||||
|
|
||||||
|
extractMisc(byteBuffer, state);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractMisc(ByteBuffer byteBuffer, MachineState state) {
|
||||||
// Actual state
|
// Actual state
|
||||||
state.programCounter = byteBuffer.getInt();
|
state.programCounter = byteBuffer.getInt();
|
||||||
state.onStopAddress = byteBuffer.getInt();
|
state.onStopAddress = byteBuffer.getInt();
|
||||||
@ -599,24 +693,23 @@ public class MachineState {
|
|||||||
state.b3 = byteBuffer.getLong();
|
state.b3 = byteBuffer.getLong();
|
||||||
state.b4 = byteBuffer.getLong();
|
state.b4 = byteBuffer.getLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns data bytes from saved state to allow external analysis, e.g. confirming expected payouts, etc. */
|
/** Returns data bytes from saved state to allow external analysis, e.g. confirming expected payouts, etc. */
|
||||||
public static byte[] extractDataBytes(AtLoggerFactory loggerFactory, byte[] stateBytes) {
|
public static byte[] extractDataBytes(byte[] stateBytes) {
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(stateBytes);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(stateBytes);
|
||||||
|
|
||||||
byte[] headerBytes = new byte[HEADER_LENGTH];
|
short version = byteBuffer.getShort(0);
|
||||||
byteBuffer.get(headerBytes);
|
VersionedConstants constants = VERSIONED_CONSTANTS.get(version);
|
||||||
|
|
||||||
MachineState state = new MachineState(headerBytes, null, loggerFactory);
|
short numDataPages = byteBuffer.getShort(2 /*version*/ + 2 /*reserved*/ + 2 /*code pages*/);
|
||||||
|
|
||||||
// Extract data bytes
|
// Extract data bytes
|
||||||
int dataBytesLength = state.dataByteBuffer.capacity();
|
int dataBytesLength = numDataPages * constants.DATA_PAGE_SIZE;
|
||||||
byte[] dataBytes = new byte[dataBytesLength];
|
byte[] dataBytes = new byte[dataBytesLength];
|
||||||
|
|
||||||
// More efficient than ByteBuffer.get()
|
// More efficient than ByteBuffer.get()
|
||||||
System.arraycopy(stateBytes, byteBuffer.position(), dataBytes, 0, dataBytesLength);
|
System.arraycopy(stateBytes, HEADER_LENGTH, dataBytes, 0, dataBytesLength);
|
||||||
|
|
||||||
return dataBytes;
|
return dataBytes;
|
||||||
}
|
}
|
||||||
@ -649,6 +742,11 @@ public class MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert short to big-endian byte array */
|
||||||
|
public static byte[] toByteArray(short value) {
|
||||||
|
return new byte[] { (byte) (value >> 8), (byte) (value) };
|
||||||
|
}
|
||||||
|
|
||||||
/** Convert int to big-endian byte array */
|
/** Convert int to big-endian byte array */
|
||||||
public static byte[] toByteArray(int value) {
|
public static byte[] toByteArray(int value) {
|
||||||
return new byte[] { (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) (value) };
|
return new byte[] { (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) (value) };
|
||||||
|
@ -107,6 +107,8 @@ public class SerializationTests extends ExecutableTest {
|
|||||||
byte[] packedRestoredSate = restoredState.toBytes();
|
byte[] packedRestoredSate = restoredState.toBytes();
|
||||||
|
|
||||||
assertTrue(Arrays.equals(packedState, packedRestoredSate));
|
assertTrue(Arrays.equals(packedState, packedRestoredSate));
|
||||||
|
|
||||||
|
restoredState = MachineState.fromBytes(api, loggerFactory, packedState, codeBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] simulate() {
|
private byte[] simulate() {
|
||||||
|
Loading…
Reference in New Issue
Block a user