Skip to content

Commit

Permalink
feat: memory management revamp & more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
xxDark committed Mar 29, 2022
1 parent 7151c7d commit 172436b
Show file tree
Hide file tree
Showing 33 changed files with 1,552 additions and 235 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group 'dev.xdark'
version '1.1.1'
version '1.2.0'

repositories {
mavenCentral()
Expand Down
1 change: 1 addition & 0 deletions src/main/java/dev/xdark/ssvm/NativeJava.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ static void init(VirtualMachine vm) {
ProxyNatives.init(vm);
InflaterNatives.init(vm);
ProcessEnvironmentNatives.init(vm);
WindowsNativeDispatcherNatives.init(vm);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/dev/xdark/ssvm/VirtualMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ public void execute(ExecutionContext ctx, boolean useInvokers) {
.forEach(invocation -> invocation.handle(ctx));
} finally {
ctx.deallocate();
if (lock != null) {
if (lock != null && lock.isHeldByCurrentThread()) {
lock.monitorExit();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public long newFD() {
long handle;
Long wrapper;
do {
handle = rng.nextLong() & 0xFFFFFFFFL;
handle = rng.nextLong();
} while (inputs.containsKey(wrapper = handle) || outputs.containsKey(wrapper) || zipFiles.containsKey(wrapper));
return handle;
}
Expand Down
203 changes: 203 additions & 0 deletions src/main/java/dev/xdark/ssvm/memory/BufferMemoryData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package dev.xdark.ssvm.memory;

import dev.xdark.ssvm.execution.PanicException;
import dev.xdark.ssvm.util.VolatileBufferAccess;
import lombok.RequiredArgsConstructor;
import lombok.val;

import java.nio.ByteBuffer;
import java.util.Arrays;

/**
* Memory data backed by byte buffer.
*
* @author xDark
*/
@RequiredArgsConstructor
final class BufferMemoryData implements MemoryData {

private static final int MEMSET_THRESHOLD = 256;
private final ByteBuffer buffer;
private VolatileBufferAccess volatileAccess;

@Override
public long readLong(long offset) {
return buffer.getLong(validate(offset));
}

@Override
public int readInt(long offset) {
return buffer.getInt(validate(offset));
}

@Override
public char readChar(long offset) {
return buffer.getChar(validate(offset));
}

@Override
public short readShort(long offset) {
return buffer.getShort(validate(offset));
}

@Override
public byte readByte(long offset) {
return buffer.get(validate(offset));
}

@Override
public void writeLong(long offset, long value) {
buffer.putLong(validate(offset), value);
}

@Override
public void writeInt(long offset, int value) {
buffer.putInt(validate(offset), value);
}

@Override
public void writeChar(long offset, char value) {
buffer.putChar(validate(offset), value);
}

@Override
public void writeShort(long offset, short value) {
buffer.putShort(validate(offset), value);
}

@Override
public void writeByte(long offset, byte value) {
buffer.put(validate(offset), value);
}

@Override
public long readLongVolatile(long offset) {
return volatileAccess().getLong(validate(offset));
}

@Override
public int readIntVolatile(long offset) {
return volatileAccess().getInt(validate(offset));
}

@Override
public char readCharVolatile(long offset) {
return volatileAccess().getChar(validate(offset));
}

@Override
public short readShortVolatile(long offset) {
return volatileAccess().getShort(validate(offset));
}

@Override
public byte readByteVolatile(long offset) {
return volatileAccess().getByte(validate(offset));
}

@Override
public void writeLongVolatile(long offset, long value) {
volatileAccess().putLong(validate(offset), value);
}

@Override
public void writeIntVolatile(long offset, int value) {
volatileAccess().putInt(validate(offset), value);
}

@Override
public void writeCharVolatile(long offset, char value) {
volatileAccess().putChar(validate(offset), value);
}

@Override
public void writeShortVolatile(long offset, short value) {
volatileAccess().putShort(validate(offset), value);
}

@Override
public void writeByteVolatile(long offset, byte value) {
volatileAccess().putByte(validate(offset), value);
}

@Override
public void set(long offset, long bytes, byte value) {
val buffer = this.buffer;
int $offset = validate(offset);
int $bytes = validate(bytes);
if ($bytes >= MEMSET_THRESHOLD) {
byte[] buf = new byte[MEMSET_THRESHOLD];
Arrays.fill(buf, value);
val slice = buffer.slice().order(buffer.order());
slice.position($offset);
while ($bytes != 0) {
int len = Math.min($bytes, MEMSET_THRESHOLD);
slice.put(buf, 0, len);
$bytes -= len;
}
} else {
while ($bytes-- != 0) {
buffer.put($offset++, value);
}
}
}

@Override
public void copy(long srcOffset, MemoryData dst, long dstOffset, long bytes) {
if (dst instanceof BufferMemoryData) {
val dstBuf = ((BufferMemoryData) dst).buffer;
int $srcOffset = validate(srcOffset);
copyOrder(((ByteBuffer) dstBuf.slice().position(validate(dstOffset)))).put((ByteBuffer) buffer.slice().position($srcOffset).limit($srcOffset + validate(bytes)));
} else {
int start = validate(dstOffset);
int $bytes = validate(bytes);
int $offset = validate(srcOffset);
val buffer = this.buffer;
while ($bytes-- != 0) {
dst.writeByte(start++, buffer.get($offset++));
}
}
}

@Override
public void write(long dstOffset, ByteBuffer buffer) {
copyOrder(((ByteBuffer) this.buffer.slice().position(validate(dstOffset)))).put(buffer);
}

@Override
public void write(long dstOffset, byte[] array, int arrayOffset, int length) {
copyOrder(((ByteBuffer) buffer.slice().position(validate(dstOffset)))).put(array, arrayOffset, length);
}

@Override
public long length() {
return buffer.capacity();
}

@Override
public MemoryData slice(long offset, long bytes) {
int $offset = validate(offset);
return MemoryData.buffer(copyOrder(((ByteBuffer) buffer.slice().position($offset).limit($offset + validate(bytes))).slice()));
}

// This is so stupid, calling ByteBuffer#slice()
// resets buffer's byte order, copy it back
private ByteBuffer copyOrder(ByteBuffer buffer) {
return buffer.order(this.buffer.order());
}

private VolatileBufferAccess volatileAccess() {
VolatileBufferAccess volatileAccess = this.volatileAccess;
if (volatileAccess == null) {
return this.volatileAccess = VolatileBufferAccess.wrap(buffer);
}
return volatileAccess;
}

private static int validate(long offset) {
if (offset > Integer.MAX_VALUE || offset < 0) {
throw new PanicException("Segfault");
}
return (int) offset;
}
}
2 changes: 1 addition & 1 deletion src/main/java/dev/xdark/ssvm/memory/Memory.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface Memory {
*
* @return memory data.
*/
ByteBuffer getData();
MemoryData getData();

/**
* Returns memory address.
Expand Down
Loading

0 comments on commit 172436b

Please sign in to comment.