Skip to content

Commit 5e573c9

Browse files
committed
fix: Enforce TOP values in locals table
1 parent eec67a4 commit 5e573c9

File tree

12 files changed

+307
-99
lines changed

12 files changed

+307
-99
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ plugins {
55
}
66

77
group 'dev.xdark'
8-
version '1.3.3'
8+
version '1.3.4'
99

1010
repositories {
1111
mavenCentral()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public VirtualMachine(Object... args) {
100100
val groupClass = symbols.java_lang_ThreadGroup;
101101
groupClass.initialize();
102102

103-
IntrinsicsNatives.init(this);
103+
IntrinsicsNatives.init(this);
104104
}
105105

106106
public VirtualMachine() {

src/main/java/dev/xdark/ssvm/execution/asm/DoubleStoreProcessor.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import dev.xdark.ssvm.execution.ExecutionContext;
44
import dev.xdark.ssvm.execution.InstructionProcessor;
55
import dev.xdark.ssvm.execution.Result;
6+
import dev.xdark.ssvm.value.TopValue;
7+
import lombok.val;
68
import org.objectweb.asm.tree.VarInsnNode;
79

810
/**
@@ -14,7 +16,10 @@ public final class DoubleStoreProcessor implements InstructionProcessor<VarInsnN
1416

1517
@Override
1618
public Result execute(VarInsnNode insn, ExecutionContext ctx) {
17-
ctx.getLocals().set(insn.var, ctx.getStack().popWide());
19+
val locals = ctx.getLocals();
20+
val var = insn.var;
21+
locals.set(var, ctx.getStack().popWide());
22+
locals.set(var + 1, TopValue.INSTANCE);
1823
return Result.CONTINUE;
1924
}
2025
}

src/main/java/dev/xdark/ssvm/execution/asm/LongStoreProcessor.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import dev.xdark.ssvm.execution.ExecutionContext;
44
import dev.xdark.ssvm.execution.InstructionProcessor;
55
import dev.xdark.ssvm.execution.Result;
6+
import dev.xdark.ssvm.value.TopValue;
7+
import lombok.val;
68
import org.objectweb.asm.tree.VarInsnNode;
79

810
/**
@@ -14,7 +16,10 @@ public final class LongStoreProcessor implements InstructionProcessor<VarInsnNod
1416

1517
@Override
1618
public Result execute(VarInsnNode insn, ExecutionContext ctx) {
17-
ctx.getLocals().set(insn.var, ctx.getStack().popWide());
19+
val locals = ctx.getLocals();
20+
val var = insn.var;
21+
locals.set(var, ctx.getStack().popWide());
22+
locals.set(var + 1, TopValue.INSTANCE);
1823
return Result.CONTINUE;
1924
}
2025
}

src/main/java/dev/xdark/ssvm/jit/JitCompiler.java

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public final class JitCompiler {
6262
private static final ClassType VALUES = ClassType.of(Value[].class);
6363
private static final ClassType VM_EXCEPTION = ClassType.of(VMException.class);
6464
private static final ClassType INSTANCE = ClassType.of(InstanceValue.class);
65+
private static final ClassType TOP = ClassType.of(TopValue.class);
6566

6667
// ctx methods
6768
private static final Access GET_LOCALS = virtualCall(CTX, "getLocals", LOCALS);
@@ -149,7 +150,7 @@ public final class JitCompiler {
149150
private static final Access GET_STATIC_BYTE = staticCall(JIT_HELPER, "getStaticB", J_BYTE, J_OBJECT, J_LONG, CTX);
150151
private static final Access GET_STATIC_VALUE = staticCall(JIT_HELPER, "getStaticA", VALUE, J_OBJECT, J_LONG, CTX);
151152
private static final Access GET_STATIC_FAIL = staticCall(JIT_HELPER, "getStaticFail", J_VOID, J_OBJECT, J_OBJECT, CTX);
152-
private static final Access GET_STATIC_SLOW = staticCall(JIT_HELPER, "getStatic", VALUE, J_STRING, J_STRING, J_STRING, CTX);
153+
private static final Access GET_STATIC_SLOW = staticCall(JIT_HELPER, "getStaticA", VALUE, J_STRING, J_STRING, J_STRING, CTX);
153154

154155
private static final Access GET_FIELD_LONG = staticCall(JIT_HELPER, "getFieldJ", J_LONG, VALUE, J_OBJECT, J_STRING, J_STRING, CTX);
155156
private static final Access GET_FIELD_DOUBLE = staticCall(JIT_HELPER, "getFieldD", J_DOUBLE, VALUE, J_OBJECT, J_STRING, J_STRING, CTX);
@@ -181,6 +182,8 @@ public final class JitCompiler {
181182

182183
private static final Access DYNAMIC_CALL = staticCall(JIT_HELPER, "invokeDynamic", VALUE, VALUES, J_OBJECT, J_INT, CTX);
183184

185+
private static final Access GET_TOP = getStatic(TOP, "INSTANCE", TOP);
186+
184187
private static final int CTX_SLOT = 1;
185188
private static final int LOCALS_SLOT = 2;
186189
private static final int HELPER_SLOT = 3;
@@ -1040,7 +1043,7 @@ private void invokeStatic(MethodInsnNode node) {
10401043
jit.visitLdcInsn(node.owner + name + desc);
10411044
access = INVOKE_FAIL;
10421045
} else {
1043-
loadArgs(false, desc);
1046+
collectStaticCallArgs(desc);
10441047
loadCompilerConstant(jc);
10451048
loadCompilerConstant(mn);
10461049
access = INVOKE_STATIC_INTRINSIC;
@@ -1065,7 +1068,7 @@ private void invokeStatic(MethodInsnNode node) {
10651068

10661069
private void invokeStaticSlow(MethodInsnNode node) {
10671070
val desc = node.desc;
1068-
loadArgs(false, desc);
1071+
collectStaticCallArgs(desc);
10691072
pushMethod(node);
10701073
loadCtx();
10711074
INVOKE_STATIC_SLOW.emit(jit);
@@ -1093,7 +1096,7 @@ private void invokeSpecial(MethodInsnNode node) {
10931096
jit.visitLdcInsn(node.owner + name + desc);
10941097
access = INVOKE_FAIL;
10951098
} else {
1096-
loadArgs(true, desc);
1099+
collectVirtualCallArgs(desc);
10971100
loadCompilerConstant(jc);
10981101
loadCompilerConstant(mn);
10991102
access = INVOKE_SPECIAL_INTRINSIC;
@@ -1118,7 +1121,7 @@ private void invokeSpecial(MethodInsnNode node) {
11181121

11191122
private void invokeSpecialSlow(MethodInsnNode node) {
11201123
val desc = node.desc;
1121-
loadArgs(true, desc);
1124+
collectVirtualCallArgs(desc);
11221125
pushMethod(node);
11231126
loadCtx();
11241127
INVOKE_SPECIAL_SLOW.emit(jit);
@@ -1127,7 +1130,7 @@ private void invokeSpecialSlow(MethodInsnNode node) {
11271130

11281131
private void invokeVirtual(MethodInsnNode node) {
11291132
val desc = node.desc;
1130-
loadArgs(true, desc);
1133+
collectVirtualCallArgs(desc);
11311134
loadCompilerConstant(node.name);
11321135
loadCompilerConstant(desc);
11331136
loadCtx();
@@ -1136,17 +1139,17 @@ private void invokeVirtual(MethodInsnNode node) {
11361139
}
11371140

11381141
private void invokeInterface(MethodInsnNode node) {
1139-
loadArgs(true, node.desc);
1142+
val desc = node.desc;
1143+
collectVirtualCallArgs(desc);
11401144
pushMethod(node);
11411145
loadCtx();
11421146
INVOKE_INTERFACE.emit(jit);
1143-
toJava(Type.getReturnType(node.desc));
1147+
toJava(Type.getReturnType(desc));
11441148
}
11451149

11461150
private void invokeDynamic(InvokeDynamicInsnNode node) {
11471151
val jit = this.jit;
1148-
val types = Type.getArgumentTypes(node.desc);
1149-
loadArgs(false, types.length + 1, types); // args
1152+
collectArgs(1, 1, node.desc); // args
11501153
loadConstants(); // args constants
11511154
emitInt(makeConstant(node), jit); // args constants index
11521155
loadCtx(); // args constants index ctx
@@ -1234,25 +1237,38 @@ private Object tryMethodType(Type type) {
12341237
}
12351238
}
12361239

1237-
private void loadArgs(boolean vrt, int arrayLength, Type[] args) {
1238-
int offset = Math.abs(args.length - arrayLength);
1239-
int idx = vrt ? 1 : 0;
1240+
private void collectArgs(int insertionOffset, int extra, String desc) {
1241+
val args = Type.getArgumentTypes(desc);
1242+
int count = totalSize(args) + extra;
12401243
val jit = this.jit;
1241-
jit.visitLdcInsn(arrayLength + idx);
1244+
jit.visitLdcInsn(count);
12421245
jit.visitTypeInsn(ANEWARRAY, VALUE.internalName);
1243-
int i = args.length;
1244-
while (i-- != 0)
1245-
loadArgTo(i + idx + offset, args[i]);
1246-
if (vrt)
1247-
loadArgTo(offset, VALUE.type);
1246+
int idx = args.length;
1247+
count--;
1248+
while (idx-- != 0) {
1249+
val arg = args[idx];
1250+
if (arg.getSize() == 2) {
1251+
loadTopTo(count-- + insertionOffset);
1252+
}
1253+
loadArgTo(count-- + insertionOffset, arg);
1254+
}
1255+
}
1256+
1257+
private void collectVirtualCallArgs(String desc) {
1258+
collectArgs(0, 1, desc);
1259+
loadArgTo(0, VALUE.type);
12481260
}
12491261

1250-
private void loadArgs(boolean vrt, Type[] args) {
1251-
loadArgs(vrt, args.length, args);
1262+
private void collectStaticCallArgs(String desc) {
1263+
collectArgs(0, 0, desc);
12521264
}
12531265

1254-
private void loadArgs(boolean vrt, String desc) {
1255-
loadArgs(vrt, Type.getArgumentTypes(desc));
1266+
private static int totalSize(Type[] args) {
1267+
int size = 0;
1268+
for (val arg : args) {
1269+
size += arg.getSize();
1270+
}
1271+
return size;
12561272
}
12571273

12581274
private void loadArgTo(int idx, Type type) {
@@ -1266,6 +1282,14 @@ private void loadArgTo(int idx, Type type) {
12661282
jit.visitInsn(AASTORE);
12671283
}
12681284

1285+
private void loadTopTo(int idx) {
1286+
val jit = this.jit;
1287+
jit.visitInsn(DUP); // args args
1288+
jit.visitLdcInsn(idx); // args args idx
1289+
GET_TOP.emit(jit); // args args idx value
1290+
jit.visitInsn(AASTORE);
1291+
}
1292+
12691293
private void toJava(Type type) {
12701294
val jit = this.jit;
12711295
switch (type.getSort()) {

src/main/java/dev/xdark/ssvm/jit/JitHelper.java

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.xdark.ssvm.jit;
22

3+
import dev.xdark.ssvm.VirtualMachine;
34
import dev.xdark.ssvm.execution.ExecutionContext;
45
import dev.xdark.ssvm.execution.VMException;
56
import dev.xdark.ssvm.mirror.ArrayJavaClass;
@@ -233,19 +234,23 @@ public Value compareDouble(Value a, Value b, int nan) {
233234
}
234235
}
235236

236-
public void getStatic(String owner, String name, String desc, ExecutionContext ctx) {
237+
public Value getStaticA(String owner, String name, String desc, ExecutionContext ctx) {
237238
val vm = ctx.getVM();
238239
val helper = vm.getHelper();
239240
InstanceJavaClass klass = (InstanceJavaClass) helper.findClass(ctx.getOwner().getClassLoader(), owner, true);
240241
while (klass != null) {
241242
val value = klass.getStaticValue(name, desc);
242243
if (value != null) {
243-
ctx.getStack().pushGeneric(value);
244-
return;
244+
return value;
245245
}
246246
klass = klass.getSuperClass();
247247
}
248248
helper.throwException(vm.getSymbols().java_lang_NoSuchFieldError, name);
249+
return null;
250+
}
251+
252+
public void getStatic(String owner, String name, String desc, ExecutionContext ctx) {
253+
ctx.getStack().pushGeneric(getStaticA(owner, name, desc, ctx));
249254
}
250255

251256
// special intrinsic versions.
@@ -511,10 +516,13 @@ public void invokeVirtual(String owner, String name, String desc, ExecutionConte
511516
val vm = ctx.getVM();
512517
val stack = ctx.getStack();
513518
val args = Type.getArgumentTypes(desc);
514-
int localsLength = args.length + 1;
519+
int localsLength = 1;
520+
for (val arg : args) {
521+
localsLength += arg.getSize();
522+
}
515523
val locals = new Value[localsLength];
516524
while (localsLength-- != 0) {
517-
locals[localsLength] = stack.popGeneric();
525+
locals[localsLength] = stack.pop();
518526
}
519527
val result = vm.getHelper().invokeVirtual(name, desc, new Value[0], locals);
520528
val v = result.getResult();
@@ -537,10 +545,13 @@ public void invokeSpecial(String owner, String name, String desc, ExecutionConte
537545
val klass = (InstanceJavaClass) helper.findClass(ctx.getOwner().getClassLoader(), owner, true);
538546
val stack = ctx.getStack();
539547
val args = Type.getArgumentTypes(desc);
540-
int localsLength = args.length + 1;
548+
int localsLength = 1;
549+
for (val arg : args) {
550+
localsLength += arg.getSize();
551+
}
541552
val locals = new Value[localsLength];
542553
while (localsLength-- != 0) {
543-
locals[localsLength] = stack.popGeneric();
554+
locals[localsLength] = stack.pop();
544555
}
545556
val result = helper.invokeExact(klass, name, desc, new Value[0], locals);
546557
val v = result.getResult();
@@ -550,31 +561,16 @@ public void invokeSpecial(String owner, String name, String desc, ExecutionConte
550561
}
551562

552563
public void invokeStatic(String owner, String name, String desc, ExecutionContext ctx) {
553-
val vm = ctx.getVM();
554-
val helper = vm.getHelper();
555-
InstanceJavaClass klass;
556-
try {
557-
klass = (InstanceJavaClass) helper.findClass(ctx.getOwner().getClassLoader(), owner, true);
558-
} catch (VMException ex) {
559-
val oop = ex.getOop();
560-
if (oop.isNull() || !vm.getSymbols().java_lang_Error.isAssignableFrom(oop.getJavaClass())) {
561-
val cnfe = helper.newException(vm.getSymbols().java_lang_NoClassDefFoundError, owner, oop);
562-
throw new VMException(cnfe);
563-
}
564-
throw ex;
565-
}
566-
val mn = klass.getStaticMethodRecursively(name, desc);
567-
if (mn == null) {
568-
helper.throwException(vm.getSymbols().java_lang_NoSuchMethodError, owner + '.' + name + desc);
569-
}
564+
val mn = resolveStaticMethod(owner, name, desc, ctx);
570565
val stack = ctx.getStack();
571-
val args = mn.getArgumentTypes();
572-
int localsLength = args.length;
566+
int localsLength = mn.getMaxArgs();
573567
val locals = new Value[localsLength];
574568
while (localsLength-- != 0) {
575-
locals[localsLength] = stack.popGeneric();
569+
locals[localsLength] = stack.pop();
576570
}
577-
val result = helper.invokeStatic(klass, mn, new Value[0], locals);
571+
val vm = ctx.getVM();
572+
val helper = vm.getHelper();
573+
val result = helper.invokeStatic(mn.getOwner(), mn, new Value[0], locals);
578574
val v = result.getResult();
579575
if (!v.isVoid()) {
580576
stack.pushGeneric(v);
@@ -601,6 +597,14 @@ public Value invokeStatic(Value[] locals, Object owner, Object method, Execution
601597
return result.getResult();
602598
}
603599

600+
public Value invokeStatic(Value[] locals, String owner, String name, String desc, ExecutionContext ctx) {
601+
val helper = ctx.getHelper();
602+
val mn = resolveStaticMethod(owner, name, desc, ctx);
603+
val stack = ctx.getStack();
604+
val result = helper.invokeStatic(mn.getOwner(), mn, new Value[0], locals);
605+
return result.getResult();
606+
}
607+
604608
public Value invokeSpecial(Value[] locals, Object owner, Object method, ExecutionContext ctx) {
605609
val vm = ctx.getVM();
606610
val helper = vm.getHelper();
@@ -631,10 +635,13 @@ public void invokeInterface(String owner, String name, String desc, ExecutionCon
631635
val klass = (InstanceJavaClass) helper.findClass(ctx.getOwner().getClassLoader(), owner, true);
632636
val stack = ctx.getStack();
633637
val args = Type.getArgumentTypes(desc);
634-
int localsLength = args.length + 1;
638+
int localsLength = 1;
639+
for (val arg : args) {
640+
localsLength += arg.getSize();
641+
}
635642
val locals = new Value[localsLength];
636643
while (localsLength-- != 0) {
637-
locals[localsLength] = stack.popGeneric();
644+
locals[localsLength] = stack.pop();
638645
}
639646
val result = helper.invokeInterface(klass, name, desc, new Value[0], locals);
640647
val v = result.getResult();
@@ -900,7 +907,28 @@ public Value invokeDynamic(Value[] args, Object constants, int index, ExecutionC
900907
}
901908
return InvokeDynamicLinker.dynamicCall(args, result.desc, result.handle, ctx);
902909
}
903-
910+
911+
private static JavaMethod resolveStaticMethod(String owner, String name, String desc, ExecutionContext ctx) {
912+
val vm = ctx.getVM();
913+
val helper = vm.getHelper();
914+
InstanceJavaClass klass;
915+
try {
916+
klass = (InstanceJavaClass) helper.findClass(ctx.getOwner().getClassLoader(), owner, true);
917+
} catch (VMException ex) {
918+
val oop = ex.getOop();
919+
if (oop.isNull() || !vm.getSymbols().java_lang_Error.isAssignableFrom(oop.getJavaClass())) {
920+
val cnfe = helper.newException(vm.getSymbols().java_lang_NoClassDefFoundError, owner, oop);
921+
throw new VMException(cnfe);
922+
}
923+
throw ex;
924+
}
925+
val mn = klass.getStaticMethodRecursively(name, desc);
926+
if (mn == null) {
927+
helper.throwException(vm.getSymbols().java_lang_NoSuchMethodError, owner + '.' + name + desc);
928+
}
929+
return mn;
930+
}
931+
904932
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
905933
private static final class DynamicLinkResult {
906934
final InstanceValue handle;

0 commit comments

Comments
 (0)