Skip to content

Commit 172436b

Browse files
committed
feat: memory management revamp & more tests
1 parent 7151c7d commit 172436b

33 files changed

+1552
-235
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
}
44

55
group 'dev.xdark'
6-
version '1.1.1'
6+
version '1.2.0'
77

88
repositories {
99
mavenCentral()

src/main/java/dev/xdark/ssvm/NativeJava.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static void init(VirtualMachine vm) {
8080
ProxyNatives.init(vm);
8181
InflaterNatives.init(vm);
8282
ProcessEnvironmentNatives.init(vm);
83+
WindowsNativeDispatcherNatives.init(vm);
8384
}
8485

8586
/**

src/main/java/dev/xdark/ssvm/VirtualMachine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ public void execute(ExecutionContext ctx, boolean useInvokers) {
438438
.forEach(invocation -> invocation.handle(ctx));
439439
} finally {
440440
ctx.deallocate();
441-
if (lock != null) {
441+
if (lock != null && lock.isHeldByCurrentThread()) {
442442
lock.monitorExit();
443443
}
444444
}

src/main/java/dev/xdark/ssvm/fs/HostFileDescriptorManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public long newFD() {
8383
long handle;
8484
Long wrapper;
8585
do {
86-
handle = rng.nextLong() & 0xFFFFFFFFL;
86+
handle = rng.nextLong();
8787
} while (inputs.containsKey(wrapper = handle) || outputs.containsKey(wrapper) || zipFiles.containsKey(wrapper));
8888
return handle;
8989
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package dev.xdark.ssvm.memory;
2+
3+
import dev.xdark.ssvm.execution.PanicException;
4+
import dev.xdark.ssvm.util.VolatileBufferAccess;
5+
import lombok.RequiredArgsConstructor;
6+
import lombok.val;
7+
8+
import java.nio.ByteBuffer;
9+
import java.util.Arrays;
10+
11+
/**
12+
* Memory data backed by byte buffer.
13+
*
14+
* @author xDark
15+
*/
16+
@RequiredArgsConstructor
17+
final class BufferMemoryData implements MemoryData {
18+
19+
private static final int MEMSET_THRESHOLD = 256;
20+
private final ByteBuffer buffer;
21+
private VolatileBufferAccess volatileAccess;
22+
23+
@Override
24+
public long readLong(long offset) {
25+
return buffer.getLong(validate(offset));
26+
}
27+
28+
@Override
29+
public int readInt(long offset) {
30+
return buffer.getInt(validate(offset));
31+
}
32+
33+
@Override
34+
public char readChar(long offset) {
35+
return buffer.getChar(validate(offset));
36+
}
37+
38+
@Override
39+
public short readShort(long offset) {
40+
return buffer.getShort(validate(offset));
41+
}
42+
43+
@Override
44+
public byte readByte(long offset) {
45+
return buffer.get(validate(offset));
46+
}
47+
48+
@Override
49+
public void writeLong(long offset, long value) {
50+
buffer.putLong(validate(offset), value);
51+
}
52+
53+
@Override
54+
public void writeInt(long offset, int value) {
55+
buffer.putInt(validate(offset), value);
56+
}
57+
58+
@Override
59+
public void writeChar(long offset, char value) {
60+
buffer.putChar(validate(offset), value);
61+
}
62+
63+
@Override
64+
public void writeShort(long offset, short value) {
65+
buffer.putShort(validate(offset), value);
66+
}
67+
68+
@Override
69+
public void writeByte(long offset, byte value) {
70+
buffer.put(validate(offset), value);
71+
}
72+
73+
@Override
74+
public long readLongVolatile(long offset) {
75+
return volatileAccess().getLong(validate(offset));
76+
}
77+
78+
@Override
79+
public int readIntVolatile(long offset) {
80+
return volatileAccess().getInt(validate(offset));
81+
}
82+
83+
@Override
84+
public char readCharVolatile(long offset) {
85+
return volatileAccess().getChar(validate(offset));
86+
}
87+
88+
@Override
89+
public short readShortVolatile(long offset) {
90+
return volatileAccess().getShort(validate(offset));
91+
}
92+
93+
@Override
94+
public byte readByteVolatile(long offset) {
95+
return volatileAccess().getByte(validate(offset));
96+
}
97+
98+
@Override
99+
public void writeLongVolatile(long offset, long value) {
100+
volatileAccess().putLong(validate(offset), value);
101+
}
102+
103+
@Override
104+
public void writeIntVolatile(long offset, int value) {
105+
volatileAccess().putInt(validate(offset), value);
106+
}
107+
108+
@Override
109+
public void writeCharVolatile(long offset, char value) {
110+
volatileAccess().putChar(validate(offset), value);
111+
}
112+
113+
@Override
114+
public void writeShortVolatile(long offset, short value) {
115+
volatileAccess().putShort(validate(offset), value);
116+
}
117+
118+
@Override
119+
public void writeByteVolatile(long offset, byte value) {
120+
volatileAccess().putByte(validate(offset), value);
121+
}
122+
123+
@Override
124+
public void set(long offset, long bytes, byte value) {
125+
val buffer = this.buffer;
126+
int $offset = validate(offset);
127+
int $bytes = validate(bytes);
128+
if ($bytes >= MEMSET_THRESHOLD) {
129+
byte[] buf = new byte[MEMSET_THRESHOLD];
130+
Arrays.fill(buf, value);
131+
val slice = buffer.slice().order(buffer.order());
132+
slice.position($offset);
133+
while ($bytes != 0) {
134+
int len = Math.min($bytes, MEMSET_THRESHOLD);
135+
slice.put(buf, 0, len);
136+
$bytes -= len;
137+
}
138+
} else {
139+
while ($bytes-- != 0) {
140+
buffer.put($offset++, value);
141+
}
142+
}
143+
}
144+
145+
@Override
146+
public void copy(long srcOffset, MemoryData dst, long dstOffset, long bytes) {
147+
if (dst instanceof BufferMemoryData) {
148+
val dstBuf = ((BufferMemoryData) dst).buffer;
149+
int $srcOffset = validate(srcOffset);
150+
copyOrder(((ByteBuffer) dstBuf.slice().position(validate(dstOffset)))).put((ByteBuffer) buffer.slice().position($srcOffset).limit($srcOffset + validate(bytes)));
151+
} else {
152+
int start = validate(dstOffset);
153+
int $bytes = validate(bytes);
154+
int $offset = validate(srcOffset);
155+
val buffer = this.buffer;
156+
while ($bytes-- != 0) {
157+
dst.writeByte(start++, buffer.get($offset++));
158+
}
159+
}
160+
}
161+
162+
@Override
163+
public void write(long dstOffset, ByteBuffer buffer) {
164+
copyOrder(((ByteBuffer) this.buffer.slice().position(validate(dstOffset)))).put(buffer);
165+
}
166+
167+
@Override
168+
public void write(long dstOffset, byte[] array, int arrayOffset, int length) {
169+
copyOrder(((ByteBuffer) buffer.slice().position(validate(dstOffset)))).put(array, arrayOffset, length);
170+
}
171+
172+
@Override
173+
public long length() {
174+
return buffer.capacity();
175+
}
176+
177+
@Override
178+
public MemoryData slice(long offset, long bytes) {
179+
int $offset = validate(offset);
180+
return MemoryData.buffer(copyOrder(((ByteBuffer) buffer.slice().position($offset).limit($offset + validate(bytes))).slice()));
181+
}
182+
183+
// This is so stupid, calling ByteBuffer#slice()
184+
// resets buffer's byte order, copy it back
185+
private ByteBuffer copyOrder(ByteBuffer buffer) {
186+
return buffer.order(this.buffer.order());
187+
}
188+
189+
private VolatileBufferAccess volatileAccess() {
190+
VolatileBufferAccess volatileAccess = this.volatileAccess;
191+
if (volatileAccess == null) {
192+
return this.volatileAccess = VolatileBufferAccess.wrap(buffer);
193+
}
194+
return volatileAccess;
195+
}
196+
197+
private static int validate(long offset) {
198+
if (offset > Integer.MAX_VALUE || offset < 0) {
199+
throw new PanicException("Segfault");
200+
}
201+
return (int) offset;
202+
}
203+
}

src/main/java/dev/xdark/ssvm/memory/Memory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public interface Memory {
2121
*
2222
* @return memory data.
2323
*/
24-
ByteBuffer getData();
24+
MemoryData getData();
2525

2626
/**
2727
* Returns memory address.

0 commit comments

Comments
 (0)