Allow redefined intrinsics
We make a change to allow intrinsics to be redefined. Note that
redefined intrinisics will no-longer be optimized as much and will not
be inlined or moved out of loops.
Test: ART_TEST_JIT=true mma -j40 test-art-host
Change-Id: Id6df89bb247d21f7859b48356ceba310eef9d105
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 3d51fdd..99d7a49 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -223,13 +223,10 @@
}
bool IsObsolete() {
- // TODO Should maybe make this IsIntrinsic check not needed
- return !IsIntrinsic() && (GetAccessFlags() & kAccObsoleteMethod) != 0;
+ return (GetAccessFlags() & kAccObsoleteMethod) != 0;
}
void SetIsObsolete() {
- // TODO We should really support redefining intrinsic if possible.
- DCHECK(!IsIntrinsic());
AddAccessFlags(kAccObsoleteMethod);
}
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index ae6b31d..461f870 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -45,6 +45,9 @@
static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init>
static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
+// Set to indicate that the ArtMethod is obsolete and has a different DexCache + DexFile from its
+// declaring class. This flag may only be applied to methods.
+static constexpr uint32_t kAccObsoleteMethod = 0x00040000; // method (runtime)
// Used by a method to denote that its execution does not need to go through slow path interpreter.
static constexpr uint32_t kAccSkipAccessChecks = 0x00080000; // method (dex only)
// Used by a class to denote that the verifier has attempted to check it at least once.
@@ -67,10 +70,6 @@
// Set by the verifier for a method that could not be verified to follow structured locking.
static constexpr uint32_t kAccMustCountLocks = 0x02000000; // method (runtime)
-// Set to indicate that the ArtMethod is obsolete and has a different DexCache from its declaring
-// class.
-// TODO Might want to re-arrange some of these so that we can have obsolete + intrinsic methods.
-static constexpr uint32_t kAccObsoleteMethod = 0x04000000; // method (runtime)
// Set by the class linker for a method that has only one implementation for a
// virtual call.
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 8436045..2d532d1 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -170,10 +170,6 @@
// We cannot ensure that the right dex file is used in inlined frames so we don't support
// redefining them.
DCHECK(!IsInInlinedFrame()) << "Inlined frames are not supported when using redefinition";
- // TODO We should really support intrinsic obsolete methods.
- // TODO We should really support redefining intrinsics.
- // We don't support intrinsics so check for them here.
- DCHECK(!old_method->IsIntrinsic());
art::ArtMethod* new_obsolete_method = obsolete_maps_->FindObsoleteVersion(old_method);
if (new_obsolete_method == nullptr) {
// Create a new Obsolete Method and put it in the list.
@@ -518,6 +514,11 @@
CallbackCtx ctx(&map, linker->GetAllocatorForClassLoader(art_klass->GetClassLoader()));
// Add all the declared methods to the map
for (auto& m : art_klass->GetDeclaredMethods(art::kRuntimePointerSize)) {
+ if (m.IsIntrinsic()) {
+ LOG(WARNING) << "Redefining intrinsic method " << m.PrettyMethod() << ". This may cause the "
+ << "unexpected use of the original definition of " << m.PrettyMethod() << "in "
+ << "methods that have already been compiled.";
+ }
// It is possible to simply filter out some methods where they cannot really become obsolete,
// such as native methods and keep their original (possibly optimized) implementations. We don't
// do this, however, since we would need to mark these functions (still in the classes
@@ -526,8 +527,6 @@
// error checking from the interpreter which ensure we don't try to start executing obsolete
// methods.
ctx.obsolete_methods.insert(&m);
- // TODO Allow this or check in IsModifiableClass.
- DCHECK(!m.IsIntrinsic());
}
{
art::MutexLock mu(driver_->self_, *art::Locks::thread_list_lock_);
@@ -1143,6 +1142,10 @@
holder.GetOriginalDexFileBytes(counter));
counter++;
}
+ // TODO We should check for if any of the redefined methods are intrinsic methods here and, if any
+ // are, force a full-world deoptimization before finishing redefinition. If we don't do this then
+ // methods that have been jitted prior to the current redefinition being applied might continue
+ // to use the old versions of the intrinsics!
// TODO Shrink the obsolete method maps if possible?
// TODO Put this into a scoped thing.
runtime_->GetThreadList()->ResumeAll();
@@ -1193,6 +1196,8 @@
linker->SetEntryPointsToInterpreter(&method);
method.SetCodeItemOffset(dex_file_->FindCodeItemOffset(class_def, dex_method_idx));
method.SetDexCacheResolvedMethods(new_dex_cache->GetResolvedMethods(), image_pointer_size);
+ // Clear all the intrinsics related flags.
+ method.ClearAccessFlags(art::kAccIntrinsic | (~art::kAccFlagsNotUsedByIntrinsic));
// Notify the jit that this method is redefined.
art::jit::Jit* jit = driver_->runtime_->GetJit();
if (jit != nullptr) {
diff --git a/test/950-redefine-intrinsic/expected.txt b/test/950-redefine-intrinsic/expected.txt
new file mode 100644
index 0000000..1264c94
--- /dev/null
+++ b/test/950-redefine-intrinsic/expected.txt
@@ -0,0 +1 @@
+Finished!
diff --git a/test/950-redefine-intrinsic/info.txt b/test/950-redefine-intrinsic/info.txt
new file mode 100644
index 0000000..c19d2b4
--- /dev/null
+++ b/test/950-redefine-intrinsic/info.txt
@@ -0,0 +1,3 @@
+Tests basic functions in the jvmti plugin.
+
+Tests that we are able to redefine intrinsic functions.
diff --git a/test/950-redefine-intrinsic/run b/test/950-redefine-intrinsic/run
new file mode 100755
index 0000000..e92b873
--- /dev/null
+++ b/test/950-redefine-intrinsic/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+./default-run "$@" --jvmti
diff --git a/test/950-redefine-intrinsic/src/Main.java b/test/950-redefine-intrinsic/src/Main.java
new file mode 100644
index 0000000..30cd3ab
--- /dev/null
+++ b/test/950-redefine-intrinsic/src/Main.java
@@ -0,0 +1,471 @@
+/*
+ * 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.
+ */
+
+import java.util.Base64;
+import java.util.Random;
+import java.util.function.*;
+import java.util.stream.*;
+
+public class Main {
+
+ // The bytes below define the following java program.
+ // package java.lang;
+ // import java.math.*;
+ // public final class Long extends Number implements Comparable<Long> {
+ // public static final long MIN_VALUE = 0;
+ // public static final long MAX_VALUE = 0;
+ // public static final Class<Long> TYPE = null;
+ // static { }
+ // // Used for Stream.count for some reason.
+ // public static long sum(long a, long b) {
+ // return a + b;
+ // }
+ // // Used in stream/lambda functions.
+ // public Long(long value) {
+ // this.value = value;
+ // }
+ // // Used in stream/lambda functions.
+ // public static Long valueOf(long l) {
+ // return new Long(l);
+ // }
+ // // Intrinsic! Do something cool. Return i + 1
+ // public static long highestOneBit(long i) {
+ // return i + 1;
+ // }
+ // // Intrinsic! Do something cool. Return i - 1
+ // public static long lowestOneBit(long i) {
+ // return i - 1;
+ // }
+ // // Intrinsic! Do something cool. Return i + i
+ // public static int numberOfLeadingZeros(long i) {
+ // return (int)(i + i);
+ // }
+ // // Intrinsic! Do something cool. Return i & (i >>> 1);
+ // public static int numberOfTrailingZeros(long i) {
+ // return (int)(i & (i >>> 1));
+ // }
+ // // Intrinsic! Do something cool. Return 5
+ // public static int bitCount(long i) {
+ // return 5;
+ // }
+ // // Intrinsic! Do something cool. Return i
+ // public static long rotateLeft(long i, int distance) {
+ // return i;
+ // }
+ // // Intrinsic! Do something cool. Return 10 * i
+ // public static long rotateRight(long i, int distance) {
+ // return 10 * i;
+ // }
+ // // Intrinsic! Do something cool. Return -i
+ // public static long reverse(long i) {
+ // return -i;
+ // }
+ // // Intrinsic! Do something cool. Return 0
+ // public static int signum(long i) {
+ // return 0;
+ // }
+ // // Intrinsic! Do something cool. Return 0
+ // public static long reverseBytes(long i) {
+ // return 0;
+ // }
+ // public String toString() {
+ // return "Redefined Long! value (as double)=" + ((double)value);
+ // }
+ // public static String toString(long i, int radix) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static String toUnsignedString(long i, int radix) {
+ // throw new Error("Method redefined away!");
+ // }
+ // private static BigInteger toUnsignedBigInteger(long i) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static String toHexString(long i) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static String toOctalString(long i) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static String toBinaryString(long i) {
+ // throw new Error("Method redefined away!");
+ // }
+ // static String toUnsignedString0(long val, int shift) {
+ // throw new Error("Method redefined away!");
+ // }
+ // static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static String toString(long i) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static String toUnsignedString(long i) {
+ // throw new Error("Method redefined away!");
+ // }
+ // static void getChars(long i, int index, char[] buf) {
+ // throw new Error("Method redefined away!");
+ // }
+ // static int stringSize(long x) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long parseLong(String s, int radix) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long parseLong(String s) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long parseUnsignedLong(String s, int radix) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long parseUnsignedLong(String s) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static Long valueOf(String s, int radix) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static Long valueOf(String s) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static Long decode(String nm) throws NumberFormatException {
+ // throw new Error("Method redefined away!");
+ // }
+ // private final long value;
+ // public Long(String s) throws NumberFormatException {
+ // this(0);
+ // throw new Error("Method redefined away!");
+ // }
+ // public byte byteValue() {
+ // throw new Error("Method redefined away!");
+ // }
+ // public short shortValue() {
+ // throw new Error("Method redefined away!");
+ // }
+ // public int intValue() {
+ // throw new Error("Method redefined away!");
+ // }
+ // public long longValue() {
+ // return value;
+ // }
+ // public float floatValue() {
+ // throw new Error("Method redefined away!");
+ // }
+ // public double doubleValue() {
+ // throw new Error("Method redefined away!");
+ // }
+ // public int hashCode() {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static int hashCode(long value) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public boolean equals(Object obj) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static Long getLong(String nm) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static Long getLong(String nm, long val) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static Long getLong(String nm, Long val) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public int compareTo(Long anotherLong) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static int compare(long x, long y) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static int compareUnsigned(long x, long y) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long divideUnsigned(long dividend, long divisor) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long remainderUnsigned(long dividend, long divisor) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static final int SIZE = 64;
+ // public static final int BYTES = SIZE / Byte.SIZE;
+ // public static long max(long a, long b) {
+ // throw new Error("Method redefined away!");
+ // }
+ // public static long min(long a, long b) {
+ // throw new Error("Method redefined away!");
+ // }
+ // private static final long serialVersionUID = 0;
+ // }
+ private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
+ "yv66vgAAADQAiQUAAAAAAAAACgcAdQoAAwB2CAB3CgADAHgJAA0AeQoAAwB6CgADAHsHAHwIAH0K" +
+ "AAoAfgcAfwoADQCACgASAHYKAA0AgQkADQCCBwCDBwCEAQAJTUlOX1ZBTFVFAQABSgEADUNvbnN0" +
+ "YW50VmFsdWUFAAAAAAAAAAABAAlNQVhfVkFMVUUBAARUWVBFAQARTGphdmEvbGFuZy9DbGFzczsB" +
+ "AAlTaWduYXR1cmUBACNMamF2YS9sYW5nL0NsYXNzPExqYXZhL2xhbmcvTG9uZzs+OwEABXZhbHVl" +
+ "AQAEU0laRQEAAUkDAAAAQAEABUJZVEVTAwAAAAgBABBzZXJpYWxWZXJzaW9uVUlEAQANaGlnaGVz" +
+ "dE9uZUJpdAEABChKKUoBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAMbG93ZXN0T25lQml0AQAU" +
+ "bnVtYmVyT2ZMZWFkaW5nWmVyb3MBAAQoSilJAQAVbnVtYmVyT2ZUcmFpbGluZ1plcm9zAQAIYml0" +
+ "Q291bnQBAApyb3RhdGVMZWZ0AQAFKEpJKUoBAAtyb3RhdGVSaWdodAEAB3JldmVyc2UBAAZzaWdu" +
+ "dW0BAAxyZXZlcnNlQnl0ZXMBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAWKEpJ" +
+ "KUxqYXZhL2xhbmcvU3RyaW5nOwEAEHRvVW5zaWduZWRTdHJpbmcBABR0b1Vuc2lnbmVkQmlnSW50" +
+ "ZWdlcgEAGShKKUxqYXZhL21hdGgvQmlnSW50ZWdlcjsBAAt0b0hleFN0cmluZwEAFShKKUxqYXZh" +
+ "L2xhbmcvU3RyaW5nOwEADXRvT2N0YWxTdHJpbmcBAA50b0JpbmFyeVN0cmluZwEAEXRvVW5zaWdu" +
+ "ZWRTdHJpbmcwAQASZm9ybWF0VW5zaWduZWRMb25nAQAJKEpJW0NJSSlJAQAIZ2V0Q2hhcnMBAAco" +
+ "SklbQylWAQAKc3RyaW5nU2l6ZQEACXBhcnNlTG9uZwEAFihMamF2YS9sYW5nL1N0cmluZztJKUoB" +
+ "AApFeGNlcHRpb25zBwCFAQAVKExqYXZhL2xhbmcvU3RyaW5nOylKAQARcGFyc2VVbnNpZ25lZExv" +
+ "bmcBAAd2YWx1ZU9mAQAlKExqYXZhL2xhbmcvU3RyaW5nO0kpTGphdmEvbGFuZy9Mb25nOwEAJChM" +
+ "amF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Mb25nOwEAEyhKKUxqYXZhL2xhbmcvTG9uZzsB" +
+ "AAZkZWNvZGUBAAY8aW5pdD4BAAQoSilWAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAJYnl0ZVZh" +
+ "bHVlAQADKClCAQAKc2hvcnRWYWx1ZQEAAygpUwEACGludFZhbHVlAQADKClJAQAJbG9uZ1ZhbHVl" +
+ "AQADKClKAQAKZmxvYXRWYWx1ZQEAAygpRgEAC2RvdWJsZVZhbHVlAQADKClEAQAIaGFzaENvZGUB" +
+ "AAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBAAdnZXRMb25nAQAlKExqYXZhL2xhbmcv" +
+ "U3RyaW5nO0opTGphdmEvbGFuZy9Mb25nOwEANChMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5n" +
+ "L0xvbmc7KUxqYXZhL2xhbmcvTG9uZzsBAAljb21wYXJlVG8BABMoTGphdmEvbGFuZy9Mb25nOylJ" +
+ "AQAHY29tcGFyZQEABShKSilJAQAPY29tcGFyZVVuc2lnbmVkAQAOZGl2aWRlVW5zaWduZWQBAAUo" +
+ "SkopSgEAEXJlbWFpbmRlclVuc2lnbmVkAQADc3VtAQADbWF4AQADbWluAQAVKExqYXZhL2xhbmcv" +
+ "T2JqZWN0OylJAQAIPGNsaW5pdD4BAAMoKVYBADpMamF2YS9sYW5nL051bWJlcjtMamF2YS9sYW5n" +
+ "L0NvbXBhcmFibGU8TGphdmEvbGFuZy9Mb25nOz47AQAKU291cmNlRmlsZQEACUxvbmcuamF2YQEA" +
+ "F2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDABPAHEBACJSZWRlZmluZWQgTG9uZyEgdmFsdWUgKGFz" +
+ "IGRvdWJsZSk9DACGAIcMAB4AFQwAhgCIDAA0ADUBAA9qYXZhL2xhbmcvRXJyb3IBABZNZXRob2Qg" +
+ "cmVkZWZpbmVkIGF3YXkhDABPAFEBAA5qYXZhL2xhbmcvTG9uZwwATwBQDABkAGUMABoAGwEAEGph" +
+ "dmEvbGFuZy9OdW1iZXIBABRqYXZhL2xhbmcvQ29tcGFyYWJsZQEAH2phdmEvbGFuZy9OdW1iZXJG" +
+ "b3JtYXRFeGNlcHRpb24BAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcv" +
+ "U3RyaW5nQnVpbGRlcjsBABwoRClMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ADEADQASAAEAEwAH" +
+ "ABkAFAAVAAEAFgAAAAIAFwAZABkAFQABABYAAAACABcAGQAaABsAAQAcAAAAAgAdABIAHgAVAAAA" +
+ "GQAfACAAAQAWAAAAAgAhABkAIgAgAAEAFgAAAAIAIwAaACQAFQABABYAAAACABcANwAJACUAJgAB" +
+ "ACcAAAAcAAQAAgAAAAQeCmGtAAAAAQAoAAAABgABAAAADgAJACkAJgABACcAAAAcAAQAAgAAAAQe" +
+ "CmWtAAAAAQAoAAAABgABAAAAEwAJACoAKwABACcAAAAdAAQAAgAAAAUeHmGIrAAAAAEAKAAAAAYA" +
+ "AQAAABgACQAsACsAAQAnAAAAHwAFAAIAAAAHHh4EfX+IrAAAAAEAKAAAAAYAAQAAAB0ACQAtACsA" +
+ "AQAnAAAAGgABAAIAAAACCKwAAAABACgAAAAGAAEAAAAiAAkALgAvAAEAJwAAABoAAgADAAAAAh6t" +
+ "AAAAAQAoAAAABgABAAAAJwAJADAALwABACcAAAAeAAQAAwAAAAYUAAEeaa0AAAABACgAAAAGAAEA" +
+ "AAAsAAkAMQAmAAEAJwAAABsAAgACAAAAAx51rQAAAAEAKAAAAAYAAQAAADEACQAyACsAAQAnAAAA" +
+ "GgABAAIAAAACA6wAAAABACgAAAAGAAEAAAA2AAkAMwAmAAEAJwAAABoAAgACAAAAAgmtAAAAAQAo" +
+ "AAAABgABAAAAOwABADQANQABACcAAAAwAAMAAQAAABi7AANZtwAEEgW2AAYqtAAHirYACLYACbAA" +
+ "AAABACgAAAAGAAEAAAA/AAkANAA2AAEAJwAAACIAAwADAAAACrsAClkSC7cADL8AAAABACgAAAAG" +
+ "AAEAAABDAAkANwA2AAEAJwAAACIAAwADAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABGAAoA" +
+ "OAA5AAEAJwAAACIAAwACAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABKAAkAOgA7AAEAJwAA" +
+ "ACIAAwACAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABNAAkAPAA7AAEAJwAAACIAAwACAAAA" +
+ "CrsAClkSC7cADL8AAAABACgAAAAGAAEAAABRAAkAPQA7AAEAJwAAACIAAwACAAAACrsAClkSC7cA" +
+ "DL8AAAABACgAAAAGAAEAAABVAAgAPgA2AAEAJwAAACIAAwADAAAACrsAClkSC7cADL8AAAABACgA" +
+ "AAAGAAEAAABZAAgAPwBAAAEAJwAAACIAAwAGAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABd" +
+ "AAkANAA7AAEAJwAAACIAAwACAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABhAAkANwA7AAEA" +
+ "JwAAACIAAwACAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABlAAgAQQBCAAEAJwAAACIAAwAE" +
+ "AAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAABpAAgAQwArAAEAJwAAACIAAwACAAAACrsAClkS" +
+ "C7cADL8AAAABACgAAAAGAAEAAABtAAkARABFAAIAJwAAACIAAwACAAAACrsAClkSC7cADL8AAAAB" +
+ "ACgAAAAGAAEAAABxAEYAAAAEAAEARwAJAEQASAACACcAAAAiAAMAAQAAAAq7AApZEgu3AAy/AAAA" +
+ "AQAoAAAABgABAAAAdQBGAAAABAABAEcACQBJAEUAAgAnAAAAIgADAAIAAAAKuwAKWRILtwAMvwAA" +
+ "AAEAKAAAAAYAAQAAAHkARgAAAAQAAQBHAAkASQBIAAIAJwAAACIAAwABAAAACrsAClkSC7cADL8A" +
+ "AAABACgAAAAGAAEAAAB9AEYAAAAEAAEARwAJAEoASwACACcAAAAiAAMAAgAAAAq7AApZEgu3AAy/" +
+ "AAAAAQAoAAAABgABAAAAgQBGAAAABAABAEcACQBKAEwAAgAnAAAAIgADAAEAAAAKuwAKWRILtwAM" +
+ "vwAAAAEAKAAAAAYAAQAAAIQARgAAAAQAAQBHAAkASgBNAAEAJwAAACEABAACAAAACbsADVketwAO" +
+ "sAAAAAEAKAAAAAYAAQAAAIcACQBOAEwAAgAnAAAAIgADAAEAAAAKuwAKWRILtwAMvwAAAAEAKAAA" +
+ "AAYAAQAAAIsARgAAAAQAAQBHAAEATwBQAAEAJwAAACoAAwADAAAACiq3AA8qH7UAB7EAAAABACgA" +
+ "AAAOAAMAAACQAAQAkQAJAJIAAQBPAFEAAgAnAAAAKwADAAIAAAAPKgm3AA67AApZEgu3AAy/AAAA" +
+ "AQAoAAAACgACAAAAlQAFAJYARgAAAAQAAQBHAAEAUgBTAAEAJwAAACIAAwABAAAACrsAClkSC7cA" +
+ "DL8AAAABACgAAAAGAAEAAACaAAEAVABVAAEAJwAAACIAAwABAAAACrsAClkSC7cADL8AAAABACgA" +
+ "AAAGAAEAAACeAAEAVgBXAAEAJwAAACIAAwABAAAACrsAClkSC7cADL8AAAABACgAAAAGAAEAAACi" +
+ "AAEAWABZAAEAJwAAAB0AAgABAAAABSq0AAetAAAAAQAoAAAABgABAAAApgABAFoAWwABACcAAAAi" +
+ "AAMAAQAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAAqgABAFwAXQABACcAAAAiAAMAAQAAAAq7" +
+ "AApZEgu3AAy/AAAAAQAoAAAABgABAAAArgABAF4AVwABACcAAAAiAAMAAQAAAAq7AApZEgu3AAy/" +
+ "AAAAAQAoAAAABgABAAAAsgAJAF4AKwABACcAAAAiAAMAAgAAAAq7AApZEgu3AAy/AAAAAQAoAAAA" +
+ "BgABAAAAtgABAF8AYAABACcAAAAiAAMAAgAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAAugAJ" +
+ "AGEATAABACcAAAAiAAMAAQAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAAvgAJAGEAYgABACcA" +
+ "AAAiAAMAAwAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAAwgAJAGEAYwABACcAAAAiAAMAAgAA" +
+ "AAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAAxgABAGQAZQABACcAAAAiAAMAAgAAAAq7AApZEgu3" +
+ "AAy/AAAAAQAoAAAABgABAAAAyQAJAGYAZwABACcAAAAiAAMABAAAAAq7AApZEgu3AAy/AAAAAQAo" +
+ "AAAABgABAAAAzQAJAGgAZwABACcAAAAiAAMABAAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAA" +
+ "0QAJAGkAagABACcAAAAiAAMABAAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAA1QAJAGsAagAB" +
+ "ACcAAAAiAAMABAAAAAq7AApZEgu3AAy/AAAAAQAoAAAABgABAAAA2QAJAGwAagABACcAAAAcAAQA" +
+ "BAAAAAQeIGGtAAAAAQAoAAAABgABAAAA4AAJAG0AagABACcAAAAiAAMABAAAAAq7AApZEgu3AAy/" +
+ "AAAAAQAoAAAABgABAAAA5AAJAG4AagABACcAAAAiAAMABAAAAAq7AApZEgu3AAy/AAAAAQAoAAAA" +
+ "BgABAAAA5xBBAGQAbwABACcAAAAhAAIAAgAAAAkqK8AADbYAEKwAAAABACgAAAAGAAEAAAAFAAgA" +
+ "cABxAAEAJwAAACEAAQAAAAAABQGzABGxAAAAAQAoAAAACgACAAAACAAEAAoAAgAcAAAAAgByAHMA" +
+ "AAACAHQ=");
+ private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
+ "ZGV4CjAzNQAFtMupmeDN6Ck5nxdemGsp43KmLNpYLrMYFgAAcAAAAHhWNBIAAAAAAAAAAEgVAABl" +
+ "AAAAcAAAABUAAAAEAgAAIAAAAFgCAAAHAAAA2AMAAD0AAAAQBAAAAQAAAPgFAAAAEAAAGAYAAB4O" +
+ "AAAhDgAAKw4AADMOAAA3DgAAOg4AAEEOAABEDgAARw4AAEoOAABODgAAVg4AAFsOAABfDgAAYg4A" +
+ "AGYOAABrDgAAcA4AAHQOAAB5DgAAfA4AAIAOAACEDgAAiQ4AAI0OAACSDgAAlw4AAJwOAAC7DgAA" +
+ "1w4AAOkOAAD8DgAAEw8AACsPAAA+DwAAUA8AAGQPAACHDwAAmw8AAK8PAADKDwAA4g8AAO0PAAD4" +
+ "DwAAAxAAABsQAAA/EAAAQhAAAEgQAABOEAAAURAAAFUQAABbEAAAXxAAAGIQAABmEAAAahAAAHIQ" +
+ "AAB8EAAAhxAAAJAQAACbEAAArBAAALQQAADEEAAA0RAAAOUQAADtEAAA+RAAAA0RAAAXEQAAIBEA" +
+ "ACoRAAA5EQAAQxEAAE4RAABcEQAAYREAAGYRAAB8EQAAkxEAAJ4RAACxEQAAxBEAAM0RAADbEQAA" +
+ "5xEAAPQRAAAGEgAAEhIAABoSAAAmEgAAKxIAADsSAABIEgAAVxIAAGESAAB3EgAAiRIAAJwSAACj" +
+ "EgAABAAAAAYAAAAHAAAACAAAAA0AAAAbAAAAHAAAAB4AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUA" +
+ "AAAmAAAAJwAAACgAAAAuAAAAMQAAADUAAAA3AAAABAAAAAAAAAAAAAAABgAAAAEAAAAAAAAABwAA" +
+ "AAIAAAAAAAAACAAAAAMAAAAAAAAACQAAAAMAAAC0DQAACgAAAAMAAAC8DQAACwAAAAMAAADMDQAA" +
+ "DAAAAAMAAADUDQAADAAAAAMAAADcDQAADQAAAAQAAAAAAAAADgAAAAQAAAC0DQAADwAAAAQAAADk" +
+ "DQAAEAAAAAQAAADMDQAAEQAAAAQAAADsDQAAEgAAAAQAAAD0DQAAFQAAAAoAAAC0DQAAFwAAAAoA" +
+ "AADsDQAAGAAAAAoAAAD0DQAAGQAAAAoAAAD8DQAAGgAAAAoAAAAEDgAAEwAAAA4AAAAAAAAAFQAA" +
+ "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" +
+ "EwAAAwAAAJsAAgQQAAAABAACAAIAAACPEwAACQAAACIACQAbASwAAABwIAAAEAAnAAAABAACAAIA" +
+ "AACVEwAACQAAACIACQAbASwAAABwIAAAEAAnAAAABAACAAIAAACbEwAACQAAACIACQAbASwAAABw" +
+ "IAAAEAAnAAAABAACAAIAAAChEwAACQAAACIACQAbASwAAABwIAAAEAAnAAAABQADAAIAAACnEwAA" +
+ "CQAAACIACQAbASwAAABwIAAAEAAnAAAABAACAAIAAACuEwAACQAAACIACQAbASwAAABwIAAAEAAn" +
+ "AAAABAACAAIAAAC0EwAACQAAACIACQAbASwAAABwIAAAEAAnAAAABQADAAIAAAC6EwAACQAAACIA" +
+ "CQAbASwAAABwIAAAEAAnAAAABQADAAIAAADBEwAACQAAACIACQAbASwAAABwIAAAEAAnAAAABAAC" +
+ "AAMAAADIEwAABgAAACIACgBwMAIAIAMRAAMAAQACAAAAzxMAAAkAAAAiAAkAGwEsAAAAcCAAABAA" +
+ "JwAAAAQAAgACAAAA1hMAAAkAAAAiAAkAGwEsAAAAcCAAABAAJwAAAAMAAQACAAAA3hMAAAkAAAAi" +
+ "AAkAGwEsAAAAcCAAABAAJwAAAAQAAgACAAAA5BMAAAkAAAAiAAkAGwEsAAAAcCAAABAAJwAAAAMA" +
+ "AgACAAAA6xMAAAcAAAAfAgoAbiAHACEACgAPAAAAAwABAAIAAADyEwAACQAAACIACQAbASwAAABw" +
+ "IAAAEAAnAAAABAACAAIAAAD4EwAACQAAACIACQAbASwAAABwIAAAEAAnAAAAAwABAAIAAAD/EwAA" +
+ "CQAAACIACQAbASwAAABwIAAAEAAnAAAAAwABAAIAAAAFFAAACQAAACIACQAbASwAAABwIAAAEAAn" +
+ "AAAAAwABAAIAAAALFAAACQAAACIACQAbASwAAABwIAAAEAAnAAAAAwABAAAAAAARFAAAAwAAAFMg" +
+ "BgAQAAAAAwABAAIAAAAXFAAACQAAACIACQAbASwAAABwIAAAEAAnAAAABQABAAMAAAAdFAAAGAAA" +
+ "ACIADwBwEDkAAAAbAS0AAABuIDsAEAAMAFNCBgCGIm4wOgAgAwwAbhA8AAAADAARABgGAAABAAAA" +
+ "CAAAAAAAAAAEAAAAIAYAAAMAAAAoBgAACgAAACgGAAAeAAAAKAYAAB8AAAAoBgAAIAAAACgGAAAh" +
+ "AAAAKAYAADYAAAAoBgAANwAAACgGAAABAAAACAAAAAEAAAAEAAAABQAAAAQAAwAUAAMAAwAAAAIA" +
+ "AAAEAAQAAQAAAAoAAAABAAAADQAAAAIAAAAEAAMAAQAAAA4AAAACAAAADgADAAIAAAAOAAQAAgAA" +
+ "AA4ACgABAAAAAQAAAAMAAAAEAAMAFAABPAAIPGNsaW5pdD4ABjxpbml0PgACPjsAAUIABUJZVEVT" +
+ "AAFEAAFGAAFJAAJJSgAGSUpJTElJAANJSkoAAklMAAFKAAJKSgADSkpJAANKSkoAAkpMAANKTEkA" +
+ "AUwAAkxEAAJMSgADTEpJAAJMTAADTExJAANMTEoAA0xMTAAdTGRhbHZpay9hbm5vdGF0aW9uL1Np" +
+ "Z25hdHVyZTsAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ABBMamF2YS9sYW5nL0NsYXNzABFM" +
+ "amF2YS9sYW5nL0NsYXNzOwAVTGphdmEvbGFuZy9Db21wYXJhYmxlABZMamF2YS9sYW5nL0NvbXBh" +
+ "cmFibGU7ABFMamF2YS9sYW5nL0Vycm9yOwAQTGphdmEvbGFuZy9Mb25nOwASTGphdmEvbGFuZy9O" +
+ "dW1iZXI7ACFMamF2YS9sYW5nL051bWJlckZvcm1hdEV4Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2Jq" +
+ "ZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABZMamF2" +
+ "YS9tYXRoL0JpZ0ludGVnZXI7AAlMb25nLmphdmEACU1BWF9WQUxVRQAJTUlOX1ZBTFVFABZNZXRo" +
+ "b2QgcmVkZWZpbmVkIGF3YXkhACJSZWRlZmluZWQgTG9uZyEgdmFsdWUgKGFzIGRvdWJsZSk9AAFT" +
+ "AARTSVpFAARUWVBFAAFWAAJWSgAEVkpJTAACVkwAAVoAAlpMAAJbQwAGYXBwZW5kAAhiaXRDb3Vu" +
+ "dAAJYnl0ZVZhbHVlAAdjb21wYXJlAAljb21wYXJlVG8AD2NvbXBhcmVVbnNpZ25lZAAGZGVjb2Rl" +
+ "AA5kaXZpZGVVbnNpZ25lZAALZG91YmxlVmFsdWUAEmVtaXR0ZXI6IGphY2stNC4yNQAGZXF1YWxz" +
+ "AApmbG9hdFZhbHVlABJmb3JtYXRVbnNpZ25lZExvbmcACGdldENoYXJzAAdnZXRMb25nAAhoYXNo" +
+ "Q29kZQANaGlnaGVzdE9uZUJpdAAIaW50VmFsdWUACWxvbmdWYWx1ZQAMbG93ZXN0T25lQml0AANt" +
+ "YXgAA21pbgAUbnVtYmVyT2ZMZWFkaW5nWmVyb3MAFW51bWJlck9mVHJhaWxpbmdaZXJvcwAJcGFy" +
+ "c2VMb25nABFwYXJzZVVuc2lnbmVkTG9uZwARcmVtYWluZGVyVW5zaWduZWQAB3JldmVyc2UADHJl" +
+ "dmVyc2VCeXRlcwAKcm90YXRlTGVmdAALcm90YXRlUmlnaHQAEHNlcmlhbFZlcnNpb25VSUQACnNo" +
+ "b3J0VmFsdWUABnNpZ251bQAKc3RyaW5nU2l6ZQADc3VtAA50b0JpbmFyeVN0cmluZwALdG9IZXhT" +
+ "dHJpbmcADXRvT2N0YWxTdHJpbmcACHRvU3RyaW5nABR0b1Vuc2lnbmVkQmlnSW50ZWdlcgAQdG9V" +
+ "bnNpZ25lZFN0cmluZwARdG9VbnNpZ25lZFN0cmluZzAABXZhbHVlAAd2YWx1ZU9mAAUABw4AkAEB" +
+ "AAcOPC0AlQEBAAcOWgAiAQAHDgDNAQIAAAcOANEBAgAABw4AiwEBAAcOANUBAgAABw4AXQUAAAAA" +
+ "AAcOAGkDAAAABw4AvgEBAAcOAMIBAgAABw4AxgECAAAHDgC2AQEABw4ADgEABw4AEwEABw4A5AEC" +
+ "AAAHDgDnAQIAAAcOABgBAAcOAB0BAAcOAHUBAAcOAHECAAAHDgB9AQAHDgB5AgAABw4A2QECAAAH" +
+ "DgAxAQAHDgA7AQAHDgAnAgAABw4ALAIAAAcOADYBAAcOAG0BAAcOAOABAgAABw4AVQEABw4ATQEA" +
+ "Bw4AUQEABw4AYQEABw4AQwIAAAcOAEoBAAcOAGUBAAcOAEYCAAAHDgBZAgAABw4AhwEBAAcOAIQB" +
+ "AQAHDgCBAQIAAAcOAJoBAAcOAMkBAQAHDgDIAQEABw4ArgEABw4AugEBAAcOAKoBAAcOALIBAAcO" +
+ "AKIBAAcOAKYBAAcOAJ4BAAcOAD8ABw4AAgUBYxwFFyMXHxcAFyIXAwIFAWMcBBcdFwAXIhcDAgYB" +
+ "YxwBGAwEBAgGAAYABEAGASwLABkBGQEZARkBGQEaBhIBiIAEsAwBgYAExAwBgYAE4AwBCYwNAgmg" +
+ "DQMJxA0BCegNAQmMDgQIsA4BCNQOAQn4DgEJnA8BCcAPAgnkDwEJiBADCaAQAQm8EAEJ4BABCYQR" +
+ "AQmcEQEJuBEBCdwRAQmAEgEJpBIBCcgSAQnsEgEJgBMBCZgTAQmsEwIJxBMBCNgTAQn8EwEJlBQB" +
+ "CbgUAQncFAIJgBUBCaQVAQrIFQEJ7BUBCZAWAQi0FgEJ2BYBCfQWAQmYFwUBvBcCAeAXAcEghBgE" +
+ "AaQYAQHIGAEB7BgGAZAZAwG0GQEB2BkPAfAZBwGUGgAAEQAAAAAAAAABAAAAAAAAAAEAAABlAAAA" +
+ "cAAAAAIAAAAVAAAABAIAAAMAAAAgAAAAWAIAAAQAAAAHAAAA2AMAAAUAAAA9AAAAEAQAAAYAAAAB" +
+ "AAAA+AUAAAMQAAADAAAAGAYAAAEgAAA3AAAAMAYAAAYgAAABAAAAVA0AAAEQAAANAAAArA0AAAIg" +
+ "AABlAAAAHg4AAAMgAAA3AAAArBIAAAQgAAADAAAAIhQAAAUgAAABAAAASBQAAAAgAAABAAAAURQA" +
+ "AAAQAAABAAAASBUAAA==");
+
+ static class FuncCmp implements LongPredicate {
+ final String name;
+ final LongPredicate p;
+ public FuncCmp(String name, LongPredicate p) {
+ this.name = name;
+ this.p = p;
+ }
+
+ public boolean test(long l) {
+ return p.test(l);
+ }
+ }
+ static FuncCmp l2l(String name, final LongUnaryOperator a, final LongUnaryOperator b) {
+ return new FuncCmp(name, (v) -> a.applyAsLong(v) == b.applyAsLong(v));
+ }
+ static FuncCmp l2i(String name, final LongToIntFunction a, final LongToIntFunction b) {
+ return new FuncCmp(name, (v) -> a.applyAsInt(v) == b.applyAsInt(v));
+ }
+
+ /** Interface for a long, int -> long function. */
+ static interface LI2IFunction { public long applyToLongInt(long a, int b); }
+
+ static FuncCmp li2l(String name, final Random r, final LI2IFunction a, final LI2IFunction b) {
+ return new FuncCmp(name, new LongPredicate() {
+ public boolean test(long v) {
+ int i = r.nextInt();
+ return a.applyToLongInt(v, i) == b.applyToLongInt(v, i);
+ }
+ });
+ }
+
+ public static void main(String[] args) {
+ doTest(10000);
+ }
+
+ public static void doTest(int iters) {
+ // Just transform immediately.
+ doCommonClassRedefinition(Long.class, CLASS_BYTES, DEX_BYTES);
+ final Random r = new Random();
+ FuncCmp[] comps = new FuncCmp[] {
+ l2l("highestOneBit", Long::highestOneBit, RedefinedLongIntrinsics::highestOneBit),
+ l2l("lowestOneBit", Long::lowestOneBit, RedefinedLongIntrinsics::lowestOneBit),
+ l2i("numberOfLeadingZeros",
+ Long::numberOfLeadingZeros,
+ RedefinedLongIntrinsics::numberOfLeadingZeros),
+ l2i("numberOfTrailingZeros",
+ Long::numberOfTrailingZeros,
+ RedefinedLongIntrinsics::numberOfTrailingZeros),
+ l2i("bitCount", Long::bitCount, RedefinedLongIntrinsics::bitCount),
+ li2l("rotateLeft", r, Long::rotateLeft, RedefinedLongIntrinsics::rotateLeft),
+ li2l("rotateRight", r, Long::rotateRight, RedefinedLongIntrinsics::rotateRight),
+ l2l("reverse", Long::reverse, RedefinedLongIntrinsics::reverse),
+ l2i("signum", Long::signum, RedefinedLongIntrinsics::signum),
+ l2l("reverseBytes", Long::reverseBytes, RedefinedLongIntrinsics::reverseBytes),
+ };
+ for (FuncCmp f : comps) {
+ // Just actually use ints so we can cast them back int the tests to print them (since we
+ // deleted a bunch of the Long methods needed for printing longs)!
+ int failures = (int)r.ints(iters)
+ .mapToLong((v) -> (long)v)
+ .filter(f.negate()) // Get all the test cases that failed.
+ .count();
+ if (failures != 0) {
+ double percent = 100.0d*((double)failures/(double)iters);
+ System.out.println("for intrinsic " + f.name + " " + failures + "/" + iters
+ + " (" + Double.toString(percent) + "%) tests failed!");
+ }
+ }
+ System.out.println("Finished!");
+ }
+
+ // Transforms the class
+ private static native void doCommonClassRedefinition(Class<?> target,
+ byte[] class_file,
+ byte[] dex_file);
+}
diff --git a/test/950-redefine-intrinsic/src/RedefinedLongIntrinsics.java b/test/950-redefine-intrinsic/src/RedefinedLongIntrinsics.java
new file mode 100644
index 0000000..0ada4a6
--- /dev/null
+++ b/test/950-redefine-intrinsic/src/RedefinedLongIntrinsics.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+/**
+ * The methods that are intrinsified in Long and their expected redefined implementations.
+ */
+class RedefinedLongIntrinsics {
+ // Intrinsic! Do something cool. Return i + 1
+ public static long highestOneBit(long i) {
+ return i + 1;
+ }
+
+ // Intrinsic! Do something cool. Return i - 1
+ public static long lowestOneBit(long i) {
+ return i - 1;
+ }
+
+ // Intrinsic! Do something cool. Return i + i
+ public static int numberOfLeadingZeros(long i) {
+ return (int)(i + i);
+ }
+
+ // Intrinsic! Do something cool. Return i & (i >>> 1);
+ public static int numberOfTrailingZeros(long i) {
+ return (int)(i & (i >>> 1));
+ }
+
+ // Intrinsic! Do something cool. Return 5
+ public static int bitCount(long i) {
+ return 5;
+ }
+
+ // Intrinsic! Do something cool. Return i
+ public static long rotateLeft(long i, int distance) {
+ return i;
+ }
+
+ // Intrinsic! Do something cool. Return 10 * i
+ public static long rotateRight(long i, int distance) {
+ return 10 * i;
+ }
+
+ // Intrinsic! Do something cool. Return -i
+ public static long reverse(long i) {
+ return -i;
+ }
+
+ // Intrinsic! Do something cool. Return 0
+ public static int signum(long i) {
+ return 0;
+ }
+
+ // Intrinsic! Do something cool. Return 0
+ public static long reverseBytes(long i) {
+ return 0;
+ }
+}