changeset 14081:6d7136544168

Enhancement: add support for 'typed' bytecode prefix to bytecode API
author mcimadamore
date Mon, 12 Dec 2016 17:47:00 +0000
parents c7c97756db18
children 88a6e49ec676
files src/java.base/share/classes/jdk/experimental/bytecode/AttributeBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/BasicClassBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/ClassBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/CodeBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/FieldBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/GrowableByteBuffer.java src/java.base/share/classes/jdk/experimental/bytecode/MacroCodeBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/MemberBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/MethodBuilder.java src/java.base/share/classes/jdk/experimental/bytecode/Opcode.java src/java.base/share/classes/jdk/experimental/bytecode/PoolHelper.java src/java.base/share/classes/jdk/experimental/bytecode/TypedCodeBuilder.java src/java.base/share/classes/jdk/experimental/value/MethodHandleBuilder.java
diffstat 13 files changed, 330 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/jdk/experimental/bytecode/AttributeBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/AttributeBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -35,7 +35,7 @@
         super(poolHelper, typeHelper);
     }
 
-    public D withAttribute(String name, byte[] bytes) {
+    public D withAttribute(CharSequence name, byte[] bytes) {
         attributes.writeChar(poolHelper.putUtf8(name));
         attributes.writeInt(bytes.length);
         attributes.writeBytes(bytes);
@@ -43,7 +43,7 @@
         return thisBuilder();
     }
 
-    public <Z> D withAttribute(String name, Z attr, AttributeWriter<S, T, E, Z> attrWriter) {
+    public <Z> D withAttribute(CharSequence name, Z attr, AttributeWriter<S, T, E, Z> attrWriter) {
         attributes.writeChar(poolHelper.putUtf8(name));
         int offset = attributes.offset;
         attributes.writeInt(0);
--- a/src/java.base/share/classes/jdk/experimental/bytecode/BasicClassBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/BasicClassBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -131,7 +131,7 @@
             int index = -1;
             PoolKey next;
 
-            void setUtf8(String s) {
+            void setUtf8(CharSequence s) {
                 tag = PoolTag.CONSTANT_UTF8;
                 o1 = s;
                 size = 1;
@@ -145,7 +145,7 @@
                 hash = tag.tag | (clazz.hashCode() << 1);
             }
 
-            void setNameAndType(String name, String type) {
+            void setNameAndType(CharSequence name, String type) {
                 tag = PoolTag.CONSTANT_NAMEANDTYPE;
                 o1 = name;
                 o2 = type;
@@ -153,7 +153,7 @@
                 hash = tag.tag | ((name.hashCode() | type.hashCode()) << 1);
             }
 
-            void setMemberRef(PoolTag poolTag, String owner, String name, String type) {
+            void setMemberRef(PoolTag poolTag, String owner, CharSequence name, String type) {
                 tag = poolTag;
                 o1 = owner;
                 o2 = name;
@@ -272,17 +272,17 @@
         }
 
         @Override
-        public int putFieldRef(String owner, String name, String type) {
+        public int putFieldRef(String owner, CharSequence name, String type) {
             return putMemberRef(PoolTag.CONSTANT_FIELDREF, owner, name, type);
         }
 
         @Override
-        public int putMethodRef(String owner, String name, String type, boolean isInterface) {
+        public int putMethodRef(String owner, CharSequence name, String type, boolean isInterface) {
             return putMemberRef(isInterface ? PoolTag.CONSTANT_INTERFACEMETHODREF : PoolTag.CONSTANT_METHODREF,
                     owner, name, type);
         }
 
-        int putMemberRef(PoolTag poolTag, String owner, String name, String type) {
+        int putMemberRef(PoolTag poolTag, String owner, CharSequence name, String type) {
             key.setMemberRef(poolTag, owner, name, type);
             PoolKey poolKey = lookup(key);
             if (poolKey == null) {
@@ -422,7 +422,17 @@
         }
 
         @Override
-        public int putInvokeDynamic(String invokedName, String invokedType, String bsmClass, String bsmName, String bsmType, Object... staticArgs) {
+        public int putInvokeDynamic(CharSequence invokedName, String invokedType, int bsmKind, String bsmClass, CharSequence bsmName, String bsmType, Object... staticArgs) {
+            return 0; //TODO
+        }
+
+        @Override
+        public int putMethodType(String s) {
+            return 0; //TODO
+        }
+
+        @Override
+        public int putHandle(int refKind, String owner, CharSequence name, String type) {
             return 0; //TODO
         }
 
@@ -431,7 +441,7 @@
             return putUtf8(s);
         }
 
-        public int putUtf8(String s) {
+        public int putUtf8(CharSequence s) {
             key.setUtf8(s);
             PoolKey poolKey = lookup(key);
             if (poolKey == null) {
@@ -451,7 +461,7 @@
          * @param s a String whose UTF8 encoded length must be less than 65536.
          * @return this byte vector.
          */
-        void putUTF8Internal(final String s) {
+        void putUTF8Internal(final CharSequence s) {
             int charLength = s.length();
             if (charLength > 65535) {
                 throw new IllegalArgumentException();
@@ -488,7 +498,7 @@
          *                      already encoded characters.
          * @return this byte vector.
          */
-        void encodeUTF8(final String s, int i, int maxByteLength) {
+        void encodeUTF8(final CharSequence s, int i, int maxByteLength) {
             int charLength = s.length();
             int byteLength = i;
             char c;
@@ -522,7 +532,7 @@
             }
         }
 
-        int putNameAndType(String name, String type) {
+        int putNameAndType(CharSequence name, String type) {
             key.setNameAndType(name, type);
             PoolKey poolKey = lookup(key);
             if (poolKey == null) {
@@ -748,6 +758,22 @@
                                                         .invoke(InvocationKind.INVOKESPECIAL, "Foo", "<init>", "()V", false)
                                                         .invoke(InvocationKind.INVOKEVIRTUAL, "Foo", "run", "()V", false)
                                                         .label("hey")
+                                                        .iconst_0()
+                                                        .iconst_0()
+                                                        .typed(TypeTag.I)
+                                                        .if_acmpne("hey")
+                                                        .const_(10)
+                                                        .typed(TypeTag.I)
+                                                        .astore_1()
+                                                        .typed(TypeTag.I)
+                                                        .aload_1()
+                                                        .typed(TypeTag.F)
+                                                        .anewarray("F")
+                                                        .typed(TypeTag.F)
+                                                        .aconst_null()
+                                                        .typed(TypeTag.F)
+                                                        .aaload()
+                                                        .pop()
                                                         .const_(1)
                                                         .pop()
                                                         .withLocal("50", "B")
--- a/src/java.base/share/classes/jdk/experimental/bytecode/ClassBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/ClassBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -80,12 +80,12 @@
         return thisBuilder();
     }
 
-    public final C withField(String name, T type) {
+    public final C withField(CharSequence name, T type) {
         return withField(name, type, FB -> {
         });
     }
 
-    public C withField(String name, T type, Consumer<? super FieldBuilder<S, T, byte[]>> fieldBuilder) {
+    public C withField(CharSequence name, T type, Consumer<? super FieldBuilder<S, T, byte[]>> fieldBuilder) {
         FieldBuilder<S, T, byte[]> F = new FieldBuilder<>(name, type, poolHelper, typeHelper);
         fieldBuilder.accept(F);
         F.build(fields);
@@ -93,12 +93,12 @@
         return thisBuilder();
     }
 
-    public final C withMethod(String name, T type) {
+    public final C withMethod(CharSequence name, T type) {
         return withMethod(name, type, MB -> {
         });
     }
 
-    public C withMethod(String name, T type, Consumer<? super MethodBuilder<S, T, byte[]>> methodBuilder) {
+    public C withMethod(CharSequence name, T type, Consumer<? super MethodBuilder<S, T, byte[]>> methodBuilder) {
         MethodBuilder<S, T, byte[]> M = new MethodBuilder<>(thisClass, name, type, poolHelper, typeHelper);
         methodBuilder.accept(M);
         M.build(methods);
--- a/src/java.base/share/classes/jdk/experimental/bytecode/CodeBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/CodeBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -29,10 +29,11 @@
 import java.lang.invoke.MethodType;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Function;
 
 public class CodeBuilder<S, T, E, C extends CodeBuilder<S, T, E, C>> extends AttributeBuilder<S, T, E, C> {
 
-    GrowableByteBuffer code = new GrowableByteBuffer();
+    protected GrowableByteBuffer code = new GrowableByteBuffer();
     GrowableByteBuffer catchers = new GrowableByteBuffer();
     GrowableByteBuffer stackmaps = new GrowableByteBuffer();
     MethodBuilder<S, T, E> methodBuilder;
@@ -51,55 +52,55 @@
         this.methodBuilder = methodBuilder;
     }
 
-    public C getstatic(S owner, String name, T type) {
+    public C getstatic(S owner, CharSequence name, T type) {
         emitOp(Opcode.GETSTATIC, type);
         code.writeChar(poolHelper.putFieldRef(owner, name, type));
         return thisBuilder();
     }
 
-    public C putstatic(S owner, String name, T type) {
+    public C putstatic(S owner, CharSequence name, T type) {
         emitOp(Opcode.PUTSTATIC, type);
         code.writeChar(poolHelper.putFieldRef(owner, name, type));
         return thisBuilder();
     }
 
-    public C getfield(S owner, String name, T type) {
+    public C getfield(S owner, CharSequence name, T type) {
         emitOp(Opcode.GETFIELD, type);
         code.writeChar(poolHelper.putFieldRef(owner, name, type));
         return thisBuilder();
     }
 
-    public C vgetfield(S owner, String name, T type) {
+    public C vgetfield(S owner, CharSequence name, T type) {
         emitOp(Opcode.VGETFIELD, type);
         code.writeChar(poolHelper.putFieldRef(owner, name, type));
         return thisBuilder();
     }
 
-    public C putfield(S owner, String name, T type) {
+    public C putfield(S owner, CharSequence name, T type) {
         emitOp(Opcode.PUTFIELD, type);
         code.writeChar(poolHelper.putFieldRef(owner, name, type));
         return thisBuilder();
     }
 
-    public C invokevirtual(S owner, String name, T type, boolean isInterface) {
+    public C invokevirtual(S owner, CharSequence name, T type, boolean isInterface) {
         emitOp(Opcode.INVOKEVIRTUAL, type);
         code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface));
         return thisBuilder();
     }
 
-    public C invokespecial(S owner, String name, T type, boolean isInterface) {
+    public C invokespecial(S owner, CharSequence name, T type, boolean isInterface) {
         emitOp(Opcode.INVOKESPECIAL, type);
         code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface));
         return thisBuilder();
     }
 
-    public C invokestatic(S owner, String name, T type, boolean isInterface) {
+    public C invokestatic(S owner, CharSequence name, T type, boolean isInterface) {
         emitOp(Opcode.INVOKESTATIC, type);
         code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface));
         return thisBuilder();
     }
 
-    public C invokeinterface(S owner, String name, T type) {
+    public C invokeinterface(S owner, CharSequence name, T type) {
         emitOp(Opcode.INVOKEINTERFACE, type);
         code.writeChar(poolHelper.putMethodRef(owner, name, type, true));
         int nargs = 1;
@@ -112,7 +113,7 @@
         return thisBuilder();
     }
 
-    public C invokedynamic(String invokedName, T invokedType, S bsmClass, String bsmName, T bsmType, Object... staticArgs) {
+    public C invokedynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Object... staticArgs) {
         throw new UnsupportedOperationException("Not supported yet");
     }
 
@@ -122,7 +123,7 @@
         return thisBuilder();
     }
 
-    public C vnew_(S clazz, String name, T desc) {
+    public C vnew_(S clazz, CharSequence name, T desc) {
         emitOp(Opcode.VNEW, clazz);
         code.writeChar(poolHelper.putMethodRef(clazz, name, desc, false));
         return thisBuilder();
@@ -304,6 +305,86 @@
         return thisBuilder();
     }
 
+    public TypedBuilder typed(TypeTag typeTag) {
+        return typed(typeTag, _unused -> new TypedBuilder());
+    }
+
+    protected <TB extends TypedBuilder> TB typed(TypeTag typeTag, Function<TypeTag, TB> typedBuilderFunc) {
+        emitOp(Opcode.TYPED);
+        code.writeChar(poolHelper.putType(typeHelper.fromTag(typeTag)));
+        return typedBuilderFunc.apply(typeTag);
+    }
+
+    public class TypedBuilder {
+        public C aload_0() {
+            return CodeBuilder.this.aload_0();
+        }
+
+        public C aload_1() {
+            return CodeBuilder.this.aload_1();
+        }
+
+        public C aload_2() {
+            return CodeBuilder.this.aload_2();
+        }
+
+        public C aload_3() {
+            return CodeBuilder.this.aload_3();
+        }
+
+        public C aload(int n) {
+            return CodeBuilder.this.aload(n);
+        }
+
+        public C astore_0() {
+            return CodeBuilder.this.astore_0();
+        }
+
+        public C astore_1() {
+            return CodeBuilder.this.astore_1();
+        }
+
+        public C astore_2() {
+            return CodeBuilder.this.astore_2();
+        }
+
+        public C astore_3() {
+            return CodeBuilder.this.astore_3();
+        }
+
+        public C astore(int n) {
+            return CodeBuilder.this.astore(n);
+        }
+
+        public C aaload() {
+            return CodeBuilder.this.aaload();
+        }
+
+        public C aastore() {
+            return CodeBuilder.this.aastore();
+        }
+
+        public C areturn() {
+            return CodeBuilder.this.areturn();
+        }
+
+        public C anewarray(S s) {
+            return CodeBuilder.this.anewarray(s);
+        }
+
+        public C aconst_null() {
+            return CodeBuilder.this.aconst_null();
+        }
+
+        public C if_acmpeq(short target) {
+            return CodeBuilder.this.if_acmpeq(target);
+        }
+
+        public C if_acmpne(short target) {
+            return CodeBuilder.this.if_acmpeq(target);
+        }
+    }
+
     public C vload(int i) {
         return emitWideIfNeeded(Opcode.VLOAD, i);
     }
@@ -999,8 +1080,11 @@
         emitOp(Opcode.TABLESWITCH);
         //padding
         int start = code.offset;
-        for (int i = 0; i < (4 - (start % 4)); i++) {
-            code.writeByte(0);
+        if ((start % 4) != 0) {
+            //add padding
+            for (int i = 0; i < 4 - (start % 4); i++) {
+                code.writeByte(0);
+            }
         }
         code.writeInt(defaultTarget)
                 .writeInt(low)
--- a/src/java.base/share/classes/jdk/experimental/bytecode/FieldBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/FieldBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -26,7 +26,7 @@
 package jdk.experimental.bytecode;
 
 public class FieldBuilder<S, T, E> extends MemberBuilder<S, T, E, FieldBuilder<S, T, E>> {
-    public FieldBuilder(String name, T type, PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
+    public FieldBuilder(CharSequence name, T type, PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
         super(name, type, poolHelper, typeHelper);
     }
 }
--- a/src/java.base/share/classes/jdk/experimental/bytecode/GrowableByteBuffer.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/GrowableByteBuffer.java	Mon Dec 12 17:47:00 2016 +0000
@@ -102,7 +102,7 @@
         }
     }
 
-    byte[] bytes() {
+    public byte[] bytes() {
         byte[] bytes = new byte[offset];
         System.arraycopy(elems, 0, bytes, 0, offset);
         return bytes;
--- a/src/java.base/share/classes/jdk/experimental/bytecode/MacroCodeBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/MacroCodeBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -39,19 +39,19 @@
 
     JumpMode jumpMode = JumpMode.NARROW;
 
-    Map<String, Integer> labels = new HashMap<>();
+    Map<CharSequence, Integer> labels = new HashMap<>();
     List<PendingJump> pendingJumps = new LinkedList<>();
 
     class PendingJump {
-        String label;
+        CharSequence label;
         int pc;
 
-        PendingJump(String label, int pc) {
+        PendingJump(CharSequence label, int pc) {
             this.label = label;
             this.pc = pc;
         }
 
-        boolean resolve(String label, int offset) {
+        boolean resolve(CharSequence label, int offset) {
             if (this.label.equals(label)) {
                 //patch offset
                 code.withOffset(pc + 1, buf -> emitOffset(buf, jumpMode, offset - pc));
@@ -154,11 +154,11 @@
         }
     }
 
-    public C iaload(TypeTag type) {
+    public C arrayload(TypeTag type) {
         return emitOp(Opcode.IALOAD.at(type));
     }
 
-    public C iastore(TypeTag type, int n) {
+    public C arraystore(TypeTag type, int n) {
         return emitOp(Opcode.IASTORE.at(type));
     }
 
@@ -221,7 +221,7 @@
         }
     }
 
-    public C getfield(FieldAccessKind fak, S owner, String name, T type) {
+    public C getfield(FieldAccessKind fak, S owner, CharSequence name, T type) {
         switch (fak) {
             case INSTANCE:
                 return getfield(owner, name, type);
@@ -232,7 +232,7 @@
         }
     }
 
-    public C putfield(FieldAccessKind fak, S owner, String name, T type) {
+    public C putfield(FieldAccessKind fak, S owner, CharSequence name, T type) {
         switch (fak) {
             case INSTANCE:
                 return putfield(owner, name, type);
@@ -243,7 +243,7 @@
         }
     }
 
-    public C invoke(InvocationKind ik, S owner, String name, T type, boolean isInterface) {
+    public C invoke(InvocationKind ik, S owner, CharSequence name, T type, boolean isInterface) {
         switch (ik) {
             case INVOKESTATIC:
                 return invokestatic(owner, name, type, isInterface);
@@ -318,6 +318,21 @@
         }
     }
 
+    @Override
+    public LabelledTypedBuilder typed(TypeTag typeTag) {
+        return super.typed(typeTag, _unused -> new LabelledTypedBuilder());
+    }
+
+    public class LabelledTypedBuilder extends TypedBuilder {
+        public C if_acmpeq(CharSequence target) {
+            return ifcmp(TypeTag.A, CondKind.EQ, target);
+        }
+
+        public C if_acmpne(CharSequence target) {
+            return ifcmp(TypeTag.A, CondKind.NE, target);
+        }
+    }
+
     public C conv(TypeTag from, TypeTag to) {
         switch (from) {
             case B:
@@ -383,7 +398,7 @@
         return thisBuilder();
     }
 
-    public C ifcmp(TypeTag type, CondKind cond, String label) {
+    public C ifcmp(TypeTag type, CondKind cond, CharSequence label) {
         switch (type) {
             case I:
                 return emitCondJump(Opcode.IF_ICMPEQ, cond, label);
@@ -400,13 +415,13 @@
         }
     }
 
-    public C goto_(String label) {
+    public C goto_(CharSequence label) {
         emitOp(jumpMode == JumpMode.NARROW ? Opcode.GOTO_ : Opcode.GOTO_W);
         emitOffset(code, jumpMode, labelOffset(label));
         return thisBuilder();
     }
 
-    protected int labelOffset(String label) {
+    protected int labelOffset(CharSequence label) {
         int pc = code.offset - 1;
         Integer labelPc = labels.get(label);
         if (labelPc == null) {
@@ -415,7 +430,7 @@
         return labelPc == null ? 0 : (labelPc - pc);
     }
 
-    public C label(String s) {
+    public C label(CharSequence s) {
         int pc = code.offset;
         Object old = labels.put(s, pc);
         if (old != null) {
@@ -426,7 +441,7 @@
     }
 
     //FIXME: address this jumpy mess - i.e. offset and state update work against each other!
-    public C emitCondJump(Opcode opcode, CondKind ck, String label) {
+    public C emitCondJump(Opcode opcode, CondKind ck, CharSequence label) {
         if (jumpMode == JumpMode.NARROW) {
             emitOp(opcode.at(ck));
             emitOffset(code, jumpMode, labelOffset(label));
@@ -438,11 +453,11 @@
         return thisBuilder();
     }
 
-    void addPendingJump(String label, int pc) {
+    void addPendingJump(CharSequence label, int pc) {
         pendingJumps.add(new PendingJump(label, pc));
     }
 
-    void resolveJumps(String label, int pc) {
+    void resolveJumps(CharSequence label, int pc) {
         Iterator<PendingJump> jumpsIt = pendingJumps.iterator();
         while (jumpsIt.hasNext()) {
             PendingJump jump = jumpsIt.next();
@@ -460,7 +475,7 @@
         super.emitOffset(buf, jumpMode, offset);
     }
 
-    public C jsr(String label) {
+    public C jsr(CharSequence label) {
         emitOp(jumpMode == JumpMode.NARROW ? Opcode.JSR : Opcode.JSR_W);
         emitOffset(code, jumpMode, labelOffset(label));
         return thisBuilder();
--- a/src/java.base/share/classes/jdk/experimental/bytecode/MemberBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/MemberBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -27,10 +27,10 @@
 
 public class MemberBuilder<S, T, E, M extends MemberBuilder<S, T, E, M>> extends DeclBuilder<S, T, E, M> {
 
-    String name;
+    CharSequence name;
     T desc;
 
-    MemberBuilder(String name, T type, PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
+    MemberBuilder(CharSequence name, T type, PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
         super(poolHelper, typeHelper);
         this.name = name;
         this.desc = type;
--- a/src/java.base/share/classes/jdk/experimental/bytecode/MethodBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/MethodBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -37,7 +37,7 @@
     ParameterAnnotationsBuilder runtimeVisibleParameterAnnotations;
     ParameterAnnotationsBuilder runtimeInvisibleParameterAnnotations;
 
-    public MethodBuilder(S thisClass, String name, T type, PoolHelper<S, T, E> pool, TypeHelper<S, T> typeHelper) {
+    public MethodBuilder(S thisClass, CharSequence name, T type, PoolHelper<S, T, E> pool, TypeHelper<S, T> typeHelper) {
         super(name, type, pool, typeHelper);
         this.thisClass = thisClass;
     }
--- a/src/java.base/share/classes/jdk/experimental/bytecode/Opcode.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/Opcode.java	Mon Dec 12 17:47:00 2016 +0000
@@ -240,6 +240,7 @@
     MULTIVNEWARRAY(209),
     VRETURN(210),
     VGETFIELD(211),
+    TYPED(212),
     VBOX(216),
     VUNBOX(217);
 
--- a/src/java.base/share/classes/jdk/experimental/bytecode/PoolHelper.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/PoolHelper.java	Mon Dec 12 17:47:00 2016 +0000
@@ -28,17 +28,21 @@
 public interface PoolHelper<S, T, E> {
     int putClass(S symbol);
 
-    int putFieldRef(S owner, String name, T type);
+    int putFieldRef(S owner, CharSequence name, T type);
 
-    int putMethodRef(S owner, String name, T type, boolean isInterface);
+    int putMethodRef(S owner, CharSequence name, T type, boolean isInterface);
 
-    int putUtf8(String s);
+    int putUtf8(CharSequence s);
 
     int putType(T t);
 
     int putValue(Object v);
 
-    int putInvokeDynamic(String invokedName, T invokedType, S bsmClass, String bsmName, T bsmType, Object... staticArgs);
+    int putMethodType(T t);
+
+    int putHandle(int refKind, S owner, CharSequence name, T type);
+
+    int putInvokeDynamic(CharSequence invokedName, T invokedType, int bsmKind, S bsmClass, CharSequence bsmName, T bsmType, Object... staticArgs);
 
     int size();
 
--- a/src/java.base/share/classes/jdk/experimental/bytecode/TypedCodeBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/bytecode/TypedCodeBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -35,13 +35,14 @@
 import java.util.Map.Entry;
 import java.util.Vector;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 public class TypedCodeBuilder<S, T, E, C extends TypedCodeBuilder<S, T, E, C>> extends MacroCodeBuilder<S, T, E, C> {
 
     State lastStackMapState;
     int lastStackMapPc = -1;
-    Map<String, LocalVarInfo> lvarOffsets = new HashMap<>();
-    State state;
+    Map<CharSequence, LocalVarInfo> lvarOffsets = new HashMap<>();
+    protected State state;
     int depth = 0;
     int currLocalOffset = 0;
 
@@ -49,13 +50,13 @@
 
         State state;
 
-        StatefulPendingJump(String label, int pc, State state) {
+        StatefulPendingJump(CharSequence label, int pc, State state) {
             super(label, pc);
             this.state = state;
         }
 
         @Override
-        boolean resolve(String label, int pc) {
+        boolean resolve(CharSequence label, int pc) {
             boolean b = super.resolve(label, pc);
             if (b) {
                 TypedCodeBuilder.this.state = TypedCodeBuilder.this.state.merge(state);
@@ -65,12 +66,12 @@
     }
 
     class LocalVarInfo {
-        String name;
+        CharSequence name;
         int offset;
         int depth;
         TypeTag type;
 
-        LocalVarInfo(String name, int offset, int depth, TypeTag type) {
+        LocalVarInfo(CharSequence name, int offset, int depth, TypeTag type) {
             this.name = name;
             this.offset = offset;
             this.depth = depth;
@@ -139,49 +140,98 @@
         }
     }
 
-//    @Override
-//    public C goto_(String label) {
-//        if (!labels.containsKey(label)) {
-//            throw new IllegalStateException("Illegal uncoditional forward jump");
-//        }
-//        return super.goto_(label);
-//    }
-//
-//    @Override
-//    public C goto_(short target) {
-//        if (target > 0) {
-//            throw new IllegalStateException("Illegal uncoditional forward jump");
-//        }
-//        return super.goto_(target);
-//    }
-//
-//    @Override
-//    public C goto_w(int target) {
-//        if (target > 0) {
-//            throw new IllegalStateException("Illegal uncoditional forward jump");
-//        }
-//        return super.goto_w(target);
-//    }
-//
-//    @Override
-//    public C jsr(String label) {
-//        if (!labels.containsKey(label)) {
-//            throw new IllegalStateException("Illegal uncoditional forward jump");
-//        }
-//        return super.jsr(label);
-//    }
-//
-//    @Override
-//    public C jsr(short target) {
-//        if (target > 0) {
-//            throw new IllegalStateException("Illegal uncoditional forward jump");
-//        }
-//        return super.jsr(target);
-//    }
+    @Override
+    public StatefulTypedBuilder typed(TypeTag tag) {
+        return super.typed(tag, StatefulTypedBuilder::new);
+    }
 
-    class State {
-        ArrayList<T> stack;
-        Vector<T> locals;
+    public class StatefulTypedBuilder extends LabelledTypedBuilder {
+
+        TypeTag tag;
+
+        StatefulTypedBuilder(TypeTag tag) {
+            this.tag = tag;
+        }
+
+        @Override
+        public C astore_0() {
+            return storeAndUpdate(super::astore_0);
+        }
+
+        @Override
+        public C astore_1() {
+            return storeAndUpdate(super::astore_1);
+        }
+
+        @Override
+        public C astore_2() {
+            return storeAndUpdate(super::astore_2);
+        }
+
+        @Override
+        public C astore_3() {
+            return storeAndUpdate(super::astore_3);
+        }
+
+        @Override
+        public C astore(int n) {
+            return storeAndUpdate(() -> super.astore(n));
+        }
+
+        @Override
+        public C aastore() {
+            return storeAndUpdate(super::aastore);
+        }
+
+        @Override
+        public C areturn() {
+            state.pop(tag);
+            state.push(typeHelper.nullType());
+            return super.areturn();
+        }
+
+        @Override
+        public C anewarray(S s) {
+            super.anewarray(s);
+            state.pop();
+            state.push(typeHelper.arrayOf(typeHelper.type(s)));
+            return thisBuilder();
+        }
+
+        @Override
+        public C aconst_null() {
+            super.aconst_null();
+            state.pop();
+            state.push(tag);
+            return thisBuilder();
+        }
+
+        public C if_acmpeq(CharSequence label) {
+            return jumpAndUpdate(() -> super.if_acmpeq(label));
+        }
+
+        public C if_acmpne(CharSequence label) {
+            return jumpAndUpdate(() -> super.if_acmpne(label));
+        }
+
+        private C storeAndUpdate(Supplier<C> op) {
+            state.pop(tag);
+            state.push(typeHelper.nullType());
+            return op.get();
+        }
+
+        private C jumpAndUpdate(Supplier<C> op) {
+            state.pop(tag);
+            state.pop(tag);
+            state.push(typeHelper.nullType());
+            state.push(typeHelper.nullType());
+            return op.get();
+        }
+    }
+
+    public class State {
+        public final ArrayList<T> stack;
+        public final Vector<T> locals;
 
         State(ArrayList<T> stack, Vector<T> locals) {
             this.stack = stack;
@@ -216,6 +266,15 @@
             return stack.get(stack.size() - 1);
         }
 
+        T tosType() {
+            T tos = peek();
+            if (tos == null) {
+                //double slot
+                tos = stack.get(stack.size() - 2);
+            }
+            return tos;
+        }
+
         T popInternal() {
             return stack.remove(stack.size() - 1);
         }
@@ -235,6 +294,11 @@
             return o;
         }
 
+        T pop(TypeTag t) {
+            return (t.width() == 2) ?
+                pop2() : pop();
+        }
+
         void load(TypeTag tag, int index) {
             if (tag == TypeTag.A) throw new IllegalStateException("Bad type tag");
             load(typeHelper.fromTag(tag), index);
@@ -315,7 +379,9 @@
     }
 
     int width(T o) {
-        return typeHelper.tag(o).width;
+        return o == typeHelper.nullType() ?
+                TypeTag.A.width() :
+                typeHelper.tag(o).width;
     }
 
     @SuppressWarnings("unchecked")
@@ -765,8 +831,11 @@
                 state.pop();
                 state.push(typeHelper.arrayOf(typeHelper.fromTag((TypeTag) optValue)));
                 break;
+            case ANEWARRAY:
+                state.pop();
+                state.push(typeHelper.arrayOf(typeHelper.arrayOf(typeHelper.type((S)optValue))));
+                break;
             case VNEWARRAY:
-            case ANEWARRAY:
             case VBOX:
             case VUNBOX:
                 state.pop();
@@ -800,7 +869,6 @@
                 } else {
                     state.pop2();
                 }
-                pop();
                 break;
             }
             case PUTFIELD: {
@@ -810,6 +878,7 @@
                 } else {
                     state.pop2();
                 }
+                state.pop();
                 break;
             }
             case BIPUSH:
@@ -846,6 +915,7 @@
                 state.pop();
                 state.push(TypeTag.Z);
                 break;
+            case TYPED:
             case CHECKCAST:
                 break;
 
@@ -902,7 +972,7 @@
     }
 
     public C store(int index) {
-        return store(typeHelper.tag(state.locals.get(index)), index);
+        return store(typeHelper.tag(state.tosType()), index);
     }
 
     @Override
@@ -915,7 +985,7 @@
         throw new IllegalStateException("Stack size automatically computed");
     }
 
-    public C withLocal(String name, T type) {
+    public C withLocal(CharSequence name, T type) {
         int offset = currLocalOffset;
         TypeTag tag = typeHelper.tag(type);
         lvarOffsets.put(name, new LocalVarInfo(name, offset, depth, tag));
@@ -924,11 +994,11 @@
         return thisBuilder();
     }
 
-    public C load(String local) {
+    public C load(CharSequence local) {
         return load(lvarOffsets.get(local).offset);
     }
 
-    public C store(String local) {
+    public C store(CharSequence local) {
         return store(lvarOffsets.get(local).offset);
     }
 
@@ -980,7 +1050,7 @@
             depth++;
             runnable.run();
         } finally {
-            Iterator<Entry<String, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator();
+            Iterator<Entry<CharSequence, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator();
             while (lvarIt.hasNext()) {
                 LocalVarInfo lvi = lvarIt.next().getValue();
                 if (lvi.depth == depth) {
@@ -994,12 +1064,12 @@
     }
 
     @Override
-    void addPendingJump(String label, int pc) {
+    void addPendingJump(CharSequence label, int pc) {
         pendingJumps.add(new StatefulPendingJump(label, pc, state.dup()));
     }
 
     @Override
-    void resolveJumps(String label, int pc) {
+    void resolveJumps(CharSequence label, int pc) {
         super.resolveJumps(label, pc);
         emitStackMap(pc);
     }
--- a/src/java.base/share/classes/jdk/experimental/value/MethodHandleBuilder.java	Thu Dec 01 15:06:38 2016 +0100
+++ b/src/java.base/share/classes/jdk/experimental/value/MethodHandleBuilder.java	Mon Dec 12 17:47:00 2016 +0000
@@ -171,17 +171,17 @@
             }
 
             @Override
-            public int putFieldRef(Class<?> owner, String name, String type) {
+            public int putFieldRef(Class<?> owner, CharSequence name, String type) {
                 return basicPoolHelper.putFieldRef(from(owner), name, type);
             }
 
             @Override
-            public int putMethodRef(Class<?> owner, String name, String type, boolean isInterface) {
+            public int putMethodRef(Class<?> owner, CharSequence name, String type, boolean isInterface) {
                 return basicPoolHelper.putMethodRef(from(owner), name, type, isInterface);
             }
 
             @Override
-            public int putUtf8(String s) {
+            public int putUtf8(CharSequence s) {
                 return basicPoolHelper.putUtf8(s);
             }
 
@@ -196,8 +196,18 @@
             }
 
             @Override
-            public int putInvokeDynamic(String invokedName, String invokedType, Class<?> bsmClass, String bsmName, String bsmType, Object... staticArgs) {
-                return basicPoolHelper.putInvokeDynamic(invokedName, invokedType, from(bsmClass), bsmName, bsmType, staticArgs);
+            public int putMethodType(String s) {
+                return basicPoolHelper.putMethodType(s);
+            }
+
+            @Override
+            public int putHandle(int refKind, Class<?> owner, CharSequence name, String type) {
+                return basicPoolHelper.putHandle(refKind, from(owner), name, type);
+            }
+
+            @Override
+            public int putInvokeDynamic(CharSequence invokedName, String invokedType, int bskKind, Class<?> bsmClass, CharSequence bsmName, String bsmType, Object... staticArgs) {
+                return basicPoolHelper.putInvokeDynamic(invokedName, invokedType, bskKind, from(bsmClass), bsmName, bsmType, staticArgs);
             }
 
             @Override