implements PR-O3.2
This commit is contained in:
parent
a38fedc591
commit
0df936e36f
@ -6,6 +6,7 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ public class BytecodeEmitter {
|
|||||||
public BytecodeModule emit(
|
public BytecodeModule emit(
|
||||||
final EmissionPlan plan) {
|
final EmissionPlan plan) {
|
||||||
final var inputPlan = plan == null ? EmissionPlan.empty() : plan;
|
final var inputPlan = plan == null ? EmissionPlan.empty() : plan;
|
||||||
|
final var canonicalConstPool = dedupeConstPool(inputPlan.constPool());
|
||||||
|
final var canonicalExports = dedupeExports(inputPlan.exports());
|
||||||
final var functionFragments = new ArrayList<BytecodeFunctionLayoutBuilder.FunctionFragment>(inputPlan.functions().size());
|
final var functionFragments = new ArrayList<BytecodeFunctionLayoutBuilder.FunctionFragment>(inputPlan.functions().size());
|
||||||
final var orderedSyscalls = new LinkedHashMap<SyscallIdentity, BytecodeModule.SyscallDecl>();
|
final var orderedSyscalls = new LinkedHashMap<SyscallIdentity, BytecodeModule.SyscallDecl>();
|
||||||
final var syscallIndexByIdentity = new LinkedHashMap<SyscallIdentity, Integer>();
|
final var syscallIndexByIdentity = new LinkedHashMap<SyscallIdentity, Integer>();
|
||||||
@ -101,11 +104,11 @@ public class BytecodeEmitter {
|
|||||||
final var layout = BytecodeFunctionLayoutBuilder.build(ReadOnlyList.wrap(functionFragments));
|
final var layout = BytecodeFunctionLayoutBuilder.build(ReadOnlyList.wrap(functionFragments));
|
||||||
return new BytecodeModule(
|
return new BytecodeModule(
|
||||||
inputPlan.version(),
|
inputPlan.version(),
|
||||||
inputPlan.constPool(),
|
canonicalConstPool,
|
||||||
layout.functions(),
|
layout.functions(),
|
||||||
layout.code(),
|
layout.code(),
|
||||||
layout.debugInfo(),
|
layout.debugInfo(),
|
||||||
inputPlan.exports(),
|
canonicalExports,
|
||||||
ReadOnlyList.wrap(orderedSyscalls.values()));
|
ReadOnlyList.wrap(orderedSyscalls.values()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +128,34 @@ public class BytecodeEmitter {
|
|||||||
return span;
|
return span;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReadOnlyList<BytecodeModule.ConstantPoolEntry> dedupeConstPool(
|
||||||
|
final ReadOnlyList<BytecodeModule.ConstantPoolEntry> input) {
|
||||||
|
if (input == null || input.isEmpty()) {
|
||||||
|
return ReadOnlyList.empty();
|
||||||
|
}
|
||||||
|
final var ordered = new LinkedHashSet<BytecodeModule.ConstantPoolEntry>(input.size());
|
||||||
|
for (final var constant : input) {
|
||||||
|
if (constant != null) {
|
||||||
|
ordered.add(constant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ReadOnlyList.wrap(ordered.stream().toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReadOnlyList<BytecodeModule.Export> dedupeExports(
|
||||||
|
final ReadOnlyList<BytecodeModule.Export> input) {
|
||||||
|
if (input == null || input.isEmpty()) {
|
||||||
|
return ReadOnlyList.empty();
|
||||||
|
}
|
||||||
|
final var ordered = new LinkedHashSet<BytecodeModule.Export>(input.size());
|
||||||
|
for (final var export : input) {
|
||||||
|
if (export != null) {
|
||||||
|
ordered.add(export);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ReadOnlyList.wrap(ordered.stream().toList());
|
||||||
|
}
|
||||||
|
|
||||||
private record SyscallIdentity(
|
private record SyscallIdentity(
|
||||||
String module,
|
String module,
|
||||||
String name,
|
String name,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import p.studio.utilities.structures.ReadOnlyList;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@ -167,6 +168,60 @@ class BytecodeEmitterTest {
|
|||||||
assertEquals(2, readU32(module.code(), 8));
|
assertEquals(2, readU32(module.code(), 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emitMustDeduplicateConstPoolAndExportsByFirstOccurrence() {
|
||||||
|
final var emitter = new BytecodeEmitter();
|
||||||
|
final var module = emitter.emit(new BytecodeEmitter.EmissionPlan(
|
||||||
|
0,
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new BytecodeModule.Int32Constant(7),
|
||||||
|
new BytecodeModule.Int32Constant(7),
|
||||||
|
new BytecodeModule.StringConstant("abc"),
|
||||||
|
new BytecodeModule.StringConstant("abc")),
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new BytecodeModule.Export("main", 0),
|
||||||
|
new BytecodeModule.Export("main", 0),
|
||||||
|
new BytecodeModule.Export("aux", 1)),
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new BytecodeEmitter.FunctionPlan(
|
||||||
|
"main",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(BytecodeEmitter.Operation.ret())))));
|
||||||
|
|
||||||
|
assertEquals(2, module.constPool().size());
|
||||||
|
assertEquals(2, module.exports().size());
|
||||||
|
assertEquals("main", module.exports().get(0).symbol());
|
||||||
|
assertEquals("aux", module.exports().get(1).symbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emitMustRemainDeterministicAfterInterning() {
|
||||||
|
final var emitter = new BytecodeEmitter();
|
||||||
|
final var plan = new BytecodeEmitter.EmissionPlan(
|
||||||
|
0,
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new BytecodeModule.Int32Constant(1),
|
||||||
|
new BytecodeModule.Int32Constant(1)),
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new BytecodeModule.Export("main", 0),
|
||||||
|
new BytecodeModule.Export("main", 0)),
|
||||||
|
ReadOnlyList.from(
|
||||||
|
new BytecodeEmitter.FunctionPlan(
|
||||||
|
"main",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(BytecodeEmitter.Operation.halt()))));
|
||||||
|
|
||||||
|
final var first = emitter.emit(plan).serialize();
|
||||||
|
final var second = emitter.emit(plan).serialize();
|
||||||
|
assertArrayEquals(first, second);
|
||||||
|
}
|
||||||
|
|
||||||
private static int readU16(final byte[] bytes, final int offset) {
|
private static int readU16(final byte[] bytes, final int offset) {
|
||||||
return ByteBuffer.wrap(bytes, offset, 2).order(ByteOrder.LITTLE_ENDIAN).getShort() & 0xFFFF;
|
return ByteBuffer.wrap(bytes, offset, 2).order(ByteOrder.LITTLE_ENDIAN).getShort() & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user