summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYohann Roussel <yroussel@google.com>2017-05-22 13:50:24 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-05-22 13:50:24 +0000
commit2670278628e07f0d4149df6c4b435213c4cb43ad (patch)
tree8f6c3a4f0059755921df74174a39051d0e58cf9a
parentea734824caa4a07a8c6f32a5ec1ec17032216890 (diff)
parent3309d346ac3512793826d81b1cb24fe053672754 (diff)
downloaddalvik-2670278628e07f0d4149df6c4b435213c4cb43ad.tar.gz
Merge "Allow parsing constant pool of class file 52" am: 4a3fa67c49 am: e209cfd599 am: f1ddf61a9a
am: 3309d346ac Change-Id: I991d99b2907005917a22cadece81dc58e5b9991e
-rw-r--r--dx/src/com/android/dx/cf/cst/ConstantPoolParser.java63
-rw-r--r--dx/src/com/android/dx/rop/cst/CstInvokeDynamic.java102
-rw-r--r--dx/src/com/android/dx/rop/cst/CstMethodHandle.java112
-rw-r--r--dx/src/com/android/dx/rop/cst/CstMethodType.java84
-rw-r--r--dx/tests/134-maindexlist-lambdas/expected.txt2
-rw-r--r--dx/tests/134-maindexlist-lambdas/info.txt2
-rw-r--r--dx/tests/134-maindexlist-lambdas/lambda/A.java14
-rw-r--r--dx/tests/134-maindexlist-lambdas/lambda/B.java8
-rw-r--r--dx/tests/134-maindexlist-lambdas/run36
9 files changed, 417 insertions, 6 deletions
diff --git a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
index 036c8802a..147edf3bb 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.CstFieldRef;
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 @@ public final class ConstantPoolParser {
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 @@ public final class ConstantPoolParser {
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 000000000..7d4f97ab9
--- /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 000000000..d5e0f738a
--- /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 000000000..29a1964c5
--- /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 000000000..1917a61bb
--- /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 000000000..1dffae9ab
--- /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 000000000..9afc37634
--- /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 000000000..0108a54fa
--- /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 000000000..449ea41d2
--- /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