Merge "Hidden API: only log what we deny."
diff --git a/adbconnection/Android.bp b/adbconnection/Android.bp
index 441b706..95fc274 100644
--- a/adbconnection/Android.bp
+++ b/adbconnection/Android.bp
@@ -65,6 +65,7 @@
defaults: ["adbconnection-defaults"],
shared_libs: [
"libart",
+ "libartbase",
],
}
@@ -76,5 +77,6 @@
],
shared_libs: [
"libartd",
+ "libartbased",
],
}
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 3daaf01..b481352 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -277,6 +277,16 @@
$(TARGET_CORE_IMAGE_DEFAULT_32) \
dexdump2-target
+# The dexanalyze test requires an image and the dexanalyze utility.
+ART_GTEST_dexanalyze_test_HOST_DEPS := \
+ $(HOST_CORE_IMAGE_DEFAULT_64) \
+ $(HOST_CORE_IMAGE_DEFAULT_32) \
+ dexanalyze-host
+ART_GTEST_dexanalyze_test_TARGET_DEPS := \
+ $(TARGET_CORE_IMAGE_DEFAULT_64) \
+ $(TARGET_CORE_IMAGE_DEFAULT_32) \
+ dexanalyze-target
+
# The dexlayout test requires an image and the dexlayout utility.
# TODO: rename into dexdump when migration completes
ART_GTEST_dexlayout_test_HOST_DEPS := \
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 5884a54..be963fb 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -246,6 +246,7 @@
"libart",
"libprofile",
"libdexfile",
+ "libartbase",
],
target: {
@@ -295,6 +296,7 @@
"libartd",
"libprofiled",
"libdexfiled",
+ "libartbased",
],
}
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 0e20a65..42031f9 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1360,9 +1360,15 @@
if (arg_this->IsNewInstance()) {
ssa_builder_->AddUninitializedString(arg_this->AsNewInstance());
} else {
+ // The only reason a HPhi can flow in a String.<init> is when there is an
+ // irreducible loop, which will create HPhi for all dex registers at loop entry.
DCHECK(arg_this->IsPhi());
- // NewInstance is not the direct input of the StringFactory call. It might
- // be redundant but optimizing this case is not worth the effort.
+ DCHECK(graph_->HasIrreducibleLoops());
+ // Don't bother compiling a method in that situation. While we could look at all
+ // phis related to the HNewInstance, it's not worth the trouble.
+ MaybeRecordStat(compilation_stats_,
+ MethodCompilationStat::kNotCompiledIrreducibleAndStringInit);
+ return false;
}
// Walk over all vregs and replace any occurrence of `arg_this` with `invoke`.
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 9a26f2f..f246228 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -50,6 +50,7 @@
kNotCompiledThrowCatchLoop,
kNotCompiledAmbiguousArrayOp,
kNotCompiledHugeMethod,
+ kNotCompiledIrreducibleAndStringInit,
kNotCompiledLargeMethodNoBranches,
kNotCompiledMalformedOpcode,
kNotCompiledNoCodegen,
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 18548ba..e74947a 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -202,6 +202,7 @@
"libart-dexlayout",
"libart",
"libdexfile",
+ "libartbase",
"libbase",
"liblz4",
"libsigchain",
@@ -239,6 +240,7 @@
"libartd-dexlayout",
"libartd",
"libdexfiled",
+ "libartbased",
"libbase",
"liblz4",
"libsigchain",
@@ -267,12 +269,13 @@
"-z muldefs",
],
static_libs: [
- "libprofile",
"libart-dex2oat",
"libart-compiler",
"libart-dexlayout",
"libart",
+ "libartbase",
"libdexfile",
+ "libprofile",
"libvixl-arm",
"libvixl-arm64",
] + art_static_dependencies,
@@ -309,6 +312,7 @@
"libartd-compiler",
"libartd-dexlayout",
"libartd",
+ "libartbased",
"libprofiled",
"libdexfiled",
"libvixld-arm",
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index c63d6c3..2f0962c 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -35,6 +35,7 @@
host_supported: true,
shared_libs: [
"libdexfile",
+ "libartbase",
"libbase",
],
}
@@ -46,6 +47,7 @@
device_supported: false,
static_libs: [
"libdexfile",
+ "libartbase",
] + art_static_dependencies,
target: {
darwin: {
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index b009774..147af0c 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -39,8 +39,8 @@
"dex2oat-pgo-defaults",
],
shared_libs: [
- "libart",
"libdexfile",
+ "libartbase",
"libprofile",
],
@@ -60,8 +60,8 @@
"art_debug_defaults",
],
shared_libs: [
- "libartd",
"libdexfiled",
+ "libartbased",
"libprofiled",
],
}
@@ -70,7 +70,6 @@
name: "dexlayout-defaults",
defaults: ["art_defaults"],
host_supported: true,
- srcs: ["dexlayout_main.cc"],
shared_libs: [
"libbase",
],
@@ -79,9 +78,11 @@
art_cc_binary {
name: "dexlayout",
defaults: ["dexlayout-defaults"],
+ srcs: ["dexlayout_main.cc"],
shared_libs: [
+ "libdexfile",
"libprofile",
- "libart",
+ "libartbase",
"libart-dexlayout",
],
}
@@ -92,9 +93,11 @@
"art_debug_defaults",
"dexlayout-defaults",
],
+ srcs: ["dexlayout_main.cc"],
shared_libs: [
+ "libdexfiled",
"libprofiled",
- "libartd",
+ "libartbased",
"libartd-dexlayout",
],
}
@@ -117,6 +120,8 @@
cflags: ["-Wall"],
shared_libs: [
"libart",
+ "libdexfile",
+ "libartbase",
"libart-dexlayout",
"libbase",
],
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 6cb141f..aa4e6d0 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -27,7 +27,6 @@
#include "android-base/stringprintf.h"
#include "base/logging.h" // For InitLogging.
-#include "base/mutex.h"
#include "base/stringpiece.h"
#include "dexlayout.h"
@@ -37,7 +36,6 @@
#ifdef ART_TARGET_ANDROID
#include "pagemap/pagemap.h"
#endif
-#include "runtime.h"
#include "vdex_file.h"
namespace art {
@@ -446,6 +444,11 @@
PrintLetterKey();
}
+NO_RETURN static void Abort(const char* msg) {
+ std::cerr << msg;
+ exit(1);
+}
+
static int DexDiagMain(int argc, char* argv[]) {
if (argc < 2) {
Usage(argv[0]);
@@ -471,8 +474,7 @@
}
// Art specific set up.
- Locks::Init();
- InitLogging(argv, Runtime::Abort);
+ InitLogging(argv, Abort);
MemMap::Init();
#ifdef ART_TARGET_ANDROID
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 185c142..71e56d19 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -34,7 +34,6 @@
#include "base/logging.h" // For InitLogging.
#include "base/mem_map.h"
#include "profile/profile_compilation_info.h"
-#include "runtime.h"
namespace art {
@@ -66,12 +65,17 @@
LOG(ERROR) << " -x : compact dex generation level, either 'none' or 'fast'";
}
+NO_RETURN static void Abort(const char* msg) {
+ LOG(ERROR) << msg;
+ exit(1);
+}
+
/*
* Main driver of the dexlayout utility.
*/
int DexlayoutDriver(int argc, char** argv) {
// Art specific set up.
- InitLogging(argv, Runtime::Abort);
+ InitLogging(argv, Abort);
MemMap::Init();
Options options;
diff --git a/dexlist/Android.bp b/dexlist/Android.bp
index 2703732..bd521ac 100644
--- a/dexlist/Android.bp
+++ b/dexlist/Android.bp
@@ -17,7 +17,11 @@
host_supported: true,
srcs: ["dexlist.cc"],
cflags: ["-Wall", "-Werror"],
- shared_libs: ["libdexfile", "libbase"],
+ shared_libs: [
+ "libdexfile",
+ "libartbase",
+ "libbase"
+ ],
// TODO: fix b/72216369 and remove the need for this.
include_dirs: [
"art/runtime" // dex utils.
diff --git a/dexoptanalyzer/Android.bp b/dexoptanalyzer/Android.bp
index 33366ad..99a11cd 100644
--- a/dexoptanalyzer/Android.bp
+++ b/dexoptanalyzer/Android.bp
@@ -38,6 +38,7 @@
defaults: ["dexoptanalyzer-defaults"],
shared_libs: [
"libart",
+ "libartbase",
],
}
@@ -49,6 +50,7 @@
],
shared_libs: [
"libartd",
+ "libartbased",
],
}
diff --git a/imgdiag/Android.bp b/imgdiag/Android.bp
index 2b89497..972c8f7 100644
--- a/imgdiag/Android.bp
+++ b/imgdiag/Android.bp
@@ -57,6 +57,7 @@
defaults: ["imgdiag-defaults"],
shared_libs: [
"libart",
+ "libartbase",
"libart-compiler",
],
}
@@ -69,6 +70,7 @@
],
shared_libs: [
"libartd",
+ "libartbased",
"libartd-compiler",
],
}
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 9d49f37..3818624 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -19,6 +19,7 @@
defaults: ["art_defaults"],
host_supported: true,
srcs: [
+ "dex/art_dex_file_loader.cc",
"dex/compact_dex_file.cc",
"dex/compact_offset_table.cc",
"dex/descriptors_names.cc",
@@ -55,25 +56,20 @@
},
generated_sources: ["dexfile_operator_srcs"],
shared_libs: [
+ // For MemMap.
"libartbase",
- // Important note: relying on libartbase's header_lib is perfectly acceptable.
- // However, relying on the libartbase shared library introduces further, possibly cyclic,
- // dependencies for clients outside of ART.
"liblog",
+ // For atrace.
+ "libcutils",
// For common macros.
"libbase",
"libz",
],
- header_libs: [
- "art_libartbase_headers",
- ],
export_include_dirs: ["."],
export_shared_lib_headers: [
+ "libartbase",
"libbase",
],
- export_header_lib_headers: [
- "art_libartbase_headers",
- ],
}
gensrcs {
@@ -115,6 +111,7 @@
"art_gtest_defaults",
],
srcs: [
+ "dex/art_dex_file_loader_test.cc",
"dex/code_item_accessors_test.cc",
"dex/compact_dex_file_test.cc",
"dex/compact_offset_table_test.cc",
diff --git a/runtime/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc
similarity index 100%
rename from runtime/dex/art_dex_file_loader.cc
rename to libdexfile/dex/art_dex_file_loader.cc
diff --git a/runtime/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h
similarity index 97%
rename from runtime/dex/art_dex_file_loader.h
rename to libdexfile/dex/art_dex_file_loader.h
index 7577945..a460aee 100644
--- a/runtime/dex/art_dex_file_loader.h
+++ b/libdexfile/dex/art_dex_file_loader.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
-#define ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
+#ifndef ART_LIBDEXFILE_DEX_ART_DEX_FILE_LOADER_H_
+#define ART_LIBDEXFILE_DEX_ART_DEX_FILE_LOADER_H_
#include <cstdint>
#include <memory>
@@ -137,4 +137,4 @@
} // namespace art
-#endif // ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_
+#endif // ART_LIBDEXFILE_DEX_ART_DEX_FILE_LOADER_H_
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/libdexfile/dex/art_dex_file_loader_test.cc
similarity index 100%
rename from runtime/dex/art_dex_file_loader_test.cc
rename to libdexfile/dex/art_dex_file_loader_test.cc
diff --git a/libprofile/Android.bp b/libprofile/Android.bp
index bcb90cb..b9883f6 100644
--- a/libprofile/Android.bp
+++ b/libprofile/Android.bp
@@ -45,6 +45,7 @@
shared_libs: [
"libartbase",
"libdexfile",
+ "libartbase",
// For atrace.
"libcutils",
],
@@ -97,6 +98,7 @@
shared_libs: [
"libartbased",
"libdexfiled",
+ "libartbased",
"libziparchive",
],
}
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index 535acdf..77dede3 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -39,6 +39,7 @@
"libart-compiler",
"libart-disassembler",
"libdexfile",
+ "libartbase",
"libprofile",
"libbase",
],
@@ -55,6 +56,7 @@
"libartd-compiler",
"libartd-disassembler",
"libdexfiled",
+ "libartbased",
"libprofiled",
"libbase",
],
@@ -82,6 +84,7 @@
"libart",
"libdexfile",
"libprofile",
+ "libartbase",
"libart-compiler",
"libart-disassembler",
"libvixl-arm",
@@ -117,6 +120,7 @@
"libartd",
"libdexfiled",
"libprofiled",
+ "libartbased",
"libartd-compiler",
"libartd-disassembler",
"libvixld-arm",
diff --git a/openjdkjvm/Android.bp b/openjdkjvm/Android.bp
index a178993..907315e 100644
--- a/openjdkjvm/Android.bp
+++ b/openjdkjvm/Android.bp
@@ -29,7 +29,10 @@
art_cc_library {
name: "libopenjdkjvm",
defaults: ["libopenjdkjvm_defaults"],
- shared_libs: ["libart"],
+ shared_libs: [
+ "libart",
+ "libartbase",
+ ],
}
art_cc_library {
@@ -38,5 +41,8 @@
"art_debug_defaults",
"libopenjdkjvm_defaults",
],
- shared_libs: ["libartd"],
+ shared_libs: [
+ "libartd",
+ "libartbased",
+ ],
}
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index 81b69e8..d8902d6 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -71,6 +71,7 @@
"libart-compiler",
"libart-dexlayout",
"libdexfile",
+ "libartbase",
],
}
@@ -85,5 +86,6 @@
"libartd-compiler",
"libartd-dexlayout",
"libdexfiled",
+ "libartbased",
],
}
diff --git a/patchoat/Android.bp b/patchoat/Android.bp
index 1e2f328..13c8f47 100644
--- a/patchoat/Android.bp
+++ b/patchoat/Android.bp
@@ -59,7 +59,6 @@
"patchoat_test.cc",
],
shared_libs: [
- "libartd",
"libcrypto", // For computing the digest of image file
],
}
diff --git a/profman/Android.bp b/profman/Android.bp
index 3c8c72c..5aaccb0 100644
--- a/profman/Android.bp
+++ b/profman/Android.bp
@@ -42,6 +42,7 @@
"libart",
"libprofile",
"libdexfile",
+ "libartbase",
],
}
@@ -55,6 +56,7 @@
"libartd",
"libprofiled",
"libdexfiled",
+ "libartbased",
],
}
diff --git a/profman/profman.cc b/profman/profman.cc
index cd88d03..1f77239 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -33,6 +33,7 @@
#include "base/dumpable.h"
#include "base/logging.h" // For InitLogging.
+#include "base/mem_map.h"
#include "base/scoped_flock.h"
#include "base/stringpiece.h"
#include "base/time_utils.h"
@@ -49,7 +50,6 @@
#include "dex/type_reference.h"
#include "profile/profile_compilation_info.h"
#include "profile_assistant.h"
-#include "runtime.h"
namespace art {
@@ -177,6 +177,11 @@
static constexpr char kMethodFlagStringStartup = 'S';
static constexpr char kMethodFlagStringPostStartup = 'P';
+NO_RETURN static void Abort(const char* msg) {
+ LOG(ERROR) << msg;
+ exit(1);
+}
+
// TODO(calin): This class has grown too much from its initial design. Split the functionality
// into smaller, more contained pieces.
class ProfMan FINAL {
@@ -202,8 +207,8 @@
original_argc = argc;
original_argv = argv;
- Locks::Init();
- InitLogging(argv, Runtime::Abort);
+ MemMap::Init();
+ InitLogging(argv, Abort);
// Skip over the command name.
argv++;
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 3db4ee5..92607f5 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -45,7 +45,6 @@
"compiler_filter.cc",
"debug_print.cc",
"debugger.cc",
- "dex/art_dex_file_loader.cc",
"dex/dex_file_annotations.cc",
"dex_to_dex_decompiler.cc",
"elf_file.cc",
@@ -195,6 +194,7 @@
"ti/agent.cc",
"trace.cc",
"transaction.cc",
+ "var_handles.cc",
"vdex_file.cc",
"verifier/instruction_flags.cc",
"verifier/method_verifier.cc",
@@ -463,9 +463,9 @@
keep_symbols: true,
},
whole_static_libs: [
- "libartbase",
],
shared_libs: [
+ "libartbase",
"libdexfile",
"libprofile",
],
@@ -488,9 +488,9 @@
"libart_defaults",
],
whole_static_libs: [
- "libartbased",
],
shared_libs: [
+ "libartbased",
"libdexfiled",
"libprofiled",
],
@@ -544,7 +544,6 @@
"class_loader_context_test.cc",
"class_table_test.cc",
"compiler_filter_test.cc",
- "dex/art_dex_file_loader_test.cc",
"entrypoints/math_entrypoints_test.cc",
"entrypoints/quick/quick_trampoline_entrypoints_test.cc",
"entrypoints_order_test.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index be9e08f..b88aa5e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -828,9 +828,24 @@
return true;
}
+static void CreateStringInitBindings(Thread* self, ClassLinker* class_linker)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Find String.<init> -> StringFactory bindings.
+ ObjPtr<mirror::Class> string_factory_class =
+ class_linker->FindSystemClass(self, "Ljava/lang/StringFactory;");
+ CHECK(string_factory_class != nullptr);
+ ObjPtr<mirror::Class> string_class =
+ class_linker->GetClassRoot(ClassLinker::ClassRoot::kJavaLangString);
+ WellKnownClasses::InitStringInit(string_class, string_factory_class);
+ // Update the primordial thread.
+ self->InitStringEntryPoints();
+}
+
void ClassLinker::FinishInit(Thread* self) {
VLOG(startup) << "ClassLinker::FinishInit entering";
+ CreateStringInitBindings(self, this);
+
// Let the heap know some key offsets into java.lang.ref instances
// Note: we hard code the field indexes here rather than using FindInstanceField
// as the types of the field can't be resolved prior to the runtime being
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 37e074d..9c2a40b 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -29,6 +29,7 @@
#include "instrumentation.h"
#include "interpreter/shadow_frame.h"
#include "interpreter/unstarted_runtime.h"
+#include "jvalue-inl.h"
#include "mirror/class.h"
#include "mirror/object.h"
#include "obj_ptr-inl.h"
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 7e3c3db..0a186f4 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -42,6 +42,7 @@
#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/var_handle.h"
#include "oat_file.h"
#include "oat_quick_method_header.h"
#include "quick_exception_handler.h"
@@ -49,6 +50,7 @@
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread-inl.h"
+#include "var_handles.h"
#include "well_known_classes.h"
namespace art {
@@ -2789,13 +2791,6 @@
return static_cast<uintptr_t>('V');
}
- // TODO(oth): Ensure this path isn't taken for VarHandle accessors (b/65872996).
- DCHECK_EQ(resolved_method->GetDeclaringClass(),
- WellKnownClasses::ToClass(WellKnownClasses::java_lang_invoke_MethodHandle));
-
- Handle<mirror::MethodHandle> method_handle(hs.NewHandle(
- ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
-
Handle<mirror::MethodType> method_type(
hs.NewHandle(linker->ResolveMethodType(self, proto_idx, caller_method)));
@@ -2835,24 +2830,43 @@
// Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in
// consecutive order.
RangeInstructionOperands operands(first_arg + 1, num_vregs - 1);
- bool isExact = (jni::EncodeArtMethod(resolved_method) ==
- WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
+ Intrinsics intrinsic = static_cast<Intrinsics>(resolved_method->GetIntrinsic());
bool success = false;
- if (isExact) {
- success = MethodHandleInvokeExact(self,
+ if (resolved_method->GetDeclaringClass() == mirror::MethodHandle::StaticClass()) {
+ Handle<mirror::MethodHandle> method_handle(hs.NewHandle(
+ ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
+ if (intrinsic == Intrinsics::kMethodHandleInvokeExact) {
+ success = MethodHandleInvokeExact(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
+ } else {
+ DCHECK_EQ(static_cast<uint32_t>(intrinsic),
+ static_cast<uint32_t>(Intrinsics::kMethodHandleInvoke));
+ success = MethodHandleInvoke(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ &operands,
+ result);
+ }
+ } else {
+ DCHECK_EQ(mirror::VarHandle::StaticClass(), resolved_method->GetDeclaringClass());
+ Handle<mirror::VarHandle> var_handle(hs.NewHandle(
+ ObjPtr<mirror::VarHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
+ mirror::VarHandle::AccessMode access_mode =
+ mirror::VarHandle::GetAccessModeByIntrinsic(intrinsic);
+ success = VarHandleInvokeAccessor(self,
*shadow_frame,
- method_handle,
+ var_handle,
method_type,
+ access_mode,
&operands,
result);
- } else {
- success = MethodHandleInvoke(self,
- *shadow_frame,
- method_handle,
- method_type,
- &operands,
- result);
}
+
DCHECK(success || self->IsExceptionPending());
// Pop transition record.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ded8cef..5a50ec5 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -24,7 +24,7 @@
#include "entrypoints/runtime_asm_entrypoints.h"
#include "intrinsics_enum.h"
#include "jit/jit.h"
-#include "jvalue.h"
+#include "jvalue-inl.h"
#include "method_handles-inl.h"
#include "method_handles.h"
#include "mirror/array-inl.h"
@@ -37,6 +37,7 @@
#include "stack.h"
#include "thread-inl.h"
#include "transaction.h"
+#include "var_handles.h"
#include "well_known_classes.h"
namespace art {
@@ -725,38 +726,6 @@
}
}
-static bool DoVarHandleInvokeChecked(Thread* self,
- Handle<mirror::VarHandle> var_handle,
- Handle<mirror::MethodType> callsite_type,
- mirror::VarHandle::AccessMode access_mode,
- ShadowFrame& shadow_frame,
- InstructionOperands* operands,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- // TODO(oth): GetMethodTypeForAccessMode() allocates a MethodType()
- // which is only required if we need to convert argument and/or
- // return types.
- StackHandleScope<1> hs(self);
- Handle<mirror::MethodType> accessor_type(hs.NewHandle(
- var_handle->GetMethodTypeForAccessMode(self, access_mode)));
- const size_t num_vregs = accessor_type->NumberOfVRegs();
- const int num_params = accessor_type->GetPTypes()->GetLength();
- ShadowFrameAllocaUniquePtr accessor_frame =
- CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
- ShadowFrameGetter getter(shadow_frame, operands);
- static const uint32_t kFirstDestinationReg = 0;
- ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
- if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) {
- return false;
- }
- RangeInstructionOperands accessor_operands(kFirstDestinationReg,
- kFirstDestinationReg + num_vregs);
- if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
- return false;
- }
- return ConvertReturnValue(callsite_type, accessor_type, result);
-}
-
static bool DoVarHandleInvokeCommon(Thread* self,
ShadowFrame& shadow_frame,
const Instruction* inst,
@@ -769,21 +738,8 @@
return false;
}
- bool is_var_args = inst->HasVarArgs();
- const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc();
- ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC));
- if (receiver.IsNull()) {
- ThrowNullPointerExceptionFromDexPC();
- return false;
- }
-
StackHandleScope<2> hs(self);
- Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr())));
- if (!var_handle->IsAccessModeSupported(access_mode)) {
- ThrowUnsupportedOperationException();
- return false;
- }
-
+ bool is_var_args = inst->HasVarArgs();
const uint16_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::MethodType> callsite_type(hs.NewHandle(
@@ -794,34 +750,31 @@
return false;
}
- if (!var_handle->IsMethodTypeCompatible(access_mode, callsite_type.Get())) {
- ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode),
- callsite_type.Get());
- return false;
- }
-
+ const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc();
+ ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC));
+ Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr())));
if (is_var_args) {
uint32_t args[Instruction::kMaxVarArgRegs];
inst->GetVarArgs(args, inst_data);
VarArgsInstructionOperands all_operands(args, inst->VRegA_45cc());
NoReceiverInstructionOperands operands(&all_operands);
- return DoVarHandleInvokeChecked(self,
- var_handle,
- callsite_type,
- access_mode,
- shadow_frame,
- &operands,
- result);
+ return VarHandleInvokeAccessor(self,
+ shadow_frame,
+ var_handle,
+ callsite_type,
+ access_mode,
+ &operands,
+ result);
} else {
RangeInstructionOperands all_operands(inst->VRegC_4rcc(), inst->VRegA_4rcc());
NoReceiverInstructionOperands operands(&all_operands);
- return DoVarHandleInvokeChecked(self,
- var_handle,
- callsite_type,
- access_mode,
- shadow_frame,
- &operands,
- result);
+ return VarHandleInvokeAccessor(self,
+ shadow_frame,
+ var_handle,
+ callsite_type,
+ access_mode,
+ &operands,
+ result);
}
}
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 0684b46..86e69f4 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -46,8 +46,6 @@
namespace jit {
static constexpr bool kEnableOnStackReplacement = true;
-// At what priority to schedule jit threads. 9 is the lowest foreground priority on device.
-static constexpr int kJitPoolThreadPthreadPriority = 9;
// Different compilation threshold constants. These can be overridden on the command line.
static constexpr size_t kJitDefaultCompileThreshold = 10000; // Non-debug default.
@@ -80,6 +78,8 @@
options.Exists(RuntimeArgumentMap::DumpJITInfoOnShutdown);
jit_options->profile_saver_options_ =
options.GetOrDefault(RuntimeArgumentMap::ProfileSaverOpts);
+ jit_options->thread_pool_pthread_priority_ =
+ options.GetOrDefault(RuntimeArgumentMap::JITPoolThreadPthreadPriority);
if (options.Exists(RuntimeArgumentMap::JITCompileThreshold)) {
jit_options->compile_threshold_ = *options.Get(RuntimeArgumentMap::JITCompileThreshold);
@@ -167,21 +167,14 @@
cumulative_timings_.AddLogger(logger);
}
-Jit::Jit() : dump_info_on_shutdown_(false),
- cumulative_timings_("JIT timings"),
- memory_use_("Memory used for compilation", 16),
- lock_("JIT memory use lock"),
- use_jit_compilation_(true),
- hot_method_threshold_(0),
- warm_method_threshold_(0),
- osr_method_threshold_(0),
- priority_thread_weight_(0),
- invoke_transition_weight_(0) {}
+Jit::Jit(JitOptions* options) : options_(options),
+ cumulative_timings_("JIT timings"),
+ memory_use_("Memory used for compilation", 16),
+ lock_("JIT memory use lock") {}
Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
DCHECK(options->UseJitCompilation() || options->GetProfileSaverOptions().IsEnabled());
- std::unique_ptr<Jit> jit(new Jit);
- jit->dump_info_on_shutdown_ = options->DumpJitInfoOnShutdown();
+ std::unique_ptr<Jit> jit(new Jit(options));
if (jit_compiler_handle_ == nullptr && !LoadCompiler(error_msg)) {
return nullptr;
}
@@ -195,8 +188,6 @@
if (jit->GetCodeCache() == nullptr) {
return nullptr;
}
- jit->use_jit_compilation_ = options->UseJitCompilation();
- jit->profile_saver_options_ = options->GetProfileSaverOptions();
VLOG(jit) << "JIT created with initial_capacity="
<< PrettySize(options->GetCodeCacheInitialCapacity())
<< ", max_capacity=" << PrettySize(options->GetCodeCacheMaxCapacity())
@@ -204,12 +195,6 @@
<< ", profile_saver_options=" << options->GetProfileSaverOptions();
- jit->hot_method_threshold_ = options->GetCompileThreshold();
- jit->warm_method_threshold_ = options->GetWarmupThreshold();
- jit->osr_method_threshold_ = options->GetOsrThreshold();
- jit->priority_thread_weight_ = options->GetPriorityThreadWeight();
- jit->invoke_transition_weight_ = options->GetInvokeTransitionWeight();
-
jit->CreateThreadPool();
// Notify native debugger about the classes already loaded before the creation of the jit.
@@ -330,7 +315,7 @@
constexpr bool kJitPoolNeedsPeers = true;
thread_pool_.reset(new ThreadPool("Jit thread pool", 1, kJitPoolNeedsPeers));
- thread_pool_->SetPthreadPriority(kJitPoolThreadPthreadPriority);
+ thread_pool_->SetPthreadPriority(options_->GetThreadPoolPthreadPriority());
Start();
}
@@ -360,8 +345,8 @@
void Jit::StartProfileSaver(const std::string& filename,
const std::vector<std::string>& code_paths) {
- if (profile_saver_options_.IsEnabled()) {
- ProfileSaver::Start(profile_saver_options_,
+ if (options_->GetSaveProfilingInfo()) {
+ ProfileSaver::Start(options_->GetProfileSaverOptions(),
filename,
code_cache_.get(),
code_paths);
@@ -369,8 +354,8 @@
}
void Jit::StopProfileSaver() {
- if (profile_saver_options_.IsEnabled() && ProfileSaver::IsStarted()) {
- ProfileSaver::Stop(dump_info_on_shutdown_);
+ if (options_->GetSaveProfilingInfo() && ProfileSaver::IsStarted()) {
+ ProfileSaver::Stop(options_->DumpJitInfoOnShutdown());
}
}
@@ -383,8 +368,8 @@
}
Jit::~Jit() {
- DCHECK(!profile_saver_options_.IsEnabled() || !ProfileSaver::IsStarted());
- if (dump_info_on_shutdown_) {
+ DCHECK(!options_->GetSaveProfilingInfo() || !ProfileSaver::IsStarted());
+ if (options_->DumpJitInfoOnShutdown()) {
DumpInfo(LOG_STREAM(INFO));
Runtime::Current()->DumpDeoptimizations(LOG_STREAM(INFO));
}
@@ -671,25 +656,25 @@
if (IgnoreSamplesForMethod(method)) {
return;
}
- if (hot_method_threshold_ == 0) {
+ if (HotMethodThreshold() == 0) {
// Tests might request JIT on first use (compiled synchronously in the interpreter).
return;
}
DCHECK(thread_pool_ != nullptr);
- DCHECK_GT(warm_method_threshold_, 0);
- DCHECK_GT(hot_method_threshold_, warm_method_threshold_);
- DCHECK_GT(osr_method_threshold_, hot_method_threshold_);
- DCHECK_GE(priority_thread_weight_, 1);
- DCHECK_LE(priority_thread_weight_, hot_method_threshold_);
+ DCHECK_GT(WarmMethodThreshold(), 0);
+ DCHECK_GT(HotMethodThreshold(), WarmMethodThreshold());
+ DCHECK_GT(OSRMethodThreshold(), HotMethodThreshold());
+ DCHECK_GE(PriorityThreadWeight(), 1);
+ DCHECK_LE(PriorityThreadWeight(), HotMethodThreshold());
- int32_t starting_count = method->GetCounter();
+ uint16_t starting_count = method->GetCounter();
if (Jit::ShouldUsePriorityThreadWeight(self)) {
- count *= priority_thread_weight_;
+ count *= PriorityThreadWeight();
}
- int32_t new_count = starting_count + count; // int32 here to avoid wrap-around;
+ uint32_t new_count = starting_count + count;
// Note: Native method have no "warm" state or profiling info.
- if (LIKELY(!method->IsNative()) && starting_count < warm_method_threshold_) {
- if ((new_count >= warm_method_threshold_) &&
+ if (LIKELY(!method->IsNative()) && starting_count < WarmMethodThreshold()) {
+ if ((new_count >= WarmMethodThreshold()) &&
(method->GetProfilingInfo(kRuntimePointerSize) == nullptr)) {
bool success = ProfilingInfo::Create(self, method, /* retry_allocation */ false);
if (success) {
@@ -710,23 +695,23 @@
}
}
// Avoid jumping more than one state at a time.
- new_count = std::min(new_count, hot_method_threshold_ - 1);
- } else if (use_jit_compilation_) {
- if (starting_count < hot_method_threshold_) {
- if ((new_count >= hot_method_threshold_) &&
+ new_count = std::min(new_count, static_cast<uint32_t>(HotMethodThreshold() - 1));
+ } else if (UseJitCompilation()) {
+ if (starting_count < HotMethodThreshold()) {
+ if ((new_count >= HotMethodThreshold()) &&
!code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
DCHECK(thread_pool_ != nullptr);
thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
}
// Avoid jumping more than one state at a time.
- new_count = std::min(new_count, osr_method_threshold_ - 1);
- } else if (starting_count < osr_method_threshold_) {
+ new_count = std::min(new_count, static_cast<uint32_t>(OSRMethodThreshold() - 1));
+ } else if (starting_count < OSRMethodThreshold()) {
if (!with_backedges) {
// If the samples don't contain any back edge, we don't increment the hotness.
return;
}
DCHECK(!method->IsNative()); // No back edges reported for native methods.
- if ((new_count >= osr_method_threshold_) && !code_cache_->IsOsrCompiled(method)) {
+ if ((new_count >= OSRMethodThreshold()) && !code_cache_->IsOsrCompiled(method)) {
DCHECK(thread_pool_ != nullptr);
thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
}
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 4b8b891..edaf348 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -44,6 +44,110 @@
static constexpr int16_t kJitCheckForOSR = -1;
static constexpr int16_t kJitHotnessDisabled = -2;
+// At what priority to schedule jit threads. 9 is the lowest foreground priority on device.
+// See android/os/Process.java.
+static constexpr int kJitPoolThreadPthreadDefaultPriority = 9;
+
+class JitOptions {
+ public:
+ static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options);
+
+ uint16_t GetCompileThreshold() const {
+ return compile_threshold_;
+ }
+
+ uint16_t GetWarmupThreshold() const {
+ return warmup_threshold_;
+ }
+
+ uint16_t GetOsrThreshold() const {
+ return osr_threshold_;
+ }
+
+ uint16_t GetPriorityThreadWeight() const {
+ return priority_thread_weight_;
+ }
+
+ uint16_t GetInvokeTransitionWeight() const {
+ return invoke_transition_weight_;
+ }
+
+ size_t GetCodeCacheInitialCapacity() const {
+ return code_cache_initial_capacity_;
+ }
+
+ size_t GetCodeCacheMaxCapacity() const {
+ return code_cache_max_capacity_;
+ }
+
+ bool DumpJitInfoOnShutdown() const {
+ return dump_info_on_shutdown_;
+ }
+
+ const ProfileSaverOptions& GetProfileSaverOptions() const {
+ return profile_saver_options_;
+ }
+
+ bool GetSaveProfilingInfo() const {
+ return profile_saver_options_.IsEnabled();
+ }
+
+ int GetThreadPoolPthreadPriority() const {
+ return thread_pool_pthread_priority_;
+ }
+
+ bool UseJitCompilation() const {
+ return use_jit_compilation_;
+ }
+
+ void SetUseJitCompilation(bool b) {
+ use_jit_compilation_ = b;
+ }
+
+ void SetSaveProfilingInfo(bool save_profiling_info) {
+ profile_saver_options_.SetEnabled(save_profiling_info);
+ }
+
+ void SetWaitForJitNotificationsToSaveProfile(bool value) {
+ profile_saver_options_.SetWaitForJitNotificationsToSave(value);
+ }
+
+ void SetProfileAOTCode(bool value) {
+ profile_saver_options_.SetProfileAOTCode(value);
+ }
+
+ void SetJitAtFirstUse() {
+ use_jit_compilation_ = true;
+ compile_threshold_ = 0;
+ }
+
+ private:
+ bool use_jit_compilation_;
+ size_t code_cache_initial_capacity_;
+ size_t code_cache_max_capacity_;
+ uint16_t compile_threshold_;
+ uint16_t warmup_threshold_;
+ uint16_t osr_threshold_;
+ uint16_t priority_thread_weight_;
+ uint16_t invoke_transition_weight_;
+ bool dump_info_on_shutdown_;
+ int thread_pool_pthread_priority_;
+ ProfileSaverOptions profile_saver_options_;
+
+ JitOptions()
+ : use_jit_compilation_(false),
+ code_cache_initial_capacity_(0),
+ code_cache_max_capacity_(0),
+ compile_threshold_(0),
+ warmup_threshold_(0),
+ osr_threshold_(0),
+ priority_thread_weight_(0),
+ invoke_transition_weight_(0),
+ dump_info_on_shutdown_(false),
+ thread_pool_pthread_priority_(kJitPoolThreadPthreadDefaultPriority) {}
+
+ DISALLOW_COPY_AND_ASSIGN(JitOptions);
+};
class Jit {
public:
@@ -77,29 +181,29 @@
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- size_t OSRMethodThreshold() const {
- return osr_method_threshold_;
+ uint16_t OSRMethodThreshold() const {
+ return options_->GetOsrThreshold();
}
- size_t HotMethodThreshold() const {
- return hot_method_threshold_;
+ uint16_t HotMethodThreshold() const {
+ return options_->GetCompileThreshold();
}
- size_t WarmMethodThreshold() const {
- return warm_method_threshold_;
+ uint16_t WarmMethodThreshold() const {
+ return options_->GetWarmupThreshold();
}
uint16_t PriorityThreadWeight() const {
- return priority_thread_weight_;
+ return options_->GetPriorityThreadWeight();
}
// Returns false if we only need to save profile information and not compile methods.
bool UseJitCompilation() const {
- return use_jit_compilation_;
+ return options_->UseJitCompilation();
}
bool GetSaveProfilingInfo() const {
- return profile_saver_options_.IsEnabled();
+ return options_->GetSaveProfilingInfo();
}
// Wait until there is no more pending compilation tasks.
@@ -120,12 +224,12 @@
void NotifyInterpreterToCompiledCodeTransition(Thread* self, ArtMethod* caller)
REQUIRES_SHARED(Locks::mutator_lock_) {
- AddSamples(self, caller, invoke_transition_weight_, false);
+ AddSamples(self, caller, options_->GetInvokeTransitionWeight(), false);
}
void NotifyCompiledCodeToInterpreterTransition(Thread* self, ArtMethod* callee)
REQUIRES_SHARED(Locks::mutator_lock_) {
- AddSamples(self, callee, invoke_transition_weight_, false);
+ AddSamples(self, callee, options_->GetInvokeTransitionWeight(), false);
}
// Starts the profile saver if the config options allow profile recording.
@@ -177,7 +281,7 @@
void Start();
private:
- Jit();
+ explicit Jit(JitOptions* options);
static bool LoadCompiler(std::string* error_msg);
@@ -189,107 +293,22 @@
static bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool);
static void (*jit_types_loaded_)(void*, mirror::Class**, size_t count);
+ // We make this static to simplify the interaction with libart-compiler.so.
+ static bool generate_debug_info_;
+
+ const JitOptions* const options_;
+
+ std::unique_ptr<jit::JitCodeCache> code_cache_;
+ std::unique_ptr<ThreadPool> thread_pool_;
+
// Performance monitoring.
- bool dump_info_on_shutdown_;
CumulativeLogger cumulative_timings_;
Histogram<uint64_t> memory_use_ GUARDED_BY(lock_);
Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- std::unique_ptr<jit::JitCodeCache> code_cache_;
-
- bool use_jit_compilation_;
- ProfileSaverOptions profile_saver_options_;
- static bool generate_debug_info_;
- uint16_t hot_method_threshold_;
- uint16_t warm_method_threshold_;
- uint16_t osr_method_threshold_;
- uint16_t priority_thread_weight_;
- uint16_t invoke_transition_weight_;
- std::unique_ptr<ThreadPool> thread_pool_;
-
DISALLOW_COPY_AND_ASSIGN(Jit);
};
-class JitOptions {
- public:
- static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options);
- size_t GetCompileThreshold() const {
- return compile_threshold_;
- }
- size_t GetWarmupThreshold() const {
- return warmup_threshold_;
- }
- size_t GetOsrThreshold() const {
- return osr_threshold_;
- }
- uint16_t GetPriorityThreadWeight() const {
- return priority_thread_weight_;
- }
- size_t GetInvokeTransitionWeight() const {
- return invoke_transition_weight_;
- }
- size_t GetCodeCacheInitialCapacity() const {
- return code_cache_initial_capacity_;
- }
- size_t GetCodeCacheMaxCapacity() const {
- return code_cache_max_capacity_;
- }
- bool DumpJitInfoOnShutdown() const {
- return dump_info_on_shutdown_;
- }
- const ProfileSaverOptions& GetProfileSaverOptions() const {
- return profile_saver_options_;
- }
- bool GetSaveProfilingInfo() const {
- return profile_saver_options_.IsEnabled();
- }
- bool UseJitCompilation() const {
- return use_jit_compilation_;
- }
- void SetUseJitCompilation(bool b) {
- use_jit_compilation_ = b;
- }
- void SetSaveProfilingInfo(bool save_profiling_info) {
- profile_saver_options_.SetEnabled(save_profiling_info);
- }
- void SetWaitForJitNotificationsToSaveProfile(bool value) {
- profile_saver_options_.SetWaitForJitNotificationsToSave(value);
- }
- void SetProfileAOTCode(bool value) {
- profile_saver_options_.SetProfileAOTCode(value);
- }
-
- void SetJitAtFirstUse() {
- use_jit_compilation_ = true;
- compile_threshold_ = 0;
- }
-
- private:
- bool use_jit_compilation_;
- size_t code_cache_initial_capacity_;
- size_t code_cache_max_capacity_;
- size_t compile_threshold_;
- size_t warmup_threshold_;
- size_t osr_threshold_;
- uint16_t priority_thread_weight_;
- size_t invoke_transition_weight_;
- bool dump_info_on_shutdown_;
- ProfileSaverOptions profile_saver_options_;
-
- JitOptions()
- : use_jit_compilation_(false),
- code_cache_initial_capacity_(0),
- code_cache_max_capacity_(0),
- compile_threshold_(0),
- warmup_threshold_(0),
- osr_threshold_(0),
- priority_thread_weight_(0),
- invoke_transition_weight_(0),
- dump_info_on_shutdown_(false) {}
-
- DISALLOW_COPY_AND_ASSIGN(JitOptions);
-};
-
// Helper class to stop the JIT for a given scope. This will wait for the JIT to quiesce.
class ScopedJitSuspend {
public:
diff --git a/runtime/jvalue-inl.h b/runtime/jvalue-inl.h
index 25e34b2..5bd4f17 100644
--- a/runtime/jvalue-inl.h
+++ b/runtime/jvalue-inl.h
@@ -19,7 +19,7 @@
#include "jvalue.h"
-#include "obj_ptr.h"
+#include "obj_ptr-inl.h"
namespace art {
diff --git a/runtime/jvalue.h b/runtime/jvalue.h
index 266abcf..b42d995 100644
--- a/runtime/jvalue.h
+++ b/runtime/jvalue.h
@@ -33,7 +33,7 @@
// We default initialize JValue instances to all-zeros.
JValue() : j(0) {}
- template<typename T> static JValue FromPrimitive(T v);
+ template<typename T> ALWAYS_INLINE static JValue FromPrimitive(T v);
int8_t GetB() const { return b; }
void SetB(int8_t new_b) {
@@ -62,6 +62,7 @@
mirror::Object* GetL() const REQUIRES_SHARED(Locks::mutator_lock_) {
return l;
}
+ ALWAYS_INLINE
void SetL(ObjPtr<mirror::Object> new_l) REQUIRES_SHARED(Locks::mutator_lock_);
int16_t GetS() const { return s; }
diff --git a/runtime/method_handles-inl.h b/runtime/method_handles-inl.h
index 41c8384..00a8c00 100644
--- a/runtime/method_handles-inl.h
+++ b/runtime/method_handles-inl.h
@@ -22,7 +22,7 @@
#include "common_throws.h"
#include "dex/dex_instruction.h"
#include "interpreter/interpreter_common.h"
-#include "jvalue.h"
+#include "jvalue-inl.h"
#include "mirror/class.h"
#include "mirror/method_type.h"
#include "mirror/object.h"
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 64ab789..1d45aae 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -20,7 +20,6 @@
#include "common_dex_operations.h"
#include "jvalue-inl.h"
-#include "jvalue.h"
#include "mirror/emulated_stack_frame.h"
#include "mirror/method_handle_impl-inl.h"
#include "mirror/method_type.h"
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index b309f59..d31e06c 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1425,21 +1425,24 @@
return GetField32(AccessModesBitMaskOffset());
}
-bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) {
- StackHandleScope<3> hs(Thread::Current());
- Handle<Class> mt_rtype(hs.NewHandle(method_type->GetRType()));
- Handle<VarHandle> vh(hs.NewHandle(this));
- Handle<Class> var_type(hs.NewHandle(vh->GetVarType()));
+VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode access_mode,
+ MethodType* method_type) {
+ MatchKind match = MatchKind::kExact;
+
+ ObjPtr<VarHandle> vh = this;
+ ObjPtr<Class> var_type = vh->GetVarType();
+ ObjPtr<Class> mt_rtype = method_type->GetRType();
AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
- // Check return type first.
- if (mt_rtype->GetPrimitiveType() == Primitive::Type::kPrimVoid) {
- // The result of the operation will be discarded. The return type
- // of the VarHandle is immaterial.
- } else {
- ObjPtr<Class> vh_rtype(GetReturnType(access_mode_template, var_type.Get()));
- if (!IsReturnTypeConvertible(vh_rtype, mt_rtype.Get())) {
- return false;
+ // Check return type first. If the return type of the method
+ // of the VarHandle is immaterial.
+ if (mt_rtype->GetPrimitiveType() != Primitive::Type::kPrimVoid) {
+ ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type.Ptr());
+ if (vh_rtype != mt_rtype) {
+ if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) {
+ return MatchKind::kNone;
+ }
+ match = MatchKind::kWithConversions;
}
}
@@ -1447,21 +1450,25 @@
ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
access_mode_template,
- var_type.Get(),
+ var_type,
GetCoordinateType0(),
GetCoordinateType1());
if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
- return false;
+ return MatchKind::kNone;
}
// Check the parameter types are compatible.
ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
for (int32_t i = 0; i < vh_ptypes_count; ++i) {
- if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) {
- return false;
+ if (mt_ptypes->Get(i) == vh_ptypes[i]) {
+ continue;
}
+ if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) {
+ return MatchKind::kNone;
+ }
+ match = MatchKind::kWithConversions;
}
- return true;
+ return match;
}
bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode,
@@ -1508,7 +1515,7 @@
MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self,
ObjPtr<VarHandle> var_handle,
AccessMode access_mode) {
- // This is a static as the var_handle might be moved by the GC during it's execution.
+ // This is a static method as the var_handle might be moved by the GC during it's execution.
AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
StackHandleScope<3> hs(self);
@@ -1540,7 +1547,7 @@
bool VarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
Class* klass = GetClass();
if (klass == FieldVarHandle::StaticClass()) {
@@ -1671,7 +1678,7 @@
bool FieldVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
ArtField* field = GetField();
@@ -1743,7 +1750,7 @@
bool ArrayElementVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
@@ -1856,7 +1863,7 @@
bool ByteArrayViewVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
@@ -1965,7 +1972,7 @@
bool ByteBufferViewVarHandle::Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result) {
ShadowFrameGetter getter(*shadow_frame, operands);
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index d46d900..eb3704e 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -99,14 +99,16 @@
return (GetAccessModesBitMask() & (1u << static_cast<uint32_t>(accessMode))) != 0;
}
- // Returns true if the MethodType specified is compatible with the
- // method type associated with the specified AccessMode. The
- // supplied MethodType is assumed to be from the point of invocation
- // so it is valid for the supplied MethodType to have a void return
- // value when the return value for the AccessMode is non-void. This
- // corresponds to the result of the accessor being discarded.
- bool IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ enum MatchKind : uint8_t {
+ kNone,
+ kWithConversions,
+ kExact
+ };
+
+ // Returns match information on the compatability between the exact method type for
+ // 'access_mode' and the provided 'method_type'.
+ MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, MethodType* method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if the MethodType specified is compatible with the
// specified access_mode if the first parameter of method_type is
@@ -124,7 +126,7 @@
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -192,7 +194,7 @@
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -225,7 +227,7 @@
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -248,7 +250,7 @@
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -281,7 +283,7 @@
public:
bool Access(AccessMode access_mode,
ShadowFrame* shadow_frame,
- InstructionOperands* operands,
+ const InstructionOperands* const operands,
JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc
index d9fa07f..005aba3 100644
--- a/runtime/mirror/var_handle_test.cc
+++ b/runtime/mirror/var_handle_test.cc
@@ -246,6 +246,47 @@
return MethodType::Create(self, rtype, ptypes);
}
+static bool AccessModeMatch(VarHandle* vh,
+ VarHandle::AccessMode access_mode,
+ MethodType* method_type,
+ VarHandle::MatchKind expected_match)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return vh->GetMethodTypeMatchForAccessMode(access_mode, method_type) == expected_match;
+}
+
+template <typename VH>
+static bool AccessModeExactMatch(Handle<VH> vh,
+ VarHandle::AccessMode access_mode,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return AccessModeMatch(vh.Get(),
+ access_mode,
+ MethodTypeOf(descriptor),
+ VarHandle::MatchKind::kExact);
+}
+
+template <typename VH>
+static bool AccessModeWithConversionsMatch(Handle<VH> vh,
+ VarHandle::AccessMode access_mode,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return AccessModeMatch(vh.Get(),
+ access_mode,
+ MethodTypeOf(descriptor),
+ VarHandle::MatchKind::kWithConversions);
+}
+
+template <typename VH>
+static bool AccessModeNoMatch(Handle<VH> vh,
+ VarHandle::AccessMode access_mode,
+ const char* descriptor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return AccessModeMatch(vh.Get(),
+ access_mode,
+ MethodTypeOf(descriptor),
+ VarHandle::MatchKind::kNone);
+}
+
TEST_F(VarHandleTest, InstanceFieldVarHandle) {
Thread * const self = Thread::Current();
ScopedObjectAccess soa(self);
@@ -296,47 +337,53 @@
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;)D"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;S)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("(Ljava/lang/Integer;II)I")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)Z"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;II)Ljava/lang/Boolean;"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;IB)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;II)I"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIII)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)V"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;II)J"));
+ EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;BS)F"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(IIII)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)S"));
}
// Check synthesized method types match expected forms.
@@ -430,48 +477,47 @@
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "()I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "()V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(F)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(F)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("(II)Ljava/lang/String;")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(ID)I")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIJ)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(ID)I"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)S"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(IIJ)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)I")));
- EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)Z")));
- EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)I"));
+ EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
@@ -594,50 +640,46 @@
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Ljava/lang/String;")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;Ljava/lang/String;)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;I)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;Ljava/lang/String;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(
- vh->IsMethodTypeCompatible(
- access_mode,
- MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("([Ljava/lang/String;III)I")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;III)I"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;II)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;II)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
@@ -747,50 +789,46 @@
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)C")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BC)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BI)C"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BI)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BC)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(
- vh->IsMethodTypeCompatible(
- access_mode,
- MethodTypeOf("([BICC)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("([BIII)I")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BIII)I"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)C")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BII)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)C"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BII)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)C")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)C"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BIC)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
@@ -900,50 +938,46 @@
// Check compatibility - "Get" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)D")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;D)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)D"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;D)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z"));
}
// Check compatibility - "Set" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndSet" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
- EXPECT_TRUE(
- vh->IsMethodTypeCompatible(
- access_mode,
- MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
- MethodTypeOf("(Ljava/nio/ByteBuffer;IDI)D")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDI)D"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V"));
}
// Check compatibility - "CompareAndExchange" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)D")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;II)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)D"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;II)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V"));
}
// Check compatibility - "GetAndUpdate" pattern
{
const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)D")));
- EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)Z")));
- EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)D"));
+ EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)V"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)Z"));
+ EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V"));
}
// Check synthesized method types match expected forms.
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index e0afbee..2559984 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -27,6 +27,7 @@
#include "dex/dex_file-inl.h"
#include "dex/dex_file_annotations.h"
#include "jni/jni_internal.h"
+#include "jvalue-inl.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
#include "native_util.h"
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 3aa481a..7383d47 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -194,6 +194,9 @@
.Define("-Xjittransitionweight:_")
.WithType<unsigned int>()
.IntoKey(M::JITInvokeTransitionWeight)
+ .Define("-Xjitpthreadpriority:_")
+ .WithType<int>()
+ .IntoKey(M::JITPoolThreadPthreadPriority)
.Define("-Xjitsaveprofilinginfo")
.WithType<ProfileSaverOptions>()
.AppendValues()
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index dfa4b3d..66eba1e 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -25,6 +25,7 @@
#include "indirect_reference_table-inl.h"
#include "jni/java_vm_ext.h"
#include "jni/jni_internal.h"
+#include "jvalue-inl.h"
#include "mirror/class-inl.h"
#include "mirror/executable.h"
#include "mirror/object_array-inl.h"
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 427385d..e647423 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -77,6 +77,7 @@
RUNTIME_OPTIONS_KEY (unsigned int, JITOsrThreshold)
RUNTIME_OPTIONS_KEY (unsigned int, JITPriorityThreadWeight)
RUNTIME_OPTIONS_KEY (unsigned int, JITInvokeTransitionWeight)
+RUNTIME_OPTIONS_KEY (int, JITPoolThreadPthreadPriority, jit::kJitPoolThreadPthreadDefaultPriority)
RUNTIME_OPTIONS_KEY (MemoryKiB, JITCodeCacheInitialCapacity, jit::JitCodeCache::kInitialCapacity)
RUNTIME_OPTIONS_KEY (MemoryKiB, JITCodeCacheMaxCapacity, jit::JitCodeCache::kMaxCapacity)
RUNTIME_OPTIONS_KEY (MillisecondsToNanoseconds, \
diff --git a/runtime/var_handles.cc b/runtime/var_handles.cc
new file mode 100644
index 0000000..e6730c6
--- /dev/null
+++ b/runtime/var_handles.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "var_handles.h"
+
+#include "common_throws.h"
+#include "dex/dex_instruction.h"
+#include "handle.h"
+#include "method_handles-inl.h"
+#include "mirror/method_type.h"
+#include "mirror/var_handle.h"
+
+namespace art {
+
+namespace {
+
+bool VarHandleInvokeAccessorWithConversions(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodType> accessor_type(hs.NewHandle(
+ var_handle->GetMethodTypeForAccessMode(self, access_mode)));
+ const size_t num_vregs = accessor_type->NumberOfVRegs();
+ const int num_params = accessor_type->GetPTypes()->GetLength();
+ ShadowFrameAllocaUniquePtr accessor_frame =
+ CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
+ ShadowFrameGetter getter(shadow_frame, operands);
+ static const uint32_t kFirstDestinationReg = 0;
+ ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
+ if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) {
+ return false;
+ }
+ RangeInstructionOperands accessor_operands(kFirstDestinationReg,
+ kFirstDestinationReg + num_vregs);
+ if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
+ return false;
+ }
+ return ConvertReturnValue(callsite_type, accessor_type, result);
+}
+
+} // namespace
+
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result) {
+ if (var_handle.IsNull()) {
+ ThrowNullPointerExceptionFromDexPC();
+ return false;
+ }
+
+ if (!var_handle->IsAccessModeSupported(access_mode)) {
+ ThrowUnsupportedOperationException();
+ return false;
+ }
+
+ mirror::VarHandle::MatchKind match_kind =
+ var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type.Get());
+ if (LIKELY(match_kind == mirror::VarHandle::MatchKind::kExact)) {
+ return var_handle->Access(access_mode, &shadow_frame, operands, result);
+ } else if (match_kind == mirror::VarHandle::MatchKind::kWithConversions) {
+ return VarHandleInvokeAccessorWithConversions(self,
+ shadow_frame,
+ var_handle,
+ callsite_type,
+ access_mode,
+ operands,
+ result);
+ } else {
+ DCHECK_EQ(match_kind, mirror::VarHandle::MatchKind::kNone);
+ ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode),
+ callsite_type.Get());
+ return false;
+ }
+}
+
+} // namespace art
diff --git a/runtime/var_handles.h b/runtime/var_handles.h
new file mode 100644
index 0000000..2ff8405
--- /dev/null
+++ b/runtime/var_handles.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef ART_RUNTIME_VAR_HANDLES_H_
+#define ART_RUNTIME_VAR_HANDLES_H_
+
+#include "mirror/var_handle.h"
+
+namespace art {
+
+bool VarHandleInvokeAccessor(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const mirror::VarHandle::AccessMode access_mode,
+ const InstructionOperands* const operands,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+} // namespace art
+
+#endif // ART_RUNTIME_VAR_HANDLES_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 92ee98a..91cec23 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4210,8 +4210,6 @@
expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name);
} else if (klass == mirror::VarHandle::StaticClass()) {
expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name);
- // TODO: add compiler support for VarHandle accessor methods (b/71781600)
- Fail(VERIFY_ERROR_FORCE_INTERPRETER);
} else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "Signature polymorphic method in unsuppported class: " << klass->PrettyDescriptor();
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 4843061..f7cdf39 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -23,6 +23,8 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "base/enums.h"
+#include "class_linker.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "hidden_api.h"
#include "jni/jni_internal.h"
@@ -30,6 +32,7 @@
#include "mirror/throwable.h"
#include "nativehelper/scoped_local_ref.h"
#include "obj_ptr-inl.h"
+#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
@@ -231,19 +234,28 @@
V(java_lang_String_init_StringBuilder, "(Ljava/lang/StringBuilder;)V", newStringFromStringBuilder, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;", NewStringFromStringBuilder) \
#define STATIC_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, ...) \
- static ArtMethod* init_runtime_name; \
- static ArtMethod* new_runtime_name;
+ static ArtMethod* init_runtime_name = nullptr; \
+ static ArtMethod* new_runtime_name = nullptr;
STRING_INIT_LIST(STATIC_STRING_INIT)
#undef STATIC_STRING_INIT
-void WellKnownClasses::InitStringInit(JNIEnv* env) {
- ScopedObjectAccess soa(Thread::Current());
- #define LOAD_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, \
- new_java_name, new_signature, ...) \
- init_runtime_name = jni::DecodeArtMethod( \
- CacheMethod(env, java_lang_String, false, "<init>", init_signature)); \
- new_runtime_name = jni::DecodeArtMethod( \
- CacheMethod(env, java_lang_StringFactory, true, new_java_name, new_signature));
+void WellKnownClasses::InitStringInit(ObjPtr<mirror::Class> string_class,
+ ObjPtr<mirror::Class> string_builder_class) {
+ PointerSize p_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+ auto find_method = [p_size](ObjPtr<mirror::Class> klass,
+ const char* name,
+ const char* sig,
+ bool expext_static) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* ret = klass->FindClassMethod(name, sig, p_size);
+ CHECK(ret != nullptr);
+ CHECK_EQ(expext_static, ret->IsStatic());
+ return ret;
+ };
+
+ #define LOAD_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, ...) \
+ init_runtime_name = find_method(string_class, "<init>", init_signature, false); \
+ new_runtime_name = find_method(string_builder_class, new_java_name, new_signature, true);
STRING_INIT_LIST(LOAD_STRING_INIT)
#undef LOAD_STRING_INIT
}
@@ -252,6 +264,7 @@
QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
#define SET_ENTRY_POINT(init_runtime_name, init_signature, new_runtime_name, \
new_java_name, new_signature, entry_point_name) \
+ DCHECK(!Runtime::Current()->IsStarted() || (new_runtime_name) != nullptr); \
qpoints->p ## entry_point_name = reinterpret_cast<void(*)()>(new_runtime_name);
STRING_INIT_LIST(SET_ENTRY_POINT)
#undef SET_ENTRY_POINT
@@ -260,7 +273,9 @@
ArtMethod* WellKnownClasses::StringInitToStringFactory(ArtMethod* string_init) {
#define TO_STRING_FACTORY(init_runtime_name, init_signature, new_runtime_name, \
new_java_name, new_signature, entry_point_name) \
+ DCHECK((init_runtime_name) != nullptr); \
if (string_init == (init_runtime_name)) { \
+ DCHECK((new_runtime_name) != nullptr); \
return (new_runtime_name); \
}
STRING_INIT_LIST(TO_STRING_FACTORY)
@@ -410,9 +425,6 @@
java_lang_Integer_valueOf = CachePrimitiveBoxingMethod(env, 'I', "java/lang/Integer");
java_lang_Long_valueOf = CachePrimitiveBoxingMethod(env, 'J', "java/lang/Long");
java_lang_Short_valueOf = CachePrimitiveBoxingMethod(env, 'S', "java/lang/Short");
-
- InitStringInit(env);
- Thread::Current()->InitStringEntryPoints();
}
void WellKnownClasses::LateInit(JNIEnv* env) {
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 25c07b2..c06e4a7 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -40,6 +40,9 @@
static void Clear();
+ static void InitStringInit(ObjPtr<mirror::Class> string_class,
+ ObjPtr<mirror::Class> string_builder_class)
+ REQUIRES_SHARED(Locks::mutator_lock_);
static ArtMethod* StringInitToStringFactory(ArtMethod* method);
static uint32_t StringInitToEntryPoint(ArtMethod* method);
@@ -168,9 +171,6 @@
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_type;
-
- private:
- static void InitStringInit(JNIEnv* env);
};
} // namespace art
diff --git a/simulator/Android.bp b/simulator/Android.bp
index 74b5a90..8690426 100644
--- a/simulator/Android.bp
+++ b/simulator/Android.bp
@@ -44,6 +44,7 @@
defaults: ["libart_simulator_defaults"],
shared_libs: [
"libart",
+ "libartbase",
"libvixl-arm64",
],
}
@@ -56,6 +57,7 @@
],
shared_libs: [
"libartd",
+ "libartbased",
"libvixld-arm64",
],
}
@@ -80,6 +82,7 @@
name: "libart-simulator-container",
defaults: ["libart_simulator_container_defaults"],
shared_libs: [
+ "libartbase",
"libart",
],
}
@@ -91,6 +94,7 @@
"libart_simulator_container_defaults",
],
shared_libs: [
+ "libartbased",
"libartd",
],
}
diff --git a/test/563-checker-fakestring/smali/TestCase.smali b/test/563-checker-fakestring/smali/TestCase.smali
index adafb78..8898c48 100644
--- a/test/563-checker-fakestring/smali/TestCase.smali
+++ b/test/563-checker-fakestring/smali/TestCase.smali
@@ -133,17 +133,8 @@
.end method
-# Test that the compiler does not assume that the first argument of String.<init>
-# is a NewInstance by inserting an irreducible loop between them (b/26676472).
-
-# We verify the type of the input instruction (Phi) in debuggable mode, because
-# it is eliminated by later stages of SsaBuilder otherwise.
-
-## CHECK-START-DEBUGGABLE: java.lang.String TestCase.thisNotNewInstance1(byte[], boolean) register (after)
-## CHECK-DAG: InvokeStaticOrDirect env:[[<<Phi:l\d+>>,{{.*]]}}
-## CHECK-DAG: <<Phi>> Phi
-
-.method public static thisNotNewInstance1([BZ)Ljava/lang/String;
+# Test #1 for irreducible loops and String.<init>.
+.method public static irreducibleLoopAndStringInit1([BZ)Ljava/lang/String;
.registers 5
new-instance v0, Ljava/lang/String;
@@ -164,11 +155,8 @@
.end method
-## CHECK-START-DEBUGGABLE: java.lang.String TestCase.thisNotNewInstance2(byte[], boolean) register (after)
-## CHECK-DAG: InvokeStaticOrDirect env:[[<<Phi:l\d+>>,{{.*]]}}
-## CHECK-DAG: <<Phi>> Phi
-
-.method public static thisNotNewInstance2([BZ)Ljava/lang/String;
+# Test #2 for irreducible loops and String.<init>.
+.method public static irreducibleLoopAndStringInit2([BZ)Ljava/lang/String;
.registers 5
new-instance v0, Ljava/lang/String;
@@ -188,3 +176,26 @@
return-object v0
.end method
+
+# Test #3 for irreducible loops and String.<init> alias.
+.method public static irreducibleLoopAndStringInit3([BZ)Ljava/lang/String;
+ .registers 5
+
+ new-instance v0, Ljava/lang/String;
+ move-object v2, v0
+
+ # Irreducible loop
+ if-eqz p1, :loop_entry
+ :loop_header
+ const v1, 0x1
+ xor-int p1, p1, v1
+ :loop_entry
+ if-eqz p1, :string_init
+ goto :loop_header
+
+ :string_init
+ const-string v1, "UTF8"
+ invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
+ return-object v2
+
+.end method
diff --git a/test/563-checker-fakestring/src/Main.java b/test/563-checker-fakestring/src/Main.java
index 78cb37a..d38b7f4 100644
--- a/test/563-checker-fakestring/src/Main.java
+++ b/test/563-checker-fakestring/src/Main.java
@@ -65,14 +65,21 @@
}
{
- Method m = c.getMethod("thisNotNewInstance1", byte[].class, boolean.class);
+ Method m = c.getMethod("irreducibleLoopAndStringInit1", byte[].class, boolean.class);
String result = (String) m.invoke(null, new Object[] { testData, true });
assertEqual(testString, result);
result = (String) m.invoke(null, new Object[] { testData, false });
assertEqual(testString, result);
}
{
- Method m = c.getMethod("thisNotNewInstance2", byte[].class, boolean.class);
+ Method m = c.getMethod("irreducibleLoopAndStringInit2", byte[].class, boolean.class);
+ String result = (String) m.invoke(null, new Object[] { testData, true });
+ assertEqual(testString, result);
+ result = (String) m.invoke(null, new Object[] { testData, false });
+ assertEqual(testString, result);
+ }
+ {
+ Method m = c.getMethod("irreducibleLoopAndStringInit3", byte[].class, boolean.class);
String result = (String) m.invoke(null, new Object[] { testData, true });
assertEqual(testString, result);
result = (String) m.invoke(null, new Object[] { testData, false });
diff --git a/test/Android.bp b/test/Android.bp
index 84f2e22..7909bf8 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -64,6 +64,7 @@
"libart-gtest",
"libdexfiled",
"libprofiled",
+ "libartbased",
"libbase",
"libicuuc",
@@ -117,6 +118,7 @@
"libartd-compiler",
"libdexfiled",
"libprofiled",
+ "libartbased",
],
static_libs: [
"libgtest",
@@ -156,6 +158,7 @@
"libartd-compiler",
"libdexfiled",
"libprofiled",
+ "libartbased",
"libbase",
"libbacktrace",
],
@@ -187,6 +190,7 @@
"libart",
"libdexfile",
"libprofile",
+ "libartbase",
],
}
@@ -201,6 +205,7 @@
"libartd",
"libdexfiled",
"libprofiled",
+ "libartbased",
],
}
@@ -322,6 +327,7 @@
"libart",
"libdexfile",
"libprofile",
+ "libartbase",
],
}
@@ -335,6 +341,7 @@
"libartd",
"libdexfiled",
"libprofiled",
+ "libartbased",
],
}
@@ -496,6 +503,7 @@
"libart",
"libdexfile",
"libprofile",
+ "libartbase",
],
}
@@ -509,6 +517,7 @@
"libartd",
"libdexfiled",
"libprofiled",
+ "libartbased",
],
}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index fad8011..1ba433e 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -861,9 +861,9 @@
# System libraries needed by libarttestd.so
PUBLIC_LIBS=libc++.so:libbacktrace.so:libbase.so:libnativehelper.so
if [ "$TEST_IS_NDEBUG" = "y" ]; then
- PUBLIC_LIBS=$PUBLIC_LIBS:libart.so:libdexfile.so:libprofile.so
+ PUBLIC_LIBS=$PUBLIC_LIBS:libart.so:libdexfile.so:libprofile.so:libartbase.so
else
- PUBLIC_LIBS=$PUBLIC_LIBS:libartd.so:libdexfiled.so:libprofiled.so
+ PUBLIC_LIBS=$PUBLIC_LIBS:libartd.so:libdexfiled.so:libprofiled.so:libartbased.so
fi
# Create a script with the command. The command can get longer than the longest
diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp
index 39e57bd..23cc917 100644
--- a/tools/cpp-define-generator/Android.bp
+++ b/tools/cpp-define-generator/Android.bp
@@ -31,6 +31,7 @@
include_dirs: [
"art/libartbase",
"art/libdexfile",
+ "art/libartbase",
"art/runtime",
],
srcs: ["main.cc"],
diff --git a/tools/dexanalyze/Android.bp b/tools/dexanalyze/Android.bp
index 2754e64..a229d73 100644
--- a/tools/dexanalyze/Android.bp
+++ b/tools/dexanalyze/Android.bp
@@ -37,6 +37,7 @@
defaults: ["dexanalyze-defaults"],
shared_libs: [
"libdexfile",
+ "libartbase",
"libbase",
],
}
diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc
index c4aebc6..58b1fc7 100644
--- a/tools/dexanalyze/dexanalyze.cc
+++ b/tools/dexanalyze/dexanalyze.cc
@@ -63,6 +63,8 @@
run_all_experiments_ = true;
} else if (arg == "-count-indices") {
exp_count_indices_ = true;
+ } else if (arg == "-analyze-strings") {
+ exp_analyze_strings_ = true;
} else if (arg == "-d") {
dump_per_input_dex_ = true;
} else if (!arg.empty() && arg[0] == '-') {
@@ -82,6 +84,7 @@
bool run_dex_file_verifier_ = true;
bool dump_per_input_dex_ = false;
bool exp_count_indices_ = false;
+ bool exp_analyze_strings_ = false;
bool run_all_experiments_ = false;
std::vector<std::string> filenames_;
};
@@ -92,25 +95,30 @@
if (options->run_all_experiments_ || options->exp_count_indices_) {
experiments_.emplace_back(new CountDexIndices);
}
+ if (options->run_all_experiments_ || options->exp_analyze_strings_) {
+ experiments_.emplace_back(new AnalyzeStrings);
+ }
}
bool ProcessDexFile(const DexFile& dex_file) {
for (std::unique_ptr<Experiment>& experiment : experiments_) {
experiment->ProcessDexFile(dex_file);
}
+ total_size_ += dex_file.Size();
++dex_count_;
return true;
}
void Dump(std::ostream& os) {
for (std::unique_ptr<Experiment>& experiment : experiments_) {
- experiment->Dump(os);
+ experiment->Dump(os, total_size_);
}
}
const Options* const options_;
std::vector<std::unique_ptr<Experiment>> experiments_;
size_t dex_count_ = 0;
+ uint64_t total_size_ = 0u;
};
public:
@@ -130,7 +138,7 @@
// TODO: once added, use an api to android::base to read a std::vector<uint8_t>.
if (!android::base::ReadFileToString(filename.c_str(), &content)) {
LOG(ERROR) << "ReadFileToString failed for " + filename << std::endl;
- continue;
+ return 2;
}
std::vector<std::unique_ptr<const DexFile>> dex_files;
const DexFileLoader dex_file_loader;
@@ -142,14 +150,14 @@
&error_msg,
&dex_files)) {
LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl;
- continue;
+ return 3;
}
for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
if (options.dump_per_input_dex_) {
Analysis current(&options);
if (!current.ProcessDexFile(*dex_file)) {
LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
- continue;
+ return 4;
}
LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl;
current.Dump(LOG_STREAM(INFO));
diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc
index e1f119d..bfeb4b9 100644
--- a/tools/dexanalyze/dexanalyze_experiments.cc
+++ b/tools/dexanalyze/dexanalyze_experiments.cc
@@ -15,12 +15,91 @@
*/
#include "dexanalyze_experiments.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <iostream>
+#include <map>
+#include <vector>
+
+#include "android-base/stringprintf.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_instruction-inl.h"
#include "dex/standard_dex_file.h"
namespace art {
+std::string Percent(uint64_t value, uint64_t max) {
+ if (max == 0) {
+ ++max;
+ }
+ return android::base::StringPrintf("%" PRId64 "(%.2f%%)",
+ value,
+ static_cast<double>(value * 100) / static_cast<double>(max));
+}
+
+static size_t PrefixLen(const std::string& a, const std::string& b) {
+ size_t len = 0;
+ for (; len < a.length() && len < b.length() && a[len] == b[len]; ++len) {}
+ return len;
+}
+
+void AnalyzeStrings::ProcessDexFile(const DexFile& dex_file) {
+ std::vector<std::string> strings;
+ for (size_t i = 0; i < dex_file.NumStringIds(); ++i) {
+ uint32_t length = 0;
+ const char* data =
+ dex_file.GetStringDataAndUtf16Length(dex_file.GetStringId(dex::StringIndex(i)), &length);
+ strings.push_back(data);
+ }
+ // Note that the strings are probably already sorted.
+ std::sort(strings.begin(), strings.end());
+
+ // Tunable parameters.
+ static const size_t kMinPrefixLen = 3;
+ static const size_t kPrefixConstantCost = 5;
+ static const size_t kPrefixIndexCost = 2;
+
+ // Calculate total shared prefix.
+ std::vector<size_t> shared_len;
+ std::set<std::string> prefixes;
+ for (size_t i = 0; i < strings.size(); ++i) {
+ size_t best_len = 0;
+ if (i > 0) {
+ best_len = std::max(best_len, PrefixLen(strings[i], strings[i - 1]));
+ }
+ if (i < strings.size() - 1) {
+ best_len = std::max(best_len, PrefixLen(strings[i], strings[i + 1]));
+ }
+ std::string prefix;
+ if (best_len >= kMinPrefixLen) {
+ prefix = strings[i].substr(0, best_len);
+ prefixes.insert(prefix);
+ total_prefix_savings_ += prefix.length();
+ }
+ total_prefix_index_cost_ += kPrefixIndexCost;
+ }
+ total_num_prefixes_ += prefixes.size();
+ for (const std::string& s : prefixes) {
+ // 4 bytes for an offset, one for length.
+ total_prefix_dict_ += s.length();
+ total_prefix_table_ += kPrefixConstantCost;
+ }
+}
+
+void AnalyzeStrings::Dump(std::ostream& os, uint64_t total_size) const {
+ os << "Total shared prefix bytes " << Percent(total_prefix_savings_, total_size) << "\n";
+ os << "Prefix dictionary cost " << Percent(total_prefix_dict_, total_size) << "\n";
+ os << "Prefix table cost " << Percent(total_prefix_table_, total_size) << "\n";
+ os << "Prefix index cost " << Percent(total_prefix_index_cost_, total_size) << "\n";
+ int64_t net_savings = total_prefix_savings_;
+ net_savings -= total_prefix_dict_;
+ net_savings -= total_prefix_table_;
+ net_savings -= total_prefix_index_cost_;
+ os << "Prefix net savings " << Percent(net_savings, total_size) << "\n";
+ os << "Prefix dictionary elements " << total_num_prefixes_ << "\n";
+}
+
void CountDexIndices::ProcessDexFile(const DexFile& dex_file) {
num_string_ids_ += dex_file.NumStringIds();
num_method_ids_ += dex_file.NumMethodIds();
@@ -107,7 +186,7 @@
}
}
-void CountDexIndices::Dump(std::ostream& os) const {
+void CountDexIndices::Dump(std::ostream& os, uint64_t total_size) const {
os << "Num string ids: " << num_string_ids_ << "\n";
os << "Num method ids: " << num_method_ids_ << "\n";
os << "Num field ids: " << num_field_ids_ << "\n";
@@ -127,6 +206,7 @@
os << "Same class invoke: " << same_class_total << "\n";
os << "Other class invoke: " << other_class_total << "\n";
os << "Invokes from code: " << (same_class_total + other_class_total) << "\n";
+ os << "Total dex size: " << total_size << "\n";
}
} // namespace art
diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h
index 5d0f51b..6f70f5d 100644
--- a/tools/dexanalyze/dexanalyze_experiments.h
+++ b/tools/dexanalyze/dexanalyze_experiments.h
@@ -24,12 +24,28 @@
class DexFile;
+std::string Percent(uint64_t value, uint64_t max);
+
// An experiment a stateful visitor that runs on dex files. Results are cumulative.
class Experiment {
public:
virtual ~Experiment() {}
virtual void ProcessDexFile(const DexFile& dex_file) = 0;
- virtual void Dump(std::ostream& os) const = 0;
+ virtual void Dump(std::ostream& os, uint64_t total_size) const = 0;
+};
+
+// Analyze string data and strings accessed from code.
+class AnalyzeStrings : public Experiment {
+ public:
+ void ProcessDexFile(const DexFile& dex_file);
+ void Dump(std::ostream& os, uint64_t total_size) const;
+
+ private:
+ int64_t total_prefix_savings_ = 0u;
+ int64_t total_prefix_dict_ = 0u;
+ int64_t total_prefix_table_ = 0u;
+ int64_t total_prefix_index_cost_ = 0u;
+ int64_t total_num_prefixes_ = 0u;
};
// Count numbers of dex indices.
@@ -37,7 +53,7 @@
public:
void ProcessDexFile(const DexFile& dex_file);
- void Dump(std::ostream& os) const;
+ void Dump(std::ostream& os, uint64_t total_size) const;
private:
// Total string ids loaded from dex code.
@@ -65,4 +81,3 @@
} // namespace art
#endif // ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_
-
diff --git a/tools/dexanalyze/dexanalyze_test.cc b/tools/dexanalyze/dexanalyze_test.cc
index c9b8f53..96be3f9 100644
--- a/tools/dexanalyze/dexanalyze_test.cc
+++ b/tools/dexanalyze/dexanalyze_test.cc
@@ -36,10 +36,22 @@
}
};
+TEST_F(DexAnalyzeTest, NoInputFileGiven) {
+ DexAnalyzeExec({ "-a" }, /*expect_success*/ false);
+}
+
+TEST_F(DexAnalyzeTest, CantOpenInput) {
+ DexAnalyzeExec({ "-a", "/non/existent/path" }, /*expect_success*/ false);
+}
+
TEST_F(DexAnalyzeTest, TestAnalyzeMultidex) {
DexAnalyzeExec({ "-a", GetTestDexFileName("MultiDex") }, /*expect_success*/ true);
}
+TEST_F(DexAnalyzeTest, TestAnalizeCoreDex) {
+ DexAnalyzeExec({ "-a", GetLibCoreDexFileNames()[0] }, /*expect_success*/ true);
+}
+
TEST_F(DexAnalyzeTest, TestInvalidArg) {
DexAnalyzeExec({ "-invalid-option" }, /*expect_success*/ false);
}
diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp
index af87d31..3b364b6 100644
--- a/tools/hiddenapi/Android.bp
+++ b/tools/hiddenapi/Android.bp
@@ -40,6 +40,7 @@
shared_libs: [
"libart",
"libdexfile",
+ "libartbase",
],
}
@@ -52,6 +53,7 @@
shared_libs: [
"libartd",
"libdexfiled",
+ "libartbased",
],
}
diff --git a/tools/public.libraries.buildbot.txt b/tools/public.libraries.buildbot.txt
index 6c81145..9b171a2 100644
--- a/tools/public.libraries.buildbot.txt
+++ b/tools/public.libraries.buildbot.txt
@@ -1,5 +1,7 @@
libart.so
libartd.so
+libartbase.so
+libartbased.so
libdexfile.so
libdexfiled.so
libbacktrace.so
diff --git a/tools/ti-fast/tifast.cc b/tools/ti-fast/tifast.cc
index 952fba8..428304e 100644
--- a/tools/ti-fast/tifast.cc
+++ b/tools/ti-fast/tifast.cc
@@ -62,7 +62,7 @@
#define FOR_ALL_SUPPORTED_EVENTS(fun) \
fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation)) \
fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv*, JNIEnv*, jthread, jmethodID)) \
- fun(MethodExit, EVENT(METHOD_ENTRY), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jboolean, jvalue)) \
+ fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jboolean, jvalue)) \
fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, void*, void**)) \
fun(Exception, EVENT(EXCEPTION), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject, jmethodID, jlocation)) \
fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject)) \
diff --git a/tools/veridex/Android.bp b/tools/veridex/Android.bp
index 570960c..5186c43 100644
--- a/tools/veridex/Android.bp
+++ b/tools/veridex/Android.bp
@@ -24,7 +24,11 @@
"veridex.cc",
],
cflags: ["-Wall", "-Werror"],
- shared_libs: ["libdexfile", "libbase"],
+ shared_libs: [
+ "libdexfile",
+ "libartbase",
+ "libbase",
+ ],
header_libs: [
"art_libartbase_headers",
],