Merge "ART: Introduce Uint8 compiler data type."
diff --git a/build/Android.bp b/build/Android.bp
index 8e8a2f6..ff762dd 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -83,7 +83,7 @@
"bionic/libc/private",
],
},
- linux: {
+ linux_glibc: {
cflags: [
// Enable missing-noreturn only on non-Mac. As lots of things are not implemented for
// Apple, it's a pain.
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index f4f8d49..3247e54 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -84,12 +84,6 @@
HOST_CORE_DEX_FILES := $(foreach jar,$(HOST_CORE_JARS), $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
-# Classpath for Jack compilation: we only need core-libart.
-HOST_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack
-HOST_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack)
-TARGET_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack
-TARGET_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack)
-
ART_HOST_DEX_DEPENDENCIES := $(foreach jar,$(HOST_CORE_JARS),$(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
ART_TARGET_DEX_DEPENDENCIES := $(foreach jar,$(TARGET_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 1ae79ac..37e6d42 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -202,9 +202,9 @@
# $(5): a make variable used to collate target dependencies, e.g ART_TEST_TARGET_OAT_HelloWorld_DEX
# $(6): a make variable used to collate host dependencies, e.g ART_TEST_HOST_OAT_HelloWorld_DEX
#
-# If the input test directory contains a file called main.list and main.jpp,
+# If the input test directory contains a file called main.list,
# then a multi-dex file is created passing main.list as the --main-dex-list
-# argument to dx and main.jpp for Jack.
+# argument to dx.
define build-art-test-dex
ifeq ($(ART_BUILD_TARGET),true)
include $(CLEAR_VARS)
@@ -219,7 +219,6 @@
LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT)
ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),)
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex
- LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true -D jack.preprocessor.file=$(LOCAL_PATH)/$(2)/main.jpp
endif
include $(BUILD_JAVA_LIBRARY)
$(5) := $$(LOCAL_INSTALLED_MODULE)
@@ -235,7 +234,6 @@
LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION)
ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),)
LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex
- LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true -D jack.preprocessor.file=$(LOCAL_PATH)/$(2)/main.jpp
endif
include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
$(6) := $$(LOCAL_INSTALLED_MODULE)
diff --git a/compiler/intrinsics_list.h b/compiler/intrinsics_list.h
index c8a0119..bfefead 100644
--- a/compiler/intrinsics_list.h
+++ b/compiler/intrinsics_list.h
@@ -158,7 +158,12 @@
V(UnsafeFullFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "fullFence", "()V") \
V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/ref/Reference;", "getReferent", "()Ljava/lang/Object;") \
V(IntegerValueOf, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "valueOf", "(I)Ljava/lang/Integer;") \
- V(ThreadInterrupted, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kNoThrow, "Ljava/lang/Thread;", "interrupted", "()Z")
+ V(ThreadInterrupted, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kNoThrow, "Ljava/lang/Thread;", "interrupted", "()Z") \
+ V(VarHandleFullFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "fullFence", "()V") \
+ V(VarHandleAcquireFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "acquireFence", "()V") \
+ V(VarHandleReleaseFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "releaseFence", "()V") \
+ V(VarHandleLoadLoadFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "loadLoadFence", "()V") \
+ V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \
#endif // ART_COMPILER_INTRINSICS_LIST_H_
#undef ART_COMPILER_INTRINSICS_LIST_H_ // #define is only for lint.
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index f739d7b..a85354c 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -2320,6 +2320,21 @@
case Intrinsics::kUnsafeFullFence:
SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny);
break;
+ case Intrinsics::kVarHandleFullFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny);
+ break;
+ case Intrinsics::kVarHandleAcquireFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);
+ break;
+ case Intrinsics::kVarHandleReleaseFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kAnyStore);
+ break;
+ case Intrinsics::kVarHandleLoadLoadFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);
+ break;
+ case Intrinsics::kVarHandleStoreStoreFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kStoreStore);
+ break;
default:
break;
}
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index daec634..0f14d27 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -34,7 +34,7 @@
#define CHECK_INTRINSICS_ENUM_VALUES(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
static_assert( \
static_cast<uint32_t>(Intrinsics::k ## Name) <= (kAccIntrinsicBits >> CTZ(kAccIntrinsicBits)), \
- "Instrinsics enumeration space overflow: ");
+ "Instrinsics enumeration space overflow.");
#include "intrinsics_list.h"
INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES)
#undef INTRINSICS_LIST
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 6411e82..7abfd5b 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -256,25 +256,30 @@
LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \
<< " should have been converted to HIR"; \
}
-#define UNREACHABLE_INTRINSICS(Arch) \
-UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
-UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
-UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \
-UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \
-UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \
-UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \
-UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \
-UNREACHABLE_INTRINSIC(Arch, LongCompare) \
-UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \
-UNREACHABLE_INTRINSIC(Arch, LongSignum) \
-UNREACHABLE_INTRINSIC(Arch, StringCharAt) \
-UNREACHABLE_INTRINSIC(Arch, StringIsEmpty) \
-UNREACHABLE_INTRINSIC(Arch, StringLength) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)
+#define UNREACHABLE_INTRINSICS(Arch) \
+UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
+UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
+UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \
+UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \
+UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \
+UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \
+UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \
+UNREACHABLE_INTRINSIC(Arch, LongCompare) \
+UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \
+UNREACHABLE_INTRINSIC(Arch, LongSignum) \
+UNREACHABLE_INTRINSIC(Arch, StringCharAt) \
+UNREACHABLE_INTRINSIC(Arch, StringIsEmpty) \
+UNREACHABLE_INTRINSIC(Arch, StringLength) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence)
template <typename IntrinsicLocationsBuilder, typename Codegenerator>
bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp
index 0405fe1..cca9ac4 100644
--- a/dalvikvm/Android.bp
+++ b/dalvikvm/Android.bp
@@ -36,7 +36,7 @@
],
ldflags: ["-Wl,--export-dynamic"],
},
- linux: {
+ linux_glibc: {
ldflags: ["-Wl,--export-dynamic"],
},
},
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 0db790b..7599d23 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -906,14 +906,27 @@
// Call site information is too large to detail in disassembly so just output the index.
outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
break;
- // SOME NOT SUPPORTED:
- // case Instruction::kIndexVaries:
- // case Instruction::kIndexInlineMethod:
- default:
- outSize = snprintf(buf.get(), bufSize, "<?>");
+ case Instruction::kIndexMethodHandleRef:
+ // Method handle information is too large to detail in disassembly so just output the index.
+ outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
+ break;
+ case Instruction::kIndexProtoRef:
+ if (index < pDexFile->GetHeader().proto_ids_size_) {
+ const DexFile::ProtoId& protoId = pDexFile->GetProtoId(index);
+ const Signature signature = pDexFile->GetProtoSignature(protoId);
+ const std::string& proto = signature.ToString();
+ outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
+ } else {
+ outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
+ }
break;
} // switch
+ if (outSize == 0) {
+ // The index type has not been handled in the switch above.
+ outSize = snprintf(buf.get(), bufSize, "<?>");
+ }
+
// Determine success of string construction.
if (outSize >= bufSize) {
// The buffer wasn't big enough; retry with computed size. Note: snprintf()
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 772f042..eeb5569 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8033,6 +8033,15 @@
return type.Get();
}
+mirror::MethodType* ClassLinker::ResolveMethodType(uint32_t proto_idx, ArtMethod* referrer) {
+ Thread* const self = Thread::Current();
+ StackHandleScope<2> hs(self);
+ const DexFile* dex_file = referrer->GetDexFile();
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+ return ResolveMethodType(*dex_file, proto_idx, dex_cache, class_loader);
+}
+
mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
Thread* self,
const DexFile::MethodHandleItem& method_handle,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index f97433c..e436b99 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -371,6 +371,9 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ mirror::MethodType* ResolveMethodType(uint32_t proto_idx, ArtMethod* referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
// Resolve a method handle with a given ID from the DexFile. The
// result is not cached in the DexCache as the instance will only be
// used once in most circumstances.
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index be157a3..2e776b0 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -66,8 +66,10 @@
// Dex version 036 skipped because of an old dalvik bug on some versions of android where dex
// files with that version number would erroneously be accepted and run.
{'0', '3', '7', '\0'},
- // Dex version 038: Android "O" and beyond.
- {'0', '3', '8', '\0'}
+ // Dex version 038: Android "O".
+ {'0', '3', '8', '\0'},
+ // Dex verion 039: Beyond Android "O".
+ {'0', '3', '9', '\0'},
};
uint32_t DexFile::CalculateChecksum() const {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index ac91d52..9c5fd10 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -47,7 +47,7 @@
static const uint32_t kClassDefinitionOrderEnforcedVersion = 37;
static const uint8_t kDexMagic[];
- static constexpr size_t kNumDexVersions = 3;
+ static constexpr size_t kNumDexVersions = 4;
static constexpr size_t kDexVersionLen = 4;
static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index a7bf59e..67cd428 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -75,7 +75,7 @@
"AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
"AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
-// kRawDex38 and 39 are dex'ed versions of the following Java source :
+// kRawDex{38,39,40,41} are dex'ed versions of the following Java source :
//
// public class Main {
// public static void main(String[] foo) {
@@ -108,6 +108,30 @@
"uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
"AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
+static const char kRawDex40[] =
+ "ZGV4CjA0MAC4OovJlJ1089ikzK6asMf/f8qp3Kve5VsgAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAI"
+ "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAwAQAA8AAAACIB"
+ "AAAqAQAAMgEAAEYBAABRAQAAVAEAAFgBAABtAQAAAQAAAAIAAAAEAAAABgAAAAQAAAACAAAAAAAA"
+ "AAUAAAACAAAAHAEAAAAAAAAAAAAAAAABAAcAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAA"
+ "AAAAAH4BAAAAAAAAAQABAAEAAABzAQAABAAAAHAQAgAAAA4AAQABAAAAAAB4AQAAAQAAAA4AAAAB"
+ "AAAAAwAGPGluaXQ+AAZMTWFpbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAJTWFpbi5qYXZhAAFWAAJW"
+ "TAATW0xqYXZhL2xhbmcvU3RyaW5nOwAEbWFpbgABAAcOAAMBAAcOAAAAAgAAgYAE8AEBCYgCDAAA"
+ "AAAAAAABAAAAAAAAAAEAAAAIAAAAcAAAAAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAA"
+ "uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
+ "AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
+
+static const char kRawDex41[] =
+ "ZGV4CjA0MQC4OovJlJ1089ikzK6asMf/f8qp3Kve5VsgAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAI"
+ "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAwAQAA8AAAACIB"
+ "AAAqAQAAMgEAAEYBAABRAQAAVAEAAFgBAABtAQAAAQAAAAIAAAAEAAAABgAAAAQAAAACAAAAAAAA"
+ "AAUAAAACAAAAHAEAAAAAAAAAAAAAAAABAAcAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAA"
+ "AAAAAH4BAAAAAAAAAQABAAEAAABzAQAABAAAAHAQAgAAAA4AAQABAAAAAAB4AQAAAQAAAA4AAAAB"
+ "AAAAAwAGPGluaXQ+AAZMTWFpbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAJTWFpbi5qYXZhAAFWAAJW"
+ "TAATW0xqYXZhL2xhbmcvU3RyaW5nOwAEbWFpbgABAAcOAAMBAAcOAAAAAgAAgYAE8AEBCYgCDAAA"
+ "AAAAAAABAAAAAAAAAAEAAAAIAAAAcAAAAAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAA"
+ "uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
+ "AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
+
static const char kRawDexZeroLength[] =
"UEsDBAoAAAAAAOhxAkkAAAAAAAAAAAAAAAALABwAY2xhc3Nlcy5kZXhVVAkAA2QNoVdnDaFXdXgL"
"AAEE5AMBAASIEwAAUEsBAh4DCgAAAAAA6HECSQAAAAAAAAAAAAAAAAsAGAAAAAAAAAAAAKCBAAAA"
@@ -323,10 +347,31 @@
EXPECT_EQ(38u, header.GetVersion());
}
-TEST_F(DexFileTest, Version39Rejected) {
+TEST_F(DexFileTest, Version39Accepted) {
+ ScratchFile tmp;
+ std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex39, tmp.GetFilename().c_str()));
+ ASSERT_TRUE(raw.get() != nullptr);
+
+ const DexFile::Header& header = raw->GetHeader();
+ EXPECT_EQ(39u, header.GetVersion());
+}
+
+TEST_F(DexFileTest, Version40Rejected) {
ScratchFile tmp;
const char* location = tmp.GetFilename().c_str();
- DecodeAndWriteDexFile(kRawDex39, location);
+ DecodeAndWriteDexFile(kRawDex40, location);
+
+ ScopedObjectAccess soa(Thread::Current());
+ static constexpr bool kVerifyChecksum = true;
+ std::string error_msg;
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ ASSERT_FALSE(DexFile::Open(location, location, kVerifyChecksum, &error_msg, &dex_files));
+}
+
+TEST_F(DexFileTest, Version41Rejected) {
+ ScratchFile tmp;
+ const char* location = tmp.GetFilename().c_str();
+ DecodeAndWriteDexFile(kRawDex41, location);
ScopedObjectAccess soa(Thread::Current());
static constexpr bool kVerifyChecksum = true;
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 9a17576..2f28dff 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -135,6 +135,8 @@
kIndexVtableOffset, // vtable offset (for static linked methods)
kIndexMethodAndProtoRef, // method and a proto reference index (for invoke-polymorphic)
kIndexCallSiteRef, // call site reference index
+ kIndexMethodHandleRef, // constant method handle reference index
+ kIndexProtoRef, // prototype reference index
};
enum Flags : uint8_t {
@@ -195,7 +197,9 @@
kVerifyRuntimeOnly = 0x0200000,
kVerifyError = 0x0400000,
kVerifyRegHPrototype = 0x0800000,
- kVerifyRegBCallSite = 0x1000000
+ kVerifyRegBCallSite = 0x1000000,
+ kVerifyRegBMethodHandle = 0x2000000,
+ kVerifyRegBPrototype = 0x4000000,
};
// Collect the enums in a struct for better locality.
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index d0a4ae5..ef83bdc 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -273,8 +273,8 @@
V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kVerifyRegHPrototype) \
V(0xFC, INVOKE_CUSTOM, "invoke-custom", k35c, kIndexCallSiteRef, kContinue | kThrow, 0, kVerifyRegBCallSite | kVerifyVarArg) \
V(0xFD, INVOKE_CUSTOM_RANGE, "invoke-custom/range", k3rc, kIndexCallSiteRef, kContinue | kThrow, 0, kVerifyRegBCallSite | kVerifyVarArgRange) \
- V(0xFE, UNUSED_FE, "unused-fe", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xFF, UNUSED_FF, "unused-ff", k10x, kIndexUnknown, 0, 0, kVerifyError)
+ V(0xFE, CONST_METHOD_HANDLE, "const-method-handle", k21c, kIndexMethodHandleRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBMethodHandle) \
+ V(0xFF, CONST_METHOD_TYPE, "const-method-type", k21c, kIndexProtoRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBPrototype)
#define DEX_INSTRUCTION_FORMAT_LIST(V) \
V(k10x) \
diff --git a/runtime/image.cc b/runtime/image.cc
index 4c6529b..aae572b 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '9', '\0' }; // 256 intrinsics
+const uint8_t ImageHeader::kImageVersion[] = { '0', '4', 'A', '\0' }; // VarHandle fence intrinsics
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 50bd7e7..fafb2a3 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -202,6 +202,25 @@
}
}
+static inline mirror::MethodHandle* ResolveMethodHandle(uint32_t method_handle_index,
+ ArtMethod* referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->ResolveMethodHandle(method_handle_index, referrer);
+}
+
+static inline mirror::MethodType* ResolveMethodType(Thread* self,
+ uint32_t method_type_index,
+ ArtMethod* referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const DexFile* dex_file = referrer->GetDexFile();
+ StackHandleScope<2> hs(self);
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+ return class_linker->ResolveMethodType(*dex_file, method_type_index, dex_cache, class_loader);
+}
+
// Performs a signature polymorphic invoke (invoke-polymorphic/invoke-polymorphic-range).
template<bool is_range>
bool DoInvokePolymorphic(Thread* self,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index 74e6cd2..26de6b4 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -323,6 +323,25 @@
return true;
}
+#define VARHANDLE_FENCE_INTRINSIC(name, std_memory_operation) \
+static ALWAYS_INLINE bool name(ShadowFrame* /* shadow_frame */, \
+ const Instruction* /* inst */, \
+ uint16_t /* inst_data */, \
+ JValue* /* result_register */) \
+ REQUIRES_SHARED(Locks::mutator_lock_) { \
+ std::atomic_thread_fence(std_memory_operation); \
+ return true; \
+}
+
+// The VarHandle fence methods are static (unlike sun.misc.Unsafe versions).
+// The fences for the LoadLoadFence and StoreStoreFence are stronger
+// than strictly required, but the impact should be marginal.
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleFullFence, std::memory_order_seq_cst)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleAcquireFence, std::memory_order_acquire)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleReleaseFence, std::memory_order_release)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleLoadLoadFence, std::memory_order_acquire)
+VARHANDLE_FENCE_INTRINSIC(MterpVarHandleStoreStoreFence, std::memory_order_release)
+
// Macro to help keep track of what's left to implement.
#define UNIMPLEMENTED_CASE(name) \
case Intrinsics::k##name: \
@@ -470,6 +489,11 @@
UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */)
UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */)
+ INTRINSIC_CASE(VarHandleFullFence)
+ INTRINSIC_CASE(VarHandleAcquireFence)
+ INTRINSIC_CASE(VarHandleReleaseFence)
+ INTRINSIC_CASE(VarHandleLoadLoadFence)
+ INTRINSIC_CASE(VarHandleStoreStoreFence)
case Intrinsics::kNone:
res = false;
break;
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 850419b..2514f0c 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -525,6 +525,30 @@
}
break;
}
+ case Instruction::CONST_METHOD_HANDLE: {
+ PREAMBLE();
+ ObjPtr<mirror::MethodHandle> mh =
+ Runtime::Current()->GetClassLinker()->ResolveMethodHandle(inst->VRegB_21c(), method);
+ if (UNLIKELY(mh == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mh.Ptr());
+ inst = inst->Next_2xx();
+ }
+ break;
+ }
+ case Instruction::CONST_METHOD_TYPE: {
+ PREAMBLE();
+ ObjPtr<mirror::MethodType> mt =
+ Runtime::Current()->GetClassLinker()->ResolveMethodType(inst->VRegB_21c(), method);
+ if (UNLIKELY(mt == nullptr)) {
+ HANDLE_PENDING_EXCEPTION();
+ } else {
+ shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mt.Ptr());
+ inst = inst->Next_2xx();
+ }
+ break;
+ }
case Instruction::MONITOR_ENTER: {
PREAMBLE();
ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
@@ -2435,10 +2459,8 @@
inst = inst->Next_2xx();
break;
case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
+ case Instruction::UNUSED_79 ... Instruction::UNUSED_7A:
case Instruction::UNUSED_F3 ... Instruction::UNUSED_F9:
- case Instruction::UNUSED_FE ... Instruction::UNUSED_FF:
- case Instruction::UNUSED_79:
- case Instruction::UNUSED_7A:
UnexpectedOpcode(inst, shadow_frame);
}
} while (!interpret_one_instruction);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index ee428ed..7246bae 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -43,6 +43,7 @@
#include "mirror/class.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/method_handle_impl.h"
+#include "mirror/method_type.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reg_type-inl.h"
@@ -1169,6 +1170,15 @@
case Instruction::kVerifyRegBWide:
result = result && CheckWideRegisterIndex(inst->VRegB());
break;
+ case Instruction::kVerifyRegBCallSite:
+ result = result && CheckCallSiteIndex(inst->VRegB());
+ break;
+ case Instruction::kVerifyRegBMethodHandle:
+ result = result && CheckMethodHandleIndex(inst->VRegB());
+ break;
+ case Instruction::kVerifyRegBPrototype:
+ result = result && CheckPrototypeIndex(inst->VRegB());
+ break;
}
switch (inst->GetVerifyTypeArgumentC()) {
case Instruction::kVerifyRegC:
@@ -1260,6 +1270,16 @@
return true;
}
+inline bool MethodVerifier::CheckCallSiteIndex(uint32_t idx) {
+ uint32_t limit = dex_file_->NumCallSiteIds();
+ if (UNLIKELY(idx >= limit)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad call site index " << idx << " (max "
+ << limit << ")";
+ return false;
+ }
+ return true;
+}
+
inline bool MethodVerifier::CheckFieldIndex(uint32_t idx) {
if (UNLIKELY(idx >= dex_file_->GetHeader().field_ids_size_)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad field index " << idx << " (max "
@@ -1278,6 +1298,16 @@
return true;
}
+inline bool MethodVerifier::CheckMethodHandleIndex(uint32_t idx) {
+ uint32_t limit = dex_file_->NumMethodHandles();
+ if (UNLIKELY(idx >= limit)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad method handle index " << idx << " (max "
+ << limit << ")";
+ return false;
+ }
+ return true;
+}
+
inline bool MethodVerifier::CheckNewInstance(dex::TypeIndex idx) {
if (UNLIKELY(idx.index_ >= dex_file_->GetHeader().type_ids_size_)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
@@ -2320,6 +2350,18 @@
: reg_types_.JavaLangClass());
break;
}
+ case Instruction::CONST_METHOD_HANDLE:
+ work_line_->SetRegisterType<LockOp::kClear>(
+ this, inst->VRegA_21c(), reg_types_.JavaLangInvokeMethodHandle());
+ // TODO: add compiler support for const-method-{handle,type} (b/66890674)
+ Fail(VERIFY_ERROR_FORCE_INTERPRETER);
+ break;
+ case Instruction::CONST_METHOD_TYPE:
+ work_line_->SetRegisterType<LockOp::kClear>(
+ this, inst->VRegA_21c(), reg_types_.JavaLangInvokeMethodType());
+ // TODO: add compiler support for const-method-{handle,type} (b/66890674)
+ Fail(VERIFY_ERROR_FORCE_INTERPRETER);
+ break;
case Instruction::MONITOR_ENTER:
work_line_->PushMonitor(this, inst->VRegA_11x(), work_insn_idx_);
// Check whether the previous instruction is a move-object with vAA as a source, creating
@@ -3454,7 +3496,6 @@
/* These should never appear during verification. */
case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
case Instruction::UNUSED_F3 ... Instruction::UNUSED_F9:
- case Instruction::UNUSED_FE ... Instruction::UNUSED_FF:
case Instruction::UNUSED_79:
case Instruction::UNUSED_7A:
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_);
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index da4102a..8afbe78 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -404,6 +404,10 @@
/* Ensure that the wide register index is valid for this code item. */
bool CheckWideRegisterIndex(uint32_t idx);
+ // Perform static checks on an instruction referencing a CallSite. All we do here is ensure that
+ // the call site index is in the valid range.
+ bool CheckCallSiteIndex(uint32_t idx);
+
// Perform static checks on a field Get or set instruction. All we do here is ensure that the
// field index is in the valid range.
bool CheckFieldIndex(uint32_t idx);
@@ -412,6 +416,10 @@
// method index is in the valid range.
bool CheckMethodIndex(uint32_t idx);
+ // Perform static checks on an instruction referencing a constant method handle. All we do here
+ // is ensure that the method index is in the valid range.
+ bool CheckMethodHandleIndex(uint32_t idx);
+
// Perform static checks on a "new-instance" instruction. Specifically, make sure the class
// reference isn't for an array class.
bool CheckNewInstance(dex::TypeIndex idx);
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index b57a2c8..197c976 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -19,6 +19,8 @@
#include "class_linker.h"
#include "mirror/class-inl.h"
+#include "mirror/method_handle_impl.h"
+#include "mirror/method_type.h"
#include "mirror/string.h"
#include "mirror/throwable.h"
#include "reg_type.h"
@@ -131,6 +133,20 @@
return *down_cast<const PreciseReferenceType*>(result);
}
+inline const PreciseReferenceType& RegTypeCache::JavaLangInvokeMethodHandle() {
+ const RegType* result = &FromClass("Ljava/lang/invoke/MethodHandle;",
+ mirror::MethodHandle::StaticClass(), true);
+ DCHECK(result->IsPreciseReference());
+ return *down_cast<const PreciseReferenceType*>(result);
+}
+
+inline const PreciseReferenceType& RegTypeCache::JavaLangInvokeMethodType() {
+ const RegType* result = &FromClass("Ljava/lang/invoke/MethodType;",
+ mirror::MethodType::StaticClass(), true);
+ DCHECK(result->IsPreciseReference());
+ return *down_cast<const PreciseReferenceType*>(result);
+}
+
inline const RegType& RegTypeCache::JavaLangThrowable(bool precise) {
const RegType* result = &FromClass("Ljava/lang/Throwable;",
mirror::Throwable::GetJavaLangThrowable(), precise);
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 7077c55..96eca05 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -126,6 +126,8 @@
const PreciseReferenceType& JavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_);
const PreciseReferenceType& JavaLangString() REQUIRES_SHARED(Locks::mutator_lock_);
+ const PreciseReferenceType& JavaLangInvokeMethodHandle() REQUIRES_SHARED(Locks::mutator_lock_);
+ const PreciseReferenceType& JavaLangInvokeMethodType() REQUIRES_SHARED(Locks::mutator_lock_);
const RegType& JavaLangThrowable(bool precise) REQUIRES_SHARED(Locks::mutator_lock_);
const RegType& JavaLangObject(bool precise) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/test/709-checker-varhandles/build b/test/709-checker-varhandles/build
new file mode 100755
index 0000000..2b0b2c1
--- /dev/null
+++ b/test/709-checker-varhandles/build
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+# make us exit on a failure
+set -e
+
+./default-build "$@" --experimental method-handles
diff --git a/test/709-checker-varhandles/expected.txt b/test/709-checker-varhandles/expected.txt
new file mode 100644
index 0000000..651da72
--- /dev/null
+++ b/test/709-checker-varhandles/expected.txt
@@ -0,0 +1,2 @@
+starting
+passed
diff --git a/test/709-checker-varhandles/info.txt b/test/709-checker-varhandles/info.txt
new file mode 100644
index 0000000..2221240
--- /dev/null
+++ b/test/709-checker-varhandles/info.txt
@@ -0,0 +1 @@
+Test support for intrinsics in Java 9 java.lang.invoke.VarHandle.
diff --git a/test/709-checker-varhandles/src-art/Main.java b/test/709-checker-varhandles/src-art/Main.java
new file mode 100644
index 0000000..46aaa38
--- /dev/null
+++ b/test/709-checker-varhandles/src-art/Main.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 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.lang.invoke.VarHandle;
+
+/**
+ * Checker test on the 1.8 unsafe operations. Note, this is by no means an
+ * exhaustive unit test for these CAS (compare-and-swap) and fence operations.
+ * Instead, this test ensures the methods are recognized as intrinsic and behave
+ * as expected.
+ */
+public class Main {
+
+ //
+ // Fences (native).
+ //
+
+ /// CHECK-START: void Main.fullFence() intrinsics_recognition (after)
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleFullFence
+ //
+ /// CHECK-START: void Main.fullFence() instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleFullFence
+ //
+ /// CHECK-START: void Main.fullFence() instruction_simplifier (after)
+ /// CHECK-DAG: MemoryBarrier kind:AnyAny
+ private static void fullFence() {
+ VarHandle.fullFence();
+ }
+
+ /// CHECK-START: void Main.acquireFence() intrinsics_recognition (after)
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleAcquireFence
+ //
+ /// CHECK-START: void Main.acquireFence() instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleAcquireFence
+ //
+ /// CHECK-START: void Main.acquireFence() instruction_simplifier (after)
+ /// CHECK-DAG: MemoryBarrier kind:LoadAny
+ private static void acquireFence() {
+ VarHandle.acquireFence();
+ }
+
+ /// CHECK-START: void Main.releaseFence() intrinsics_recognition (after)
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleReleaseFence
+ //
+ /// CHECK-START: void Main.releaseFence() instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleReleaseFence
+ //
+ /// CHECK-START: void Main.releaseFence() instruction_simplifier (after)
+ /// CHECK-DAG: MemoryBarrier kind:AnyStore
+ private static void releaseFence() {
+ VarHandle.releaseFence();
+ }
+
+ /// CHECK-START: void Main.loadLoadFence() intrinsics_recognition (after)
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleLoadLoadFence
+ //
+ /// CHECK-START: void Main.loadLoadFence() instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleLoadLoadFence
+ //
+ /// CHECK-START: void Main.loadLoadFence() instruction_simplifier (after)
+ /// CHECK-DAG: MemoryBarrier kind:LoadAny
+ private static void loadLoadFence() {
+ VarHandle.loadLoadFence();
+ }
+
+ /// CHECK-START: void Main.storeStoreFence() intrinsics_recognition (after)
+ /// CHECK-DAG: InvokeStaticOrDirect intrinsic:VarHandleStoreStoreFence
+ //
+ /// CHECK-START: void Main.storeStoreFence() instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect intrinsic:VarHandleStoreStoreFence
+ //
+ /// CHECK-START: void Main.storeStoreFence() instruction_simplifier (after)
+ /// CHECK-DAG: MemoryBarrier kind:StoreStore
+ private static void storeStoreFence() {
+ VarHandle.storeStoreFence();
+ }
+
+ //
+ // Driver.
+ //
+
+ public static void main(String[] args) {
+ System.out.println("starting");
+ acquireFence();
+ releaseFence();
+ loadLoadFence();
+ storeStoreFence();
+ fullFence();
+ System.out.println("passed");
+ }
+}
diff --git a/test/910-methods/check b/test/910-methods/check
index 8358500..f9552ad 100644
--- a/test/910-methods/check
+++ b/test/910-methods/check
@@ -19,4 +19,8 @@
patch -p0 expected.txt < expected_jack.diff
fi
+if [[ "$DX" == 'd8' ]]; then
+ patch -p0 expected.txt < expected_d8.diff
+fi
+
./default-check "$@"
diff --git a/test/910-methods/expected_d8.diff b/test/910-methods/expected_d8.diff
new file mode 100644
index 0000000..2c5d085
--- /dev/null
+++ b/test/910-methods/expected_d8.diff
@@ -0,0 +1,4 @@
+7c7
+< Location end: 39
+---
+> Location end: 36
diff --git a/test/979-const-method-handle/build b/test/979-const-method-handle/build
new file mode 100644
index 0000000..966ecf4
--- /dev/null
+++ b/test/979-const-method-handle/build
@@ -0,0 +1,22 @@
+#!/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.
+
+# Stop if something fails.
+set -e
+
+${DX} --dex --min-sdk-version=27 --output=classes.dex classes
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/979-const-method-handle/classes/Main.class b/test/979-const-method-handle/classes/Main.class
new file mode 100644
index 0000000..8d6b7d8
--- /dev/null
+++ b/test/979-const-method-handle/classes/Main.class
Binary files differ
diff --git a/test/979-const-method-handle/classes/constmethodhandle/ConstTest.class b/test/979-const-method-handle/classes/constmethodhandle/ConstTest.class
new file mode 100644
index 0000000..a21b0a3
--- /dev/null
+++ b/test/979-const-method-handle/classes/constmethodhandle/ConstTest.class
Binary files differ
diff --git a/test/979-const-method-handle/expected.txt b/test/979-const-method-handle/expected.txt
new file mode 100644
index 0000000..573b80d
--- /dev/null
+++ b/test/979-const-method-handle/expected.txt
@@ -0,0 +1,2 @@
+MethodHandle MethodHandle(Object)Class => class java.lang.Float
+MethodType (char,short,int,long,float,double,Object)boolean
diff --git a/test/979-const-method-handle/info.txt b/test/979-const-method-handle/info.txt
new file mode 100644
index 0000000..e8514ce
--- /dev/null
+++ b/test/979-const-method-handle/info.txt
@@ -0,0 +1,7 @@
+This test checks const-method-handle and const-method-type bytecodes.
+
+The class files in this test come from:
+
+ dalvik/dx/tests/142-const-method-handle
+
+and are built using ASM bytecode manipulation library.
diff --git a/test/988-method-trace/gen_srcs.py b/test/988-method-trace/gen_srcs.py
index c1ce35c..8f1082f 100755
--- a/test/988-method-trace/gen_srcs.py
+++ b/test/988-method-trace/gen_srcs.py
@@ -38,7 +38,8 @@
IDX_CLASS_NAME = -3
# Exclude all hidden API.
-KLASS_BLACK_LIST = ['sun.misc.Unsafe', 'libcore.io.Memory', 'java.lang.StringFactory']
+KLASS_BLACK_LIST = ['sun.misc.Unsafe', 'libcore.io.Memory', 'java.lang.StringFactory',
+ 'java.lang.invoke.VarHandle' ] # TODO(b/65872996): Enable when VarHandle is visible.
METHOD_BLACK_LIST = [('java.lang.ref.Reference', 'getReferent'),
('java.lang.String', 'getCharsNoCheck'),
('java.lang.System', 'arraycopy')] # arraycopy has a manual test.
diff --git a/test/Android.bp b/test/Android.bp
index 2af03e3..cb18070 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -74,7 +74,7 @@
],
target: {
- linux: {
+ linux_glibc: {
ldflags: [
// Allow jni_compiler_test to find Java_MyClassNatives_bar
// within itself using dlopen(NULL, ...).
@@ -143,7 +143,7 @@
"-Wno-missing-noreturn",
],
},
- linux: {
+ linux_glibc: {
cflags: [
// gtest issue
"-Wno-used-but-marked-unused",
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 6017d28..4b49142 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -22,8 +22,7 @@
$(HOST_OUT_EXECUTABLES)/dx \
$(HOST_OUT_EXECUTABLES)/jasmin \
$(HOST_OUT_EXECUTABLES)/smali \
- $(HOST_OUT_EXECUTABLES)/dexmerger \
- $(JACK)
+ $(HOST_OUT_EXECUTABLES)/dexmerger
# Convert's a rule name to the form used in variables, e.g. no-relocate to NO_RELOCATE
define name-to-var
@@ -124,19 +123,9 @@
# Host executables.
host_prereq_rules := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
-ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
-# Classpath for Jack compilation for host.
-host_prereq_rules += $(HOST_JACK_CLASSPATH_DEPENDENCIES)
-endif
-
-# Required for dx, jasmin, smali, dexmerger, jack.
+# Required for dx, jasmin, smali, dexmerger.
host_prereq_rules += $(TEST_ART_RUN_TEST_DEPENDENCIES)
-ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
-# Classpath for Jack compilation for target.
-target_prereq_rules := $(TARGET_JACK_CLASSPATH_DEPENDENCIES)
-endif
-
# Sync test files to the target, depends upon all things that must be pushed
#to the target.
target_prereq_rules += test-art-target-sync
diff --git a/test/dexdump/const-method-handle.dex b/test/dexdump/const-method-handle.dex
new file mode 100644
index 0000000..1fe28e5
--- /dev/null
+++ b/test/dexdump/const-method-handle.dex
Binary files differ
diff --git a/test/dexdump/const-method-handle.lst b/test/dexdump/const-method-handle.lst
new file mode 100644
index 0000000..961d427
--- /dev/null
+++ b/test/dexdump/const-method-handle.lst
@@ -0,0 +1,9 @@
+#const-method-handle.dex
+0x000003c0 8 Main <init> ()V Main.java 22
+0x000003d8 50 Main main ([Ljava/lang/String;)V Main.java 26
+0x0000041c 8 constmethodhandle.ConstTest <init> ()V ConstTest.java 22
+0x00000434 94 constmethodhandle.ConstTest displayMethodHandle (Ljava/lang/invoke/MethodHandle;)V ConstTest.java 24
+0x000004a4 50 constmethodhandle.ConstTest displayMethodType (Ljava/lang/invoke/MethodType;)V ConstTest.java 29
+0x000004e8 30 constmethodhandle.ConstTest main ([Ljava/lang/String;)V ConstTest.java -1
+0x00000518 6 constmethodhandle.ConstTest test1 ()Ljava/lang/invoke/MethodHandle; ConstTest.java -1
+0x00000530 6 constmethodhandle.ConstTest test2 ()Ljava/lang/invoke/MethodType; ConstTest.java -1
diff --git a/test/dexdump/const-method-handle.txt b/test/dexdump/const-method-handle.txt
new file mode 100644
index 0000000..6b33502
--- /dev/null
+++ b/test/dexdump/const-method-handle.txt
@@ -0,0 +1,275 @@
+Processing 'const-method-handle.dex'...
+Opened 'const-method-handle.dex', DEX version '039'
+DEX file header:
+magic : 'dex\n039\0'
+checksum : 16656a27
+signature : 1953...5aa5
+file_size : 2524
+header_size : 112
+link_size : 0
+link_off : 0 (0x000000)
+string_ids_size : 57
+string_ids_off : 112 (0x000070)
+type_ids_size : 26
+type_ids_off : 340 (0x000154)
+proto_ids_size : 18
+proto_ids_off : 444 (0x0001bc)
+field_ids_size : 2
+field_ids_off : 660 (0x000294)
+method_ids_size : 23
+method_ids_off : 676 (0x0002a4)
+class_defs_size : 2
+class_defs_off : 860 (0x00035c)
+data_size : 1588
+data_off : 936 (0x0003a8)
+
+Class #0 header:
+class_idx : 5
+access_flags : 1 (0x0001)
+superclass_idx : 11
+interfaces_off : 0 (0x000000)
+source_file_idx : 29
+annotations_off : 1336 (0x000538)
+class_data_off : 2270 (0x0008de)
+static_fields_size : 0
+instance_fields_size: 0
+direct_methods_size : 2
+virtual_methods_size: 0
+
+Class #0 annotations:
+Annotations on method #1 'main'
+ VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+
+Class #0 -
+ Class descriptor : 'LMain;'
+ Access flags : 0x0001 (PUBLIC)
+ Superclass : 'Ljava/lang/Object;'
+ Interfaces -
+ Static fields -
+ Instance fields -
+ Direct methods -
+ #0 : (in LMain;)
+ name : '<init>'
+ type : '()V'
+ access : 0x10001 (PUBLIC CONSTRUCTOR)
+ code -
+ registers : 1
+ ins : 1
+ outs : 1
+ insns size : 4 16-bit code units
+0003b0: |[0003b0] Main.<init>:()V
+0003c0: 7010 0a00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@000a
+0003c6: 0e00 |0003: return-void
+ catches : (none)
+ positions :
+ 0x0000 line=22
+ locals :
+ 0x0000 - 0x0004 reg=0 this LMain;
+
+ #1 : (in LMain;)
+ name : 'main'
+ type : '([Ljava/lang/String;)V'
+ access : 0x0009 (PUBLIC STATIC)
+ code -
+ registers : 6
+ ins : 1
+ outs : 4
+ insns size : 25 16-bit code units
+0003c8: |[0003c8] Main.main:([Ljava/lang/String;)V
+0003d8: 7100 1500 0000 |0000: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0015
+0003de: 0c00 |0003: move-result-object v0
+0003e0: 1c01 0600 |0004: const-class v1, Lconstmethodhandle/ConstTest; // type@0006
+0003e4: 1a02 3000 |0006: const-string v2, "main" // string@0030
+0003e8: 6203 0100 |0008: sget-object v3, Ljava/lang/Void;.TYPE:Ljava/lang/Class; // field@0001
+0003ec: 1c04 1900 |000a: const-class v4, [Ljava/lang/String; // type@0019
+0003f0: 7120 1600 4300 |000c: invoke-static {v3, v4}, Ljava/lang/invoke/MethodType;.methodType:(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType; // method@0016
+0003f6: 0c03 |000f: move-result-object v3
+0003f8: 6e40 1400 1032 |0010: invoke-virtual {v0, v1, v2, v3}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0014
+0003fe: 0c00 |0013: move-result-object v0
+000400: fa20 1200 5000 1000 |0014: invoke-polymorphic {v0, v5}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/String;)V // method@0012, proto@0010
+000408: 0e00 |0018: return-void
+ catches : (none)
+ positions :
+ 0x0000 line=26
+ 0x000c line=27
+ 0x0014 line=28
+ 0x0018 line=29
+ locals :
+ 0x0000 - 0x0019 reg=5 (null) [Ljava/lang/String;
+
+ Virtual methods -
+ source_file_idx : 29 (Main.java)
+
+Class #1 header:
+class_idx : 6
+access_flags : 1 (0x0001)
+superclass_idx : 11
+interfaces_off : 0 (0x000000)
+source_file_idx : 3
+annotations_off : 1360 (0x000550)
+class_data_off : 2284 (0x0008ec)
+static_fields_size : 0
+instance_fields_size: 0
+direct_methods_size : 6
+virtual_methods_size: 0
+
+Class #1 annotations:
+Annotations on method #3 'displayMethodHandle'
+ VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+
+Class #1 -
+ Class descriptor : 'Lconstmethodhandle/ConstTest;'
+ Access flags : 0x0001 (PUBLIC)
+ Superclass : 'Ljava/lang/Object;'
+ Interfaces -
+ Static fields -
+ Instance fields -
+ Direct methods -
+ #0 : (in Lconstmethodhandle/ConstTest;)
+ name : '<init>'
+ type : '()V'
+ access : 0x10001 (PUBLIC CONSTRUCTOR)
+ code -
+ registers : 1
+ ins : 1
+ outs : 1
+ insns size : 4 16-bit code units
+00040c: |[00040c] constmethodhandle.ConstTest.<init>:()V
+00041c: 7010 0a00 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@000a
+000422: 0e00 |0003: return-void
+ catches : (none)
+ positions :
+ 0x0000 line=22
+ locals :
+ 0x0000 - 0x0004 reg=0 this Lconstmethodhandle/ConstTest;
+
+ #1 : (in Lconstmethodhandle/ConstTest;)
+ name : 'displayMethodHandle'
+ type : '(Ljava/lang/invoke/MethodHandle;)V'
+ access : 0x000a (PRIVATE STATIC)
+ code -
+ registers : 4
+ ins : 1
+ outs : 2
+ insns size : 47 16-bit code units
+000424: |[000424] constmethodhandle.ConstTest.displayMethodHandle:(Ljava/lang/invoke/MethodHandle;)V
+000434: 6200 0000 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0000
+000438: 2201 0d00 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@000d
+00043c: 7010 0c00 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@000c
+000442: 1a02 1e00 |0007: const-string v2, "MethodHandle " // string@001e
+000446: 6e20 0e00 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@000e
+00044c: 0c01 |000c: move-result-object v1
+00044e: 6e20 0d00 3100 |000d: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@000d
+000454: 0c01 |0010: move-result-object v1
+000456: 1a02 0000 |0011: const-string v2, " => " // string@0000
+00045a: 6e20 0e00 2100 |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@000e
+000460: 0c01 |0016: move-result-object v1
+000462: 1402 0030 4046 |0017: const v2, #float 12300 // #46403000
+000468: 7110 0900 0200 |001a: invoke-static {v2}, Ljava/lang/Float;.valueOf:(F)Ljava/lang/Float; // method@0009
+00046e: 0c02 |001d: move-result-object v2
+000470: fa20 1100 2300 0100 |001e: invoke-polymorphic {v3, v2}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/Object;)Ljava/lang/Class; // method@0011, proto@0001
+000478: 0c02 |0022: move-result-object v2
+00047a: 6e20 0d00 2100 |0023: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@000d
+000480: 0c01 |0026: move-result-object v1
+000482: 6e10 0f00 0100 |0027: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@000f
+000488: 0c01 |002a: move-result-object v1
+00048a: 6e20 0800 1000 |002b: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0008
+000490: 0e00 |002e: return-void
+ catches : (none)
+ positions :
+ 0x0000 line=24
+ 0x001a line=25
+ 0x002b line=24
+ 0x002e line=26
+ locals :
+ 0x0000 - 0x002f reg=3 (null) Ljava/lang/invoke/MethodHandle;
+
+ #2 : (in Lconstmethodhandle/ConstTest;)
+ name : 'displayMethodType'
+ type : '(Ljava/lang/invoke/MethodType;)V'
+ access : 0x000a (PRIVATE STATIC)
+ code -
+ registers : 4
+ ins : 1
+ outs : 2
+ insns size : 25 16-bit code units
+000494: |[000494] constmethodhandle.ConstTest.displayMethodType:(Ljava/lang/invoke/MethodType;)V
+0004a4: 6200 0000 |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0000
+0004a8: 2201 0d00 |0002: new-instance v1, Ljava/lang/StringBuilder; // type@000d
+0004ac: 7010 0c00 0100 |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@000c
+0004b2: 1a02 1f00 |0007: const-string v2, "MethodType " // string@001f
+0004b6: 6e20 0e00 2100 |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@000e
+0004bc: 0c01 |000c: move-result-object v1
+0004be: 6e20 0d00 3100 |000d: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@000d
+0004c4: 0c01 |0010: move-result-object v1
+0004c6: 6e10 0f00 0100 |0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@000f
+0004cc: 0c01 |0014: move-result-object v1
+0004ce: 6e20 0800 1000 |0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0008
+0004d4: 0e00 |0018: return-void
+ catches : (none)
+ positions :
+ 0x0000 line=29
+ 0x0018 line=30
+ locals :
+ 0x0000 - 0x0019 reg=3 (null) Ljava/lang/invoke/MethodType;
+
+ #3 : (in Lconstmethodhandle/ConstTest;)
+ name : 'main'
+ type : '([Ljava/lang/String;)V'
+ access : 0x0009 (PUBLIC STATIC)
+ code -
+ registers : 2
+ ins : 1
+ outs : 1
+ insns size : 15 16-bit code units
+0004d8: |[0004d8] constmethodhandle.ConstTest.main:([Ljava/lang/String;)V
+0004e8: 7100 0600 0000 |0000: invoke-static {}, Lconstmethodhandle/ConstTest;.test1:()Ljava/lang/invoke/MethodHandle; // method@0006
+0004ee: 0c00 |0003: move-result-object v0
+0004f0: 7110 0300 0000 |0004: invoke-static {v0}, Lconstmethodhandle/ConstTest;.displayMethodHandle:(Ljava/lang/invoke/MethodHandle;)V // method@0003
+0004f6: 7100 0700 0000 |0007: invoke-static {}, Lconstmethodhandle/ConstTest;.test2:()Ljava/lang/invoke/MethodType; // method@0007
+0004fc: 0c00 |000a: move-result-object v0
+0004fe: 7110 0400 0000 |000b: invoke-static {v0}, Lconstmethodhandle/ConstTest;.displayMethodType:(Ljava/lang/invoke/MethodType;)V // method@0004
+000504: 0e00 |000e: return-void
+ catches : (none)
+ positions :
+ locals :
+
+ #4 : (in Lconstmethodhandle/ConstTest;)
+ name : 'test1'
+ type : '()Ljava/lang/invoke/MethodHandle;'
+ access : 0x0009 (PUBLIC STATIC)
+ code -
+ registers : 1
+ ins : 0
+ outs : 0
+ insns size : 3 16-bit code units
+000508: |[000508] constmethodhandle.ConstTest.test1:()Ljava/lang/invoke/MethodHandle;
+000518: fe00 0000 |0000: const-method-handle v0, method_handle@0000
+00051c: 1100 |0002: return-object v0
+ catches : (none)
+ positions :
+ locals :
+
+ #5 : (in Lconstmethodhandle/ConstTest;)
+ name : 'test2'
+ type : '()Ljava/lang/invoke/MethodType;'
+ access : 0x0009 (PUBLIC STATIC)
+ code -
+ registers : 1
+ ins : 0
+ outs : 0
+ insns size : 3 16-bit code units
+000520: |[000520] constmethodhandle.ConstTest.test2:()Ljava/lang/invoke/MethodType;
+000530: ff00 1100 |0000: const-method-type v0, (CSIJFDLjava/lang/Object;)Z // proto@0011
+000534: 1100 |0002: return-object v0
+ catches : (none)
+ positions :
+ locals :
+
+ Virtual methods -
+ source_file_idx : 3 (ConstTest.java)
+
+Method handle #0:
+ type : invoke-instance
+ target : Ljava/lang/Object; getClass
+ target_type : (Ljava/lang/Object;)Ljava/lang/Class;
diff --git a/test/dexdump/const-method-handle.xml b/test/dexdump/const-method-handle.xml
new file mode 100644
index 0000000..f1cf9f8
--- /dev/null
+++ b/test/dexdump/const-method-handle.xml
@@ -0,0 +1,91 @@
+<api>
+<package name=""
+>
+<class name="Main"
+ extends="java.lang.Object"
+ interface="false"
+ abstract="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<constructor name="Main"
+ type="Main"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+<method name="main"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.String[]">
+</parameter>
+</method>
+</class>
+</package>
+<package name="constmethodhandle"
+>
+<class name="ConstTest"
+ extends="java.lang.Object"
+ interface="false"
+ abstract="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<constructor name="ConstTest"
+ type="constmethodhandle.ConstTest"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+<method name="main"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="test1"
+ return="java.lang.invoke.MethodHandle"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test2"
+ return="java.lang.invoke.MethodType"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+</class>
+<method_handle index="0"
+ type="invoke-instance"
+ target_class="Ljava/lang/Object;"
+ target_member="getClass"
+ target_member_type="(Ljava/lang/Object;)Ljava/lang/Class;"
+>
+</method_handle>
+</package>
+</api>
diff --git a/tools/run-prebuilt-libjdwp-tests.sh b/tools/run-prebuilt-libjdwp-tests.sh
new file mode 100755
index 0000000..46c2a15
--- /dev/null
+++ b/tools/run-prebuilt-libjdwp-tests.sh
@@ -0,0 +1,112 @@
+#!/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.
+
+if [[ ! -d libcore ]]; then
+ echo "Script needs to be run at the root of the android tree"
+ exit 1
+fi
+
+source build/envsetup.sh >&/dev/null # for get_build_var, setpaths
+setpaths # include platform prebuilt java, javac, etc in $PATH.
+
+if [[ `uname` != 'Linux' ]]; then
+ echo "Script cannot be run on $(uname). It is Linux only."
+ exit 2
+fi
+
+jdwp_path=${ANDROID_JAVA_HOME}/jre/lib/amd64/libjdwp.so
+if [[ ! -f $jdwp_path ]]; then
+ echo "Unable to find prebuilts libjdwp.so! Did the version change from jdk8?"
+ exit 3
+fi
+
+args=("$@")
+debug="no"
+has_variant="no"
+has_mode="no"
+
+while true; do
+ if [[ $1 == "--debug" ]]; then
+ debug="yes"
+ shift
+ elif [[ "$1" == --mode=* ]]; then
+ has_mode="yes"
+ if [[ $1 != "--mode=host" ]]; then
+ # Just print out an actually helpful error message.
+ echo "Only host tests can be run against prebuilt libjdwp"
+ exit 4
+ fi
+ shift
+ elif [[ $1 == --variant=* ]]; then
+ has_variant="yes"
+ if [[ $1 != "--variant=x64" ]] && [[ $1 != "--variant=X64" ]]; then
+ # Just print out an actually helpful error message.
+ echo "Only 64bit runs can be tested against the prebuilt libjdwp!"
+ exit 5
+ fi
+ shift
+ elif [[ "$1" == "" ]]; then
+ break
+ else
+ shift
+ fi
+done
+
+if [[ "$has_mode" = "no" ]]; then
+ args+=(--mode=host)
+fi
+
+if [[ "$has_variant" = "no" ]]; then
+ args+=(--variant=X64)
+fi
+
+wrapper_name=""
+plugin=""
+if [[ "$debug" = "yes" ]]; then
+ wrapper_name=libwrapagentpropertiesd
+ plugin="$ANDROID_HOST_OUT/lib64/libopenjdkjvmtid.so"
+else
+ wrapper_name=libwrapagentproperties
+ plugin="$ANDROID_HOST_OUT/lib64/libopenjdkjvmti.so"
+fi
+wrapper=$ANDROID_HOST_OUT/lib64/${wrapper_name}.so
+
+if [[ ! -f $wrapper ]]; then
+ echo "need to build $wrapper to run prebuild-libjdwp-tests!"
+ echo "m -j40 ${wrapper/.so/}"
+ exit 6
+fi
+
+if [[ ! -f $plugin ]]; then
+ echo "jvmti plugin not built!"
+ exit 7
+fi
+
+props_path=$PWD/art/tools/libjdwp-compat.props
+expect_path=$PWD/art/tools/libjdwp_art_failures.txt
+
+function verbose_run() {
+ echo "$@"
+ env "$@"
+}
+
+verbose_run LD_LIBRARY_PATH="$(dirname $jdwp_path):$LD_LIBRARY_PATH" \
+ ./art/tools/run-jdwp-tests.sh \
+ "${args[@]}" \
+ "-Xplugin:$plugin" \
+ --agent-wrapper "${wrapper}"="${props_path}" \
+ --jdwp-path "$jdwp_path" \
+ --expectations "$expect_path"