diff options
author | Yohann Roussel <yroussel@google.com> | 2017-05-22 13:50:24 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-05-22 13:50:24 +0000 |
commit | 2670278628e07f0d4149df6c4b435213c4cb43ad (patch) | |
tree | 8f6c3a4f0059755921df74174a39051d0e58cf9a | |
parent | ea734824caa4a07a8c6f32a5ec1ec17032216890 (diff) | |
parent | 3309d346ac3512793826d81b1cb24fe053672754 (diff) | |
download | dalvik-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.java | 63 | ||||
-rw-r--r-- | dx/src/com/android/dx/rop/cst/CstInvokeDynamic.java | 102 | ||||
-rw-r--r-- | dx/src/com/android/dx/rop/cst/CstMethodHandle.java | 112 | ||||
-rw-r--r-- | dx/src/com/android/dx/rop/cst/CstMethodType.java | 84 | ||||
-rw-r--r-- | dx/tests/134-maindexlist-lambdas/expected.txt | 2 | ||||
-rw-r--r-- | dx/tests/134-maindexlist-lambdas/info.txt | 2 | ||||
-rw-r--r-- | dx/tests/134-maindexlist-lambdas/lambda/A.java | 14 | ||||
-rw-r--r-- | dx/tests/134-maindexlist-lambdas/lambda/B.java | 8 | ||||
-rw-r--r-- | dx/tests/134-maindexlist-lambdas/run | 36 |
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 |