Merge "Refactor array access for the interpreter."
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index ec6efbc..10dc2d3 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -68,7 +68,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.oat.mk
LOCAL_ADDITIONAL_DEPENDENCIES += $(HOST_CORE_IMG_OUT)
include $(BUILD_PHONY_PACKAGE)
-endif
+endif # ART_BUILD_HOST
# If we aren't building the host toolchain, skip building the target core.art.
ifeq ($(WITH_HOST_DALVIK),true)
@@ -80,15 +80,5 @@
LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.oat.mk
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_CORE_IMG_OUT)
include $(BUILD_PHONY_PACKAGE)
-endif
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-include $(CLEAR_VARS)
-LOCAL_MODULE := boot.art
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.oat.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += $(DEFAULT_DEX_PREOPT_INSTALLED_IMAGE)
-include $(BUILD_PHONY_PACKAGE)
-endif
-endif
+endif # ART_BUILD_TARGET
+endif # WITH_HOST_DALVIK
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 25dfb0a..c6662c2 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -59,7 +59,8 @@
dex/frontend.cc \
dex/mir_graph.cc \
dex/mir_analysis.cc \
- dex/verified_methods_data.cc \
+ dex/verified_method.cc \
+ dex/verification_results.cc \
dex/vreg_analysis.cc \
dex/ssa_transformation.cc \
driver/compiler_driver.cc \
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 3368132..ff8fea0 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -176,8 +176,7 @@
if (!kEnableCheckCastEllision || !PerformOptimizations()) {
return inst;
}
- MethodReference referrer(&GetDexFile(), unit_.GetDexMethodIndex());
- if (!driver_.IsSafeCast(referrer, dex_pc)) {
+ if (!driver_.IsSafeCast(&unit_, dex_pc)) {
return inst;
}
// Ok, this is a safe cast. Since the "check-cast" instruction size is 2 code
@@ -272,15 +271,16 @@
} // namespace optimizer
} // namespace art
-extern "C" void ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item,
+extern "C" void ArtCompileDEX(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item,
uint32_t access_flags, art::InvokeType invoke_type,
uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
const art::DexFile& dex_file,
art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) {
art::DexCompilationUnit unit(NULL, class_loader, art::Runtime::Current()->GetClassLinker(),
- dex_file, code_item, class_def_idx, method_idx, access_flags);
- art::optimizer::DexCompiler dex_compiler(compiler, unit, dex_to_dex_compilation_level);
+ dex_file, code_item, class_def_idx, method_idx, access_flags,
+ driver.GetVerifiedMethod(&dex_file, method_idx));
+ art::optimizer::DexCompiler dex_compiler(driver, unit, dex_to_dex_compilation_level);
dex_compiler.Compile();
}
}
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 8c90edb..9dbb341 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -529,7 +529,8 @@
current_offset_ = 0;
// TODO: will need to snapshot stack image and use that as the mir context identification.
m_units_.push_back(new DexCompilationUnit(cu_, class_loader, Runtime::Current()->GetClassLinker(),
- dex_file, current_code_item_, class_def_idx, method_idx, access_flags));
+ dex_file, current_code_item_, class_def_idx, method_idx, access_flags,
+ cu_->compiler_driver->GetVerifiedMethod(&dex_file, method_idx)));
const uint16_t* code_ptr = current_code_item_->insns_;
const uint16_t* code_end =
current_code_item_->insns_ + current_code_item_->insns_size_in_code_units_;
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 1eb79c9..7f19ea1 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -21,7 +21,8 @@
#include "mir_to_lir-inl.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "verifier/dex_gc_map.h"
#include "verifier/method_verifier.h"
@@ -763,10 +764,10 @@
}
}
MethodReference method_ref(cu_->dex_file, cu_->method_idx);
- const std::vector<uint8_t>* gc_map_raw =
- cu_->compiler_driver->GetVerifiedMethodsData()->GetDexGcMap(method_ref);
- verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[0]);
- DCHECK_EQ(gc_map_raw->size(), dex_gc_map.RawSize());
+ const std::vector<uint8_t>& gc_map_raw =
+ mir_graph_->GetCurrentDexCompilationUnit()->GetVerifiedMethod()->GetDexGcMap();
+ verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]);
+ DCHECK_EQ(gc_map_raw.size(), dex_gc_map.RawSize());
// Compute native offset to references size.
NativePcToReferenceMapBuilder native_gc_map_builder(&native_gc_map_,
mapping_table.PcToDexSize(),
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index d8b9869..522bacb 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -207,13 +207,43 @@
RegLocation rl_src) {
FlushAllRegs(); /* Everything to home location */
ThreadOffset func_offset(-1);
- if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file,
+ const DexFile* dex_file = cu_->dex_file;
+ CompilerDriver* driver = cu_->compiler_driver;
+ if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *dex_file,
type_idx)) {
- func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArray);
+ bool is_type_initialized; // Ignored as an array does not have an initializer.
+ bool use_direct_type_ptr;
+ uintptr_t direct_type_ptr;
+ if (kEmbedClassInCode &&
+ driver->CanEmbedTypeInCode(*dex_file, type_idx,
+ &is_type_initialized, &use_direct_type_ptr, &direct_type_ptr)) {
+ // The fast path.
+ if (!use_direct_type_ptr) {
+ // Use the literal pool and a PC-relative load from a data word.
+ LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
+ if (data_target == nullptr) {
+ data_target = AddWordData(&class_literal_list_, type_idx);
+ }
+ LIR* load_pc_rel = OpPcRelLoad(TargetReg(kArg0), data_target);
+ AppendLIR(load_pc_rel);
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayResolved);
+ CallRuntimeHelperRegMethodRegLocation(func_offset, TargetReg(kArg0), rl_src, true);
+ } else {
+ // Use the direct pointer.
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArrayResolved);
+ CallRuntimeHelperImmMethodRegLocation(func_offset, direct_type_ptr, rl_src, true);
+ }
+ } else {
+ // The slow path.
+ DCHECK_EQ(func_offset.Int32Value(), -1);
+ func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArray);
+ CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
+ }
+ DCHECK_NE(func_offset.Int32Value(), -1);
} else {
func_offset= QUICK_ENTRYPOINT_OFFSET(pAllocArrayWithAccessCheck);
+ CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
}
- CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true);
RegLocation rl_result = GetReturn(false);
StoreValue(rl_dest, rl_result);
}
@@ -1133,8 +1163,7 @@
// Note: currently type_known_final is unused, as optimizing will only improve the performance
// of the exception throw path.
DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
- const MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
- if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
+ if (!needs_access_check && cu_->compiler_driver->IsSafeCast(cu, insn_idx)) {
// Verifier type analysis proved this check cast would never cause an exception.
return;
}
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index f865207..4bc1a37 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -153,6 +153,19 @@
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
+void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(ThreadOffset helper_offset, int arg0,
+ RegLocation arg2, bool safepoint_pc) {
+ int r_tgt = CallHelperSetup(helper_offset);
+ DCHECK_NE(TargetReg(kArg1), arg0);
+ if (TargetReg(kArg0) != arg0) {
+ OpRegCopy(TargetReg(kArg0), arg0);
+ }
+ LoadCurrMethodDirect(TargetReg(kArg1));
+ LoadValueDirectFixed(arg2, TargetReg(kArg2));
+ ClobberCallerSave();
+ CallHelper(r_tgt, helper_offset, safepoint_pc);
+}
+
void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0,
RegLocation arg1, bool safepoint_pc) {
int r_tgt = CallHelperSetup(helper_offset);
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 0a470a5..1f4122d 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -342,8 +342,8 @@
bool is_safe = is_null; // Always safe to store null.
if (!is_safe) {
// Check safety from verifier type information.
- const MethodReference mr(cu_->dex_file, cu_->method_idx);
- is_safe = cu_->compiler_driver->IsSafeCast(mr, mir->offset);
+ const DexCompilationUnit* unit = mir_graph_->GetCurrentDexCompilationUnit();
+ is_safe = cu_->compiler_driver->IsSafeCast(unit, mir->offset);
}
if (is_null || is_safe) {
// Store of constant null doesn't require an assignability test and can be generated inline
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 10136b6..bcd0eb1 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -530,6 +530,8 @@
void CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0,
bool safepoint_pc);
void CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc);
+ void CallRuntimeHelperRegMethodRegLocation(ThreadOffset helper_offset, int arg0,
+ RegLocation arg2, bool safepoint_pc);
void CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset,
RegLocation arg0, RegLocation arg1,
bool safepoint_pc);
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
new file mode 100644
index 0000000..edccec5
--- /dev/null
+++ b/compiler/dex/verification_results.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "verification_results.h"
+
+#include "base/stl_util.h"
+#include "base/mutex.h"
+#include "base/mutex-inl.h"
+#include "thread.h"
+#include "thread-inl.h"
+#include "verified_method.h"
+#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
+
+namespace art {
+
+VerificationResults::VerificationResults()
+ : verified_methods_lock_("compiler verified methods lock"),
+ verified_methods_(),
+ rejected_classes_lock_("compiler rejected classes lock"),
+ rejected_classes_() {
+}
+
+VerificationResults::~VerificationResults() {
+ Thread* self = Thread::Current();
+ {
+ WriterMutexLock mu(self, verified_methods_lock_);
+ STLDeleteValues(&verified_methods_);
+ }
+}
+
+bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
+ MethodReference ref = method_verifier->GetMethodReference();
+ bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
+ // TODO: Check also for virtual/interface invokes when DEX-to-DEX supports devirtualization.
+ if (!compile && !method_verifier->HasCheckCasts()) {
+ return true;
+ }
+
+ const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
+ if (verified_method == nullptr) {
+ DCHECK(method_verifier->HasFailures());
+ return false;
+ }
+
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ if (it != verified_methods_.end()) {
+ // TODO: Investigate why are we doing the work again for this method and try to avoid it.
+ LOG(WARNING) << "Method processed more than once: "
+ << PrettyMethod(ref.dex_method_index, *ref.dex_file);
+ DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
+ DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
+ DCHECK_EQ(it->second->GetDexGcMap().size(), verified_method->GetDexGcMap().size());
+ delete it->second;
+ verified_methods_.erase(it);
+ }
+ verified_methods_.Put(ref, verified_method);
+ DCHECK(verified_methods_.find(ref) != verified_methods_.end());
+ return true;
+}
+
+const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
+ ReaderMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ return (it != verified_methods_.end()) ? it->second : nullptr;
+}
+
+void VerificationResults::AddRejectedClass(ClassReference ref) {
+ {
+ WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
+ rejected_classes_.insert(ref);
+ }
+ DCHECK(IsClassRejected(ref));
+}
+
+bool VerificationResults::IsClassRejected(ClassReference ref) {
+ ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
+ return (rejected_classes_.find(ref) != rejected_classes_.end());
+}
+
+bool VerificationResults::IsCandidateForCompilation(MethodReference& method_ref,
+ const uint32_t access_flags) {
+#ifdef ART_SEA_IR_MODE
+ bool use_sea = Runtime::Current()->IsSeaIRMode();
+ use_sea = use_sea && (std::string::npos != PrettyMethod(
+ method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
+ if (use_sea) return true;
+#endif
+ // Don't compile class initializers, ever.
+ if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
+ return false;
+ }
+ return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
+}
+
+} // namespace art
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
new file mode 100644
index 0000000..2eb0713
--- /dev/null
+++ b/compiler/dex/verification_results.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEX_VERIFICATION_RESULTS_H_
+#define ART_COMPILER_DEX_VERIFICATION_RESULTS_H_
+
+#include <stdint.h>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "class_reference.h"
+#include "method_reference.h"
+#include "safe_map.h"
+
+namespace art {
+
+namespace verifier {
+class MethodVerifier;
+} // namespace verifier
+
+class VerifiedMethod;
+
+class VerificationResults {
+ public:
+ VerificationResults();
+ ~VerificationResults();
+
+ bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(verified_methods_lock_);
+
+ const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
+ LOCKS_EXCLUDED(verified_methods_lock_);
+
+ void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
+ bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
+
+ static bool IsCandidateForCompilation(MethodReference& method_ref,
+ const uint32_t access_flags);
+
+ private:
+ // Verified methods.
+ typedef SafeMap<MethodReference, const VerifiedMethod*,
+ MethodReferenceComparator> VerifiedMethodMap;
+ ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ VerifiedMethodMap verified_methods_;
+
+ // Rejected classes.
+ ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ std::set<ClassReference> rejected_classes_ GUARDED_BY(rejected_classes_lock_);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_VERIFICATION_RESULTS_H_
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
new file mode 100644
index 0000000..0f812a4
--- /dev/null
+++ b/compiler/dex/verified_method.cc
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "verified_method.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "dex_file.h"
+#include "dex_instruction.h"
+#include "dex_instruction-inl.h"
+#include "base/mutex.h"
+#include "base/mutex-inl.h"
+#include "mirror/art_method.h"
+#include "mirror/art_method-inl.h"
+#include "mirror/class.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
+#include "mirror/object.h"
+#include "mirror/object-inl.h"
+#include "UniquePtr.h"
+#include "verifier/dex_gc_map.h"
+#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
+#include "verifier/register_line.h"
+#include "verifier/register_line-inl.h"
+
+namespace art {
+
+const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_verifier,
+ bool compile) {
+ UniquePtr<VerifiedMethod> verified_method(new VerifiedMethod);
+ if (compile) {
+ /* Generate a register map. */
+ if (!verified_method->GenerateGcMap(method_verifier)) {
+ CHECK(method_verifier->HasFailures());
+ return nullptr; // Not a real failure, but a failure to encode.
+ }
+ if (kIsDebugBuild) {
+ VerifyGcMap(method_verifier, verified_method->dex_gc_map_);
+ }
+
+ // TODO: move this out when DEX-to-DEX supports devirtualization.
+ if (method_verifier->HasVirtualOrInterfaceInvokes()) {
+ verified_method->GenerateDevirtMap(method_verifier);
+ }
+ }
+
+ if (method_verifier->HasCheckCasts()) {
+ verified_method->GenerateSafeCastSet(method_verifier);
+ }
+ return verified_method.release();
+}
+
+const MethodReference* VerifiedMethod::GetDevirtTarget(uint32_t dex_pc) const {
+ auto it = devirt_map_.find(dex_pc);
+ return (it != devirt_map_.end()) ? &it->second : nullptr;
+}
+
+bool VerifiedMethod::IsSafeCast(uint32_t pc) const {
+ return std::binary_search(safe_cast_set_.begin(), safe_cast_set_.end(), pc);
+}
+
+bool VerifiedMethod::GenerateGcMap(verifier::MethodVerifier* method_verifier) {
+ DCHECK(dex_gc_map_.empty());
+ size_t num_entries, ref_bitmap_bits, pc_bits;
+ ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
+ // There's a single byte to encode the size of each bitmap.
+ if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) {
+ // TODO: either a better GC map format or per method failures
+ method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
+ return false;
+ }
+ size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
+ // There are 2 bytes to encode the number of entries.
+ if (num_entries >= 65536) {
+ // TODO: Either a better GC map format or per method failures.
+ method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Cannot encode GC map for method with " << num_entries << " entries";
+ return false;
+ }
+ size_t pc_bytes;
+ verifier::RegisterMapFormat format;
+ if (pc_bits <= 8) {
+ format = verifier::kRegMapFormatCompact8;
+ pc_bytes = 1;
+ } else if (pc_bits <= 16) {
+ format = verifier::kRegMapFormatCompact16;
+ pc_bytes = 2;
+ } else {
+ // TODO: Either a better GC map format or per method failures.
+ method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Cannot encode GC map for method with "
+ << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
+ return false;
+ }
+ size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
+ dex_gc_map_.reserve(table_size);
+ // Write table header.
+ dex_gc_map_.push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5));
+ dex_gc_map_.push_back(ref_bitmap_bytes & 0xFF);
+ dex_gc_map_.push_back(num_entries & 0xFF);
+ dex_gc_map_.push_back((num_entries >> 8) & 0xFF);
+ // Write table data.
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
+ if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
+ dex_gc_map_.push_back(i & 0xFF);
+ if (pc_bytes == 2) {
+ dex_gc_map_.push_back((i >> 8) & 0xFF);
+ }
+ verifier::RegisterLine* line = method_verifier->GetRegLine(i);
+ line->WriteReferenceBitMap(dex_gc_map_, ref_bitmap_bytes);
+ }
+ }
+ DCHECK_EQ(dex_gc_map_.size(), table_size);
+ return true;
+}
+
+void VerifiedMethod::VerifyGcMap(verifier::MethodVerifier* method_verifier,
+ const std::vector<uint8_t>& data) {
+ // Check that for every GC point there is a map entry, there aren't entries for non-GC points,
+ // that the table data is well formed and all references are marked (or not) in the bitmap.
+ verifier::DexPcToReferenceMap map(&data[0]);
+ DCHECK_EQ(data.size(), map.RawSize());
+ size_t map_index = 0;
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
+ const uint8_t* reg_bitmap = map.FindBitMap(i, false);
+ if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
+ DCHECK_LT(map_index, map.NumEntries());
+ DCHECK_EQ(map.GetDexPc(map_index), i);
+ DCHECK_EQ(map.GetBitMap(map_index), reg_bitmap);
+ map_index++;
+ verifier::RegisterLine* line = method_verifier->GetRegLine(i);
+ for (size_t j = 0; j < code_item->registers_size_; j++) {
+ if (line->GetRegisterType(j).IsNonZeroReferenceTypes()) {
+ DCHECK_LT(j / 8, map.RegWidth());
+ DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
+ } else if ((j / 8) < map.RegWidth()) {
+ DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
+ } else {
+ // If a register doesn't contain a reference then the bitmap may be shorter than the line.
+ }
+ }
+ } else {
+ DCHECK(reg_bitmap == NULL);
+ }
+ }
+}
+
+void VerifiedMethod::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
+ size_t* gc_points, size_t* ref_bitmap_bits,
+ size_t* log2_max_gc_pc) {
+ size_t local_gc_points = 0;
+ size_t max_insn = 0;
+ size_t max_ref_reg = -1;
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
+ if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
+ local_gc_points++;
+ max_insn = i;
+ verifier::RegisterLine* line = method_verifier->GetRegLine(i);
+ max_ref_reg = line->GetMaxNonZeroReferenceReg(max_ref_reg);
+ }
+ }
+ *gc_points = local_gc_points;
+ *ref_bitmap_bits = max_ref_reg + 1; // If max register is 0 we need 1 bit to encode (ie +1).
+ size_t i = 0;
+ while ((1U << i) <= max_insn) {
+ i++;
+ }
+ *log2_max_gc_pc = i;
+}
+
+void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) {
+ // It is risky to rely on reg_types for sharpening in cases of soft
+ // verification, we might end up sharpening to a wrong implementation. Just abort.
+ if (method_verifier->HasFailures()) {
+ return;
+ }
+
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ const uint16_t* insns = code_item->insns_;
+ const Instruction* inst = Instruction::At(insns);
+ const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
+
+ for (; inst < end; inst = inst->Next()) {
+ bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
+ (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
+ bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
+ (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+
+ if (!is_interface && !is_virtual) {
+ continue;
+ }
+ // Get reg type for register holding the reference to the object that will be dispatched upon.
+ uint32_t dex_pc = inst->GetDexPc(insns);
+ verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) ||
+ (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+ const verifier::RegType&
+ reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
+
+ if (!reg_type.HasClass()) {
+ // We will compute devirtualization information only when we know the Class of the reg type.
+ continue;
+ }
+ mirror::Class* reg_class = reg_type.GetClass();
+ if (reg_class->IsInterface()) {
+ // We can't devirtualize when the known type of the register is an interface.
+ continue;
+ }
+ if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) {
+ // We can't devirtualize abstract classes except on arrays of abstract classes.
+ continue;
+ }
+ mirror::ArtMethod* abstract_method = method_verifier->GetDexCache()->GetResolvedMethod(
+ is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
+ if (abstract_method == NULL) {
+ // If the method is not found in the cache this means that it was never found
+ // by ResolveMethodAndCheckAccess() called when verifying invoke_*.
+ continue;
+ }
+ // Find the concrete method.
+ mirror::ArtMethod* concrete_method = NULL;
+ if (is_interface) {
+ concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method);
+ }
+ if (is_virtual) {
+ concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
+ }
+ if (concrete_method == NULL || concrete_method->IsAbstract()) {
+ // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
+ continue;
+ }
+ if (reg_type.IsPreciseReference() || concrete_method->IsFinal() ||
+ concrete_method->GetDeclaringClass()->IsFinal()) {
+ // If we knew exactly the class being dispatched upon, or if the target method cannot be
+ // overridden record the target to be used in the compiler driver.
+ MethodReference concrete_ref(
+ concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
+ concrete_method->GetDexMethodIndex());
+ devirt_map_.Put(dex_pc, concrete_ref);
+ }
+ }
+}
+
+void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) {
+ /*
+ * Walks over the method code and adds any cast instructions in which
+ * the type cast is implicit to a set, which is used in the code generation
+ * to elide these casts.
+ */
+ if (method_verifier->HasFailures()) {
+ return;
+ }
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ const Instruction* inst = Instruction::At(code_item->insns_);
+ const Instruction* end = Instruction::At(code_item->insns_ +
+ code_item->insns_size_in_code_units_);
+
+ for (; inst < end; inst = inst->Next()) {
+ Instruction::Code code = inst->Opcode();
+ if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
+ uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+ const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+ bool is_safe_cast = false;
+ if (code == Instruction::CHECK_CAST) {
+ const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+ const verifier::RegType& cast_type =
+ method_verifier->ResolveCheckedClass(inst->VRegB_21c());
+ is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type);
+ } else {
+ const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x()));
+ // We only know its safe to assign to an array if the array type is precise. For example,
+ // an Object[] can have any type of object stored in it, but it may also be assigned a
+ // String[] in which case the stores need to be of Strings.
+ if (array_type.IsPreciseReference()) {
+ const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x()));
+ const verifier::RegType& component_type = method_verifier->GetRegTypeCache()
+ ->GetComponentType(array_type, method_verifier->GetClassLoader());
+ is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type);
+ }
+ }
+ if (is_safe_cast) {
+ // Verify ordering for push_back() to the sorted vector.
+ DCHECK(safe_cast_set_.empty() || safe_cast_set_.back() < dex_pc);
+ safe_cast_set_.push_back(dex_pc);
+ }
+ }
+ }
+}
+
+} // namespace art
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
new file mode 100644
index 0000000..aa0e72a
--- /dev/null
+++ b/compiler/dex/verified_method.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEX_VERIFIED_METHOD_H_
+#define ART_COMPILER_DEX_VERIFIED_METHOD_H_
+
+#include <vector>
+
+#include "method_reference.h"
+#include "safe_map.h"
+
+namespace art {
+
+namespace verifier {
+class MethodVerifier;
+} // namespace verifier
+
+class VerifiedMethod {
+ public:
+ // Cast elision set type.
+ // Since we're adding the dex PCs to the set in increasing order, a sorted vector
+ // is better for performance (not just memory usage), especially for large sets.
+ typedef std::vector<uint32_t> SafeCastSet;
+
+ // Devirtualization map type maps dex offset to concrete method reference.
+ typedef SafeMap<uint32_t, MethodReference> DevirtualizationMap;
+
+ static const VerifiedMethod* Create(verifier::MethodVerifier* method_verifier, bool compile)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ ~VerifiedMethod() = default;
+
+ const std::vector<uint8_t>& GetDexGcMap() const {
+ return dex_gc_map_;
+ }
+
+ const DevirtualizationMap& GetDevirtMap() const {
+ return devirt_map_;
+ }
+
+ const SafeCastSet& GetSafeCastSet() const {
+ return safe_cast_set_;
+ }
+
+ // Returns the devirtualization target method, or nullptr if none.
+ const MethodReference* GetDevirtTarget(uint32_t dex_pc) const;
+
+ // Returns true if the cast can statically be verified to be redundant
+ // by using the check-cast elision peephole optimization in the verifier.
+ bool IsSafeCast(uint32_t pc) const;
+
+ private:
+ VerifiedMethod() = default;
+
+ /*
+ * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of
+ * verification). For type-precise determination we have all the data we need, so we just need to
+ * encode it in some clever fashion.
+ * Stores the data in dex_gc_map_, returns true on success and false on failure.
+ */
+ bool GenerateGcMap(verifier::MethodVerifier* method_verifier);
+
+ // Verify that the GC map associated with method_ is well formed.
+ static void VerifyGcMap(verifier::MethodVerifier* method_verifier,
+ const std::vector<uint8_t>& data);
+
+ // Compute sizes for GC map data.
+ static void ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
+ size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
+
+ // Generate devirtualizaion map into devirt_map_.
+ void GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Generate safe case set into safe_cast_set_.
+ void GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ std::vector<uint8_t> dex_gc_map_;
+ DevirtualizationMap devirt_map_;
+ SafeCastSet safe_cast_set_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_VERIFIED_METHOD_H_
diff --git a/compiler/dex/verified_methods_data.cc b/compiler/dex/verified_methods_data.cc
deleted file mode 100644
index e6c4dda..0000000
--- a/compiler/dex/verified_methods_data.cc
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "base/stl_util.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
-#include "dex_instruction-inl.h"
-#include "base/mutex.h"
-#include "base/mutex-inl.h"
-#include "mirror/art_method.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class.h"
-#include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
-#include "mirror/dex_cache-inl.h"
-#include "mirror/object.h"
-#include "mirror/object-inl.h"
-#include "verified_methods_data.h"
-#include "verifier/dex_gc_map.h"
-#include "verifier/method_verifier.h"
-#include "verifier/method_verifier-inl.h"
-#include "verifier/register_line.h"
-#include "verifier/register_line-inl.h"
-
-namespace art {
-
-VerifiedMethodsData::VerifiedMethodsData()
- : dex_gc_maps_lock_("compiler GC maps lock"),
- dex_gc_maps_(),
- safecast_map_lock_("compiler Cast Elision lock"),
- safecast_map_(),
- devirt_maps_lock_("compiler Devirtualization lock"),
- devirt_maps_(),
- rejected_classes_lock_("compiler rejected classes lock"),
- rejected_classes_() {
-}
-
-VerifiedMethodsData::~VerifiedMethodsData() {
- Thread* self = Thread::Current();
- {
- WriterMutexLock mu(self, dex_gc_maps_lock_);
- STLDeleteValues(&dex_gc_maps_);
- }
- {
- WriterMutexLock mu(self, safecast_map_lock_);
- STLDeleteValues(&safecast_map_);
- }
- {
- WriterMutexLock mu(self, devirt_maps_lock_);
- STLDeleteValues(&devirt_maps_);
- }
-}
-
-bool VerifiedMethodsData::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
- MethodReference ref = method_verifier->GetMethodReference();
- bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
- if (compile) {
- /* Generate a register map and add it to the method. */
- const std::vector<uint8_t>* dex_gc_map = GenerateGcMap(method_verifier);
- if (dex_gc_map == NULL) {
- DCHECK(method_verifier->HasFailures());
- return false; // Not a real failure, but a failure to encode
- }
- if (kIsDebugBuild) {
- VerifyGcMap(method_verifier, *dex_gc_map);
- }
- SetDexGcMap(ref, dex_gc_map);
-
- // TODO: move this out when DEX-to-DEX supports devirtualization.
- if (method_verifier->HasVirtualOrInterfaceInvokes()) {
- PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap(method_verifier);
- if (pc_to_concrete_method != NULL) {
- SetDevirtMap(ref, pc_to_concrete_method);
- }
- }
- }
-
- if (method_verifier->HasCheckCasts()) {
- MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet(method_verifier);
- if (method_to_safe_casts != NULL) {
- SetSafeCastMap(ref, method_to_safe_casts);
- }
- }
- return true;
-}
-
-const std::vector<uint8_t>* VerifiedMethodsData::GetDexGcMap(MethodReference ref) {
- ReaderMutexLock mu(Thread::Current(), dex_gc_maps_lock_);
- DexGcMapTable::const_iterator it = dex_gc_maps_.find(ref);
- CHECK(it != dex_gc_maps_.end())
- << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file);
- CHECK(it->second != NULL);
- return it->second;
-}
-
-const MethodReference* VerifiedMethodsData::GetDevirtMap(const MethodReference& ref,
- uint32_t dex_pc) {
- ReaderMutexLock mu(Thread::Current(), devirt_maps_lock_);
- DevirtualizationMapTable::const_iterator it = devirt_maps_.find(ref);
- if (it == devirt_maps_.end()) {
- return NULL;
- }
-
- // Look up the PC in the map, get the concrete method to execute and return its reference.
- PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc);
- if (pc_to_concrete_method != it->second->end()) {
- return &(pc_to_concrete_method->second);
- } else {
- return NULL;
- }
-}
-
-bool VerifiedMethodsData::IsSafeCast(MethodReference ref, uint32_t pc) {
- ReaderMutexLock mu(Thread::Current(), safecast_map_lock_);
- SafeCastMap::const_iterator it = safecast_map_.find(ref);
- if (it == safecast_map_.end()) {
- return false;
- }
-
- // Look up the cast address in the set of safe casts
- // Use binary_search for lookup in the sorted vector.
- return std::binary_search(it->second->begin(), it->second->end(), pc);
-}
-
-void VerifiedMethodsData::AddRejectedClass(ClassReference ref) {
- {
- WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
- rejected_classes_.insert(ref);
- }
- DCHECK(IsClassRejected(ref));
-}
-
-bool VerifiedMethodsData::IsClassRejected(ClassReference ref) {
- ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
- return (rejected_classes_.find(ref) != rejected_classes_.end());
-}
-
-bool VerifiedMethodsData::IsCandidateForCompilation(MethodReference& method_ref,
- const uint32_t access_flags) {
-#ifdef ART_SEA_IR_MODE
- bool use_sea = Runtime::Current()->IsSeaIRMode();
- use_sea = use_sea && (std::string::npos != PrettyMethod(
- method_ref.dex_method_index, *(method_ref.dex_file)).find("fibonacci"));
- if (use_sea) return true;
-#endif
- // Don't compile class initializers, ever.
- if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
- return false;
- }
- return (Runtime::Current()->GetCompilerFilter() != Runtime::kInterpretOnly);
-}
-
-const std::vector<uint8_t>* VerifiedMethodsData::GenerateGcMap(
- verifier::MethodVerifier* method_verifier) {
- size_t num_entries, ref_bitmap_bits, pc_bits;
- ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
- // There's a single byte to encode the size of each bitmap
- if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) {
- // TODO: either a better GC map format or per method failures
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
- return NULL;
- }
- size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
- // There are 2 bytes to encode the number of entries
- if (num_entries >= 65536) {
- // TODO: either a better GC map format or per method failures
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with " << num_entries << " entries";
- return NULL;
- }
- size_t pc_bytes;
- verifier::RegisterMapFormat format;
- if (pc_bits <= 8) {
- format = verifier::kRegMapFormatCompact8;
- pc_bytes = 1;
- } else if (pc_bits <= 16) {
- format = verifier::kRegMapFormatCompact16;
- pc_bytes = 2;
- } else {
- // TODO: either a better GC map format or per method failures
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with "
- << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
- return NULL;
- }
- size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
- std::vector<uint8_t>* table = new std::vector<uint8_t>;
- if (table == NULL) {
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Failed to encode GC map (size=" << table_size << ")";
- return NULL;
- }
- table->reserve(table_size);
- // Write table header
- table->push_back(format | ((ref_bitmap_bytes & ~0xFF) >> 5));
- table->push_back(ref_bitmap_bytes & 0xFF);
- table->push_back(num_entries & 0xFF);
- table->push_back((num_entries >> 8) & 0xFF);
- // Write table data
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
- if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
- table->push_back(i & 0xFF);
- if (pc_bytes == 2) {
- table->push_back((i >> 8) & 0xFF);
- }
- verifier::RegisterLine* line = method_verifier->GetRegLine(i);
- line->WriteReferenceBitMap(*table, ref_bitmap_bytes);
- }
- }
- DCHECK_EQ(table->size(), table_size);
- return table;
-}
-
-void VerifiedMethodsData::VerifyGcMap(verifier::MethodVerifier* method_verifier,
- const std::vector<uint8_t>& data) {
- // Check that for every GC point there is a map entry, there aren't entries for non-GC points,
- // that the table data is well formed and all references are marked (or not) in the bitmap
- verifier::DexPcToReferenceMap map(&data[0]);
- DCHECK_EQ(data.size(), map.RawSize());
- size_t map_index = 0;
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
- const uint8_t* reg_bitmap = map.FindBitMap(i, false);
- if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
- CHECK_LT(map_index, map.NumEntries());
- CHECK_EQ(map.GetDexPc(map_index), i);
- CHECK_EQ(map.GetBitMap(map_index), reg_bitmap);
- map_index++;
- verifier::RegisterLine* line = method_verifier->GetRegLine(i);
- for (size_t j = 0; j < code_item->registers_size_; j++) {
- if (line->GetRegisterType(j).IsNonZeroReferenceTypes()) {
- CHECK_LT(j / 8, map.RegWidth());
- CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
- } else if ((j / 8) < map.RegWidth()) {
- CHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
- } else {
- // If a register doesn't contain a reference then the bitmap may be shorter than the line
- }
- }
- } else {
- CHECK(reg_bitmap == NULL);
- }
- }
-}
-
-void VerifiedMethodsData::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
- size_t* gc_points, size_t* ref_bitmap_bits,
- size_t* log2_max_gc_pc) {
- size_t local_gc_points = 0;
- size_t max_insn = 0;
- size_t max_ref_reg = -1;
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- for (size_t i = 0; i < code_item->insns_size_in_code_units_; i++) {
- if (method_verifier->GetInstructionFlags(i).IsCompileTimeInfoPoint()) {
- local_gc_points++;
- max_insn = i;
- verifier::RegisterLine* line = method_verifier->GetRegLine(i);
- max_ref_reg = line->GetMaxNonZeroReferenceReg(max_ref_reg);
- }
- }
- *gc_points = local_gc_points;
- *ref_bitmap_bits = max_ref_reg + 1; // if max register is 0 we need 1 bit to encode (ie +1)
- size_t i = 0;
- while ((1U << i) <= max_insn) {
- i++;
- }
- *log2_max_gc_pc = i;
-}
-
-void VerifiedMethodsData::SetDexGcMap(MethodReference ref, const std::vector<uint8_t>* gc_map) {
- DCHECK(Runtime::Current()->IsCompiler());
- {
- WriterMutexLock mu(Thread::Current(), dex_gc_maps_lock_);
- DexGcMapTable::iterator it = dex_gc_maps_.find(ref);
- if (it != dex_gc_maps_.end()) {
- delete it->second;
- dex_gc_maps_.erase(it);
- }
- dex_gc_maps_.Put(ref, gc_map);
- }
- DCHECK(GetDexGcMap(ref) != NULL);
-}
-
-VerifiedMethodsData::MethodSafeCastSet* VerifiedMethodsData::GenerateSafeCastSet(
- verifier::MethodVerifier* method_verifier) {
- /*
- * Walks over the method code and adds any cast instructions in which
- * the type cast is implicit to a set, which is used in the code generation
- * to elide these casts.
- */
- if (method_verifier->HasFailures()) {
- return NULL;
- }
- UniquePtr<MethodSafeCastSet> mscs;
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- const Instruction* inst = Instruction::At(code_item->insns_);
- const Instruction* end = Instruction::At(code_item->insns_ +
- code_item->insns_size_in_code_units_);
-
- for (; inst < end; inst = inst->Next()) {
- Instruction::Code code = inst->Opcode();
- if ((code == Instruction::CHECK_CAST) || (code == Instruction::APUT_OBJECT)) {
- uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
- const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
- bool is_safe_cast = false;
- if (code == Instruction::CHECK_CAST) {
- const verifier::RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
- const verifier::RegType& cast_type =
- method_verifier->ResolveCheckedClass(inst->VRegB_21c());
- is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type);
- } else {
- const verifier::RegType& array_type(line->GetRegisterType(inst->VRegB_23x()));
- // We only know its safe to assign to an array if the array type is precise. For example,
- // an Object[] can have any type of object stored in it, but it may also be assigned a
- // String[] in which case the stores need to be of Strings.
- if (array_type.IsPreciseReference()) {
- const verifier::RegType& value_type(line->GetRegisterType(inst->VRegA_23x()));
- const verifier::RegType& component_type = method_verifier->GetRegTypeCache()
- ->GetComponentType(array_type, method_verifier->GetClassLoader());
- is_safe_cast = component_type.IsStrictlyAssignableFrom(value_type);
- }
- }
- if (is_safe_cast) {
- if (mscs.get() == nullptr) {
- mscs.reset(new MethodSafeCastSet());
- } else {
- DCHECK_LT(mscs->back(), dex_pc); // Verify ordering for push_back() to the sorted vector.
- }
- mscs->push_back(dex_pc);
- }
- }
- }
- return mscs.release();
-}
-
-void VerifiedMethodsData::SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* cast_set) {
- WriterMutexLock mu(Thread::Current(), safecast_map_lock_);
- SafeCastMap::iterator it = safecast_map_.find(ref);
- if (it != safecast_map_.end()) {
- delete it->second;
- safecast_map_.erase(it);
- }
- safecast_map_.Put(ref, cast_set);
- DCHECK(safecast_map_.find(ref) != safecast_map_.end());
-}
-
-VerifiedMethodsData::PcToConcreteMethodMap* VerifiedMethodsData::GenerateDevirtMap(
- verifier::MethodVerifier* method_verifier) {
- // It is risky to rely on reg_types for sharpening in cases of soft
- // verification, we might end up sharpening to a wrong implementation. Just abort.
- if (method_verifier->HasFailures()) {
- return NULL;
- }
-
- UniquePtr<PcToConcreteMethodMap> pc_to_concrete_method_map;
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- const uint16_t* insns = code_item->insns_;
- const Instruction* inst = Instruction::At(insns);
- const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
-
- for (; inst < end; inst = inst->Next()) {
- bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
- (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
- bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
- (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
-
- if (!is_interface && !is_virtual) {
- continue;
- }
- // Get reg type for register holding the reference to the object that will be dispatched upon.
- uint32_t dex_pc = inst->GetDexPc(insns);
- verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
- bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) ||
- (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
- const verifier::RegType&
- reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
-
- if (!reg_type.HasClass()) {
- // We will compute devirtualization information only when we know the Class of the reg type.
- continue;
- }
- mirror::Class* reg_class = reg_type.GetClass();
- if (reg_class->IsInterface()) {
- // We can't devirtualize when the known type of the register is an interface.
- continue;
- }
- if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) {
- // We can't devirtualize abstract classes except on arrays of abstract classes.
- continue;
- }
- mirror::ArtMethod* abstract_method = method_verifier->GetDexCache()->GetResolvedMethod(
- is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
- if (abstract_method == NULL) {
- // If the method is not found in the cache this means that it was never found
- // by ResolveMethodAndCheckAccess() called when verifying invoke_*.
- continue;
- }
- // Find the concrete method.
- mirror::ArtMethod* concrete_method = NULL;
- if (is_interface) {
- concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method);
- }
- if (is_virtual) {
- concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
- }
- if (concrete_method == NULL || concrete_method->IsAbstract()) {
- // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
- continue;
- }
- if (reg_type.IsPreciseReference() || concrete_method->IsFinal() ||
- concrete_method->GetDeclaringClass()->IsFinal()) {
- // If we knew exactly the class being dispatched upon, or if the target method cannot be
- // overridden record the target to be used in the compiler driver.
- if (pc_to_concrete_method_map.get() == NULL) {
- pc_to_concrete_method_map.reset(new PcToConcreteMethodMap());
- }
- MethodReference concrete_ref(
- concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
- concrete_method->GetDexMethodIndex());
- pc_to_concrete_method_map->Put(dex_pc, concrete_ref);
- }
- }
- return pc_to_concrete_method_map.release();
-}
-
-void VerifiedMethodsData::SetDevirtMap(MethodReference ref,
- const PcToConcreteMethodMap* devirt_map) {
- WriterMutexLock mu(Thread::Current(), devirt_maps_lock_);
- DevirtualizationMapTable::iterator it = devirt_maps_.find(ref);
- if (it != devirt_maps_.end()) {
- delete it->second;
- devirt_maps_.erase(it);
- }
-
- devirt_maps_.Put(ref, devirt_map);
- DCHECK(devirt_maps_.find(ref) != devirt_maps_.end());
-}
-
-} // namespace art
diff --git a/compiler/dex/verified_methods_data.h b/compiler/dex/verified_methods_data.h
deleted file mode 100644
index d495dff..0000000
--- a/compiler/dex/verified_methods_data.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_
-#define ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_
-
-#include <stdint.h>
-#include <set>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "class_reference.h"
-#include "method_reference.h"
-#include "safe_map.h"
-
-namespace art {
-
-namespace verifier {
-class MethodVerifier;
-} // namespace verifier
-
-class VerifiedMethodsData {
- public:
- VerifiedMethodsData();
- ~VerifiedMethodsData();
-
- bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- LOCKS_EXCLUDED(dex_gc_maps_lock_, devirt_maps_lock_, safecast_map_lock_);
-
- const std::vector<uint8_t>* GetDexGcMap(MethodReference ref)
- LOCKS_EXCLUDED(dex_gc_maps_lock_);
-
- const MethodReference* GetDevirtMap(const MethodReference& ref, uint32_t dex_pc)
- LOCKS_EXCLUDED(devirt_maps_lock_);
-
- // Returns true if the cast can statically be verified to be redundant
- // by using the check-cast elision peephole optimization in the verifier
- bool IsSafeCast(MethodReference ref, uint32_t pc) LOCKS_EXCLUDED(safecast_map_lock_);
-
- void AddRejectedClass(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
- bool IsClassRejected(ClassReference ref) LOCKS_EXCLUDED(rejected_classes_lock_);
-
- static bool IsCandidateForCompilation(MethodReference& method_ref,
- const uint32_t access_flags);
-
- private:
- /*
- * Generate the GC map for a method that has just been verified (i.e. we're doing this as part of
- * verification). For type-precise determination we have all the data we need, so we just need to
- * encode it in some clever fashion.
- * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
- */
- const std::vector<uint8_t>* GenerateGcMap(verifier::MethodVerifier* method_verifier);
-
- // Verify that the GC map associated with method_ is well formed
- void VerifyGcMap(verifier::MethodVerifier* method_verifier, const std::vector<uint8_t>& data);
-
- // Compute sizes for GC map data
- void ComputeGcMapSizes(verifier::MethodVerifier* method_verifier,
- size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
-
- // All the GC maps that the verifier has created
- typedef SafeMap<const MethodReference, const std::vector<uint8_t>*,
- MethodReferenceComparator> DexGcMapTable;
- ReaderWriterMutex dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- DexGcMapTable dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_);
- void SetDexGcMap(MethodReference ref, const std::vector<uint8_t>* dex_gc_map)
- LOCKS_EXCLUDED(dex_gc_maps_lock_);
-
- // Cast elision types.
- // Since we're adding the dex PCs to the set in increasing order, a sorted vector
- // is better for performance (not just memory usage), especially for large sets.
- typedef std::vector<uint32_t> MethodSafeCastSet;
- typedef SafeMap<MethodReference, const MethodSafeCastSet*,
- MethodReferenceComparator> SafeCastMap;
- MethodSafeCastSet* GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* mscs)
- LOCKS_EXCLUDED(safecast_map_lock_);
- ReaderWriterMutex safecast_map_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- SafeCastMap safecast_map_ GUARDED_BY(safecast_map_lock_);
-
- // Devirtualization map.
- typedef SafeMap<uint32_t, MethodReference> PcToConcreteMethodMap;
- typedef SafeMap<MethodReference, const PcToConcreteMethodMap*,
- MethodReferenceComparator> DevirtualizationMapTable;
- PcToConcreteMethodMap* GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- ReaderWriterMutex devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- DevirtualizationMapTable devirt_maps_ GUARDED_BY(devirt_maps_lock_);
- void SetDevirtMap(MethodReference ref, const PcToConcreteMethodMap* pc_method_map)
- LOCKS_EXCLUDED(devirt_maps_lock_);
-
- // Rejected classes
- typedef std::set<ClassReference> RejectedClassesTable;
- ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- RejectedClassesTable rejected_classes_ GUARDED_BY(rejected_classes_lock_);
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_VERIFIED_METHODS_DATA_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f390b41..d504a4e 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -27,7 +27,8 @@
#include "class_linker.h"
#include "dex_compilation_unit.h"
#include "dex_file-inl.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "jni_internal.h"
#include "object_utils.h"
#include "runtime.h"
@@ -336,13 +337,13 @@
extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
std::string const& filename);
-CompilerDriver::CompilerDriver(VerifiedMethodsData* verified_methods_data,
+CompilerDriver::CompilerDriver(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes, size_t thread_count,
bool dump_stats)
- : verified_methods_data_(verified_methods_data),
+ : verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
compiler_backend_(compiler_backend),
instruction_set_(instruction_set),
@@ -1272,9 +1273,9 @@
if (enableVerifierBasedSharpening && (*invoke_type == kVirtual ||
*invoke_type == kInterface)) {
// Did the verifier record a more precise invoke target based on its type information?
- const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
+ DCHECK(mUnit->GetVerifiedMethod() != nullptr);
const MethodReference* devirt_map_target =
- verified_methods_data_->GetDevirtMap(caller_method, dex_pc);
+ mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
if (devirt_map_target != NULL) {
SirtRef<mirror::DexCache> target_dex_cache(soa.Self(), mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file));
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
@@ -1321,8 +1322,15 @@
return false; // Incomplete knowledge needs slow path.
}
-bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) {
- bool result = verified_methods_data_->IsSafeCast(mr, dex_pc);
+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) {
+ DCHECK(mUnit->GetVerifiedMethod() != nullptr);
+ bool result = mUnit->GetVerifiedMethod()->IsSafeCast(dex_pc);
if (result) {
stats_->SafeCast();
} else {
@@ -2268,7 +2276,7 @@
}
ClassReference ref(&dex_file, class_def_index);
// Skip compiling classes with generic verifier failures since they will still fail at runtime
- if (manager->GetCompiler()->verified_methods_data_->IsClassRejected(ref)) {
+ if (manager->GetCompiler()->verification_results_->IsClassRejected(ref)) {
return;
}
const byte* class_data = dex_file.GetClassData(class_def);
@@ -2351,7 +2359,7 @@
} else if ((access_flags & kAccAbstract) != 0) {
} else {
MethodReference method_ref(&dex_file, method_idx);
- bool compile = VerifiedMethodsData::IsCandidateForCompilation(method_ref, access_flags);
+ bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
CompilerFn compiler = compiler_;
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index eef94a1..a8110e7 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -44,7 +44,8 @@
class DexFileToMethodInlinerMap;
class OatWriter;
class TimingLogger;
-class VerifiedMethodsData;
+class VerificationResults;
+class VerifiedMethod;
enum CompilerBackend {
kQuick,
@@ -92,7 +93,7 @@
// enabled. "image_classes" lets the compiler know what classes it
// can assume will be in the image, with NULL implying all available
// classes.
- explicit CompilerDriver(VerifiedMethodsData* verified_methods_data,
+ explicit CompilerDriver(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
CompilerBackend compiler_backend, InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
@@ -109,8 +110,8 @@
void CompileOne(const mirror::ArtMethod* method, TimingLogger& timings)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- VerifiedMethodsData* GetVerifiedMethodsData() const {
- return verified_methods_data_;
+ VerificationResults* GetVerificationResults() const {
+ return verification_results_;
}
DexFileToMethodInlinerMap* GetMethodInlinerMap() const {
@@ -213,7 +214,8 @@
uintptr_t* direct_code, uintptr_t* direct_method)
LOCKS_EXCLUDED(Locks::mutator_lock_);
- bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc);
+ const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
+ bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
// Record patch information for later fix up.
void AddCodePatch(const DexFile* dex_file,
@@ -486,7 +488,7 @@
std::vector<const CallPatchInformation*> methods_to_patch_;
std::vector<const TypePatchInformation*> classes_to_patch_;
- VerifiedMethodsData* verified_methods_data_;
+ VerificationResults* verification_results_;
DexFileToMethodInlinerMap* method_inliner_map_;
CompilerBackend compiler_backend_;
diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc
index c441d09..840b0ad 100644
--- a/compiler/driver/dex_compilation_unit.cc
+++ b/compiler/driver/dex_compilation_unit.cc
@@ -31,7 +31,8 @@
code_item_(cu->code_item),
class_def_idx_(cu->class_def_idx),
dex_method_idx_(cu->method_idx),
- access_flags_(cu->access_flags) {
+ access_flags_(cu->access_flags),
+ verified_method_(cu_->compiler_driver->GetVerifiedMethod(cu->dex_file, cu->method_idx)) {
}
DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
@@ -41,7 +42,8 @@
const DexFile::CodeItem* code_item,
uint16_t class_def_idx,
uint32_t method_idx,
- uint32_t access_flags)
+ uint32_t access_flags,
+ const VerifiedMethod* verified_method)
: cu_(cu),
class_loader_(class_loader),
class_linker_(class_linker),
@@ -49,7 +51,8 @@
code_item_(code_item),
class_def_idx_(class_def_idx),
dex_method_idx_(method_idx),
- access_flags_(access_flags) {
+ access_flags_(access_flags),
+ verified_method_(verified_method) {
}
const std::string& DexCompilationUnit::GetSymbol() {
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 3df50ff..84f5799 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -29,6 +29,7 @@
} // namespace mirror
class ClassLinker;
struct CompilationUnit;
+class VerifiedMethod;
class DexCompilationUnit {
public:
@@ -36,7 +37,8 @@
DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker,
const DexFile& dex_file, const DexFile::CodeItem* code_item,
- uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags);
+ uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags,
+ const VerifiedMethod* verified_method);
CompilationUnit* GetCompilationUnit() const {
return cu_;
@@ -96,6 +98,10 @@
return ((access_flags_ & kAccSynchronized) != 0);
}
+ const VerifiedMethod* GetVerifiedMethod() const {
+ return verified_method_;
+ }
+
const std::string& GetSymbol();
private:
@@ -111,6 +117,7 @@
const uint16_t class_def_idx_;
const uint32_t dex_method_idx_;
const uint32_t access_flags_;
+ const VerifiedMethod* const verified_method_;
std::string symbol_;
};
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index 35d1ecd..94408bb 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -20,7 +20,8 @@
#include "base/stl_util.h"
#include "class_linker.h"
#include "compiled_method.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "globals.h"
@@ -153,11 +154,9 @@
cunit->Materialize();
- MethodReference mref(dex_compilation_unit->GetDexFile(),
- dex_compilation_unit->GetDexMethodIndex());
return new CompiledMethod(*compiler_driver_, compiler_driver_->GetInstructionSet(),
cunit->GetElfObject(),
- *compiler_driver_->GetVerifiedMethodsData()->GetDexGcMap(mref),
+ dex_compilation_unit->GetVerifiedMethod()->GetDexGcMap(),
cunit->GetDexCompilationUnit()->GetSymbol());
}
@@ -214,7 +213,7 @@
art::DexCompilationUnit dex_compilation_unit(
NULL, class_loader, class_linker, dex_file, code_item,
- class_def_idx, method_idx, access_flags);
+ class_def_idx, method_idx, access_flags, driver.GetVerifiedMethod(&dex_file, method_idx));
art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type);
return result;
@@ -226,8 +225,8 @@
art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
art::DexCompilationUnit dex_compilation_unit(
- NULL, NULL, class_linker, dex_file, NULL,
- 0, method_idx, access_flags);
+ nullptr, nullptr, class_linker, dex_file, nullptr,
+ 0, method_idx, access_flags, nullptr);
art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver);
art::CompiledMethod* result = compiler_llvm->CompileNativeMethod(&dex_compilation_unit);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 2434262..fc45412 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -79,10 +79,10 @@
InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
InstructionSetFeatures insn_features;
- verified_methods_data_.reset(new VerifiedMethodsData);
+ verification_results_.reset(new VerificationResults);
method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
- callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get());
- compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
+ callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
+ compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
method_inliner_map_.get(),
compiler_backend, insn_set,
insn_features, false, NULL, 2, true));
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 199a2b8..7a902d8 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -23,7 +23,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "dex_file-inl.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
#include "gc/space/space.h"
#include "mirror/art_method-inl.h"
#include "mirror/array.h"
@@ -218,7 +218,7 @@
mirror::Class::Status status;
if (compiled_class != NULL) {
status = compiled_class->GetStatus();
- } else if (compiler_driver_->GetVerifiedMethodsData()->IsClassRejected(class_ref)) {
+ } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
status = mirror::Class::kStatusError;
} else {
status = mirror::Class::kStatusNotReady;
@@ -433,7 +433,7 @@
mirror::Class::Status status;
if (compiled_class != NULL) {
status = compiled_class->GetStatus();
- } else if (compiler_driver_->GetVerifiedMethodsData()->IsClassRejected(class_ref)) {
+ } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
status = mirror::Class::kStatusError;
} else {
status = mirror::Class::kStatusNotReady;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 26fac23..97df199 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -32,7 +32,7 @@
#include "class_linker.h"
#include "compiler_callbacks.h"
#include "dex_file-inl.h"
-#include "dex/verified_methods_data.h"
+#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
#include "elf_fixup.h"
#include "elf_stripper.h"
@@ -268,7 +268,7 @@
Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
}
- UniquePtr<CompilerDriver> driver(new CompilerDriver(verified_methods_data_.get(),
+ UniquePtr<CompilerDriver> driver(new CompilerDriver(verification_results_.get(),
method_inliner_map_.get(),
compiler_backend_,
instruction_set_,
@@ -348,15 +348,15 @@
private:
class Dex2OatCompilerCallbacks : public CompilerCallbacks {
public:
- Dex2OatCompilerCallbacks(VerifiedMethodsData* verified_methods_data,
+ Dex2OatCompilerCallbacks(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map)
- : verified_methods_data_(verified_methods_data),
+ : verification_results_(verification_results),
method_inliner_map_(method_inliner_map) { }
virtual ~Dex2OatCompilerCallbacks() { }
virtual bool MethodVerified(verifier::MethodVerifier* verifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- bool result = verified_methods_data_->ProcessVerifiedMethod(verifier);
+ bool result = verification_results_->ProcessVerifiedMethod(verifier);
if (result && method_inliner_map_ != nullptr) {
MethodReference ref = verifier->GetMethodReference();
method_inliner_map_->GetMethodInliner(ref.dex_file)
@@ -365,11 +365,11 @@
return result;
}
virtual void ClassRejected(ClassReference ref) {
- verified_methods_data_->AddRejectedClass(ref);
+ verification_results_->AddRejectedClass(ref);
}
private:
- VerifiedMethodsData* verified_methods_data_;
+ VerificationResults* verification_results_;
DexFileToMethodInlinerMap* method_inliner_map_;
};
@@ -380,9 +380,9 @@
: compiler_backend_(compiler_backend),
instruction_set_(instruction_set),
instruction_set_features_(instruction_set_features),
- verified_methods_data_(new VerifiedMethodsData),
+ verification_results_(new VerificationResults),
method_inliner_map_(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr),
- callbacks_(verified_methods_data_.get(), method_inliner_map_.get()),
+ callbacks_(verification_results_.get(), method_inliner_map_.get()),
runtime_(nullptr),
thread_count_(thread_count),
start_ns_(NanoTime()) {
@@ -446,7 +446,7 @@
const InstructionSet instruction_set_;
const InstructionSetFeatures instruction_set_features_;
- UniquePtr<VerifiedMethodsData> verified_methods_data_;
+ UniquePtr<VerificationResults> verification_results_;
UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
Dex2OatCompilerCallbacks callbacks_;
Runtime* runtime_;
diff --git a/runtime/arch/quick_alloc_entrypoints.S b/runtime/arch/quick_alloc_entrypoints.S
index 4fdcb35..632c5f3 100644
--- a/runtime/arch/quick_alloc_entrypoints.S
+++ b/runtime/arch/quick_alloc_entrypoints.S
@@ -26,6 +26,8 @@
TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check\c_suffix, artAllocObjectFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
// Called by managed code to allocate an array.
THREE_ARG_DOWNCALL art_quick_alloc_array\c_suffix, artAllocArrayFromCode\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+// Called by managed code to allocate an array of a resolve class.
+THREE_ARG_DOWNCALL art_quick_alloc_array_resolved\c_suffix, artAllocArrayFromCodeResolved\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
// Called by managed code to allocate an array when the caller doesn't know whether it has access
// to the created type.
THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check\c_suffix, artAllocArrayFromCodeWithAccessCheck\cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
diff --git a/runtime/arch/quick_alloc_entrypoints.cc b/runtime/arch/quick_alloc_entrypoints.cc
index 0fad822..9363f81 100644
--- a/runtime/arch/quick_alloc_entrypoints.cc
+++ b/runtime/arch/quick_alloc_entrypoints.cc
@@ -19,6 +19,7 @@
#define GENERATE_ENTRYPOINTS(suffix) \
extern "C" void* art_quick_alloc_array##suffix(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved##suffix(void* klass, void*, int32_t); \
extern "C" void* art_quick_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
extern "C" void* art_quick_alloc_object##suffix(uint32_t type_idx, void* method); \
extern "C" void* art_quick_alloc_object_resolved##suffix(void* klass, void* method); \
@@ -27,6 +28,7 @@
extern "C" void* art_quick_check_and_alloc_array##suffix(uint32_t, void*, int32_t); \
extern "C" void* art_quick_check_and_alloc_array_with_access_check##suffix(uint32_t, void*, int32_t); \
extern "C" void* art_quick_alloc_array##suffix##_instrumented(uint32_t, void*, int32_t); \
+extern "C" void* art_quick_alloc_array_resolved##suffix##_instrumented(void* klass, void*, int32_t); \
extern "C" void* art_quick_alloc_array_with_access_check##suffix##_instrumented(uint32_t, void*, int32_t); \
extern "C" void* art_quick_alloc_object##suffix##_instrumented(uint32_t type_idx, void* method); \
extern "C" void* art_quick_alloc_object_resolved##suffix##_instrumented(void* klass, void* method); \
@@ -37,6 +39,7 @@
void SetQuickAllocEntryPoints##suffix(QuickEntryPoints* qpoints, bool instrumented) { \
if (instrumented) { \
qpoints->pAllocArray = art_quick_alloc_array##suffix##_instrumented; \
+ qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix##_instrumented; \
qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix##_instrumented; \
qpoints->pAllocObject = art_quick_alloc_object##suffix##_instrumented; \
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix##_instrumented; \
@@ -46,6 +49,7 @@
qpoints->pCheckAndAllocArrayWithAccessCheck = art_quick_check_and_alloc_array_with_access_check##suffix##_instrumented; \
} else { \
qpoints->pAllocArray = art_quick_alloc_array##suffix; \
+ qpoints->pAllocArrayResolved = art_quick_alloc_array_resolved##suffix; \
qpoints->pAllocArrayWithAccessCheck = art_quick_alloc_array_with_access_check##suffix; \
qpoints->pAllocObject = art_quick_alloc_object##suffix; \
qpoints->pAllocObjectResolved = art_quick_alloc_object_resolved##suffix; \
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 48c7d8d..74ec761 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -413,6 +413,8 @@
TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check ## c_suffix, artAllocObjectFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(c_suffix, cxx_suffix) \
THREE_ARG_DOWNCALL art_quick_alloc_array ## c_suffix, artAllocArrayFromCode ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
+#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(c_suffix, cxx_suffix) \
+ THREE_ARG_DOWNCALL art_quick_alloc_array_resolved ## c_suffix, artAllocArrayFromCodeResolved ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
#define GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(c_suffix, cxx_suffix) \
THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check ## c_suffix, artAllocArrayFromCodeWithAccessCheck ## cxx_suffix, RETURN_IF_RESULT_IS_NON_ZERO
#define GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(c_suffix, cxx_suffix) \
@@ -425,6 +427,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_dlmalloc, DlMalloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_dlmalloc, DlMalloc)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc, DlMalloc)
@@ -434,6 +437,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_dlmalloc_instrumented, DlMallocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_dlmalloc_instrumented, DlMallocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_dlmalloc_instrumented, DlMallocInstrumented)
@@ -443,6 +447,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc, RosAlloc)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_rosalloc, RosAlloc)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc, RosAlloc)
@@ -452,6 +457,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_rosalloc_instrumented, RosAllocInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_rosalloc_instrumented, RosAllocInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_rosalloc_instrumented, RosAllocInstrumented)
@@ -461,6 +467,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_bump_pointer, BumpPointer)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_bump_pointer, BumpPointer)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer, BumpPointer)
@@ -470,6 +477,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_bump_pointer_instrumented, BumpPointerInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_bump_pointer_instrumented, BumpPointerInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_bump_pointer_instrumented, BumpPointerInstrumented)
@@ -479,6 +487,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab, TLAB)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab, TLAB)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab, TLAB)
@@ -488,6 +497,7 @@
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY(_tlab_instrumented, TLABInstrumented)
+GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY(_tlab_instrumented, TLABInstrumented)
GENERATE_ALLOC_ENTRYPOINTS_CHECK_AND_ALLOC_ARRAY_WITH_ACCESS_CHECK(_tlab_instrumented, TLABInstrumented)
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b5d9fdf..344da3f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -199,14 +199,14 @@
Thread* self = Thread::Current();
gc::Heap* heap = Runtime::Current()->GetHeap();
// The GC can't handle an object with a null class since we can't get the size of this object.
- heap->IncrementDisableGC(self);
+ heap->IncrementDisableMovingGC(self);
SirtRef<mirror::Class> java_lang_Class(self, down_cast<mirror::Class*>(
heap->AllocNonMovableObject<true>(self, nullptr, sizeof(mirror::ClassClass))));
CHECK(java_lang_Class.get() != NULL);
mirror::Class::SetClassClass(java_lang_Class.get());
java_lang_Class->SetClass(java_lang_Class.get());
java_lang_Class->SetClassSize(sizeof(mirror::ClassClass));
- heap->DecrementDisableGC(self);
+ heap->DecrementDisableMovingGC(self);
// AllocClass(mirror::Class*) can now be used
// Class[] is used for reflection support.
diff --git a/runtime/common_test.h b/runtime/common_test.h
index ee95d5b..5e6354e 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -26,7 +26,7 @@
#include "../../external/icu4c/common/unicode/uvernum.h"
#include "../compiler/dex/quick/dex_file_to_method_inliner_map.h"
-#include "../compiler/dex/verified_methods_data.h"
+#include "../compiler/dex/verification_results.h"
#include "../compiler/driver/compiler_driver.h"
#include "base/macros.h"
#include "base/stl_util.h"
@@ -425,9 +425,9 @@
CompilerBackend compiler_backend = kQuick;
#endif
- verified_methods_data_.reset(new VerifiedMethodsData);
+ verification_results_.reset(new VerificationResults);
method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
- callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get());
+ callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
Runtime::Options options;
options.push_back(std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_)));
options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
@@ -474,7 +474,7 @@
}
}
class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
- compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
+ compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
method_inliner_map_.get(),
compiler_backend, instruction_set,
instruction_set_features,
@@ -526,7 +526,7 @@
compiler_driver_.reset();
callbacks_.Reset(nullptr, nullptr);
method_inliner_map_.reset();
- verified_methods_data_.reset();
+ verification_results_.reset();
STLDeleteElements(&opened_dex_files_);
Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test
@@ -654,18 +654,18 @@
class TestCompilerCallbacks : public CompilerCallbacks {
public:
- TestCompilerCallbacks() : verified_methods_data_(nullptr), method_inliner_map_(nullptr) { }
+ TestCompilerCallbacks() : verification_results_(nullptr), method_inliner_map_(nullptr) { }
- void Reset(VerifiedMethodsData* verified_methods_data,
+ void Reset(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map) {
- verified_methods_data_ = verified_methods_data;
+ verification_results_ = verification_results;
method_inliner_map_ = method_inliner_map;
}
virtual bool MethodVerified(verifier::MethodVerifier* verifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- CHECK(verified_methods_data_);
- bool result = verified_methods_data_->ProcessVerifiedMethod(verifier);
+ CHECK(verification_results_);
+ bool result = verification_results_->ProcessVerifiedMethod(verifier);
if (result && method_inliner_map_ != nullptr) {
MethodReference ref = verifier->GetMethodReference();
method_inliner_map_->GetMethodInliner(ref.dex_file)
@@ -674,11 +674,11 @@
return result;
}
virtual void ClassRejected(ClassReference ref) {
- verified_methods_data_->AddRejectedClass(ref);
+ verification_results_->AddRejectedClass(ref);
}
private:
- VerifiedMethodsData* verified_methods_data_;
+ VerificationResults* verification_results_;
DexFileToMethodInlinerMap* method_inliner_map_;
};
@@ -689,7 +689,7 @@
UniquePtr<Runtime> runtime_;
// Owned by the runtime
ClassLinker* class_linker_;
- UniquePtr<VerifiedMethodsData> verified_methods_data_;
+ UniquePtr<VerificationResults> verification_results_;
UniquePtr<DexFileToMethodInlinerMap> method_inliner_map_;
TestCompilerCallbacks callbacks_;
UniquePtr<CompilerDriver> compiler_driver_;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 5ee750f..f6e8ca3 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -232,6 +232,30 @@
return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, allocator_type);
}
+template <bool kAccessCheck, bool kInstrumented>
+ALWAYS_INLINE static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
+ mirror::ArtMethod* method,
+ int32_t component_count,
+ Thread* self,
+ gc::AllocatorType allocator_type)
+ NO_THREAD_SAFETY_ANALYSIS {
+ DCHECK(klass != nullptr);
+ if (UNLIKELY(component_count < 0)) {
+ ThrowNegativeArraySizeException(component_count);
+ return nullptr; // Failure
+ }
+ if (kAccessCheck) {
+ mirror::Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ ThrowIllegalAccessErrorClass(referrer, klass);
+ return nullptr; // Failure
+ }
+ }
+ // No need to retry a slow-path allocation as the above code won't
+ // cause a GC or thread suspension.
+ return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, allocator_type);
+}
+
extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::ArtMethod* method,
int32_t component_count, Thread* self,
bool access_check,
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 5657092..2e1b69d 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -56,6 +56,14 @@
return AllocArrayFromCode<false, instrumented_bool>(type_idx, method, component_count, self, \
allocator_type); \
} \
+extern "C" mirror::Array* artAllocArrayFromCodeResolved##suffix##suffix2( \
+ mirror::Class* klass, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
+ mirror::ArtMethod** sp) \
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); \
+ return AllocArrayFromCodeResolved<false, instrumented_bool>(klass, method, component_count, self, \
+ allocator_type); \
+} \
extern "C" mirror::Array* artAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
uint32_t type_idx, mirror::ArtMethod* method, int32_t component_count, Thread* self, \
mirror::ArtMethod** sp) \
diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index bbbc8f2..011e926 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -40,6 +40,7 @@
struct PACKED(4) QuickEntryPoints {
// Alloc
void* (*pAllocArray)(uint32_t, void*, int32_t);
+ void* (*pAllocArrayResolved)(void*, void*, int32_t);
void* (*pAllocArrayWithAccessCheck)(uint32_t, void*, int32_t);
void* (*pAllocObject)(uint32_t, void*);
void* (*pAllocObjectResolved)(void*, void*);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 14edc2f..06793bf 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -147,7 +147,7 @@
total_wait_time_(0),
total_allocation_time_(0),
verify_object_mode_(kHeapVerificationNotPermitted),
- gc_disable_count_(0),
+ disable_moving_gc_count_(0),
running_on_valgrind_(RUNNING_ON_VALGRIND),
use_tlab_(use_tlab) {
if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -328,19 +328,19 @@
return false;
}
-void Heap::IncrementDisableGC(Thread* self) {
+void Heap::IncrementDisableMovingGC(Thread* self) {
// Need to do this holding the lock to prevent races where the GC is about to run / running when
// we attempt to disable it.
ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
- WaitForGcToCompleteLocked(self);
- ++gc_disable_count_;
+ ++disable_moving_gc_count_;
+ // TODO: Wait for compacting GC to complete if we ever have a concurrent compacting GC.
}
-void Heap::DecrementDisableGC(Thread* self) {
+void Heap::DecrementDisableMovingGC(Thread* self) {
MutexLock mu(self, *gc_complete_lock_);
- CHECK_GE(gc_disable_count_, 0U);
- --gc_disable_count_;
+ CHECK_GE(disable_moving_gc_count_, 0U);
+ --disable_moving_gc_count_;
}
void Heap::UpdateProcessState(ProcessState process_state) {
@@ -1180,14 +1180,17 @@
Thread* self = Thread::Current();
ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
Locks::mutator_lock_->AssertNotHeld(self);
- // Busy wait until we can GC (StartGC can fail if we have a non-zero gc_disable_count_, this
- // rarely occurs however).
- while (!StartGC(self)) {
+ // Busy wait until we can GC (StartGC can fail if we have a non-zero
+ // compacting_gc_disable_count_, this should rarely occurs).
+ bool copying_transition =
+ IsCompactingGC(background_collector_type_) || IsCompactingGC(post_zygote_collector_type_);
+ while (!StartGC(self, copying_transition)) {
usleep(100);
}
tl->SuspendAll();
switch (collector_type) {
case kCollectorTypeSS:
+ // Fall-through.
case kCollectorTypeGSS: {
mprotect(temp_space_->Begin(), temp_space_->Capacity(), PROT_READ | PROT_WRITE);
CHECK(main_space_ != nullptr);
@@ -1202,7 +1205,7 @@
case kCollectorTypeMS:
// Fall through.
case kCollectorTypeCMS: {
- if (collector_type_ == kCollectorTypeSS || collector_type_ == kCollectorTypeGSS) {
+ if (IsCompactingGC(collector_type_)) {
// TODO: Use mem-map from temp space?
MemMap* mem_map = allocator_mem_map_.release();
CHECK(mem_map != nullptr);
@@ -1257,6 +1260,7 @@
gc_plan_.clear();
switch (collector_type_) {
case kCollectorTypeSS:
+ // Fall-through.
case kCollectorTypeGSS: {
concurrent_gc_ = false;
gc_plan_.push_back(collector::kGcTypeFull);
@@ -1529,7 +1533,8 @@
LOG(WARNING) << "Performing GC on a thread that is handling a stack overflow.";
}
gc_complete_lock_->AssertNotHeld(self);
- if (!StartGC(self)) {
+ const bool compacting_gc = IsCompactingGC(collector_type_);
+ if (!StartGC(self, compacting_gc)) {
return collector::kGcTypeNone;
}
if (gc_cause == kGcCauseForAlloc && runtime->HasStatsEnabled()) {
@@ -1551,7 +1556,7 @@
collector::GarbageCollector* collector = nullptr;
// TODO: Clean this up.
- if (collector_type_ == kCollectorTypeSS || collector_type_ == kCollectorTypeGSS) {
+ if (compacting_gc) {
DCHECK(current_allocator_ == kAllocatorTypeBumpPointer ||
current_allocator_ == kAllocatorTypeTLAB);
gc_type = semi_space_collector_->GetGcType();
@@ -1631,15 +1636,15 @@
return gc_type;
}
-bool Heap::StartGC(Thread* self) {
+bool Heap::StartGC(Thread* self, bool is_compacting) {
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
WaitForGcToCompleteLocked(self);
// TODO: if another thread beat this one to do the GC, perhaps we should just return here?
// Not doing at the moment to ensure soft references are cleared.
// GC can be disabled if someone has a used GetPrimitiveArrayCritical.
- if (gc_disable_count_ != 0) {
- LOG(WARNING) << "Skipping GC due to disable count " << gc_disable_count_;
+ if (is_compacting && disable_moving_gc_count_ != 0) {
+ LOG(WARNING) << "Skipping GC due to disable moving GC count " << disable_moving_gc_count_;
return false;
}
is_gc_running_ = true;
@@ -2125,7 +2130,8 @@
// Objects in the main space are only copied during background -> foreground transitions or
// visa versa.
if (main_space_ != nullptr && main_space_->HasAddress(obj) &&
- (IsCompactingGC(background_collector_type_) || IsCompactingGC(collector_type_))) {
+ (IsCompactingGC(background_collector_type_) ||
+ IsCompactingGC(post_zygote_collector_type_))) {
return true;
}
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 0232b4d..52138d1 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -243,9 +243,9 @@
// compaction related errors.
bool IsInTempSpace(const mirror::Object* obj) const;
- // Enables us to prevent GC until objects are released.
- void IncrementDisableGC(Thread* self);
- void DecrementDisableGC(Thread* self);
+ // Enables us to compacting GC until objects are released.
+ void IncrementDisableMovingGC(Thread* self);
+ void DecrementDisableMovingGC(Thread* self);
// Initiates an explicit garbage collection.
void CollectGarbage(bool clear_soft_references) LOCKS_EXCLUDED(Locks::mutator_lock_);
@@ -534,7 +534,7 @@
void Compact(space::ContinuousMemMapAllocSpace* target_space,
space::ContinuousMemMapAllocSpace* source_space);
- bool StartGC(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+ bool StartGC(Thread* self, bool is_compacting) LOCKS_EXCLUDED(gc_complete_lock_);
void FinishGC(Thread* self, collector::GcType gc_type) LOCKS_EXCLUDED(gc_complete_lock_);
static ALWAYS_INLINE bool AllocatorHasAllocationStack(AllocatorType allocator_type) {
@@ -880,8 +880,8 @@
// The current state of heap verification, may be enabled or disabled.
HeapVerificationMode verify_object_mode_;
- // GC disable count, error on GC if > 0.
- size_t gc_disable_count_ GUARDED_BY(gc_complete_lock_);
+ // Compacting GC disable count, prevents compacting GC from running iff > 0.
+ size_t disable_moving_gc_count_ GUARDED_BY(gc_complete_lock_);
std::vector<collector::GarbageCollector*> garbage_collectors_;
collector::SemiSpace* semi_space_collector_;
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 5186399..30b4ee8 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -523,6 +523,12 @@
return dlsym(handle_, symbol_name.c_str());
}
+ void VisitRoots(RootVisitor* visitor, void* arg) {
+ if (class_loader_ != nullptr) {
+ class_loader_ = visitor(class_loader_, arg);
+ }
+ }
+
private:
enum JNI_OnLoadState {
kPending,
@@ -613,6 +619,12 @@
return NULL;
}
+ void VisitRoots(RootVisitor* visitor, void* arg) {
+ for (auto& lib_pair : libraries_) {
+ lib_pair.second->VisitRoots(visitor, arg);
+ }
+ }
+
private:
SafeMap<std::string, SharedLibrary*> libraries_;
};
@@ -2195,7 +2207,7 @@
Array* array = soa.Decode<Array*>(java_array);
gc::Heap* heap = Runtime::Current()->GetHeap();
if (heap->IsMovableObject(array)) {
- heap->IncrementDisableGC(soa.Self());
+ heap->IncrementDisableMovingGC(soa.Self());
// Re-decode in case the object moved since IncrementDisableGC waits for GC to complete.
array = soa.Decode<Array*>(java_array);
}
@@ -2646,7 +2658,8 @@
if (is_copy) {
delete[] reinterpret_cast<uint64_t*>(elements);
} else if (heap->IsMovableObject(array)) {
- heap->DecrementDisableGC(soa.Self());
+ // Non copy to a movable object must means that we had disabled the moving GC.
+ heap->DecrementDisableMovingGC(soa.Self());
}
UnpinPrimitiveArray(soa, array);
}
@@ -3384,6 +3397,11 @@
MutexLock mu(self, pins_lock);
pin_table.VisitRoots(visitor, arg);
}
+ {
+ MutexLock mu(self, libraries_lock);
+ // Libraries contains shared libraries which hold a pointer to a class loader.
+ libraries->VisitRoots(visitor, arg);
+ }
// The weak_globals table is visited by the GC itself (because it mutates the table).
}
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index d3b8236..0a3e1a1 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <backtrace/BacktraceMap.h>
+#include "UniquePtr.h"
#include "base/stringprintf.h"
#include "ScopedFd.h"
#include "utils.h"
@@ -55,12 +56,12 @@
uintptr_t base = reinterpret_cast<uintptr_t>(addr);
uintptr_t limit = base + byte_count;
- BacktraceMap map(getpid());
- if (!map.Build()) {
+ UniquePtr<BacktraceMap> map(BacktraceMap::Create(getpid()));
+ if (!map->Build()) {
PLOG(WARNING) << "Failed to build process map";
return;
}
- for (BacktraceMap::const_iterator it = map.begin(); it != map.end(); ++it) {
+ for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
CHECK(!(base >= it->start && base < it->end) // start of new within old
&& !(limit > it->start && limit < it->end) // end of new within old
&& !(base <= it->start && limit > it->end)) // start/end of new includes all of old
@@ -69,7 +70,7 @@
base, limit,
static_cast<uintptr_t>(it->start), static_cast<uintptr_t>(it->end),
it->name.c_str())
- << std::make_pair(it, map.end());
+ << std::make_pair(it, map->end());
}
}
diff --git a/runtime/method_reference.h b/runtime/method_reference.h
index 1ff4ea0..8e46d7e 100644
--- a/runtime/method_reference.h
+++ b/runtime/method_reference.h
@@ -17,6 +17,8 @@
#ifndef ART_RUNTIME_METHOD_REFERENCE_H_
#define ART_RUNTIME_METHOD_REFERENCE_H_
+#include <stdint.h>
+
namespace art {
class DexFile;
diff --git a/runtime/oat.cc b/runtime/oat.cc
index caf18f1..81d4540 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '1', '3', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '1', '4', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e7fd660..d195ebf 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1624,6 +1624,7 @@
PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampoline),
PORTABLE_ENTRY_POINT_INFO(pPortableToInterpreterBridge),
QUICK_ENTRY_POINT_INFO(pAllocArray),
+ QUICK_ENTRY_POINT_INFO(pAllocArrayResolved),
QUICK_ENTRY_POINT_INFO(pAllocArrayWithAccessCheck),
QUICK_ENTRY_POINT_INFO(pAllocObject),
QUICK_ENTRY_POINT_INFO(pAllocObjectResolved),
diff --git a/test/Android.mk b/test/Android.mk
index 27834f0..d716f9b 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -71,6 +71,7 @@
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_MODULE_PATH := $(3)
LOCAL_DEX_PREOPT_IMAGE := $(TARGET_CORE_IMG_OUT)
+ LOCAL_DEX_PREOPT := false
LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
include $(BUILD_JAVA_LIBRARY)
@@ -84,6 +85,7 @@
LOCAL_JAVA_LIBRARIES := $(HOST_CORE_JARS)
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_OUT)
+ LOCAL_DEX_PREOPT := false
LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)