release-request-93b39faf-58a9-4461-bb2b-3838af644683-for-git_oc-dr1-release-4034217 snap-temp-L12900000066789025

Change-Id: I3f5e3fd5313844197757529dbfb876620c33bd27
diff --git a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
index 036c880..147edf3 100644
--- a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
+++ b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
@@ -38,8 +38,11 @@
 import com.android.dx.rop.cst.CstFloat;
 import com.android.dx.rop.cst.CstInteger;
 import com.android.dx.rop.cst.CstInterfaceMethodRef;
+import com.android.dx.rop.cst.CstInvokeDynamic;
 import com.android.dx.rop.cst.CstLong;
+import com.android.dx.rop.cst.CstMethodHandle;
 import com.android.dx.rop.cst.CstMethodRef;
+import com.android.dx.rop.cst.CstMethodType;
 import com.android.dx.rop.cst.CstNat;
 import com.android.dx.rop.cst.CstString;
 import com.android.dx.rop.cst.CstType;
@@ -217,13 +220,19 @@
                         break;
                     }
                     case CONSTANT_MethodHandle: {
-                        throw new ParseException("MethodHandle not supported");
+                        lastCategory = 1;
+                        at += 4;
+                        break;
                     }
                     case CONSTANT_MethodType: {
-                        throw new ParseException("MethodType not supported");
+                        lastCategory = 1;
+                        at += 3;
+                        break;
                     }
                     case CONSTANT_InvokeDynamic: {
-                        throw new ParseException("InvokeDynamic not supported");
+                        lastCategory = 1;
+                        at += 5;
+                        break;
                     }
                     default: {
                         throw new ParseException("unknown tag byte: " + Hex.u1(tag));
@@ -327,13 +336,55 @@
                     break;
                 }
                 case CONSTANT_MethodHandle: {
-                    throw new ParseException("MethodHandle not supported");
+                    int kind = bytes.getUnsignedByte(at + 1);
+                    int constantIndex = bytes.getUnsignedShort(at + 2);
+                    Constant ref;
+                    switch (kind) {
+                        case CstMethodHandle.KIND_GETFIELD:
+                        case CstMethodHandle.KIND_GETSTATIC:
+                        case CstMethodHandle.KIND_PUTFIELD:
+                        case CstMethodHandle.KIND_PUTSTATIC:
+                            CstFieldRef field = (CstFieldRef) parse0(constantIndex, wasUtf8);
+                            ref = field;
+                            break;
+                        case CstMethodHandle.KIND_INVOKEVIRTUAL:
+                        case CstMethodHandle.KIND_NEWINVOKESPECIAL:
+                            CstMethodRef method = (CstMethodRef) parse0(constantIndex, wasUtf8);
+                            ref = method;
+                            break;
+                        case CstMethodHandle.KIND_INVOKESTATIC:
+                        case CstMethodHandle.KIND_INVOKESPECIAL:
+                            ref = parse0(constantIndex, wasUtf8);
+                            if (!(ref instanceof CstMethodRef
+                                || ref instanceof CstInterfaceMethodRef)) {
+                              throw new ParseException(
+                                  "Unsupported ref constant type for MethodHandle "
+                                  + ref.getClass());
+                            }
+                            break;
+                        case CstMethodHandle.KIND_INVOKEINTERFACE:
+                            CstInterfaceMethodRef interfaceMethod =
+                                (CstInterfaceMethodRef) parse0(constantIndex, wasUtf8);
+                            ref = interfaceMethod;
+                            break;
+                        default:
+                            throw new ParseException("Unsupported MethodHandle kind: " + kind);
+                    }
+                    cst = CstMethodHandle.make(kind, ref);
+                    break;
                 }
                 case CONSTANT_MethodType: {
-                    throw new ParseException("MethodType not supported");
+                    int descriptorIndex = bytes.getUnsignedShort(at + 1);
+                    CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8);
+                    cst = CstMethodType.make(descriptor);
+                    break;
                 }
                 case CONSTANT_InvokeDynamic: {
-                    throw new ParseException("InvokeDynamic not supported");
+                    int bootstrapMethodIndex = bytes.getUnsignedShort(at + 1);
+                    int natIndex = bytes.getUnsignedShort(at + 3);
+                    CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
+                    cst = CstInvokeDynamic.make(bootstrapMethodIndex, nat);
+                    break;
                 }
                 default: {
                     throw new ParseException("unknown tag byte: " + Hex.u1(tag));
diff --git a/dx/src/com/android/dx/rop/cst/CstInvokeDynamic.java b/dx/src/com/android/dx/rop/cst/CstInvokeDynamic.java
new file mode 100644
index 0000000..7d4f97a
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstInvokeDynamic.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants of type {@code InvokeDynamic}.
+ */
+public final class CstInvokeDynamic extends Constant {
+
+    /** The index of the bootstrap method in the bootstrap method table */
+    private final int bootstrapMethodIndex;
+    /** {@code non-null;} the name and type */
+    private final CstNat nat;
+
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param bootstrapMethodIndex The index of the bootstrap method in the bootstrap method table
+     * @param nat the name and type
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstInvokeDynamic make(int bootstrapMethodIndex, CstNat nat) {
+        return new CstInvokeDynamic(bootstrapMethodIndex, nat);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param bootstrapMethodIndex The index of the bootstrap method in the bootstrap method table
+     * @param nat the name and type
+     */
+    private CstInvokeDynamic(int bootstrapMethodIndex, CstNat nat) {
+        this.bootstrapMethodIndex = bootstrapMethodIndex;
+        this.nat = nat;
+    }
+
+    @Override
+    public String toString() {
+        return toHuman();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "InvokeDynamic";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return "InvokeDynamic(" + bootstrapMethodIndex + ", " + nat.toHuman() + ")";
+    }
+
+    /**
+     * Gets the bootstrap method index.
+     *
+     * @return the bootstrap method index
+     */
+    public int getBootstrapMethodIndex() {
+      return bootstrapMethodIndex;
+    }
+
+    /**
+     * Gets the {@code CstNat} value.
+     *
+     * @return the name and type
+     */
+    public CstNat getNat() {
+      return nat;
+    }
+
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    @Override
+    protected int compareTo0(Constant other) {
+        CstInvokeDynamic otherInvoke = (CstInvokeDynamic) other;
+        if (bootstrapMethodIndex == otherInvoke.getBootstrapMethodIndex()) {
+            return nat.compareTo(otherInvoke.getNat());
+        } else {
+            return Integer.compare(bootstrapMethodIndex, otherInvoke.getBootstrapMethodIndex());
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstMethodHandle.java b/dx/src/com/android/dx/rop/cst/CstMethodHandle.java
new file mode 100644
index 0000000..d5e0f73
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstMethodHandle.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+/**
+ * Constants of type {@code MethodHandle}.
+ */
+public final class CstMethodHandle extends Constant {
+
+    public static final int KIND_GETFIELD = 1;
+    public static final int KIND_GETSTATIC = 2;
+    public static final int KIND_PUTFIELD = 3;
+    public static final int KIND_PUTSTATIC = 4;
+    public static final int KIND_INVOKEVIRTUAL = 5;
+    public static final int KIND_INVOKESTATIC = 6;
+    public static final int KIND_INVOKESPECIAL = 7;
+    public static final int KIND_NEWINVOKESPECIAL = 8;
+    public static final int KIND_INVOKEINTERFACE = 9;
+
+    /** The kind of MethodHandle */
+    private int kind;
+    /** {@code non-null;} the referenced constant */
+    private final Constant ref;
+
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param kind the kind of this handle
+     * @param ref the actual referenced constant
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstMethodHandle make(int kind, Constant ref) {
+        return new CstMethodHandle(kind, ref);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param kind the kind of this handle
+     * @param ref the actual referenced constant
+     */
+    private CstMethodHandle(int kind, Constant ref) {
+        this.kind = kind;
+        this.ref = ref;
+    }
+
+    @Override
+    public String toString() {
+        return ref.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "method handle";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return toString();
+    }
+
+    /**
+     * Gets the actual constant.
+     *
+     * @return the value
+     */
+    public Constant getRef() {
+        return ref;
+    }
+
+    /**
+     * Gets the kind of this method handle.
+     *
+     * @return the kind
+     */
+    public int getKind() {
+        return kind;
+    }
+
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    @Override
+    protected int compareTo0(Constant other) {
+        CstMethodHandle otherHandle = (CstMethodHandle) other;
+        if (getKind() == otherHandle.getKind()) {
+            return getRef().compareTo(otherHandle.getRef());
+        } else {
+            return Integer.compare(getKind(), otherHandle.getKind());
+        }
+    }
+}
diff --git a/dx/src/com/android/dx/rop/cst/CstMethodType.java b/dx/src/com/android/dx/rop/cst/CstMethodType.java
new file mode 100644
index 0000000..29a1964
--- /dev/null
+++ b/dx/src/com/android/dx/rop/cst/CstMethodType.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.rop.cst;
+
+import com.android.dx.rop.type.Prototype;
+
+/**
+ * Constants of type {@code MethodType}.
+ */
+public final class CstMethodType extends Constant {
+    /** {@code non-null;} the raw prototype for this method */
+    private final Prototype prototype;
+
+    /**
+     * Makes an instance for the given value. This may (but does not
+     * necessarily) return an already-allocated instance.
+     *
+     * @param descriptor the method descriptor
+     * @return {@code non-null;} the appropriate instance
+     */
+    public static CstMethodType make(CstString descriptor) {
+        return new CstMethodType(descriptor);
+    }
+
+    /**
+     * Constructs an instance. This constructor is private; use {@link #make}.
+     *
+     * @param descriptor the method descriptor
+     */
+    private CstMethodType(CstString descriptor) {
+        prototype = Prototype.fromDescriptor(descriptor.getString());
+    }
+
+    @Override
+    public String toString() {
+        return prototype.getDescriptor();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String typeName() {
+        return "method type";
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toHuman() {
+        return toString();
+    }
+
+    /**
+     * Gets the {@code Prototype} value.
+     *
+     * @return the value
+     */
+    public Prototype getValue() {
+        return prototype;
+    }
+
+    @Override
+    public boolean isCategory2() {
+        return false;
+    }
+
+    @Override
+    protected int compareTo0(Constant other) {
+        return prototype.getDescriptor().compareTo(
+            ((CstMethodType) other).getValue().getDescriptor());
+    }
+}
diff --git a/dx/tests/134-maindexlist-lambdas/expected.txt b/dx/tests/134-maindexlist-lambdas/expected.txt
new file mode 100644
index 0000000..1917a61
--- /dev/null
+++ b/dx/tests/134-maindexlist-lambdas/expected.txt
@@ -0,0 +1,2 @@
+lambda/A.class
+lambda/B.class
diff --git a/dx/tests/134-maindexlist-lambdas/info.txt b/dx/tests/134-maindexlist-lambdas/info.txt
new file mode 100644
index 0000000..1dffae9
--- /dev/null
+++ b/dx/tests/134-maindexlist-lambdas/info.txt
@@ -0,0 +1,2 @@
+This test that MainDexListBuilder can run on class files with InvokeDynamic,
+MethodType and MethodHandle entries in the constant pool.
diff --git a/dx/tests/134-maindexlist-lambdas/lambda/A.java b/dx/tests/134-maindexlist-lambdas/lambda/A.java
new file mode 100644
index 0000000..9afc376
--- /dev/null
+++ b/dx/tests/134-maindexlist-lambdas/lambda/A.java
@@ -0,0 +1,14 @@
+package lambda;
+
+public class A {
+
+  public static void main(String[] args) {
+    new A().run(new B()::doIt);
+    new A().run(B::doItStatic);
+  }
+
+  public void run(Runnable todo) {
+    todo.run();
+  }
+
+}
diff --git a/dx/tests/134-maindexlist-lambdas/lambda/B.java b/dx/tests/134-maindexlist-lambdas/lambda/B.java
new file mode 100644
index 0000000..0108a54
--- /dev/null
+++ b/dx/tests/134-maindexlist-lambdas/lambda/B.java
@@ -0,0 +1,8 @@
+package lambda;
+
+public class B {
+
+  public void doIt() {}
+  public static void doItStatic() {}
+
+}
diff --git a/dx/tests/134-maindexlist-lambdas/run b/dx/tests/134-maindexlist-lambdas/run
new file mode 100644
index 0000000..449ea41
--- /dev/null
+++ b/dx/tests/134-maindexlist-lambdas/run
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+prog=`which dx`
+progdir=`dirname "${prog}"`
+dxjar=$progdir/../framework/dx.jar
+
+if [ ! -r "$dxjar" ]; then
+    echo Missing dependency $i. Build dx.
+    exit 1
+fi
+
+JAVAC_SOURCE=1.8
+JAVAC_TARGET=1.8
+
+mkdir classes
+${JAVAC} -source ${JAVAC_SOURCE} -target ${JAVAC_TARGET} -d classes `find lambda -name '*.java'`
+mkdir -p traceOut/lambda
+cp classes/lambda/A.class traceOut/lambda/
+
+jar cf classes.jar -C classes .
+jar cf traceOut.jar -C traceOut .
+java -classpath $dxjar com.android.multidex.MainDexListBuilder traceOut.jar classes.jar | sort