summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.bp1
-rw-r--r--build/apex/Android.bp43
-rwxr-xr-xbuild/apex/runtests.sh234
-rw-r--r--build/art.go32
-rw-r--r--compiler/common_compiler_test.cc50
-rw-r--r--compiler/common_compiler_test.h8
-rw-r--r--compiler/debug/elf_debug_writer.cc2
-rw-r--r--compiler/debug/xz_utils.cc63
-rw-r--r--compiler/debug/xz_utils.h3
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc2
-rw-r--r--compiler/dex/dex_to_dex_decompiler_test.cc7
-rw-r--r--compiler/dex/verification_results.cc6
-rw-r--r--compiler/dex/verification_results.h12
-rw-r--r--compiler/driver/compiler_driver-inl.h5
-rw-r--r--compiler/driver/compiler_driver.cc93
-rw-r--r--compiler/driver/compiler_driver.h47
-rw-r--r--compiler/driver/compiler_driver_test.cc18
-rw-r--r--compiler/driver/compiler_options.cc42
-rw-r--r--compiler/driver/compiler_options.h15
-rw-r--r--compiler/jit/jit_compiler.cc2
-rw-r--r--compiler/optimizing/inliner.cc17
-rw-r--r--compiler/optimizing/inliner.h3
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc145
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc1
-rw-r--r--compiler/optimizing/intrinsics_mips.cc1
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc1
-rw-r--r--compiler/optimizing/intrinsics_x86.cc1
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc1
-rw-r--r--compiler/optimizing/optimization.cc2
-rw-r--r--compiler/optimizing/optimization.h1
-rw-r--r--compiler/optimizing/optimizing_compiler.cc20
-rw-r--r--compiler/verifier_deps_test.cc6
-rw-r--r--dex2oat/dex2oat.cc12
-rw-r--r--dex2oat/linker/image_test.h6
-rw-r--r--dex2oat/linker/oat_writer.cc2
-rw-r--r--dex2oat/linker/oat_writer_test.cc8
-rw-r--r--runtime/class_linker.cc8
-rw-r--r--runtime/class_loader_utils.h11
-rw-r--r--runtime/hidden_api.h1
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/interpreter/interpreter_intrinsics.cc1
-rw-r--r--runtime/intrinsics_list.h1
-rw-r--r--runtime/jit/jit.cc102
-rw-r--r--runtime/jit/jit.h10
-rw-r--r--runtime/jit/jit_code_cache.cc47
-rw-r--r--runtime/jit/jit_code_cache.h10
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc10
-rw-r--r--runtime/runtime.cc15
-rw-r--r--runtime/runtime.h1
-rw-r--r--runtime/thread_pool.cc49
-rw-r--r--runtime/thread_pool.h8
-rw-r--r--runtime/well_known_classes.cc2
-rw-r--r--runtime/well_known_classes.h1
-rw-r--r--test/580-crc32/src/Main.java361
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java36
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java2
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/RepeatedAnnotationHandler.java (renamed from tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java)30
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java120
-rw-r--r--tools/class2greylist/test/src/com/android/class2greylist/RepeatedAnnotationHandlerTest.java95
59 files changed, 1275 insertions, 560 deletions
diff --git a/build/Android.bp b/build/Android.bp
index 09d3a183f9..46fb0c5b97 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -7,6 +7,7 @@ bootstrap_go_package {
"blueprint-proptools",
"soong",
"soong-android",
+ "soong-apex",
"soong-cc",
],
srcs: [
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index f1a21e8428..88178a013e 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -49,10 +49,13 @@ art_runtime_debug_native_shared_libs = [
]
// Modules listed in LOCAL_REQUIRED_MODULES for module art-tools in art/Android.mk.
-art_tools_binaries = [
+art_tools_common_binaries = [
"dexdiag",
"dexdump",
"dexlist",
+]
+
+art_tools_device_binaries = [
"oatdump",
]
@@ -66,6 +69,8 @@ art_tools_host_binaries = [
// ...
]
+art_tools_binaries = art_tools_common_binaries + art_tools_device_binaries
+
apex_key {
name: "com.android.runtime.key",
public_key: "com.android.runtime.avbpubkey",
@@ -135,3 +140,39 @@ apex {
prebuilts: ["com.android.runtime.ld.config.txt"],
key: "com.android.runtime.key",
}
+
+// TODO: Do this better. art_apex will disable host builds when
+// HOST_PREFER_32_BIT is set. We cannot simply use com.android.runtime.debug
+// because binaries have different multilib classes and 'multilib: {}' isn't
+// supported by target: { ... }.
+// See b/120617876 for more information.
+art_apex {
+ name: "com.android.runtime.host",
+ compile_multilib: "both",
+ payload_type: "zip",
+ host_supported: true,
+ device_supported: false,
+ manifest: "manifest.json",
+ native_shared_libs: art_runtime_base_native_shared_libs
+ + art_runtime_fake_native_shared_libs
+ + art_runtime_debug_native_shared_libs,
+ multilib: {
+ both: {
+ // TODO: Add logic to create a `dalvikvm` symlink to `dalvikvm32` or `dalvikvm64`
+ // (see `symlink_preferred_arch` in art/dalvikvm/Android.bp).
+ binaries: art_runtime_base_binaries_both,
+ },
+ first: {
+ // TODO: oatdump cannot link with host linux_bionic due to not using clang ld
+ binaries: art_tools_common_binaries
+ + art_runtime_base_binaries_prefer32
+ + art_runtime_debug_binaries_prefer32,
+ }
+ },
+ key: "com.android.runtime.key",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index 86cd8cb758..c19c7bd94c 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -69,29 +69,129 @@ done
work_dir=$(mktemp -d)
mount_point="$work_dir/image"
+function check_binary {
+ [[ -x "$mount_point/bin/$1" ]] || die "Cannot find binary '$1' in mounted image"
+}
+
+function check_multilib_binary {
+ # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
+ # the precision of this test?
+ [[ -x "$mount_point/bin/${1}32" ]] || [[ -x "$mount_point/bin/${1}64" ]] \
+ || die "Cannot find binary '$1' in mounted image"
+}
+
+function check_binary_symlink {
+ [[ -h "$mount_point/bin/$1" ]] || die "Cannot find symbolic link '$1' in mounted image"
+}
+
+function check_library {
+ # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
+ # the precision of this test?
+ [[ -f "$mount_point/lib/$1" ]] || [[ -f "$mount_point/lib64/$1" ]] \
+ || die "Cannot find library '$1' in mounted image"
+}
+
+function build_apex {
+ if $build_apex_p; then
+ say "Building package $1" && make "$1" || die "Cannot build $1"
+ fi
+}
+
+function check_contents {
+
+ # Check that the mounted image contains a manifest.
+ [[ -f "$mount_point/apex_manifest.json" ]] || die "no manifest"
+
+ # Check that the mounted image contains ART base binaries.
+ check_multilib_binary dalvikvm
+ # TODO: Does not work yet.
+ : check_binary_symlink dalvikvm
+ check_binary dex2oat
+ check_binary dexoptanalyzer
+ check_binary profman
+
+ # Check that the mounted image contains ART tools binaries.
+ check_binary dexdiag
+ check_binary dexdump
+ check_binary dexlist
+ # oatdump is only in device apex's due to build rules
+ # check_binary oatdump
+
+ # Check that the mounted image contains ART debug binaries.
+ check_binary dex2oatd
+ check_binary dexoptanalyzerd
+ check_binary profmand
+
+ # Check that the mounted image contains ART libraries.
+ check_library libart-compiler.so
+ check_library libart.so
+ check_library libopenjdkjvm.so
+ check_library libopenjdkjvmti.so
+ check_library libadbconnection.so
+ # TODO: Should we check for these libraries too, even if they are not explicitly
+ # listed as dependencies in the Android Runtime APEX module rule?
+ check_library libartbase.so
+ check_library libart-dexlayout.so
+ check_library libdexfile.so
+ check_library libprofile.so
+
+ # Check that the mounted image contains ART debug libraries.
+ check_library libartd-compiler.so
+ check_library libartd.so
+ check_library libopenjdkd.so
+ check_library libopenjdkjvmd.so
+ check_library libopenjdkjvmtid.so
+ check_library libadbconnectiond.so
+ # TODO: Should we check for these libraries too, even if they are not explicitly
+ # listed as dependencies in the Android Runtime APEX module rule?
+ check_library libdexfiled.so
+ check_library libartbased.so
+ check_library libartd-dexlayout.so
+ check_library libprofiled.so
+
+ # TODO: Should we check for other libraries, such as:
+ #
+ # libbacktrace.so
+ # libbase.so
+ # liblog.so
+ # libsigchain.so
+ # libtombstoned_client.so
+ # libunwindstack.so
+ # libvixl.so
+ # libvixld.so
+ # ...
+ #
+ # ?
+}
+
+
+# *****************************************
+# * Testing for com.android.runtime.debug *
+# *****************************************
+
# Garbage collection.
-function finish {
+function finish_device_debug {
# Don't fail early during cleanup.
set +e
guestunmount "$mount_point"
rm -rf "$work_dir"
}
-trap finish EXIT
+trap finish_device_debug EXIT
# TODO: Also exercise the Release Runtime APEX (`com.android.runtime.release`).
apex_module="com.android.runtime.debug"
# Build the Android Runtime APEX package (optional).
-$build_apex_p && say "Building package" && make "$apex_module"
+build_apex $apex_module
system_apexdir="$ANDROID_PRODUCT_OUT/system/apex"
apex_package="$system_apexdir/$apex_module.apex"
say "Extracting and mounting image"
-# Extract the image from the Android Runtime APEX.
-image_filename="image.img"
+# Extract the payload from the Android Runtime APEX.
+image_filename="apex_payload.img"
unzip -q "$apex_package" "$image_filename" -d "$work_dir"
mkdir "$mount_point"
image_file="$work_dir/$image_filename"
@@ -111,90 +211,58 @@ $list_image_files_p && say "Listing image files" && ls -ld "$mount_point" && tre
say "Running tests"
-# Check that the mounted image contains a manifest.
-[[ -f "$mount_point/manifest.json" ]]
+check_contents
-function check_binary {
- [[ -x "$mount_point/bin/$1" ]] || die "Cannot find binary '$1' in mounted image"
-}
+# Check for files pulled in from device-only oatdump.
+check_binary oatdump
+check_library libart-disassembler.so
-function check_multilib_binary {
- # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
- # the precision of this test?
- [[ -x "$mount_point/bin/${1}32" ]] || [[ -x "$mount_point/bin/${1}64" ]] \
- || die "Cannot find binary '$1' in mounted image"
-}
+# Cleanup
+trap - EXIT
+guestunmount "$mount_point"
+rm -rf "$work_dir"
-function check_binary_symlink {
- [[ -h "$mount_point/bin/$1" ]] || die "Cannot find symbolic link '$1' in mounted image"
-}
+say "$apex_module Tests passed"
-function check_library {
- # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
- # the precision of this test?
- [[ -f "$mount_point/lib/$1" ]] || [[ -f "$mount_point/lib64/$1" ]] \
- || die "Cannot find library '$1' in mounted image"
+# ****************************************
+# * Testing for com.android.runtime.host *
+# ****************************************
+
+# Garbage collection.
+function finish_host {
+ # Don't fail early during cleanup.
+ set +e
+ rm -rf "$work_dir"
}
-# Check that the mounted image contains ART base binaries.
-check_multilib_binary dalvikvm
-# TODO: Does not work yet.
-: check_binary_symlink dalvikvm
-check_binary dex2oat
-check_binary dexoptanalyzer
-check_binary profman
-
-# Check that the mounted image contains ART tools binaries.
-check_binary dexdiag
-check_binary dexdump
-check_binary dexlist
-check_binary oatdump
+work_dir=$(mktemp -d)
+mount_point="$work_dir/zip"
-# Check that the mounted image contains ART debug binaries.
-check_binary dex2oatd
-check_binary dexoptanalyzerd
-check_binary profmand
-
-# Check that the mounted image contains ART libraries.
-check_library libart-compiler.so
-check_library libart.so
-check_library libopenjdkjvm.so
-check_library libopenjdkjvmti.so
-check_library libadbconnection.so
-# TODO: Should we check for these libraries too, even if they are not explicitly
-# listed as dependencies in the Android Runtime APEX module rule?
-check_library libartbase.so
-check_library libart-dexlayout.so
-check_library libart-disassembler.so
-check_library libdexfile.so
-check_library libprofile.so
-
-# Check that the mounted image contains ART debug libraries.
-check_library libartd-compiler.so
-check_library libartd.so
-check_library libdexfiled.so
-check_library libopenjdkd.so
-check_library libopenjdkjvmd.so
-check_library libopenjdkjvmtid.so
-check_library libadbconnectiond.so
-# TODO: Should we check for these libraries too, even if they are not explicitly
-# listed as dependencies in the Android Runtime APEX module rule?
-check_library libartbased.so
-check_library libartd-dexlayout.so
-check_library libprofiled.so
-
-# TODO: Should we check for other libraries, such as:
-#
-# libbacktrace.so
-# libbase.so
-# liblog.so
-# libsigchain.so
-# libtombstoned_client.so
-# libunwindstack.so
-# libvixl.so
-# libvixld.so
-# ...
-#
-# ?
+trap finish_host EXIT
+
+apex_module="com.android.runtime.host"
+
+# Build the Android Runtime APEX package (optional).
+build_apex $apex_module
+
+system_apexdir="$ANDROID_HOST_OUT/apex"
+apex_package="$system_apexdir/$apex_module.zipapex"
+
+say "Extracting payload"
+
+# Extract the payload from the Android Runtime APEX.
+image_filename="apex_payload.zip"
+unzip -q "$apex_package" "$image_filename" -d "$work_dir"
+mkdir "$mount_point"
+image_file="$work_dir/$image_filename"
+
+# Unzipping the payload
+unzip -q "$image_file" -d "$mount_point"
+
+say "Running tests"
+
+check_contents
+
+say "$apex_module Tests passed"
say "Tests passed"
diff --git a/build/art.go b/build/art.go
index 1c8be0f056..01848c88a7 100644
--- a/build/art.go
+++ b/build/art.go
@@ -16,8 +16,10 @@ package art
import (
"android/soong/android"
+ "android/soong/apex"
"android/soong/cc"
"fmt"
+ "log"
"sync"
"github.com/google/blueprint/proptools"
@@ -289,6 +291,36 @@ func init() {
android.RegisterModuleType("libart_static_cc_defaults", libartStaticDefaultsFactory)
android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
+
+ // TODO: This makes the module disable itself for host if HOST_PREFER_32_BIT is
+ // set. We need this because the multilib types of binaries listed in the apex
+ // rule must match the declared type. This is normally not difficult but HOST_PREFER_32_BIT
+ // changes this to 'prefer32' on all host binaries. Since HOST_PREFER_32_BIT is
+ // only used for testing we can just disable the module.
+ // See b/120617876 for more information.
+ android.RegisterModuleType("art_apex", artApexBundleFactory)
+}
+
+func artApexBundleFactory() android.Module {
+ module := apex.ApexBundleFactory()
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ if envTrue(ctx, "HOST_PREFER_32_BIT") {
+ type props struct {
+ Target struct {
+ Host struct {
+ Enabled *bool
+ }
+ }
+ }
+
+ p := &props{}
+ p.Target.Host.Enabled = proptools.BoolPtr(false)
+ ctx.AppendProperties(p)
+ log.Print("Disabling host build of " + ctx.ModuleName() + " for HOST_PREFER_32_BIT=true")
+ }
+ })
+
+ return module
}
func artGlobalDefaultsFactory() android.Module {
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 66421e2562..be6da714eb 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -22,6 +22,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/callee_save_type.h"
+#include "base/casts.h"
#include "base/enums.h"
#include "base/utils.h"
#include "class_linker.h"
@@ -152,6 +153,10 @@ void CommonCompilerTest::SetUp() {
CreateCompilerDriver();
}
+ // Note: We cannot use MemMap because some tests tear down the Runtime and destroy
+ // the gMaps, so when destroying the MemMap, the test would crash.
+ inaccessible_page_ = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ CHECK(inaccessible_page_ != MAP_FAILED) << strerror(errno);
}
void CommonCompilerTest::ApplyInstructionSet() {
@@ -190,9 +195,7 @@ void CommonCompilerTest::CreateCompilerDriver() {
compiler_options_->image_classes_.swap(*GetImageClasses());
compiler_options_->profile_compilation_info_ = GetProfileCompilationInfo();
compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
- verification_results_.get(),
compiler_kind_,
- &compiler_options_->image_classes_,
number_of_threads_,
/* swap_fd */ -1));
}
@@ -222,6 +225,10 @@ void CommonCompilerTest::TearDown() {
verification_results_.reset();
compiler_options_.reset();
image_reservation_.Reset();
+ if (inaccessible_page_ != nullptr) {
+ munmap(inaccessible_page_, kPageSize);
+ inaccessible_page_ = nullptr;
+ }
CommonRuntimeTest::TearDown();
}
@@ -267,8 +274,16 @@ void CommonCompilerTest::CompileMethod(ArtMethod* method) {
compiler_driver_->InitializeThreadPools();
- compiler_driver_->PreCompile(class_loader, dex_files, &timings);
+ compiler_driver_->PreCompile(class_loader,
+ dex_files,
+ &timings,
+ &compiler_options_->image_classes_,
+ verification_results_.get());
+ // Verification results in the `callback_` should not be used during compilation.
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ reinterpret_cast<VerificationResults*>(inaccessible_page_));
+ compiler_options_->verification_results_ = verification_results_.get();
compiler_driver_->CompileOne(self,
class_loader,
*dex_file,
@@ -279,6 +294,9 @@ void CommonCompilerTest::CompileMethod(ArtMethod* method) {
code_item,
dex_cache,
h_class_loader);
+ compiler_options_->verification_results_ = nullptr;
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ verification_results_.get());
compiler_driver_->FreeThreadPools();
@@ -334,6 +352,32 @@ void CommonCompilerTest::ReserveImageSpace() {
CHECK(image_reservation_.IsValid()) << error_msg;
}
+void CommonCompilerTest::CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ TimingLogger::ScopedTiming t(__FUNCTION__, timings);
+ SetDexFilesForOatFile(dex_files);
+
+ compiler_driver_->InitializeThreadPools();
+
+ compiler_driver_->PreCompile(class_loader,
+ dex_files,
+ timings,
+ &compiler_options_->image_classes_,
+ verification_results_.get());
+
+ // Verification results in the `callback_` should not be used during compilation.
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ reinterpret_cast<VerificationResults*>(inaccessible_page_));
+ compiler_options_->verification_results_ = verification_results_.get();
+ compiler_driver_->CompileAll(class_loader, dex_files, timings);
+ compiler_options_->verification_results_ = nullptr;
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ verification_results_.get());
+
+ compiler_driver_->FreeThreadPools();
+}
+
void CommonCompilerTest::UnreserveImageSpace() {
image_reservation_.Reset();
}
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index e6d1564621..a71908e6c8 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -20,6 +20,8 @@
#include <list>
#include <vector>
+#include <jni.h>
+
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
#include "base/hash_set.h"
@@ -37,6 +39,7 @@ class CompilerOptions;
class CumulativeLogger;
class DexFile;
class ProfileCompilationInfo;
+class TimingLogger;
class VerificationResults;
template<class T> class Handle;
@@ -88,6 +91,10 @@ class CommonCompilerTest : public CommonRuntimeTest {
const char* method_name, const char* signature)
REQUIRES_SHARED(Locks::mutator_lock_);
+ void CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
+
void ApplyInstructionSet();
void OverrideInstructionSetFeatures(InstructionSet instruction_set, const std::string& variant);
@@ -116,6 +123,7 @@ class CommonCompilerTest : public CommonRuntimeTest {
private:
MemMap image_reservation_;
+ void* inaccessible_page_;
// Chunks must not move their storage after being created - use the node-based std::list.
std::list<std::vector<uint8_t>> header_code_and_maps_chunks_;
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index baf8643e9b..1ecb1d8ed9 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -138,7 +138,7 @@ static std::vector<uint8_t> MakeMiniDebugInfoInternal(
CHECK(builder->Good());
std::vector<uint8_t> compressed_buffer;
compressed_buffer.reserve(buffer.size() / 4);
- XzCompress(ArrayRef<uint8_t>(buffer), &compressed_buffer);
+ XzCompress(ArrayRef<const uint8_t>(buffer), &compressed_buffer);
return compressed_buffer;
}
diff --git a/compiler/debug/xz_utils.cc b/compiler/debug/xz_utils.cc
index a9e30a6970..a8f60ac280 100644
--- a/compiler/debug/xz_utils.cc
+++ b/compiler/debug/xz_utils.cc
@@ -17,13 +17,16 @@
#include "xz_utils.h"
#include <vector>
+#include <mutex>
#include "base/array_ref.h"
-#include "dwarf/writer.h"
+#include "base/bit_utils.h"
#include "base/leb128.h"
+#include "dwarf/writer.h"
// liblzma.
#include "7zCrc.h"
+#include "Xz.h"
#include "XzCrc64.h"
#include "XzEnc.h"
@@ -32,10 +35,17 @@ namespace debug {
constexpr size_t kChunkSize = kPageSize;
-static void XzCompressChunk(ArrayRef<uint8_t> src, std::vector<uint8_t>* dst) {
+static void XzInitCrc() {
+ static std::once_flag crc_initialized;
+ std::call_once(crc_initialized, []() {
+ CrcGenerateTable();
+ Crc64GenerateTable();
+ });
+}
+
+static void XzCompressChunk(ArrayRef<const uint8_t> src, std::vector<uint8_t>* dst) {
// Configure the compression library.
- CrcGenerateTable();
- Crc64GenerateTable();
+ XzInitCrc();
CLzma2EncProps lzma2Props;
Lzma2EncProps_Init(&lzma2Props);
lzma2Props.lzmaProps.level = 1; // Fast compression.
@@ -62,7 +72,7 @@ static void XzCompressChunk(ArrayRef<uint8_t> src, std::vector<uint8_t>* dst) {
return SZ_OK;
}
size_t src_pos_;
- ArrayRef<uint8_t> src_;
+ ArrayRef<const uint8_t> src_;
std::vector<uint8_t>* dst_;
};
XzCallbacks callbacks;
@@ -85,7 +95,7 @@ static void XzCompressChunk(ArrayRef<uint8_t> src, std::vector<uint8_t>* dst) {
// In short, the file format is: [header] [compressed_block]* [index] [footer]
// Where [index] is: [num_records] ([compressed_size] [uncompressed_size])* [crc32]
//
-void XzCompress(ArrayRef<uint8_t> src, std::vector<uint8_t>* dst) {
+void XzCompress(ArrayRef<const uint8_t> src, std::vector<uint8_t>* dst) {
uint8_t header[] = { 0xFD, '7', 'z', 'X', 'Z', 0, 0, 1, 0x69, 0x22, 0xDE, 0x36 };
uint8_t footer[] = { 0, 1, 'Y', 'Z' };
dst->insert(dst->end(), header, header + sizeof(header));
@@ -138,6 +148,47 @@ void XzCompress(ArrayRef<uint8_t> src, std::vector<uint8_t>* dst) {
writer.UpdateUint32(0, CrcCalc(tmp.data() + 4, 6));
dst->insert(dst->end(), tmp.begin(), tmp.end());
}
+
+ // Decompress the data back and check that we get the original.
+ if (kIsDebugBuild) {
+ std::vector<uint8_t> decompressed;
+ XzDecompress(ArrayRef<const uint8_t>(*dst), &decompressed);
+ DCHECK_EQ(decompressed.size(), src.size());
+ DCHECK_EQ(memcmp(decompressed.data(), src.data(), src.size()), 0);
+ }
+}
+
+void XzDecompress(ArrayRef<const uint8_t> src, std::vector<uint8_t>* dst) {
+ XzInitCrc();
+ std::unique_ptr<CXzUnpacker> state(new CXzUnpacker());
+ ISzAlloc alloc;
+ alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
+ alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
+ XzUnpacker_Construct(state.get(), &alloc);
+
+ size_t src_offset = 0;
+ size_t dst_offset = 0;
+ ECoderStatus status;
+ do {
+ dst->resize(RoundUp(dst_offset + kPageSize / 4, kPageSize));
+ size_t src_remaining = src.size() - src_offset;
+ size_t dst_remaining = dst->size() - dst_offset;
+ int return_val = XzUnpacker_Code(state.get(),
+ dst->data() + dst_offset,
+ &dst_remaining,
+ src.data() + src_offset,
+ &src_remaining,
+ true,
+ CODER_FINISH_ANY,
+ &status);
+ CHECK_EQ(return_val, SZ_OK);
+ src_offset += src_remaining;
+ dst_offset += dst_remaining;
+ } while (status == CODER_STATUS_NOT_FINISHED);
+ CHECK_EQ(src_offset, src.size());
+ CHECK(XzUnpacker_IsStreamWasFinished(state.get()));
+ XzUnpacker_Free(state.get());
+ dst->resize(dst_offset);
}
} // namespace debug
diff --git a/compiler/debug/xz_utils.h b/compiler/debug/xz_utils.h
index c4076c6581..731b03c7e1 100644
--- a/compiler/debug/xz_utils.h
+++ b/compiler/debug/xz_utils.h
@@ -24,7 +24,8 @@
namespace art {
namespace debug {
-void XzCompress(ArrayRef<uint8_t> src, std::vector<uint8_t>* dst);
+void XzCompress(ArrayRef<const uint8_t> src, std::vector<uint8_t>* dst);
+void XzDecompress(ArrayRef<const uint8_t> src, std::vector<uint8_t>* dst);
} // namespace debug
} // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 04ad10c41e..c124ef5dde 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -528,7 +528,7 @@ CompiledMethod* DexToDexCompiler::CompileMethod(
class_def_idx,
method_idx,
access_flags,
- driver_->GetVerifiedMethod(&dex_file, method_idx),
+ driver_->GetCompilerOptions().GetVerifiedMethod(&dex_file, method_idx),
hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
std::vector<uint8_t> quicken_data;
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index f61e6c4848..b055416c1e 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -39,16 +39,15 @@ namespace art {
class DexToDexDecompilerTest : public CommonCompilerTest {
public:
void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
- TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
- TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
+ TimingLogger timings("DexToDexDecompilerTest::CompileAll", false, false);
compiler_options_->image_type_ = CompilerOptions::ImageType::kNone;
compiler_options_->SetCompilerFilter(CompilerFilter::kQuicken);
// Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
// the results for all the dex files, not just the results for the current dex file.
down_cast<QuickCompilerCallbacks*>(Runtime::Current()->GetCompilerCallbacks())->SetVerifierDeps(
new verifier::VerifierDeps(GetDexFiles(class_loader)));
- SetDexFilesForOatFile(GetDexFiles(class_loader));
- compiler_driver_->CompileAll(class_loader, GetDexFiles(class_loader), &timings);
+ std::vector<const DexFile*> dex_files = GetDexFiles(class_loader);
+ CommonCompilerTest::CompileAll(class_loader, dex_files, &timings);
}
void RunTest(const char* dex_name) {
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index dd947d90b7..5a34efb73c 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -97,7 +97,7 @@ void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method
}
}
-const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
+const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) const {
const VerifiedMethod* ret = nullptr;
if (atomic_verified_methods_.Get(ref, &ret)) {
return ret;
@@ -129,13 +129,13 @@ void VerificationResults::AddRejectedClass(ClassReference ref) {
DCHECK(IsClassRejected(ref));
}
-bool VerificationResults::IsClassRejected(ClassReference ref) {
+bool VerificationResults::IsClassRejected(ClassReference ref) const {
ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
return (rejected_classes_.find(ref) != rejected_classes_.end());
}
bool VerificationResults::IsCandidateForCompilation(MethodReference&,
- const uint32_t access_flags) {
+ const uint32_t access_flags) const {
if (!compiler_options_->IsAotCompilationEnabled()) {
return false;
}
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 56f00309c0..04c4fa65e6 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -51,13 +51,13 @@ class VerificationResults {
void CreateVerifiedMethodFor(MethodReference ref)
REQUIRES(!verified_methods_lock_);
- const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
+ const VerifiedMethod* GetVerifiedMethod(MethodReference ref) const
REQUIRES(!verified_methods_lock_);
void AddRejectedClass(ClassReference ref) REQUIRES(!rejected_classes_lock_);
- bool IsClassRejected(ClassReference ref) REQUIRES(!rejected_classes_lock_);
+ bool IsClassRejected(ClassReference ref) const REQUIRES(!rejected_classes_lock_);
- bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags);
+ bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags) const;
// Add a dex file to enable using the atomic map.
void AddDexFile(const DexFile* dex_file) REQUIRES(!verified_methods_lock_);
@@ -74,10 +74,12 @@ class VerificationResults {
// GetVerifiedMethod.
AtomicMap atomic_verified_methods_;
- ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ // TODO: External locking during CompilerDriver::PreCompile(), no locking during compilation.
+ mutable ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
// Rejected classes.
- ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ // TODO: External locking during CompilerDriver::PreCompile(), no locking during compilation.
+ mutable ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::set<ClassReference> rejected_classes_ GUARDED_BY(rejected_classes_lock_);
friend class verifier::VerifierDepsTest;
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 792f508199..63dcb4664c 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -99,11 +99,6 @@ inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
return std::make_pair(fast_get, fast_put);
}
-inline VerificationResults* CompilerDriver::GetVerificationResults() const {
- DCHECK(Runtime::Current()->IsAotCompiler());
- return verification_results_;
-}
-
} // namespace art
#endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 67cabef641..18f7105769 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -245,16 +245,12 @@ class CompilerDriver::AOTCompilationStats {
CompilerDriver::CompilerDriver(
const CompilerOptions* compiler_options,
- VerificationResults* verification_results,
Compiler::Kind compiler_kind,
- HashSet<std::string>* image_classes,
size_t thread_count,
int swap_fd)
: compiler_options_(compiler_options),
- verification_results_(verification_results),
compiler_(Compiler::Create(this, compiler_kind)),
compiler_kind_(compiler_kind),
- image_classes_(std::move(image_classes)),
number_of_soft_verifier_failures_(0),
had_hard_verifier_failure_(false),
parallel_thread_count_(thread_count),
@@ -266,10 +262,6 @@ CompilerDriver::CompilerDriver(
compiler_->Init();
- if (GetCompilerOptions().IsBootImage()) {
- CHECK(image_classes_ != nullptr) << "Expected image classes for boot image";
- }
-
compiled_method_storage_.SetDedupeEnabled(compiler_options_->DeduplicateCode());
}
@@ -325,9 +317,8 @@ void CompilerDriver::CompileAll(jobject class_loader,
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
- InitializeThreadPools();
+ CheckThreadPools();
- PreCompile(class_loader, dex_files, timings);
if (GetCompilerOptions().IsBootImage()) {
// We don't need to setup the intrinsics for non boot image compilation, as
// those compilations will pick up a boot image that have the ArtMethod already
@@ -343,8 +334,6 @@ void CompilerDriver::CompileAll(jobject class_loader,
if (GetCompilerOptions().GetDumpStats()) {
stats_->Dump();
}
-
- FreeThreadPools();
}
static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel(
@@ -496,7 +485,7 @@ static void CompileMethodDex2Dex(
optimizer::DexToDexCompiler* const compiler = &driver->GetDexToDexCompiler();
if (compiler->ShouldCompileMethod(method_ref)) {
- VerificationResults* results = driver->GetVerificationResults();
+ const VerificationResults* results = driver->GetCompilerOptions().GetVerificationResults();
DCHECK(results != nullptr);
const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
// Do not optimize if a VerifiedMethod is missing. SafeCast elision,
@@ -574,7 +563,7 @@ static void CompileMethodQuick(
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
} else {
- VerificationResults* results = driver->GetVerificationResults();
+ const VerificationResults* results = driver->GetCompilerOptions().GetVerificationResults();
DCHECK(results != nullptr);
const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
bool compile =
@@ -881,7 +870,9 @@ static void EnsureVerifiedOrVerifyAtRuntime(jobject jclass_loader,
void CompilerDriver::PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
+ TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes,
+ /*out*/ VerificationResults* verification_results) {
CheckThreadPools();
VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
@@ -898,7 +889,7 @@ void CompilerDriver::PreCompile(jobject class_loader,
// 6) Update the set of image classes.
// 7) For deterministic boot image, initialize bitstrings for type checking.
- LoadImageClasses(timings);
+ LoadImageClasses(timings, image_classes);
VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
if (compiler_options_->IsAnyCompilationEnabled()) {
@@ -932,7 +923,7 @@ void CompilerDriver::PreCompile(jobject class_loader,
ResolveConstStrings(dex_files, /*only_startup_strings=*/ true, timings);
}
- Verify(class_loader, dex_files, timings);
+ Verify(class_loader, dex_files, timings, verification_results);
VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
@@ -957,7 +948,7 @@ void CompilerDriver::PreCompile(jobject class_loader,
VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
}
- UpdateImageClasses(timings);
+ UpdateImageClasses(timings, image_classes);
VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
if (kBitstringSubtypeCheckEnabled &&
@@ -1071,7 +1062,8 @@ class RecordImageClassesVisitor : public ClassVisitor {
};
// Make a list of descriptors for classes to include in the image
-void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
+void CompilerDriver::LoadImageClasses(TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes) {
CHECK(timings != nullptr);
if (!GetCompilerOptions().IsBootImage()) {
return;
@@ -1082,15 +1074,15 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- CHECK(image_classes_ != nullptr);
- for (auto it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
+ CHECK(image_classes != nullptr);
+ for (auto it = image_classes->begin(), end = image_classes->end(); it != end;) {
const std::string& descriptor(*it);
StackHandleScope<1> hs(self);
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str())));
if (klass == nullptr) {
VLOG(compiler) << "Failed to find class " << descriptor;
- it = image_classes_->erase(it);
+ it = image_classes->erase(it);
self->ClearException();
} else {
++it;
@@ -1140,10 +1132,10 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
// We walk the roots looking for classes so that we'll pick up the
// above classes plus any classes them depend on such super
// classes, interfaces, and the required ClassLinker roots.
- RecordImageClassesVisitor visitor(image_classes_);
+ RecordImageClassesVisitor visitor(image_classes);
class_linker->VisitClasses(&visitor);
- CHECK(!image_classes_->empty());
+ CHECK(!image_classes->empty());
}
static void MaybeAddToImageClasses(Thread* self,
@@ -1312,7 +1304,8 @@ class ClinitImageUpdate {
DISALLOW_COPY_AND_ASSIGN(ClinitImageUpdate);
};
-void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
+void CompilerDriver::UpdateImageClasses(TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes) {
if (GetCompilerOptions().IsBootImage()) {
TimingLogger::ScopedTiming t("UpdateImageClasses", timings);
@@ -1324,7 +1317,7 @@ void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
VariableSizedHandleScope hs(Thread::Current());
std::string error_msg;
std::unique_ptr<ClinitImageUpdate> update(ClinitImageUpdate::Create(hs,
- image_classes_,
+ image_classes,
Thread::Current(),
runtime->GetClassLinker()));
@@ -1393,12 +1386,6 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi
}
}
-const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
- uint32_t method_idx) const {
- MethodReference ref(dex_file, method_idx);
- return verification_results_->GetVerifiedMethod(ref);
-}
-
bool CompilerDriver::IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc) {
if (!compiler_options_->IsVerificationEnabled()) {
// If we didn't verify, every cast has to be treated as non-safe.
@@ -1764,7 +1751,8 @@ static void LoadAndUpdateStatus(const ClassAccessor& accessor,
bool CompilerDriver::FastVerify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results) {
verifier::VerifierDeps* verifier_deps =
Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
// If there exist VerifierDeps that aren't the ones we just created to output, use them to verify.
@@ -1812,7 +1800,7 @@ bool CompilerDriver::FastVerify(jobject jclass_loader,
// - Quickening will not do checkcast ellision.
// TODO(ngeoffray): Reconsider this once we refactor compiler filters.
for (const ClassAccessor::Method& method : accessor.GetMethods()) {
- verification_results_->CreateVerifiedMethodFor(method.GetReference());
+ verification_results->CreateVerifiedMethodFor(method.GetReference());
}
}
} else if (!compiler_only_verifies) {
@@ -1830,8 +1818,9 @@ bool CompilerDriver::FastVerify(jobject jclass_loader,
void CompilerDriver::Verify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
- if (FastVerify(jclass_loader, dex_files, timings)) {
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results) {
+ if (FastVerify(jclass_loader, dex_files, timings, verification_results)) {
return;
}
@@ -2530,7 +2519,7 @@ void CompilerDriver::InitializeClasses(jobject class_loader,
// SetVerificationAttempted so that the access flags are set. If we do not do this they get
// changed at runtime resulting in more dirty image pages.
// Also create conflict tables.
- // Only useful if we are compiling an image (image_classes_ is not null).
+ // Only useful if we are compiling an image.
ScopedObjectAccess soa(Thread::Current());
VariableSizedHandleScope hs(soa.Self());
InitializeArrayClassesAndCreateConflictTablesVisitor visitor(hs);
@@ -2569,8 +2558,9 @@ static void CompileDexFile(CompilerDriver* driver,
ClassReference ref(&dex_file, class_def_index);
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
ClassAccessor accessor(dex_file, class_def_index);
+ CompilerDriver* const driver = context.GetCompiler();
// Skip compiling classes with generic verifier failures since they will still fail at runtime
- if (context.GetCompiler()->GetVerificationResults()->IsClassRejected(ref)) {
+ if (driver->GetCompilerOptions().GetVerificationResults()->IsClassRejected(ref)) {
return;
}
// Use a scoped object access to perform to the quick SkipClass check.
@@ -2602,8 +2592,6 @@ static void CompileDexFile(CompilerDriver* driver,
// Go to native so that we don't block GC during compilation.
ScopedThreadSuspension sts(soa.Self(), kNative);
- CompilerDriver* const driver = context.GetCompiler();
-
// Can we run DEX-to-DEX compiler on this class ?
optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level =
GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def);
@@ -2775,31 +2763,6 @@ CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const {
return compiled_method;
}
-bool CompilerDriver::IsMethodVerifiedWithoutFailures(uint32_t method_idx,
- uint16_t class_def_idx,
- const DexFile& dex_file) const {
- const VerifiedMethod* verified_method = GetVerifiedMethod(&dex_file, method_idx);
- if (verified_method != nullptr) {
- return !verified_method->HasVerificationFailures();
- }
-
- // If we can't find verification metadata, check if this is a system class (we trust that system
- // classes have their methods verified). If it's not, be conservative and assume the method
- // has not been verified successfully.
-
- // TODO: When compiling the boot image it should be safe to assume that everything is verified,
- // even if methods are not found in the verification cache.
- const char* descriptor = dex_file.GetClassDescriptor(dex_file.GetClassDef(class_def_idx));
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Thread* self = Thread::Current();
- ScopedObjectAccess soa(self);
- bool is_system_class = class_linker->FindSystemClass(self, descriptor) != nullptr;
- if (!is_system_class) {
- self->ClearException();
- }
- return is_system_class;
-}
-
std::string CompilerDriver::GetMemoryUsageString(bool extended) const {
std::ostringstream oss;
const gc::Heap* const heap = Runtime::Current()->GetHeap();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 714b2d1fc8..7c0fc6450f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -76,7 +76,6 @@ template <class Allocator> class SrcMap;
class TimingLogger;
class VdexFile;
class VerificationResults;
-class VerifiedMethod;
enum EntryPointCallingConvention {
// ABI of invocations to a method's interpreter entry point.
@@ -95,9 +94,7 @@ class CompilerDriver {
// can assume will be in the image, with null implying all available
// classes.
CompilerDriver(const CompilerOptions* compiler_options,
- VerificationResults* verification_results,
Compiler::Kind compiler_kind,
- HashSet<std::string>* image_classes,
size_t thread_count,
int swap_fd);
@@ -106,6 +103,17 @@ class CompilerDriver {
// Set dex files classpath.
void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files);
+ // Initialize and destroy thread pools. This is exposed because we do not want
+ // to do this twice, for PreCompile() and CompileAll().
+ void InitializeThreadPools();
+ void FreeThreadPools();
+
+ void PreCompile(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes,
+ /*out*/ VerificationResults* verification_results)
+ REQUIRES(!Locks::mutator_lock_);
void CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
@@ -124,8 +132,6 @@ class CompilerDriver {
Handle<mirror::ClassLoader> h_class_loader)
REQUIRES(!Locks::mutator_lock_);
- VerificationResults* GetVerificationResults() const;
-
const CompilerOptions& GetCompilerOptions() const {
return *compiler_options_;
}
@@ -194,7 +200,6 @@ class CompilerDriver {
REQUIRES_SHARED(Locks::mutator_lock_);
- const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
size_t GetThreadCount() const {
@@ -219,12 +224,6 @@ class CompilerDriver {
void RecordClassStatus(const ClassReference& ref, ClassStatus status);
- // Checks if the specified method has been verified without failures. Returns
- // false if the method is not in the verification results (GetVerificationResults).
- bool IsMethodVerifiedWithoutFailures(uint32_t method_idx,
- uint16_t class_def_idx,
- const DexFile& dex_file) const;
-
// Get memory usage during compilation.
std::string GetMemoryUsageString(bool extended) const;
@@ -265,13 +264,9 @@ class CompilerDriver {
}
private:
- void PreCompile(jobject class_loader,
- const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings)
+ void LoadImageClasses(TimingLogger* timings, /*inout*/ HashSet<std::string>* image_classes)
REQUIRES(!Locks::mutator_lock_);
- void LoadImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
-
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
// ordering semantics.
@@ -291,11 +286,13 @@ class CompilerDriver {
// verification was successful.
bool FastVerify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings);
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results);
void Verify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings);
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results);
void VerifyDexFile(jobject class_loader,
const DexFile& dex_file,
@@ -326,14 +323,13 @@ class CompilerDriver {
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_);
- void UpdateImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
+ void UpdateImageClasses(TimingLogger* timings, /*inout*/ HashSet<std::string>* image_classes)
+ REQUIRES(!Locks::mutator_lock_);
void Compile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings);
- void InitializeThreadPools();
- void FreeThreadPools();
void CheckThreadPools();
// Resolve const string literals that are loaded from dex code. If only_startup_strings is
@@ -343,7 +339,6 @@ class CompilerDriver {
/*inout*/ TimingLogger* timings);
const CompilerOptions* const compiler_options_;
- VerificationResults* const verification_results_;
std::unique_ptr<Compiler> compiler_;
Compiler::Kind compiler_kind_;
@@ -359,12 +354,6 @@ class CompilerDriver {
// All method references that this compiler has compiled.
MethodTable compiled_methods_;
- // Image classes to be updated by PreCompile().
- // TODO: Remove this member which is a non-const pointer to the CompilerOptions' data.
- // Pass this explicitly to the PreCompile() which should be called directly from
- // Dex2Oat rather than implicitly by CompileAll().
- HashSet<std::string>* image_classes_;
-
std::atomic<uint32_t> number_of_soft_verifier_failures_;
bool had_hard_verifier_failure_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index fe1568da83..b9241292ee 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -42,20 +42,18 @@ namespace art {
class CompilerDriverTest : public CommonCompilerTest {
protected:
- void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
- TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
- TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
+ void CompileAllAndMakeExecutable(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
+ TimingLogger timings("CompilerDriverTest::CompileAllAndMakeExecutable", false, false);
dex_files_ = GetDexFiles(class_loader);
- SetDexFilesForOatFile(dex_files_);
- compiler_driver_->CompileAll(class_loader, dex_files_, &timings);
- t.NewTiming("MakeAllExecutable");
+ CompileAll(class_loader, dex_files_, &timings);
+ TimingLogger::ScopedTiming t("MakeAllExecutable", &timings);
MakeAllExecutable(class_loader);
}
void EnsureCompiled(jobject class_loader, const char* class_name, const char* method,
const char* signature, bool is_virtual)
REQUIRES(!Locks::mutator_lock_) {
- CompileAll(class_loader);
+ CompileAllAndMakeExecutable(class_loader);
Thread::Current()->TransitionFromSuspendedToRunnable();
bool started = runtime_->Start();
CHECK(started);
@@ -106,7 +104,7 @@ class CompilerDriverTest : public CommonCompilerTest {
// Disabled due to 10 second runtime on host
// TODO: Update the test for hash-based dex cache arrays. Bug: 30627598
TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) {
- CompileAll(nullptr);
+ CompileAllAndMakeExecutable(nullptr);
// All libcore references should resolve
ScopedObjectAccess soa(Thread::Current());
@@ -266,7 +264,7 @@ TEST_F(CompilerDriverProfileTest, ProfileGuidedCompilation) {
ASSERT_TRUE(dex_file->EnableWrite());
}
- CompileAll(class_loader);
+ CompileAllAndMakeExecutable(class_loader);
std::unordered_set<std::string> m = GetExpectedMethodsForClass("Main");
std::unordered_set<std::string> s = GetExpectedMethodsForClass("Second");
@@ -310,7 +308,7 @@ TEST_F(CompilerDriverVerifyTest, VerifyCompilation) {
}
ASSERT_NE(class_loader, nullptr);
- CompileAll(class_loader);
+ CompileAllAndMakeExecutable(class_loader);
CheckVerifiedClass(class_loader, "LMain;");
CheckVerifiedClass(class_loader, "LSecond;");
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index b28c7e0edb..8d1ae3d524 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -24,9 +24,14 @@
#include "arch/instruction_set_features.h"
#include "base/runtime_debug.h"
#include "base/variant_map.h"
+#include "class_linker.h"
#include "cmdline_parser.h"
#include "compiler_options_map-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
#include "simple_compiler_options_map.h"
namespace art {
@@ -44,6 +49,7 @@ CompilerOptions::CompilerOptions()
no_inline_from_(),
dex_files_for_oat_file_(),
image_classes_(),
+ verification_results_(nullptr),
image_type_(ImageType::kNone),
compiling_with_core_image_(false),
baseline_(false),
@@ -141,4 +147,40 @@ bool CompilerOptions::IsImageClass(const char* descriptor) const {
return image_classes_.find(StringPiece(descriptor)) != image_classes_.end();
}
+const VerificationResults* CompilerOptions::GetVerificationResults() const {
+ DCHECK(Runtime::Current()->IsAotCompiler());
+ return verification_results_;
+}
+
+const VerifiedMethod* CompilerOptions::GetVerifiedMethod(const DexFile* dex_file,
+ uint32_t method_idx) const {
+ MethodReference ref(dex_file, method_idx);
+ return verification_results_->GetVerifiedMethod(ref);
+}
+
+bool CompilerOptions::IsMethodVerifiedWithoutFailures(uint32_t method_idx,
+ uint16_t class_def_idx,
+ const DexFile& dex_file) const {
+ const VerifiedMethod* verified_method = GetVerifiedMethod(&dex_file, method_idx);
+ if (verified_method != nullptr) {
+ return !verified_method->HasVerificationFailures();
+ }
+
+ // If we can't find verification metadata, check if this is a system class (we trust that system
+ // classes have their methods verified). If it's not, be conservative and assume the method
+ // has not been verified successfully.
+
+ // TODO: When compiling the boot image it should be safe to assume that everything is verified,
+ // even if methods are not found in the verification cache.
+ const char* descriptor = dex_file.GetClassDescriptor(dex_file.GetClassDef(class_def_idx));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ bool is_system_class = class_linker->FindSystemClass(self, descriptor) != nullptr;
+ if (!is_system_class) {
+ self->ClearException();
+ }
+ return is_system_class;
+}
+
} // namespace art
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index a8f246dcab..bd12bf7dda 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -47,6 +47,8 @@ class DexFile;
enum class InstructionSet;
class InstructionSetFeatures;
class ProfileCompilationInfo;
+class VerificationResults;
+class VerifiedMethod;
// Enum for CheckProfileMethodsCompiled. Outside CompilerOptions so it can be forward-declared.
enum class ProfileMethodsCheck : uint8_t {
@@ -283,6 +285,16 @@ class CompilerOptions final {
bool IsImageClass(const char* descriptor) const;
+ const VerificationResults* GetVerificationResults() const;
+
+ const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
+
+ // Checks if the specified method has been verified without failures. Returns
+ // false if the method is not in the verification results (GetVerificationResults).
+ bool IsMethodVerifiedWithoutFailures(uint32_t method_idx,
+ uint16_t class_def_idx,
+ const DexFile& dex_file) const;
+
bool ParseCompilerOptions(const std::vector<std::string>& options,
bool ignore_unrecognized,
std::string* error_msg);
@@ -381,6 +393,9 @@ class CompilerOptions final {
// Must not be empty for real boot image, only for tests pretending to compile boot image.
HashSet<std::string> image_classes_;
+ // Results of AOT verification.
+ const VerificationResults* verification_results_;
+
ImageType image_type_;
bool compiling_with_core_image_;
bool baseline_;
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 0eab8356e7..b9fd868f1c 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -167,9 +167,7 @@ JitCompiler::JitCompiler() {
compiler_driver_.reset(new CompilerDriver(
compiler_options_.get(),
- /* verification_results */ nullptr,
Compiler::kOptimizing,
- /* image_classes */ nullptr,
/* thread_count */ 1,
/* swap_fd */ -1));
// Disable dedupe so we can remove compiled methods.
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index ec9322270a..417d794264 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -28,7 +28,6 @@
#include "dex/inline_method_analyser.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
-#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
#include "instruction_simplifier.h"
@@ -408,7 +407,7 @@ ArtMethod* HInliner::TryCHADevirtualization(ArtMethod* resolved_method) {
return single_impl;
}
-static bool IsMethodUnverified(CompilerDriver* const compiler_driver, ArtMethod* method)
+static bool IsMethodUnverified(const CompilerOptions& compiler_options, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (!method->GetDeclaringClass()->IsVerified()) {
if (Runtime::Current()->UseJitCompilation()) {
@@ -417,8 +416,9 @@ static bool IsMethodUnverified(CompilerDriver* const compiler_driver, ArtMethod*
return true;
}
uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex();
- if (!compiler_driver->IsMethodVerifiedWithoutFailures(
- method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) {
+ if (!compiler_options.IsMethodVerifiedWithoutFailures(method->GetDexMethodIndex(),
+ class_def_idx,
+ *method->GetDexFile())) {
// Method has soft or hard failures, don't analyze.
return true;
}
@@ -426,11 +426,11 @@ static bool IsMethodUnverified(CompilerDriver* const compiler_driver, ArtMethod*
return false;
}
-static bool AlwaysThrows(CompilerDriver* const compiler_driver, ArtMethod* method)
+static bool AlwaysThrows(const CompilerOptions& compiler_options, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(method != nullptr);
// Skip non-compilable and unverified methods.
- if (!method->IsCompilable() || IsMethodUnverified(compiler_driver, method)) {
+ if (!method->IsCompilable() || IsMethodUnverified(compiler_options, method)) {
return false;
}
// Skip native methods, methods with try blocks, and methods that are too large.
@@ -518,7 +518,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) {
MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvokeVirtualOrInterface);
}
}
- } else if (!cha_devirtualize && AlwaysThrows(compiler_driver_, actual_method)) {
+ } else if (!cha_devirtualize && AlwaysThrows(codegen_->GetCompilerOptions(), actual_method)) {
// Set always throws property for non-inlined method call with single target
// (unless it was obtained through CHA, because that would imply we have
// to add the CHA dependency, which seems not worth it).
@@ -1500,7 +1500,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
return false;
}
- if (IsMethodUnverified(compiler_driver_, method)) {
+ if (IsMethodUnverified(codegen_->GetCompilerOptions(), method)) {
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified)
<< "Method " << method->PrettyMethod()
<< " couldn't be verified, so it cannot be inlined";
@@ -2069,7 +2069,6 @@ void HInliner::RunOptimizations(HGraph* callee_graph,
codegen_,
outer_compilation_unit_,
dex_compilation_unit,
- compiler_driver_,
handles_,
inline_stats_,
total_number_of_dex_registers_ + accessor.RegistersSize(),
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 6fd0c204b2..8ac2163a94 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -38,7 +38,6 @@ class HInliner : public HOptimization {
CodeGenerator* codegen,
const DexCompilationUnit& outer_compilation_unit,
const DexCompilationUnit& caller_compilation_unit,
- CompilerDriver* compiler_driver,
VariableSizedHandleScope* handles,
OptimizingCompilerStats* stats,
size_t total_number_of_dex_registers,
@@ -51,7 +50,6 @@ class HInliner : public HOptimization {
outer_compilation_unit_(outer_compilation_unit),
caller_compilation_unit_(caller_compilation_unit),
codegen_(codegen),
- compiler_driver_(compiler_driver),
total_number_of_dex_registers_(total_number_of_dex_registers),
total_number_of_instructions_(total_number_of_instructions),
parent_(parent),
@@ -280,7 +278,6 @@ class HInliner : public HOptimization {
const DexCompilationUnit& outer_compilation_unit_;
const DexCompilationUnit& caller_compilation_unit_;
CodeGenerator* const codegen_;
- CompilerDriver* const compiler_driver_;
const size_t total_number_of_dex_registers_;
size_t total_number_of_instructions_;
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 6d04b0e9d9..1688ea7811 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -2950,6 +2950,151 @@ void IntrinsicCodeGeneratorARM64::VisitCRC32Update(HInvoke* invoke) {
__ Mvn(out, out);
}
+// The threshold for sizes of arrays to use the library provided implementation
+// of CRC32.updateBytes instead of the intrinsic.
+static constexpr int32_t kCRC32UpdateBytesThreshold = 64 * 1024;
+
+void IntrinsicLocationsBuilderARM64::VisitCRC32UpdateBytes(HInvoke* invoke) {
+ if (!codegen_->GetInstructionSetFeatures().HasCRC()) {
+ return;
+ }
+
+ LocationSummary* locations
+ = new (allocator_) LocationSummary(invoke,
+ LocationSummary::kCallOnSlowPath,
+ kIntrinsified);
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(2, Location::RegisterOrConstant(invoke->InputAt(2)));
+ locations->SetInAt(3, Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister());
+}
+
+// Lower the invoke of CRC32.updateBytes(int crc, byte[] b, int off, int len)
+//
+// Note: The intrinsic is not used if len exceeds a threshold.
+void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateBytes(HInvoke* invoke) {
+ DCHECK(codegen_->GetInstructionSetFeatures().HasCRC());
+
+ auto masm = GetVIXLAssembler();
+ auto locations = invoke->GetLocations();
+
+ auto slow_path =
+ new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke);
+ codegen_->AddSlowPath(slow_path);
+
+ Register length = WRegisterFrom(locations->InAt(3));
+ __ Cmp(length, kCRC32UpdateBytesThreshold);
+ __ B(slow_path->GetEntryLabel(), hi);
+
+ const uint32_t array_data_offset =
+ mirror::Array::DataOffset(Primitive::kPrimByte).Uint32Value();
+ Register ptr = XRegisterFrom(locations->GetTemp(0));
+ Register array = XRegisterFrom(locations->InAt(1));
+ auto offset = locations->InAt(2);
+ if (offset.IsConstant()) {
+ int32_t offset_value = offset.GetConstant()->AsIntConstant()->GetValue();
+ __ Add(ptr, array, array_data_offset + offset_value);
+ } else {
+ __ Add(ptr, array, array_data_offset);
+ __ Add(ptr, ptr, XRegisterFrom(offset));
+ }
+
+ // The algorithm of CRC32 of bytes is:
+ // crc = ~crc
+ // process a few first bytes to make the array 8-byte aligned
+ // while array has 8 bytes do:
+ // crc = crc32_of_8bytes(crc, 8_bytes(array))
+ // if array has 4 bytes:
+ // crc = crc32_of_4bytes(crc, 4_bytes(array))
+ // if array has 2 bytes:
+ // crc = crc32_of_2bytes(crc, 2_bytes(array))
+ // if array has a byte:
+ // crc = crc32_of_byte(crc, 1_byte(array))
+ // crc = ~crc
+
+ vixl::aarch64::Label loop, done;
+ vixl::aarch64::Label process_4bytes, process_2bytes, process_1byte;
+ vixl::aarch64::Label aligned2, aligned4, aligned8;
+
+ // Use VIXL scratch registers as the VIXL macro assembler won't use them in
+ // instructions below.
+ UseScratchRegisterScope temps(masm);
+ Register len = temps.AcquireW();
+ Register array_elem = temps.AcquireW();
+
+ Register out = WRegisterFrom(locations->Out());
+ __ Mvn(out, WRegisterFrom(locations->InAt(0)));
+ __ Mov(len, length);
+
+ __ Tbz(ptr, 0, &aligned2);
+ __ Subs(len, len, 1);
+ __ B(&done, lo);
+ __ Ldrb(array_elem, MemOperand(ptr, 1, PostIndex));
+ __ Crc32b(out, out, array_elem);
+
+ __ Bind(&aligned2);
+ __ Tbz(ptr, 1, &aligned4);
+ __ Subs(len, len, 2);
+ __ B(&process_1byte, lo);
+ __ Ldrh(array_elem, MemOperand(ptr, 2, PostIndex));
+ __ Crc32h(out, out, array_elem);
+
+ __ Bind(&aligned4);
+ __ Tbz(ptr, 2, &aligned8);
+ __ Subs(len, len, 4);
+ __ B(&process_2bytes, lo);
+ __ Ldr(array_elem, MemOperand(ptr, 4, PostIndex));
+ __ Crc32w(out, out, array_elem);
+
+ __ Bind(&aligned8);
+ __ Subs(len, len, 8);
+ // If len < 8 go to process data by 4 bytes, 2 bytes and a byte.
+ __ B(&process_4bytes, lo);
+
+ // The main loop processing data by 8 bytes.
+ __ Bind(&loop);
+ __ Ldr(array_elem.X(), MemOperand(ptr, 8, PostIndex));
+ __ Subs(len, len, 8);
+ __ Crc32x(out, out, array_elem.X());
+ // if len >= 8, process the next 8 bytes.
+ __ B(&loop, hs);
+
+ // Process the data which is less than 8 bytes.
+ // The code generated below works with values of len
+ // which come in the range [-8, 0].
+ // The first three bits are used to detect whether 4 bytes or 2 bytes or
+ // a byte can be processed.
+ // The checking order is from bit 2 to bit 0:
+ // bit 2 is set: at least 4 bytes available
+ // bit 1 is set: at least 2 bytes available
+ // bit 0 is set: at least a byte available
+ __ Bind(&process_4bytes);
+ // Goto process_2bytes if less than four bytes available
+ __ Tbz(len, 2, &process_2bytes);
+ __ Ldr(array_elem, MemOperand(ptr, 4, PostIndex));
+ __ Crc32w(out, out, array_elem);
+
+ __ Bind(&process_2bytes);
+ // Goto process_1bytes if less than two bytes available
+ __ Tbz(len, 1, &process_1byte);
+ __ Ldrh(array_elem, MemOperand(ptr, 2, PostIndex));
+ __ Crc32h(out, out, array_elem);
+
+ __ Bind(&process_1byte);
+ // Goto done if no bytes available
+ __ Tbz(len, 0, &done);
+ __ Ldrb(array_elem, MemOperand(ptr));
+ __ Crc32b(out, out, array_elem);
+
+ __ Bind(&done);
+ __ Mvn(out, out);
+
+ __ Bind(slow_path->GetExitLabel());
+}
+
UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf);
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 4d45a9991c..88f1457c20 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -3060,6 +3060,7 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure.
UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update)
+UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32UpdateBytes)
UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 21fb7d7f1c..08ba0a0adf 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2697,6 +2697,7 @@ UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
UNIMPLEMENTED_INTRINSIC(MIPS, CRC32Update)
+UNIMPLEMENTED_INTRINSIC(MIPS, CRC32UpdateBytes)
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 4b86f5d423..59d3ba2488 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2347,6 +2347,7 @@ void IntrinsicCodeGeneratorMIPS64::VisitReachabilityFence(HInvoke* invoke ATTRIB
UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32Update)
+UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32UpdateBytes)
UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index a73f4e8b94..1d94950e4d 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -3071,6 +3071,7 @@ UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit)
UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit)
UNIMPLEMENTED_INTRINSIC(X86, CRC32Update)
+UNIMPLEMENTED_INTRINSIC(X86, CRC32UpdateBytes)
UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 88c766fabc..4f0b61d88e 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2738,6 +2738,7 @@ UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent)
UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite)
UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update)
+UNIMPLEMENTED_INTRINSIC(X86_64, CRC32UpdateBytes)
UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOf);
UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index 0f971e100e..b75afad4c8 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -181,7 +181,6 @@ ArenaVector<HOptimization*> ConstructOptimizations(
HGraph* graph,
OptimizingCompilerStats* stats,
CodeGenerator* codegen,
- CompilerDriver* driver,
const DexCompilationUnit& dex_compilation_unit,
VariableSizedHandleScope* handles) {
ArenaVector<HOptimization*> optimizations(allocator->Adapter());
@@ -258,7 +257,6 @@ ArenaVector<HOptimization*> ConstructOptimizations(
codegen,
dex_compilation_unit, // outer_compilation_unit
dex_compilation_unit, // outermost_compilation_unit
- driver,
handles,
stats,
accessor.RegistersSize(),
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 490007d9d9..ce44b5f81a 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -147,7 +147,6 @@ ArenaVector<HOptimization*> ConstructOptimizations(
HGraph* graph,
OptimizingCompilerStats* stats,
CodeGenerator* codegen,
- CompilerDriver* driver,
const DexCompilationUnit& dex_compilation_unit,
VariableSizedHandleScope* handles);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 641368b87a..92aaa19121 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -321,7 +321,6 @@ class OptimizingCompiler final : public Compiler {
graph,
compilation_stats_.get(),
codegen,
- GetCompilerDriver(),
dex_compilation_unit,
handles);
DCHECK_EQ(length, optimizations.size());
@@ -962,9 +961,9 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic(
arena_stack,
dex_file,
method_idx,
- compiler_driver->GetCompilerOptions().GetInstructionSet(),
+ compiler_options.GetInstructionSet(),
kInvalidInvokeType,
- compiler_driver->GetCompilerOptions().GetDebuggable(),
+ compiler_options.GetDebuggable(),
/* osr */ false);
DCHECK(Runtime::Current()->IsAotCompiler());
@@ -1043,12 +1042,13 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
const DexFile& dex_file,
Handle<mirror::DexCache> dex_cache) const {
CompilerDriver* compiler_driver = GetCompilerDriver();
+ const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
CompiledMethod* compiled_method = nullptr;
Runtime* runtime = Runtime::Current();
DCHECK(runtime->IsAotCompiler());
- const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);
+ const VerifiedMethod* verified_method = compiler_options.GetVerifiedMethod(&dex_file, method_idx);
DCHECK(!verified_method->HasRuntimeThrow());
- if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) ||
+ if (compiler_options.IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) ||
verifier::CanCompilerHandleVerificationFailure(
verified_method->GetEncounteredVerificationFailures())) {
ArenaAllocator allocator(runtime->GetArenaPool());
@@ -1080,7 +1080,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
// Go to native so that we don't block GC during compilation.
ScopedThreadSuspension sts(soa.Self(), kNative);
if (method != nullptr && UNLIKELY(method->IsIntrinsic())) {
- DCHECK(compiler_driver->GetCompilerOptions().IsBootImage());
+ DCHECK(compiler_options.IsBootImage());
codegen.reset(
TryCompileIntrinsic(&allocator,
&arena_stack,
@@ -1099,7 +1099,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
&code_allocator,
dex_compilation_unit,
method,
- compiler_driver->GetCompilerOptions().IsBaseline(),
+ compiler_options.IsBaseline(),
/* osr= */ false,
&handles));
}
@@ -1128,7 +1128,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
}
} else {
MethodCompilationStat method_stat;
- if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) {
+ if (compiler_options.VerifyAtRuntime()) {
method_stat = MethodCompilationStat::kNotCompiledVerifyAtRuntime;
} else {
method_stat = MethodCompilationStat::kNotCompiledVerificationError;
@@ -1137,8 +1137,8 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
}
if (kIsDebugBuild &&
- compiler_driver->GetCompilerOptions().CompilingWithCoreImage() &&
- IsInstructionSetSupported(compiler_driver->GetCompilerOptions().GetInstructionSet())) {
+ compiler_options.CompilingWithCoreImage() &&
+ IsInstructionSetSupported(compiler_options.GetInstructionSet())) {
// For testing purposes, we put a special marker on method names
// that should be compiled with this compiler (when the
// instruction set is supported). This makes sure we're not
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index eb44dd7f1d..8c90aa7e37 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -93,12 +93,12 @@ class VerifierDepsTest : public CommonCompilerTest {
verifier_deps_.reset(deps);
}
callbacks_->SetVerifierDeps(deps);
- compiler_driver_->Verify(class_loader_, dex_files_, &timings);
+ compiler_driver_->Verify(class_loader_, dex_files_, &timings, verification_results_.get());
callbacks_->SetVerifierDeps(nullptr);
// Clear entries in the verification results to avoid hitting a DCHECK that
// we always succeed inserting a new entry after verifying.
AtomicDexRefMap<MethodReference, const VerifiedMethod*>* map =
- &compiler_driver_->GetVerificationResults()->atomic_verified_methods_;
+ &verification_results_->atomic_verified_methods_;
map->Visit([](const DexFileReference& ref ATTRIBUTE_UNUSED, const VerifiedMethod* method) {
delete method;
});
@@ -126,7 +126,7 @@ class VerifierDepsTest : public CommonCompilerTest {
class_linker_->RegisterDexFile(*dex_file, loader.Get());
}
for (const DexFile* dex_file : dex_files_) {
- compiler_driver_->GetVerificationResults()->AddDexFile(dex_file);
+ verification_results_->AddDexFile(dex_file);
}
SetDexFilesForOatFile(dex_files_);
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index edd61897a9..f7299344f2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -630,6 +630,7 @@ class Dex2Oat final {
thread_count_(sysconf(_SC_NPROCESSORS_CONF)),
start_ns_(NanoTime()),
start_cputime_ns_(ProcessCpuNanoTime()),
+ strip_(false),
oat_fd_(-1),
input_vdex_fd_(-1),
output_vdex_fd_(-1),
@@ -1788,9 +1789,7 @@ class Dex2Oat final {
compiler_options_->profile_compilation_info_ = profile_compilation_info_.get();
driver_.reset(new CompilerDriver(compiler_options_.get(),
- verification_results_.get(),
compiler_kind_,
- &compiler_options_->image_classes_,
thread_count_,
swap_fd_));
if (!IsBootImage()) {
@@ -1862,7 +1861,16 @@ class Dex2Oat final {
<< soa.Self()->GetException()->Dump();
}
}
+ driver_->InitializeThreadPools();
+ driver_->PreCompile(class_loader,
+ dex_files,
+ timings_,
+ &compiler_options_->image_classes_,
+ verification_results_.get());
+ callbacks_->SetVerificationResults(nullptr); // Should not be needed anymore.
+ compiler_options_->verification_results_ = verification_results_.get();
driver_->CompileAll(class_loader, dex_files, timings_);
+ driver_->FreeThreadPools();
return class_loader;
}
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 6ffcef12a7..13fa0f033b 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -218,11 +218,9 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
{
jobject class_loader = nullptr;
TimingLogger timings("ImageTest::WriteRead", false, false);
- TimingLogger::ScopedTiming t("CompileAll", &timings);
- SetDexFilesForOatFile(class_path);
- driver->CompileAll(class_loader, class_path, &timings);
+ CompileAll(class_loader, class_path, &timings);
- t.NewTiming("WriteElf");
+ TimingLogger::ScopedTiming t("WriteElf", &timings);
SafeMap<std::string, std::string> key_value_store;
key_value_store.Put(OatHeader::kBootClassPathKey,
gc::space::ImageSpace::GetMultiImageBootClassPath(
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 6b17ef6e87..d045698d07 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -968,7 +968,7 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
ClassStatus status;
bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
if (!found) {
- VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
+ const VerificationResults* results = writer_->compiler_options_.GetVerificationResults();
if (results != nullptr && results->IsClassRejected(class_ref)) {
// The oat class status is used only for verification of resolved classes,
// so use ClassStatus::kErrorResolved whether the class was resolved or unresolved
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 598a0f846b..5de1540839 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -391,8 +391,7 @@ TEST_F(OatTest, WriteRead) {
jobject class_loader = nullptr;
if (kCompile) {
TimingLogger timings2("OatTest::WriteRead", false, false);
- SetDexFilesForOatFile(class_linker->GetBootClassPath());
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2);
+ CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2);
}
ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
@@ -405,7 +404,7 @@ TEST_F(OatTest, WriteRead) {
ASSERT_TRUE(success);
if (kCompile) { // OatWriter strips the code, regenerate to compare
- compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
+ CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
}
std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
tmp_oat.GetFilename(),
@@ -513,8 +512,7 @@ TEST_F(OatTest, EmptyTextSection) {
ScopedObjectAccess soa(Thread::Current());
class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader>(class_loader));
}
- SetDexFilesForOatFile(dex_files);
- compiler_driver_->CompileAll(class_loader, dex_files, &timings);
+ CompileAll(class_loader, dex_files, &timings);
ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
SafeMap<std::string, std::string> key_value_store;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9b2e1a10e4..c964dbcf59 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2026,7 +2026,7 @@ bool ClassLinker::AddImageSpace(
// Image class loader [A][B][C][image dex files]
// Class loader = [???][dex_elements][image dex files]
// Need to ensure that [???][dex_elements] == [A][B][C].
- // For each class loader, PathClassLoader, the laoder checks the parent first. Also the logic
+ // For each class loader, PathClassLoader, the loader checks the parent first. Also the logic
// for PathClassLoader does this by looping through the array of dex files. To ensure they
// resolve the same way, simply flatten the hierarchy in the way the resolution order would be,
// and check that the dex file names are the same.
@@ -2662,7 +2662,7 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
return true;
}
- if (IsPathOrDexClassLoader(soa, class_loader)) {
+ if (IsPathOrDexClassLoader(soa, class_loader) || IsInMemoryDexClassLoader(soa, class_loader)) {
// For regular path or dex class loader the search order is:
// - parent
// - shared libraries
@@ -2756,7 +2756,9 @@ ObjPtr<mirror::Class> ClassLinker::FindClassInBaseDexClassLoaderClassPath(
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader) {
- DCHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader))
+ DCHECK(IsPathOrDexClassLoader(soa, class_loader) ||
+ IsInMemoryDexClassLoader(soa, class_loader) ||
+ IsDelegateLastClassLoader(soa, class_loader))
<< "Unexpected class loader for descriptor " << descriptor;
ObjPtr<mirror::Class> ret;
diff --git a/runtime/class_loader_utils.h b/runtime/class_loader_utils.h
index 69476dfb98..562dc47d21 100644
--- a/runtime/class_loader_utils.h
+++ b/runtime/class_loader_utils.h
@@ -29,7 +29,7 @@
namespace art {
// Returns true if the given class loader is either a PathClassLoader or a DexClassLoader.
-// (they both have the same behaviour with respect to class lockup order)
+// (they both have the same behaviour with respect to class lookup order)
inline bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -41,6 +41,15 @@ inline bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader));
}
+// Returns true if the given class loader is an InMemoryDexClassLoader.
+inline bool IsInMemoryDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
+ Handle<mirror::ClassLoader> class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ mirror::Class* class_loader_class = class_loader->GetClass();
+ return (class_loader_class ==
+ soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_InMemoryDexClassLoader));
+}
+
inline bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index d9d81f02ae..13bead28be 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -235,6 +235,7 @@ ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
case Intrinsics::kUnsafeStoreFence:
case Intrinsics::kUnsafeFullFence:
case Intrinsics::kCRC32Update:
+ case Intrinsics::kCRC32UpdateBytes:
case Intrinsics::kStringNewStringFromBytes:
case Intrinsics::kStringNewStringFromChars:
case Intrinsics::kStringNewStringFromString:
diff --git a/runtime/image.cc b/runtime/image.cc
index ae3d8e34e6..fb581f94d2 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -29,7 +29,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '1', '\0' }; // Add image blocks.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '2', '\0' }; // CRC32UpdateBytes intrinsic
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index 24a026a92e..16e118c9cf 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -559,6 +559,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame,
UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */)
UNIMPLEMENTED_CASE(CRC32Update /* (II)I */)
+ UNIMPLEMENTED_CASE(CRC32UpdateBytes /* (I[BII)I */)
INTRINSIC_CASE(VarHandleFullFence)
INTRINSIC_CASE(VarHandleAcquireFence)
INTRINSIC_CASE(VarHandleReleaseFence)
diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h
index 093dd7f400..82ea47609b 100644
--- a/runtime/intrinsics_list.h
+++ b/runtime/intrinsics_list.h
@@ -220,6 +220,7 @@
V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \
V(ReachabilityFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/ref/Reference;", "reachabilityFence", "(Ljava/lang/Object;)V") \
V(CRC32Update, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/util/zip/CRC32;", "update", "(II)I") \
+ V(CRC32UpdateBytes, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/util/zip/CRC32;", "updateBytes", "(I[BII)I") \
SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V)
#endif // ART_RUNTIME_INTRINSICS_LIST_H_
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 4a3ef07819..e43d771270 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -291,22 +291,6 @@ bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
return success;
}
-void Jit::CreateThreadPool() {
- if (Runtime::Current()->IsSafeMode()) {
- // Never create the pool in safe mode.
- return;
- }
- // There is a DCHECK in the 'AddSamples' method to ensure the thread pool
- // is not null when we instrument.
-
- // We need peers as we may report the JIT thread, e.g., in the debugger.
- constexpr bool kJitPoolNeedsPeers = true;
- thread_pool_.reset(new ThreadPool("Jit thread pool", 1, kJitPoolNeedsPeers));
-
- thread_pool_->SetPthreadPriority(options_->GetThreadPoolPthreadPriority());
- Start();
-}
-
void Jit::DeleteThreadPool() {
Thread* self = Thread::Current();
DCHECK(Runtime::Current()->IsShuttingDown(self));
@@ -562,10 +546,10 @@ void Jit::AddMemoryUsage(ArtMethod* method, size_t bytes) {
class JitCompileTask final : public Task {
public:
- enum TaskKind {
+ enum class TaskKind {
kAllocateProfile,
kCompile,
- kCompileOsr
+ kCompileOsr,
};
JitCompileTask(ArtMethod* method, TaskKind kind) : method_(method), kind_(kind) {
@@ -582,14 +566,20 @@ class JitCompileTask final : public Task {
void Run(Thread* self) override {
ScopedObjectAccess soa(self);
- if (kind_ == kCompile) {
- Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr= */ false);
- } else if (kind_ == kCompileOsr) {
- Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr= */ true);
- } else {
- DCHECK(kind_ == kAllocateProfile);
- if (ProfilingInfo::Create(self, method_, /* retry_allocation= */ true)) {
- VLOG(jit) << "Start profiling " << ArtMethod::PrettyMethod(method_);
+ switch (kind_) {
+ case TaskKind::kCompile:
+ case TaskKind::kCompileOsr: {
+ Runtime::Current()->GetJit()->CompileMethod(
+ method_,
+ self,
+ /* osr= */ (kind_ == TaskKind::kCompileOsr));
+ break;
+ }
+ case TaskKind::kAllocateProfile: {
+ if (ProfilingInfo::Create(self, method_, /* retry_allocation= */ true)) {
+ VLOG(jit) << "Start profiling " << ArtMethod::PrettyMethod(method_);
+ }
+ break;
}
}
ProfileSaver::NotifyJitActivity();
@@ -607,6 +597,18 @@ class JitCompileTask final : public Task {
DISALLOW_IMPLICIT_CONSTRUCTORS(JitCompileTask);
};
+void Jit::CreateThreadPool() {
+ // There is a DCHECK in the 'AddSamples' method to ensure the tread pool
+ // is not null when we instrument.
+
+ // We need peers as we may report the JIT thread, e.g., in the debugger.
+ constexpr bool kJitPoolNeedsPeers = true;
+ thread_pool_.reset(new ThreadPool("Jit thread pool", 1, kJitPoolNeedsPeers));
+
+ thread_pool_->SetPthreadPriority(options_->GetThreadPoolPthreadPriority());
+ Start();
+}
+
static bool IgnoreSamplesForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
if (method->IsClassInitializer() || !method->IsCompilable()) {
// We do not want to compile such methods.
@@ -630,11 +632,10 @@ static bool IgnoreSamplesForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mut
void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_backedges) {
if (thread_pool_ == nullptr) {
- // Should only see this when shutting down, starting up, or in zygote, which doesn't
- // have a thread pool.
+ // Should only see this when shutting down, starting up, or in safe mode.
DCHECK(Runtime::Current()->IsShuttingDown(self) ||
!Runtime::Current()->IsFinishedStarting() ||
- Runtime::Current()->IsZygote());
+ Runtime::Current()->IsSafeMode());
return;
}
if (IgnoreSamplesForMethod(method)) {
@@ -675,7 +676,8 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_
if (!success) {
// We failed allocating. Instead of doing the collection on the Java thread, we push
// an allocation to a compiler thread, that will do the collection.
- thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kAllocateProfile));
+ thread_pool_->AddTask(
+ self, new JitCompileTask(method, JitCompileTask::TaskKind::kAllocateProfile));
}
}
// Avoid jumping more than one state at a time.
@@ -685,7 +687,7 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_
if ((new_count >= HotMethodThreshold()) &&
!code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
DCHECK(thread_pool_ != nullptr);
- thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
+ thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::TaskKind::kCompile));
}
// Avoid jumping more than one state at a time.
new_count = std::min(new_count, static_cast<uint32_t>(OSRMethodThreshold() - 1));
@@ -697,7 +699,8 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_
DCHECK(!method->IsNative()); // No back edges reported for native methods.
if ((new_count >= OSRMethodThreshold()) && !code_cache_->IsOsrCompiled(method)) {
DCHECK(thread_pool_ != nullptr);
- thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
+ thread_pool_->AddTask(
+ self, new JitCompileTask(method, JitCompileTask::TaskKind::kCompileOsr));
}
}
}
@@ -730,7 +733,7 @@ void Jit::MethodEntered(Thread* thread, ArtMethod* method) {
// The compiler requires a ProfilingInfo object for non-native methods.
ProfilingInfo::Create(thread, np_method, /* retry_allocation= */ true);
}
- JitCompileTask compile_task(method, JitCompileTask::kCompile);
+ JitCompileTask compile_task(method, JitCompileTask::TaskKind::kCompile);
// Fake being in a runtime thread so that class-load behavior will be the same as normal jit.
ScopedSetRuntimeThread ssrt(thread);
compile_task.Run(thread);
@@ -798,7 +801,16 @@ ScopedJitSuspend::~ScopedJitSuspend() {
}
}
-void Jit::PostForkChildAction() {
+void Jit::PostForkChildAction(bool is_zygote) {
+ if (is_zygote) {
+ // Don't transition if this is for a child zygote.
+ return;
+ }
+ if (Runtime::Current()->IsSafeMode()) {
+ // Delete the thread pool, we are not going to JIT.
+ thread_pool_.reset(nullptr);
+ return;
+ }
// At this point, the compiler options have been adjusted to the particular configuration
// of the forked child. Parse them again.
jit_update_options_(jit_compiler_handle_);
@@ -806,6 +818,28 @@ void Jit::PostForkChildAction() {
// Adjust the status of code cache collection: the status from zygote was to not collect.
code_cache_->SetGarbageCollectCode(!jit_generate_debug_info_(jit_compiler_handle_) &&
!Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled());
+
+ if (thread_pool_ != nullptr) {
+ // Remove potential tasks that have been inherited from the zygote.
+ thread_pool_->RemoveAllTasks(Thread::Current());
+
+ // Resume JIT compilation.
+ thread_pool_->CreateThreads();
+ }
+}
+
+void Jit::PreZygoteFork() {
+ if (thread_pool_ == nullptr) {
+ return;
+ }
+ thread_pool_->DeleteThreads();
+}
+
+void Jit::PostZygoteFork() {
+ if (thread_pool_ == nullptr) {
+ return;
+ }
+ thread_pool_->CreateThreads();
}
} // namespace jit
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index e12b032feb..7ce5f07672 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -285,8 +285,14 @@ class Jit {
// Start JIT threads.
void Start();
- // Transition to a zygote child state.
- void PostForkChildAction();
+ // Transition to a child state.
+ void PostForkChildAction(bool is_zygote);
+
+ // Prepare for forking.
+ void PreZygoteFork();
+
+ // Adjust state after forking.
+ void PostZygoteFork();
private:
Jit(JitCodeCache* code_cache, JitOptions* options);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 97887ccbc9..fdb6b86028 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -436,6 +436,12 @@ void JitCodeCache::InitializeState(size_t initial_capacity, size_t max_capacity)
initial_capacity = RoundDown(initial_capacity, 2 * kPageSize);
max_capacity = RoundDown(max_capacity, 2 * kPageSize);
+ used_memory_for_data_ = 0;
+ used_memory_for_code_ = 0;
+ number_of_compilations_ = 0;
+ number_of_osr_compilations_ = 0;
+ number_of_collections_ = 0;
+
data_pages_ = MemMap();
exec_pages_ = MemMap();
non_exec_pages_ = MemMap();
@@ -477,7 +483,7 @@ void JitCodeCache::InitializeSpaces() {
JitCodeCache::~JitCodeCache() {}
bool JitCodeCache::ContainsPc(const void* ptr) const {
- return exec_pages_.Begin() <= ptr && ptr < exec_pages_.End();
+ return exec_pages_.HasAddress(ptr) || zygote_exec_pages_.HasAddress(ptr);
}
bool JitCodeCache::WillExecuteJitCode(ArtMethod* method) {
@@ -1321,7 +1327,7 @@ class MarkCodeClosure final : public Closure {
return true;
}
const void* code = method_header->GetCode();
- if (code_cache_->ContainsPc(code)) {
+ if (code_cache_->ContainsPc(code) && !code_cache_->IsInZygoteExecSpace(code)) {
// Use the atomic set version, as multiple threads are executing this code.
bitmap_->AtomicTestAndSet(FromCodeToAllocation(code));
}
@@ -1493,7 +1499,7 @@ void JitCodeCache::GarbageCollectCache(Thread* self) {
// interpreter will update its entry point to the compiled code and call it.
for (ProfilingInfo* info : profiling_infos_) {
const void* entry_point = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
- if (ContainsPc(entry_point)) {
+ if (!IsInZygoteDataSpace(info) && ContainsPc(entry_point)) {
info->SetSavedEntryPoint(entry_point);
// Don't call Instrumentation::UpdateMethodsCode(), as it can check the declaring
// class of the method. We may be concurrently running a GC which makes accessing
@@ -1508,7 +1514,7 @@ void JitCodeCache::GarbageCollectCache(Thread* self) {
// Change entry points of native methods back to the GenericJNI entrypoint.
for (const auto& entry : jni_stubs_map_) {
const JniStubData& data = entry.second;
- if (!data.IsCompiled()) {
+ if (!data.IsCompiled() || IsInZygoteExecSpace(data.GetCode())) {
continue;
}
// Make sure a single invocation of the GenericJNI trampoline tries to recompile.
@@ -1540,7 +1546,9 @@ void JitCodeCache::RemoveUnmarkedCode(Thread* self) {
// Iterate over all compiled code and remove entries that are not marked.
for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
JniStubData* data = &it->second;
- if (!data->IsCompiled() || GetLiveBitmap()->Test(FromCodeToAllocation(data->GetCode()))) {
+ if (IsInZygoteExecSpace(data->GetCode()) ||
+ !data->IsCompiled() ||
+ GetLiveBitmap()->Test(FromCodeToAllocation(data->GetCode()))) {
++it;
} else {
method_headers.insert(OatQuickMethodHeader::FromCodePointer(data->GetCode()));
@@ -1550,7 +1558,7 @@ void JitCodeCache::RemoveUnmarkedCode(Thread* self) {
for (auto it = method_code_map_.begin(); it != method_code_map_.end();) {
const void* code_ptr = it->first;
uintptr_t allocation = FromCodeToAllocation(code_ptr);
- if (GetLiveBitmap()->Test(allocation)) {
+ if (IsInZygoteExecSpace(code_ptr) || GetLiveBitmap()->Test(allocation)) {
++it;
} else {
OatQuickMethodHeader* header = OatQuickMethodHeader::FromCodePointer(code_ptr);
@@ -1571,7 +1579,7 @@ void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
// Also remove the saved entry point from the ProfilingInfo objects.
for (ProfilingInfo* info : profiling_infos_) {
const void* ptr = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
- if (!ContainsPc(ptr) && !info->IsInUseByCompiler()) {
+ if (!ContainsPc(ptr) && !info->IsInUseByCompiler() && !IsInZygoteDataSpace(info)) {
info->GetMethod()->SetProfilingInfo(nullptr);
}
@@ -1596,6 +1604,9 @@ void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
for (const auto& entry : jni_stubs_map_) {
const JniStubData& data = entry.second;
const void* code_ptr = data.GetCode();
+ if (IsInZygoteExecSpace(code_ptr)) {
+ continue;
+ }
const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
for (ArtMethod* method : data.GetMethods()) {
if (method_header->GetEntryPoint() == method->GetEntryPointFromQuickCompiledCode()) {
@@ -1607,6 +1618,9 @@ void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
for (const auto& it : method_code_map_) {
ArtMethod* method = it.second;
const void* code_ptr = it.first;
+ if (IsInZygoteExecSpace(code_ptr)) {
+ continue;
+ }
const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
if (method_header->GetEntryPoint() == method->GetEntryPointFromQuickCompiledCode()) {
GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(code_ptr));
@@ -1953,6 +1967,7 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr
instrumentation->UpdateNativeMethodsCodeToJitCode(m, entrypoint);
}
if (collection_in_progress_) {
+ CHECK(!IsInZygoteExecSpace(data->GetCode()));
GetLiveBitmap()->AtomicTestAndSet(FromCodeToAllocation(data->GetCode()));
}
}
@@ -2057,6 +2072,10 @@ uint8_t* JitCodeCache::AllocateCode(size_t code_size) {
}
void JitCodeCache::FreeCode(uint8_t* code) {
+ if (IsInZygoteExecSpace(code)) {
+ // No need to free, this is shared memory.
+ return;
+ }
used_memory_for_code_ -= mspace_usable_size(code);
mspace_free(exec_mspace_, code);
}
@@ -2068,6 +2087,10 @@ uint8_t* JitCodeCache::AllocateData(size_t data_size) {
}
void JitCodeCache::FreeData(uint8_t* data) {
+ if (IsInZygoteDataSpace(data)) {
+ // No need to free, this is shared memory.
+ return;
+ }
used_memory_for_data_ -= mspace_usable_size(data);
mspace_free(data_mspace_, data);
}
@@ -2091,13 +2114,11 @@ void JitCodeCache::Dump(std::ostream& os) {
}
void JitCodeCache::PostForkChildAction(bool is_system_server, bool is_zygote) {
+ if (is_zygote) {
+ // Don't transition if this is for a child zygote.
+ return;
+ }
MutexLock mu(Thread::Current(), lock_);
- // Currently, we don't expect any compilations from zygote.
- CHECK_EQ(number_of_compilations_, 0u);
- CHECK_EQ(number_of_osr_compilations_, 0u);
- CHECK(jni_stubs_map_.empty());
- CHECK(method_code_map_.empty());
- CHECK(osr_code_map_.empty());
zygote_data_pages_ = std::move(data_pages_);
zygote_exec_pages_ = std::move(exec_pages_);
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 7a838fddd6..e2f3357ba2 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -71,6 +71,7 @@ template<class T> class ObjectArray;
namespace jit {
+class MarkCodeClosure;
class ScopedCodeCacheWrite;
// Alignment in bits that will suit all architectures.
@@ -387,6 +388,14 @@ class JitCodeCache {
const MemMap* GetUpdatableCodeMapping() const;
+ bool IsInZygoteDataSpace(const void* ptr) const {
+ return zygote_data_pages_.HasAddress(ptr);
+ }
+
+ bool IsInZygoteExecSpace(const void* ptr) const {
+ return zygote_exec_pages_.HasAddress(ptr);
+ }
+
bool IsWeakAccessEnabled(Thread* self) const;
void WaitUntilInlineCacheAccessible(Thread* self)
REQUIRES(!lock_)
@@ -487,6 +496,7 @@ class JitCodeCache {
friend class art::JitJniStubTestHelper;
friend class ScopedCodeCacheWrite;
+ friend class MarkCodeClosure;
DISALLOW_COPY_AND_ASSIGN(JitCodeCache);
};
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 0f655b94de..b7ac1e8fe3 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -249,6 +249,13 @@ static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
return reinterpret_cast<jlong>(ThreadForEnv(env));
}
+static void ZygoteHooks_nativePostZygoteFork(JNIEnv*, jclass) {
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsZygote()) {
+ runtime->PostZygoteFork();
+ }
+}
+
static void ZygoteHooks_nativePostForkSystemServer(JNIEnv* env ATTRIBUTE_UNUSED,
jclass klass ATTRIBUTE_UNUSED) {
// This JIT code cache for system server is created whilst the runtime is still single threaded.
@@ -305,7 +312,7 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env,
/* is_system_server= */ false, is_zygote);
}
// This must be called after EnableDebugFeatures.
- Runtime::Current()->GetJit()->PostForkChildAction();
+ Runtime::Current()->GetJit()->PostForkChildAction(is_zygote);
}
// Update tracing.
@@ -403,6 +410,7 @@ static void ZygoteHooks_stopZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),
+ NATIVE_METHOD(ZygoteHooks, nativePostZygoteFork, "()V"),
NATIVE_METHOD(ZygoteHooks, nativePostForkSystemServer, "()V"),
NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JIZZLjava/lang/String;)V"),
NATIVE_METHOD(ZygoteHooks, startZygoteNoThreadCreation, "()V"),
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 8be3730629..182319a27c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -600,9 +600,18 @@ void Runtime::Abort(const char* msg) {
}
void Runtime::PreZygoteFork() {
+ if (GetJit() != nullptr) {
+ GetJit()->PreZygoteFork();
+ }
heap_->PreZygoteFork();
}
+void Runtime::PostZygoteFork() {
+ if (GetJit() != nullptr) {
+ GetJit()->PostZygoteFork();
+ }
+}
+
void Runtime::CallExitHook(jint status) {
if (exit_ != nullptr) {
ScopedThreadStateChange tsc(Thread::Current(), kNative);
@@ -916,10 +925,6 @@ void Runtime::InitNonZygoteOrPostFork(
}
}
- if (jit_ != nullptr) {
- jit_->CreateThreadPool();
- }
-
if (thread_pool_ == nullptr) {
constexpr size_t kStackSize = 64 * KB;
constexpr size_t kMaxRuntimeWorkers = 4u;
@@ -2448,6 +2453,8 @@ void Runtime::CreateJit() {
LOG(WARNING) << "Failed to allocate JIT";
// Release JIT code cache resources (several MB of memory).
jit_code_cache_.reset();
+ } else {
+ jit->CreateThreadPool();
}
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 5450c0f057..45333761af 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -445,6 +445,7 @@ class Runtime {
bool UseJitCompilation() const;
void PreZygoteFork();
+ void PostZygoteFork();
void InitNonZygoteOrPostFork(
JNIEnv* env,
bool is_system_server,
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index 0f96510e86..de698c269f 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -136,26 +136,33 @@ ThreadPool::ThreadPool(const char* name,
waiting_count_(0),
start_time_(0),
total_wait_time_(0),
- // Add one since the caller of constructor waits on the barrier too.
- creation_barier_(num_threads + 1),
+ creation_barier_(0),
max_active_workers_(num_threads),
- create_peers_(create_peers) {
- while (GetThreadCount() < num_threads) {
- const std::string worker_name = StringPrintf("%s worker thread %zu", name_.c_str(),
- GetThreadCount());
- threads_.push_back(new ThreadPoolWorker(this, worker_name, worker_stack_size));
+ create_peers_(create_peers),
+ worker_stack_size_(worker_stack_size) {
+ CreateThreads();
+}
+
+void ThreadPool::CreateThreads() {
+ CHECK(threads_.empty());
+ Thread* self = Thread::Current();
+ {
+ MutexLock mu(self, task_queue_lock_);
+ shutting_down_ = false;
+ // Add one since the caller of constructor waits on the barrier too.
+ creation_barier_.Init(self, max_active_workers_ + 1);
+ while (GetThreadCount() < max_active_workers_) {
+ const std::string worker_name = StringPrintf("%s worker thread %zu", name_.c_str(),
+ GetThreadCount());
+ threads_.push_back(
+ new ThreadPoolWorker(this, worker_name, worker_stack_size_));
+ }
}
// Wait for all of the threads to attach.
creation_barier_.Wait(Thread::Current());
}
-void ThreadPool::SetMaxActiveWorkers(size_t threads) {
- MutexLock mu(Thread::Current(), task_queue_lock_);
- CHECK_LE(threads, GetThreadCount());
- max_active_workers_ = threads;
-}
-
-ThreadPool::~ThreadPool() {
+void ThreadPool::DeleteThreads() {
{
Thread* self = Thread::Current();
MutexLock mu(self, task_queue_lock_);
@@ -165,10 +172,22 @@ ThreadPool::~ThreadPool() {
task_queue_condition_.Broadcast(self);
completion_condition_.Broadcast(self);
}
- // Wait for the threads to finish.
+ // Wait for the threads to finish. We expect the user of the pool
+ // not to run multi-threaded calls to `CreateThreads` and `DeleteThreads`,
+ // so we don't guard the field here.
STLDeleteElements(&threads_);
}
+void ThreadPool::SetMaxActiveWorkers(size_t max_workers) {
+ MutexLock mu(Thread::Current(), task_queue_lock_);
+ CHECK_LE(max_workers, GetThreadCount());
+ max_active_workers_ = max_workers;
+}
+
+ThreadPool::~ThreadPool() {
+ DeleteThreads();
+}
+
void ThreadPool::StartWorkers(Thread* self) {
MutexLock mu(self, task_queue_lock_);
started_ = true;
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index fee009b7c0..f55d72ec30 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -129,6 +129,12 @@ class ThreadPool {
size_t worker_stack_size = ThreadPoolWorker::kDefaultStackSize);
virtual ~ThreadPool();
+ // Create the threads of this pool.
+ void CreateThreads();
+
+ // Stops and deletes all threads in this pool.
+ void DeleteThreads();
+
// Wait for all tasks currently on queue to get completed. If the pool has been stopped, only
// wait till all already running tasks are done.
// When the pool was created with peers for workers, do_work must not be true (see ThreadPool()).
@@ -174,7 +180,6 @@ class ThreadPool {
// How many worker threads are waiting on the condition.
volatile size_t waiting_count_ GUARDED_BY(task_queue_lock_);
std::deque<Task*> tasks_ GUARDED_BY(task_queue_lock_);
- // TODO: make this immutable/const?
std::vector<ThreadPoolWorker*> threads_;
// Work balance detection.
uint64_t start_time_ GUARDED_BY(task_queue_lock_);
@@ -182,6 +187,7 @@ class ThreadPool {
Barrier creation_barier_;
size_t max_active_workers_ GUARDED_BY(task_queue_lock_);
const bool create_peers_;
+ const size_t worker_stack_size_;
private:
friend class ThreadPoolWorker;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index cde885c288..a19cc92fe8 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -48,6 +48,7 @@ jclass WellKnownClasses::dalvik_system_DexFile;
jclass WellKnownClasses::dalvik_system_DexPathList;
jclass WellKnownClasses::dalvik_system_DexPathList__Element;
jclass WellKnownClasses::dalvik_system_EmulatedStackFrame;
+jclass WellKnownClasses::dalvik_system_InMemoryDexClassLoader;
jclass WellKnownClasses::dalvik_system_PathClassLoader;
jclass WellKnownClasses::dalvik_system_VMRuntime;
jclass WellKnownClasses::java_lang_annotation_Annotation__array;
@@ -306,6 +307,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
dalvik_system_DexPathList = CacheClass(env, "dalvik/system/DexPathList");
dalvik_system_DexPathList__Element = CacheClass(env, "dalvik/system/DexPathList$Element");
dalvik_system_EmulatedStackFrame = CacheClass(env, "dalvik/system/EmulatedStackFrame");
+ dalvik_system_InMemoryDexClassLoader = CacheClass(env, "dalvik/system/InMemoryDexClassLoader");
dalvik_system_PathClassLoader = CacheClass(env, "dalvik/system/PathClassLoader");
dalvik_system_VMRuntime = CacheClass(env, "dalvik/system/VMRuntime");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 66cbbec916..f0e98a83d7 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -57,6 +57,7 @@ struct WellKnownClasses {
static jclass dalvik_system_DexPathList;
static jclass dalvik_system_DexPathList__Element;
static jclass dalvik_system_EmulatedStackFrame;
+ static jclass dalvik_system_InMemoryDexClassLoader;
static jclass dalvik_system_PathClassLoader;
static jclass dalvik_system_VMRuntime;
static jclass java_lang_annotation_Annotation__array;
diff --git a/test/580-crc32/src/Main.java b/test/580-crc32/src/Main.java
index 7fc1273600..6199e9b2a9 100644
--- a/test/580-crc32/src/Main.java
+++ b/test/580-crc32/src/Main.java
@@ -15,29 +15,29 @@
*/
import java.util.zip.CRC32;
+import java.util.Random;
/**
- * The ART compiler can use intrinsics for the java.util.zip.CRC32 method:
- * private native static int update(int crc, int b)
+ * The ART compiler can use intrinsics for the java.util.zip.CRC32 methods:
+ * private native static int update(int crc, int b)
+ * private native static int updateBytes(int crc, byte[] b, int off, int len)
*
- * As the method is private it is not possible to check the use of intrinsics
- * for it directly.
+ * As the methods are private it is not possible to check the use of intrinsics
+ * for them directly.
* The tests check that correct checksums are produced.
*/
public class Main {
- private static CRC32 crc32 = new CRC32();
-
public Main() {
}
- public static long TestInt(int value) {
- crc32.reset();
+ public static long CRC32Byte(int value) {
+ CRC32 crc32 = new CRC32();
crc32.update(value);
return crc32.getValue();
}
- public static long TestInt(int... values) {
- crc32.reset();
+ public static long CRC32BytesUsingUpdateInt(int... values) {
+ CRC32 crc32 = new CRC32();
for (int value : values) {
crc32.update(value);
}
@@ -50,82 +50,301 @@ public class Main {
}
}
- public static void main(String args[]) {
+ private static void assertEqual(boolean expected, boolean actual) {
+ if (expected != actual) {
+ throw new Error("Expected: " + expected + ", found: " + actual);
+ }
+ }
+
+ private static void TestCRC32Update() {
// public void update(int b)
//
// Tests for checksums of the byte 0x0
- assertEqual(0xD202EF8DL, TestInt(0x0));
- assertEqual(0xD202EF8DL, TestInt(0x0100));
- assertEqual(0xD202EF8DL, TestInt(0x010000));
- assertEqual(0xD202EF8DL, TestInt(0x01000000));
- assertEqual(0xD202EF8DL, TestInt(0xff00));
- assertEqual(0xD202EF8DL, TestInt(0xffff00));
- assertEqual(0xD202EF8DL, TestInt(0xffffff00));
- assertEqual(0xD202EF8DL, TestInt(0x1200));
- assertEqual(0xD202EF8DL, TestInt(0x123400));
- assertEqual(0xD202EF8DL, TestInt(0x12345600));
- assertEqual(0xD202EF8DL, TestInt(Integer.MIN_VALUE));
+ // Check that only the low eight bits of the argument are used.
+ assertEqual(0xD202EF8DL, CRC32Byte(0x0));
+ assertEqual(0xD202EF8DL, CRC32Byte(0x0100));
+ assertEqual(0xD202EF8DL, CRC32Byte(0x010000));
+ assertEqual(0xD202EF8DL, CRC32Byte(0x01000000));
+ assertEqual(0xD202EF8DL, CRC32Byte(0xff00));
+ assertEqual(0xD202EF8DL, CRC32Byte(0xffff00));
+ assertEqual(0xD202EF8DL, CRC32Byte(0xffffff00));
+ assertEqual(0xD202EF8DL, CRC32Byte(0x1200));
+ assertEqual(0xD202EF8DL, CRC32Byte(0x123400));
+ assertEqual(0xD202EF8DL, CRC32Byte(0x12345600));
+ assertEqual(0xD202EF8DL, CRC32Byte(Integer.MIN_VALUE));
// Tests for checksums of the byte 0x1
- assertEqual(0xA505DF1BL, TestInt(0x1));
- assertEqual(0xA505DF1BL, TestInt(0x0101));
- assertEqual(0xA505DF1BL, TestInt(0x010001));
- assertEqual(0xA505DF1BL, TestInt(0x01000001));
- assertEqual(0xA505DF1BL, TestInt(0xff01));
- assertEqual(0xA505DF1BL, TestInt(0xffff01));
- assertEqual(0xA505DF1BL, TestInt(0xffffff01));
- assertEqual(0xA505DF1BL, TestInt(0x1201));
- assertEqual(0xA505DF1BL, TestInt(0x123401));
- assertEqual(0xA505DF1BL, TestInt(0x12345601));
+ // Check that only the low eight bits of the argument are used.
+ assertEqual(0xA505DF1BL, CRC32Byte(0x1));
+ assertEqual(0xA505DF1BL, CRC32Byte(0x0101));
+ assertEqual(0xA505DF1BL, CRC32Byte(0x010001));
+ assertEqual(0xA505DF1BL, CRC32Byte(0x01000001));
+ assertEqual(0xA505DF1BL, CRC32Byte(0xff01));
+ assertEqual(0xA505DF1BL, CRC32Byte(0xffff01));
+ assertEqual(0xA505DF1BL, CRC32Byte(0xffffff01));
+ assertEqual(0xA505DF1BL, CRC32Byte(0x1201));
+ assertEqual(0xA505DF1BL, CRC32Byte(0x123401));
+ assertEqual(0xA505DF1BL, CRC32Byte(0x12345601));
// Tests for checksums of the byte 0x0f
- assertEqual(0x42BDF21CL, TestInt(0x0f));
- assertEqual(0x42BDF21CL, TestInt(0x010f));
- assertEqual(0x42BDF21CL, TestInt(0x01000f));
- assertEqual(0x42BDF21CL, TestInt(0x0100000f));
- assertEqual(0x42BDF21CL, TestInt(0xff0f));
- assertEqual(0x42BDF21CL, TestInt(0xffff0f));
- assertEqual(0x42BDF21CL, TestInt(0xffffff0f));
- assertEqual(0x42BDF21CL, TestInt(0x120f));
- assertEqual(0x42BDF21CL, TestInt(0x12340f));
- assertEqual(0x42BDF21CL, TestInt(0x1234560f));
+ // Check that only the low eight bits of the argument are used.
+ assertEqual(0x42BDF21CL, CRC32Byte(0x0f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0x010f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0x01000f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0x0100000f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0xff0f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0xffff0f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0xffffff0f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0x120f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0x12340f));
+ assertEqual(0x42BDF21CL, CRC32Byte(0x1234560f));
// Tests for checksums of the byte 0xff
- assertEqual(0xFF000000L, TestInt(0x00ff));
- assertEqual(0xFF000000L, TestInt(0x01ff));
- assertEqual(0xFF000000L, TestInt(0x0100ff));
- assertEqual(0xFF000000L, TestInt(0x010000ff));
- assertEqual(0xFF000000L, TestInt(0x0000ffff));
- assertEqual(0xFF000000L, TestInt(0x00ffffff));
- assertEqual(0xFF000000L, TestInt(0xffffffff));
- assertEqual(0xFF000000L, TestInt(0x12ff));
- assertEqual(0xFF000000L, TestInt(0x1234ff));
- assertEqual(0xFF000000L, TestInt(0x123456ff));
- assertEqual(0xFF000000L, TestInt(Integer.MAX_VALUE));
+ // Check that only the low eight bits of the argument are used.
+ assertEqual(0xFF000000L, CRC32Byte(0x00ff));
+ assertEqual(0xFF000000L, CRC32Byte(0x01ff));
+ assertEqual(0xFF000000L, CRC32Byte(0x0100ff));
+ assertEqual(0xFF000000L, CRC32Byte(0x010000ff));
+ assertEqual(0xFF000000L, CRC32Byte(0x0000ffff));
+ assertEqual(0xFF000000L, CRC32Byte(0x00ffffff));
+ assertEqual(0xFF000000L, CRC32Byte(0xffffffff));
+ assertEqual(0xFF000000L, CRC32Byte(0x12ff));
+ assertEqual(0xFF000000L, CRC32Byte(0x1234ff));
+ assertEqual(0xFF000000L, CRC32Byte(0x123456ff));
+ assertEqual(0xFF000000L, CRC32Byte(Integer.MAX_VALUE));
// Tests for sequences
- assertEqual(0xFF41D912L, TestInt(0, 0, 0));
- assertEqual(0xFF41D912L, TestInt(0x0100, 0x010000, 0x01000000));
- assertEqual(0xFF41D912L, TestInt(0xff00, 0xffff00, 0xffffff00));
- assertEqual(0xFF41D912L, TestInt(0x1200, 0x123400, 0x12345600));
+ // Check that only the low eight bits of the values are used.
+ assertEqual(0xFF41D912L, CRC32BytesUsingUpdateInt(0, 0, 0));
+ assertEqual(0xFF41D912L,
+ CRC32BytesUsingUpdateInt(0x0100, 0x010000, 0x01000000));
+ assertEqual(0xFF41D912L,
+ CRC32BytesUsingUpdateInt(0xff00, 0xffff00, 0xffffff00));
+ assertEqual(0xFF41D912L,
+ CRC32BytesUsingUpdateInt(0x1200, 0x123400, 0x12345600));
+
+ assertEqual(0x909FB2F2L, CRC32BytesUsingUpdateInt(1, 1, 1));
+ assertEqual(0x909FB2F2L,
+ CRC32BytesUsingUpdateInt(0x0101, 0x010001, 0x01000001));
+ assertEqual(0x909FB2F2L,
+ CRC32BytesUsingUpdateInt(0xff01, 0xffff01, 0xffffff01));
+ assertEqual(0x909FB2F2L,
+ CRC32BytesUsingUpdateInt(0x1201, 0x123401, 0x12345601));
+
+ assertEqual(0xE33A9F71L, CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f));
+ assertEqual(0xE33A9F71L,
+ CRC32BytesUsingUpdateInt(0x010f, 0x01000f, 0x0100000f));
+ assertEqual(0xE33A9F71L,
+ CRC32BytesUsingUpdateInt(0xff0f, 0xffff0f, 0xffffff0f));
+ assertEqual(0xE33A9F71L,
+ CRC32BytesUsingUpdateInt(0x120f, 0x12340f, 0x1234560f));
+
+ assertEqual(0xFFFFFF00L, CRC32BytesUsingUpdateInt(0x0ff, 0x0ff, 0x0ff));
+ assertEqual(0xFFFFFF00L,
+ CRC32BytesUsingUpdateInt(0x01ff, 0x0100ff, 0x010000ff));
+ assertEqual(0xFFFFFF00L,
+ CRC32BytesUsingUpdateInt(0x00ffff, 0x00ffffff, 0xffffffff));
+ assertEqual(0xFFFFFF00L,
+ CRC32BytesUsingUpdateInt(0x12ff, 0x1234ff, 0x123456ff));
+
+ assertEqual(0xB6CC4292L, CRC32BytesUsingUpdateInt(0x01, 0x02));
+
+ assertEqual(0xB2DE047CL,
+ CRC32BytesUsingUpdateInt(0x0, -1, Integer.MIN_VALUE, Integer.MAX_VALUE));
+ }
+
+ private static long CRC32ByteArray(byte[] bytes, int off, int len) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(bytes, off, len);
+ return crc32.getValue();
+ }
+
+ // This is used to test we generate correct code for constant offsets.
+ // In this case the offset is 0.
+ private static long CRC32ByteArray(byte[] bytes) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(bytes);
+ return crc32.getValue();
+ }
+
+ private static long CRC32ByteAndByteArray(int value, byte[] bytes) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(value);
+ crc32.update(bytes);
+ return crc32.getValue();
+ }
+
+ private static long CRC32ByteArrayAndByte(byte[] bytes, int value) {
+ CRC32 crc32 = new CRC32();
+ crc32.update(bytes);
+ crc32.update(value);
+ return crc32.getValue();
+ }
+
+ private static boolean CRC32ByteArrayThrowsAIOOBE(byte[] bytes, int off, int len) {
+ try {
+ CRC32 crc32 = new CRC32();
+ crc32.update(bytes, off, len);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean CRC32ByteArrayThrowsNPE() {
+ try {
+ CRC32 crc32 = new CRC32();
+ crc32.update(null, 0, 0);
+ return false;
+ } catch (NullPointerException e) {}
+
+ try {
+ CRC32 crc32 = new CRC32();
+ crc32.update(null, 1, 2);
+ return false;
+ } catch (NullPointerException e) {}
- assertEqual(0x909FB2F2L, TestInt(1, 1, 1));
- assertEqual(0x909FB2F2L, TestInt(0x0101, 0x010001, 0x01000001));
- assertEqual(0x909FB2F2L, TestInt(0xff01, 0xffff01, 0xffffff01));
- assertEqual(0x909FB2F2L, TestInt(0x1201, 0x123401, 0x12345601));
+ try {
+ CRC32 crc32 = new CRC32();
+ crc32.update((byte[])null);
+ return false;
+ } catch (NullPointerException e) {}
+
+ return true;
+ }
+
+ private static long CRC32BytesUsingUpdateInt(byte[] bytes, int off, int len) {
+ CRC32 crc32 = new CRC32();
+ while (len-- > 0) {
+ crc32.update(bytes[off++]);
+ }
+ return crc32.getValue();
+ }
- assertEqual(0xE33A9F71L, TestInt(0x0f, 0x0f, 0x0f));
- assertEqual(0xE33A9F71L, TestInt(0x010f, 0x01000f, 0x0100000f));
- assertEqual(0xE33A9F71L, TestInt(0xff0f, 0xffff0f, 0xffffff0f));
- assertEqual(0xE33A9F71L, TestInt(0x120f, 0x12340f, 0x1234560f));
+ private static void TestCRC32UpdateBytes() {
+ assertEqual(0L, CRC32ByteArray(new byte[] {}));
+ assertEqual(0L, CRC32ByteArray(new byte[] {}, 0, 0));
+ assertEqual(0L, CRC32ByteArray(new byte[] {0}, 0, 0));
+ assertEqual(0L, CRC32ByteArray(new byte[] {0}, 1, 0));
+ assertEqual(0L, CRC32ByteArray(new byte[] {0, 0}, 1, 0));
- assertEqual(0xFFFFFF00L, TestInt(0x0ff, 0x0ff, 0x0ff));
- assertEqual(0xFFFFFF00L, TestInt(0x01ff, 0x0100ff, 0x010000ff));
- assertEqual(0xFFFFFF00L, TestInt(0x00ffff, 0x00ffffff, 0xffffffff));
- assertEqual(0xFFFFFF00L, TestInt(0x12ff, 0x1234ff, 0x123456ff));
+ assertEqual(true, CRC32ByteArrayThrowsNPE());
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, -1, 0));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0}, -1, 1));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0}, 0, -1));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 0, -1));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 1, 0));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, -1, 1));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 1, -1));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 0, 1));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 0, 10));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0}, 0, 10));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {}, 10, 10));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0, 0, 0, 0}, 2, 3));
+ assertEqual(true, CRC32ByteArrayThrowsAIOOBE(new byte[] {0, 0, 0, 0}, 3, 2));
- assertEqual(0xB6CC4292L, TestInt(0x01, 0x02));
+ assertEqual(CRC32Byte(0), CRC32ByteArray(new byte[] {0}));
+ assertEqual(CRC32Byte(0), CRC32ByteArray(new byte[] {0}, 0, 1));
+ assertEqual(CRC32Byte(1), CRC32ByteArray(new byte[] {1}));
+ assertEqual(CRC32Byte(1), CRC32ByteArray(new byte[] {1}, 0, 1));
+ assertEqual(CRC32Byte(0x0f), CRC32ByteArray(new byte[] {0x0f}));
+ assertEqual(CRC32Byte(0x0f), CRC32ByteArray(new byte[] {0x0f}, 0, 1));
+ assertEqual(CRC32Byte(0xff), CRC32ByteArray(new byte[] {-1}));
+ assertEqual(CRC32Byte(0xff), CRC32ByteArray(new byte[] {-1}, 0, 1));
+ assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
+ CRC32ByteArray(new byte[] {0, 0, 0}));
+ assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
+ CRC32ByteArray(new byte[] {0, 0, 0}, 0, 3));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
+ CRC32ByteArray(new byte[] {1, 1, 1}));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
+ CRC32ByteArray(new byte[] {1, 1, 1}, 0, 3));
+ assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
+ CRC32ByteArray(new byte[] {0x0f, 0x0f, 0x0f}));
+ assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
+ CRC32ByteArray(new byte[] {0x0f, 0x0f, 0x0f}, 0, 3));
+ assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
+ CRC32ByteArray(new byte[] {-1, -1, -1}));
+ assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
+ CRC32ByteArray(new byte[] {-1, -1, -1}, 0, 3));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 2),
+ CRC32ByteArray(new byte[] {1, 2}));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 2),
+ CRC32ByteArray(new byte[] {1, 2}, 0, 2));
+ assertEqual(
+ CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
+ CRC32ByteArray(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}));
+ assertEqual(
+ CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
+ CRC32ByteArray(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}, 0, 4));
- assertEqual(0xB2DE047CL, TestInt(0x0, -1, Integer.MIN_VALUE, Integer.MAX_VALUE));
+ assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
+ CRC32ByteAndByteArray(0, new byte[] {0, 0}));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
+ CRC32ByteAndByteArray(1, new byte[] {1, 1}));
+ assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
+ CRC32ByteAndByteArray(0x0f, new byte[] {0x0f, 0x0f}));
+ assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
+ CRC32ByteAndByteArray(-1, new byte[] {-1, -1}));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3),
+ CRC32ByteAndByteArray(1, new byte[] {2, 3}));
+ assertEqual(
+ CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
+ CRC32ByteAndByteArray(0, new byte[] {-1, Byte.MIN_VALUE, Byte.MAX_VALUE}));
+
+ assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0),
+ CRC32ByteArrayAndByte(new byte[] {0, 0}, 0));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1),
+ CRC32ByteArrayAndByte(new byte[] {1, 1}, 1));
+ assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f),
+ CRC32ByteArrayAndByte(new byte[] {0x0f, 0x0f}, 0x0f));
+ assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff),
+ CRC32ByteArrayAndByte(new byte[] {-1, -1}, -1));
+ assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3),
+ CRC32ByteArrayAndByte(new byte[] {1, 2}, 3));
+ assertEqual(
+ CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE),
+ CRC32ByteArrayAndByte(new byte[] {0, -1, Byte.MIN_VALUE}, Byte.MAX_VALUE));
+
+ byte[] bytes = new byte[128 * 1024];
+ Random rnd = new Random(0);
+ rnd.nextBytes(bytes);
+
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, bytes.length),
+ CRC32ByteArray(bytes));
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, 8 * 1024),
+ CRC32ByteArray(bytes, 0, 8 * 1024));
+
+ int off = rnd.nextInt(bytes.length / 2);
+ for (int len = 0; len <= 16; ++len) {
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
+ CRC32ByteArray(bytes, off, len));
+ }
+
+ // Check there are no issues with unaligned accesses.
+ for (int o = 1; o < 8; ++o) {
+ for (int l = 0; l <= 16; ++l) {
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, o, l),
+ CRC32ByteArray(bytes, o, l));
+ }
+ }
+
+ int len = bytes.length / 2;
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len - 1),
+ CRC32ByteArray(bytes, 0, len - 1));
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len),
+ CRC32ByteArray(bytes, 0, len));
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len + 1),
+ CRC32ByteArray(bytes, 0, len + 1));
+
+ len = rnd.nextInt(bytes.length + 1);
+ off = rnd.nextInt(bytes.length - len);
+ assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len),
+ CRC32ByteArray(bytes, off, len));
+ }
+
+ public static void main(String args[]) {
+ TestCRC32Update();
+ TestCRC32UpdateBytes();
}
}
diff --git a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
index 6305185471..433c2c7012 100644
--- a/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
+++ b/tools/class2greylist/src/com/android/class2greylist/Class2Greylist.java
@@ -17,7 +17,6 @@
package com.android.class2greylist;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
@@ -35,16 +34,10 @@ import org.apache.commons.cli.ParseException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
import java.util.Map;
-import java.util.HashMap;
import java.util.Set;
-import java.util.function.Predicate;
/**
* Build time tool for extracting a list of members from jar files that have the @UsedByApps
@@ -193,12 +186,31 @@ public class Class2Greylist {
new UnsupportedAppUsageAnnotationHandler(
mStatus, mOutput, mPublicApis, TARGET_SDK_TO_LIST_MAP);
GREYLIST_ANNOTATIONS.forEach(a -> builder.put(a, greylistAnnotationHandler));
+
+ CovariantReturnTypeHandler covariantReturnTypeHandler = new CovariantReturnTypeHandler(
+ mOutput, mPublicApis, FLAG_WHITELIST);
+
+ return addRepeatedAnnotationHandlers(builder, CovariantReturnTypeHandler.ANNOTATION_NAME,
+ CovariantReturnTypeHandler.REPEATED_ANNOTATION_NAME, covariantReturnTypeHandler)
+ .build();
+ }
+
+ /**
+ * Add a handler for an annotation as well as an handler for the container annotation that is
+ * used when the annotation is repeated.
+ *
+ * @param builder the builder for the map to which the handlers will be added.
+ * @param annotationName the name of the annotation.
+ * @param containerAnnotationName the name of the annotation container.
+ * @param handler the handler for the annotation.
+ */
+ private static Builder<String, AnnotationHandler> addRepeatedAnnotationHandlers(
+ Builder<String, AnnotationHandler> builder,
+ String annotationName, String containerAnnotationName,
+ AnnotationHandler handler) {
return builder
- .put(CovariantReturnTypeHandler.ANNOTATION_NAME,
- new CovariantReturnTypeHandler(mOutput, mPublicApis, FLAG_WHITELIST))
- .put(CovariantReturnTypeMultiHandler.ANNOTATION_NAME,
- new CovariantReturnTypeMultiHandler(mOutput, mPublicApis, FLAG_WHITELIST))
- .build();
+ .put(annotationName, handler)
+ .put(containerAnnotationName, new RepeatedAnnotationHandler(annotationName, handler));
}
private void main() throws IOException {
diff --git a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java b/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java
index b8de7e92fa..64d8997850 100644
--- a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java
+++ b/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeHandler.java
@@ -30,6 +30,8 @@ public class CovariantReturnTypeHandler extends AnnotationHandler {
private static final String SHORT_NAME = "CovariantReturnType";
public static final String ANNOTATION_NAME = "Ldalvik/annotation/codegen/CovariantReturnType;";
+ public static final String REPEATED_ANNOTATION_NAME =
+ "Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;";
private static final String RETURN_TYPE = "returnType";
diff --git a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java b/tools/class2greylist/src/com/android/class2greylist/RepeatedAnnotationHandler.java
index f2bc5254fa..61949e3972 100644
--- a/tools/class2greylist/src/com/android/class2greylist/CovariantReturnTypeMultiHandler.java
+++ b/tools/class2greylist/src/com/android/class2greylist/RepeatedAnnotationHandler.java
@@ -1,42 +1,26 @@
package com.android.class2greylist;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
-
import org.apache.bcel.classfile.AnnotationElementValue;
import org.apache.bcel.classfile.AnnotationEntry;
import org.apache.bcel.classfile.ArrayElementValue;
import org.apache.bcel.classfile.ElementValue;
import org.apache.bcel.classfile.ElementValuePair;
-import java.util.Set;
-
/**
- * Handles {@code CovariantReturnType$CovariantReturnTypes} annotations, which
- * are generated by the compiler when multiple {@code CovariantReturnType}
- * annotations appear on a single method.
+ * Handles a repeated annotation container.
*
- * <p>The enclosed annotations are passed to {@link CovariantReturnTypeHandler}.
+ * <p>The enclosed annotations are passed to the {@link #mWrappedHandler}.
*/
-public class CovariantReturnTypeMultiHandler extends AnnotationHandler {
-
- public static final String ANNOTATION_NAME =
- "Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;";
+public class RepeatedAnnotationHandler extends AnnotationHandler {
private static final String VALUE = "value";
- private final CovariantReturnTypeHandler mWrappedHandler;
+ private final AnnotationHandler mWrappedHandler;
private final String mInnerAnnotationName;
- public CovariantReturnTypeMultiHandler(AnnotationConsumer consumer, Set<String> publicApis,
- String hiddenapiFlag) {
- this(consumer, publicApis, hiddenapiFlag, CovariantReturnTypeHandler.ANNOTATION_NAME);
- }
-
- @VisibleForTesting
- public CovariantReturnTypeMultiHandler(AnnotationConsumer consumer, Set<String> publicApis,
- String hiddenapiFlag, String innerAnnotationName) {
- mWrappedHandler = new CovariantReturnTypeHandler(consumer, publicApis, hiddenapiFlag);
+ RepeatedAnnotationHandler(String innerAnnotationName, AnnotationHandler wrappedHandler) {
+ mWrappedHandler = wrappedHandler;
mInnerAnnotationName = innerAnnotationName;
}
@@ -45,7 +29,7 @@ public class CovariantReturnTypeMultiHandler extends AnnotationHandler {
// Verify that the annotation has the form we expect
ElementValuePair value = findValue(annotation);
if (value == null) {
- context.reportError("No value found on CovariantReturnType$CovariantReturnTypes");
+ context.reportError("No value found on %s", annotation.getAnnotationType());
return;
}
Preconditions.checkArgument(value.getValue() instanceof ArrayElementValue);
diff --git a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java
deleted file mode 100644
index 25f284455b..0000000000
--- a/tools/class2greylist/test/src/com/android/class2greylist/CovariantReturnTypeMultiHandlerTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.class2greylist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import static java.util.Collections.emptySet;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import java.io.IOException;
-import java.util.Map;
-
-public class CovariantReturnTypeMultiHandlerTest extends AnnotationHandlerTestBase {
-
- private static final String FLAG = "test-flag";
-
- @Before
- public void setup() throws IOException {
- // To keep the test simpler and more concise, we don't use the real
- // @CovariantReturnType annotation here, but use our own @Annotation
- // and @Annotation.Multi that have the same semantics. It doesn't have
- // to match the real annotation, just have the same properties
- // (returnType and value).
- mJavac.addSource("annotation.Annotation", Joiner.on('\n').join(
- "package annotation;",
- "import static java.lang.annotation.RetentionPolicy.CLASS;",
- "import java.lang.annotation.Repeatable;",
- "import java.lang.annotation.Retention;",
- "@Repeatable(Annotation.Multi.class)",
- "@Retention(CLASS)",
- "public @interface Annotation {",
- " Class<?> returnType();",
- " @Retention(CLASS)",
- " @interface Multi {",
- " Annotation[] value();",
- " }",
- "}"));
- }
-
- @Test
- public void testReturnTypeMulti() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(returnType=Integer.class)",
- " @Annotation(returnType=Long.class)",
- " public String method() {return null;}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of("Lannotation/Annotation$Multi;",
- new CovariantReturnTypeMultiHandler(
- mConsumer,
- ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"),
- FLAG,
- "Lannotation/Annotation;"));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- assertNoErrors();
- ArgumentCaptor<String> whitelist = ArgumentCaptor.forClass(String.class);
- verify(mConsumer, times(2)).consume(whitelist.capture(), any(),
- eq(ImmutableSet.of(FLAG)));
- assertThat(whitelist.getAllValues()).containsExactly(
- "La/b/Class;->method()Ljava/lang/Integer;",
- "La/b/Class;->method()Ljava/lang/Long;");
- }
-
- @Test
- public void testReturnTypeMultiNotPublicApi() throws IOException {
- mJavac.addSource("a.b.Class", Joiner.on('\n').join(
- "package a.b;",
- "import annotation.Annotation;",
- "public class Class {",
- " @Annotation(returnType=Integer.class)",
- " @Annotation(returnType=Long.class)",
- " public String method() {return null;}",
- "}"));
- mJavac.compile();
-
- Map<String, AnnotationHandler> handlerMap =
- ImmutableMap.of("Lannotation/Annotation$Multi;",
- new CovariantReturnTypeMultiHandler(
- mConsumer,
- emptySet(),
- FLAG,
- "Lannotation/Annotation;"));
- new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
-
- verify(mStatus, atLeastOnce()).error(any(), any());
- }
-}
diff --git a/tools/class2greylist/test/src/com/android/class2greylist/RepeatedAnnotationHandlerTest.java b/tools/class2greylist/test/src/com/android/class2greylist/RepeatedAnnotationHandlerTest.java
new file mode 100644
index 0000000000..f2f70ee1ba
--- /dev/null
+++ b/tools/class2greylist/test/src/com/android/class2greylist/RepeatedAnnotationHandlerTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+package com.android.class2greylist;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.bcel.classfile.AnnotationEntry;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RepeatedAnnotationHandlerTest extends AnnotationHandlerTestBase {
+
+ @Before
+ public void setup() {
+ // To keep the test simpler and more concise, we don't use a real annotation here, but use
+ // our own @Annotation and @Annotation.Multi that have the same relationship.
+ mJavac.addSource("annotation.Annotation", Joiner.on('\n').join(
+ "package annotation;",
+ "import static java.lang.annotation.RetentionPolicy.CLASS;",
+ "import java.lang.annotation.Repeatable;",
+ "import java.lang.annotation.Retention;",
+ "@Repeatable(Annotation.Multi.class)",
+ "@Retention(CLASS)",
+ "public @interface Annotation {",
+ " Class<?> clazz();",
+ " @Retention(CLASS)",
+ " @interface Multi {",
+ " Annotation[] value();",
+ " }",
+ "}"));
+ }
+
+ @Test
+ public void testRepeated() throws IOException {
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;",
+ "import annotation.Annotation;",
+ "public class Class {",
+ " @Annotation(clazz=Integer.class)",
+ " @Annotation(clazz=Long.class)",
+ " public String method() {return null;}",
+ "}"));
+ mJavac.compile();
+
+ TestAnnotationHandler handler = new TestAnnotationHandler();
+ Map<String, AnnotationHandler> handlerMap =
+ ImmutableMap.of("Lannotation/Annotation$Multi;",
+ new RepeatedAnnotationHandler("Lannotation/Annotation;", handler));
+ new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
+
+ assertNoErrors();
+ assertThat(handler.getClasses()).containsExactly(
+ "Ljava/lang/Integer;",
+ "Ljava/lang/Long;");
+ }
+
+ private static class TestAnnotationHandler extends AnnotationHandler {
+
+ private final List<String> classes;
+
+ private TestAnnotationHandler() {
+ this.classes = new ArrayList<>();
+ }
+
+ @Override
+ void handleAnnotation(AnnotationEntry annotation,
+ AnnotationContext context) {
+ classes.add(annotation.getElementValuePairs()[0].getValue().stringifyValue());
+ }
+
+ private List<String> getClasses() {
+ return classes;
+ }
+ }
+}