Alex
Alex

Reputation: 21

Transform a stack using Java Virtual Machine Instruction Set

I need to transform 654321 into 654321321, using only DUP2_X1, POP, DUP_X2, POP2. I have a really difficult time with the DUP. Can anyone help?

I tried to go like this: 654321 DUP2_X1 654654321, then POP goes to 65465432, then DUP_X2 we'd have 6543265432... but I don't think I am doing them correctly.

Upvotes: 1

Views: 75

Answers (1)

Holger
Holger

Reputation: 298499

So, basically you want to duplicate the last three elements of the operand stack while keeping all other elements intact and not use local variables nor heap space.

One sequence to achieve this would be

Instruction Resulting Stack
(initial) ...321
DUP2_X1 ...21321
POP2 ...213
DUP_X2 ...3213
DUP_X2 ...33213
POP ...3321
DUP2_X1 ...321321

A straight-forward program to test it using the ASM library looks like

package asm;

import static org.objectweb.asm.Opcodes.*;
import java.lang.invoke.*;
import org.objectweb.asm.*;

public class DuplicateThreeOperands {
  public static void main(String[] args) throws ReflectiveOperationException {
    final String s = "Ljava/lang/String;";
    ClassWriter cw = new ClassWriter(0);
    cw.visit(55, ACC_INTERFACE | ACC_ABSTRACT,
             "asm/Test", null, "java/lang/Object", args);
    MethodVisitor mv = cw.visitMethod(ACC_STATIC | ACC_PUBLIC,
             "test", "()" + s, null, null);
    mv.visitCode();
    mv.visitLdcInsn("6");
    mv.visitLdcInsn("5");
    mv.visitLdcInsn("4");
    mv.visitLdcInsn("3");
    mv.visitLdcInsn("2");
    mv.visitLdcInsn("1");

    stackManipulation(mv);

    mv.visitInvokeDynamicInsn("concat", "(" + s.repeat(9) + ")" + s, new Handle(
        H_INVOKESTATIC, "java/lang/invoke/StringConcatFactory", "makeConcat",
        MethodType.methodType(CallSite.class, MethodHandles.Lookup.class,
           String.class, MethodType.class).toMethodDescriptorString(), false));
    mv.visitInsn(ARETURN);
    mv.visitMaxs(9, 0);

    String result = (String)MethodHandles.lookup().defineClass(cw.toByteArray())
        .getMethod("test").invoke(null);
    System.out.println(result);
  }

  private static void stackManipulation(MethodVisitor mv) {
                           // ...321
    mv.visitInsn(DUP2_X1); // ...21321
    mv.visitInsn(POP2);    // ...213
    mv.visitInsn(DUP_X2);  // ...3213
    mv.visitInsn(DUP_X2);  // ...33213
    mv.visitInsn(POP);     // ...3321
    mv.visitInsn(DUP2_X1); // ...321321
  }
}

and prints

654321321

You may look at the dup instruction and following sections in JVM specification for further reference.

Upvotes: 3

Related Questions