Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.xdark.ssvm.asm;

import dev.xdark.ssvm.value.InstanceValue;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.tree.AbstractInsnNode;

public class ConstantDynamicInsnNode extends DelegatingInsnNode<AbstractInsnNode> {

private final ConstantDynamic constantDynamic;
private final InstanceValue result;

public ConstantDynamicInsnNode(AbstractInsnNode delegate, InstanceValue result, ConstantDynamic constantDynamic) {
super(delegate, VMOpcodes.VM_CONSTANT_DYNAMIC);
this.constantDynamic = constantDynamic;
this.result = result;
}

public ConstantDynamic getConstantDynamic() {
return constantDynamic;
}

public InstanceValue getResult() {
return result;
}

}
3 changes: 2 additions & 1 deletion ssvm-core/src/main/java/dev/xdark/ssvm/asm/VMOpcodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public interface VMOpcodes {
int VM_CONSTANT_LONG = VM_CONSTANT_FLOAT + 1;
int VM_CONSTANT_DOUBLE = VM_CONSTANT_LONG + 1;
int VM_CONSTANT_REFERENCE = VM_CONSTANT_DOUBLE + 1;
int VM_PUTFIELD_BOOLEAN = VM_CONSTANT_REFERENCE + 1;
int VM_CONSTANT_DYNAMIC = VM_CONSTANT_REFERENCE + 1;
int VM_PUTFIELD_BOOLEAN = VM_CONSTANT_DYNAMIC + 1;
int VM_PUTFIELD_CHAR = VM_PUTFIELD_BOOLEAN + 1;
int VM_PUTFIELD_BYTE = VM_PUTFIELD_CHAR + 1;
int VM_PUTFIELD_SHORT = VM_PUTFIELD_BYTE + 1;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package dev.xdark.ssvm.execution.asm;

import dev.xdark.ssvm.asm.ConstantDoubleInsnNode;
import dev.xdark.ssvm.asm.ConstantFloatInsnNode;
import dev.xdark.ssvm.asm.ConstantIntInsnNode;
import dev.xdark.ssvm.asm.ConstantLongInsnNode;
import dev.xdark.ssvm.asm.ConstantReferenceInsnNode;
import dev.xdark.ssvm.asm.*;
import dev.xdark.ssvm.execution.ExecutionContext;
import dev.xdark.ssvm.execution.InstructionProcessor;
import dev.xdark.ssvm.execution.Result;
import dev.xdark.ssvm.util.AsmUtil;
import dev.xdark.ssvm.value.ObjectValue;
import dev.xdark.ssvm.value.Value;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LdcInsnNode;

Expand Down Expand Up @@ -42,6 +39,10 @@ public Result execute(LdcInsnNode insn, ExecutionContext<?> ctx) {
list.set(insn, new ConstantIntInsnNode(insn, (char) cst));
} else if (cst instanceof String) {
list.set(insn, new ConstantReferenceInsnNode(insn, ctx.getVM().getStringPool().intern((String) cst)));
} else if (cst instanceof ConstantDynamic) {
ConstantDynamic dynamic = (ConstantDynamic) cst;
list.set(insn, new ConstantDynamicInsnNode(insn,
ctx.getOperations().linkDynamic(dynamic, ctx.getOwner()), dynamic));
} else {
ObjectValue ref = ctx.getOperations().referenceValue(cst);
list.set(insn, new ConstantReferenceInsnNode(insn, ref));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dev.xdark.ssvm.execution.rewrite.constant;

import dev.xdark.ssvm.asm.ConstantDynamicInsnNode;
import dev.xdark.ssvm.execution.ExecutionContext;
import dev.xdark.ssvm.execution.InstructionProcessor;
import dev.xdark.ssvm.execution.Result;
import dev.xdark.ssvm.operation.VMOperations;
import dev.xdark.ssvm.value.InstanceValue;
import org.objectweb.asm.Type;

public class ConstantDynamicProcessor implements InstructionProcessor<ConstantDynamicInsnNode> {
@Override
public Result execute(ConstantDynamicInsnNode insn, ExecutionContext<?> ctx) {
InstanceValue result = insn.getResult();
VMOperations ops = ctx.getOperations();

Type condyType = Type.getType(insn.getConstantDynamic().getDescriptor());
switch (condyType.getSort()) {
case Type.BOOLEAN:
ctx.getStack().pushInt(ops.unboxBoolean(result) ? 1 : 0);
break;
case Type.CHAR:
ctx.getStack().pushInt(ops.unboxChar(result));
break;
case Type.BYTE:
ctx.getStack().pushInt(ops.unboxByte(result));
break;
case Type.SHORT:
ctx.getStack().pushInt(ops.unboxShort(result));
break;
case Type.INT:
ctx.getStack().pushInt(ops.unboxInt(result));
break;
case Type.LONG:
ctx.getStack().pushLong(ops.unboxLong(result));
break;
case Type.FLOAT:
ctx.getStack().pushFloat(ops.unboxFloat(result));
break;
case Type.DOUBLE:
ctx.getStack().pushDouble(ops.unboxDouble(result));
break;
case Type.OBJECT:
ctx.getStack().pushReference(result);
break;
}
return Result.CONTINUE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import dev.xdark.ssvm.util.Assertions;
import dev.xdark.ssvm.value.ObjectValue;
import lombok.RequiredArgsConstructor;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Type;

Expand Down Expand Up @@ -64,6 +65,11 @@ public ObjectValue referenceValue(Object value) {
Assertions.notNull(ctx, "cannot be called without call frame");
return ops.linkMethodHandleConstant(ctx.getMethod().getOwner(), (Handle) value);
}
if (value instanceof ConstantDynamic) {
ExecutionContext<?> ctx = threadManager.currentOsThread().getBacktrace().peek();
Assertions.notNull(ctx, "cannot be called without call frame");
return ops.linkDynamic((ConstantDynamic) value, ctx.getMethod().getOwner());
}
}
throw new PanicException("Unsupported constant " + value + " " + value.getClass());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import dev.xdark.ssvm.value.ObjectValue;
import dev.xdark.ssvm.value.sink.ValueSink;
import lombok.RequiredArgsConstructor;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
Expand Down Expand Up @@ -89,6 +90,46 @@ public InstanceValue linkCall(InvokeDynamicInsnNode insn, InstanceClass caller)
return (InstanceValue) appendix.getReference(0);
}

@Override
public InstanceValue linkDynamic(ConstantDynamic node, InstanceClass caller) {
Symbols symbols = this.symbols;
Handle bootstrap = node.getBootstrapMethod();
VMOperations ops = this.ops;

InstanceValue bsm = ops.linkMethodHandleConstant(caller, bootstrap);

ArrayValue bsmArgs = ops.allocateArray(symbols.java_lang_Object(), node.getBootstrapMethodArgumentCount());
for (int i = 0; i < node.getBootstrapMethodArgumentCount(); i++) {
Object arg = node.getBootstrapMethodArgument(i);
bsmArgs.setReference(i, forInvokeDynamicCall(caller, arg));
}

InstanceClass natives = symbols.java_lang_invoke_MethodHandleNatives();
JavaMethod method = natives.getMethod("linkDynamicConstant", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
Locals linkArgs;
if (method == null) {
method = natives.getMethod("linkDynamicConstant", "(Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

linkArgs = threadManager.currentOsThread().getStorage().newLocals(method);

linkArgs.setReference(0, caller.getOop());
linkArgs.setInt(1, 0); // condy index
linkArgs.setReference(2, bsm);
linkArgs.setReference(3, stringPool.intern(node.getName()));
linkArgs.setReference(4, ops.findClass(caller, node.getDescriptor(), false).getOop());
linkArgs.setReference(5, bsmArgs);
} else {
linkArgs = threadManager.currentOsThread().getStorage().newLocals(method);
linkArgs.setReference(0, caller.getOop());
linkArgs.setReference(1, bsm);
linkArgs.setReference(2, stringPool.intern(node.getName()));
linkArgs.setReference(3, ops.findClass(caller, node.getDescriptor(), false).getOop());
linkArgs.setReference(4, bsmArgs);
}

return (InstanceValue) ops.invokeReference(method, linkArgs);
}

@Override
public void dynamicCall(Stack stack, String desc, InstanceValue handle, ValueSink sink) {
ThreadStorage ts = threadManager.currentOsThread().getStorage();
Expand Down Expand Up @@ -203,6 +244,9 @@ private ObjectValue forInvokeDynamicCall(InstanceClass caller, Object arg) {
if (arg instanceof Handle) {
return ops.linkMethodHandleConstant(caller, (Handle) arg);
}
if (arg instanceof ConstantDynamic) {
return ops.linkDynamic((ConstantDynamic) arg, caller);
}
throw new UnsupportedOperationException(Objects.toString(arg));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import dev.xdark.ssvm.mirror.type.InstanceClass;
import dev.xdark.ssvm.value.InstanceValue;
import dev.xdark.ssvm.value.sink.ValueSink;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;

/**
Expand Down Expand Up @@ -48,6 +49,15 @@ public interface InvokeDynamicOperations {
*/
InstanceValue linkCall(InvokeDynamicInsnNode insn, InstanceClass caller);

/**
* Links {@link org.objectweb.asm.ConstantDynamic}.
*
* @param node Node to link.
* @param caller Method caller.
* @return Resulting constant.
*/
InstanceValue linkDynamic(ConstantDynamic node, InstanceClass caller);

/**
* Invokes linked dynamic call.
*
Expand Down