summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--compiler/Android.mk3
-rw-r--r--compiler/dex/arena_allocator.cc1
-rw-r--r--compiler/dex/compiler_enums.h1
-rw-r--r--compiler/dex/dex_to_dex_compiler.cc6
-rw-r--r--compiler/dex/frontend.cc16
-rw-r--r--compiler/dex/frontend.h2
-rw-r--r--compiler/dex/mir_optimization.cc10
-rw-r--r--compiler/dex/quick/arm/arm_dex_file_method_inliner.cc105
-rw-r--r--compiler/dex/quick/arm/arm_dex_file_method_inliner.h37
-rw-r--r--compiler/dex/quick/arm/call_arm.cc10
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h2
-rw-r--r--compiler/dex/quick/arm/fp_arm.cc2
-rw-r--r--compiler/dex/quick/arm/target_arm.cc2
-rw-r--r--compiler/dex/quick/codegen_util.cc217
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.cc84
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.h28
-rw-r--r--compiler/dex/quick/dex_file_to_method_inliner_map.cc26
-rw-r--r--compiler/dex/quick/dex_file_to_method_inliner_map.h11
-rw-r--r--compiler/dex/quick/gen_common.cc4
-rw-r--r--compiler/dex/quick/gen_invoke.cc51
-rw-r--r--compiler/dex/quick/mips/call_mips.cc2
-rw-r--r--compiler/dex/quick/mips/codegen_mips.h2
-rw-r--r--compiler/dex/quick/mips/mips_dex_file_method_inliner.cc105
-rw-r--r--compiler/dex/quick/mips/mips_dex_file_method_inliner.h37
-rw-r--r--compiler/dex/quick/mips/target_mips.cc2
-rw-r--r--compiler/dex/quick/mips/utility_mips.cc4
-rw-r--r--compiler/dex/quick/mir_to_lir.h19
-rw-r--r--compiler/dex/quick/ralloc_util.cc2
-rw-r--r--compiler/dex/quick/x86/assemble_x86.cc481
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h12
-rw-r--r--compiler/dex/quick/x86/int_x86.cc65
-rw-r--r--compiler/dex/quick/x86/target_x86.cc7
-rw-r--r--compiler/dex/quick/x86/x86_dex_file_method_inliner.cc111
-rw-r--r--compiler/dex/quick/x86/x86_dex_file_method_inliner.h37
-rw-r--r--compiler/dex/quick/x86/x86_lir.h4
-rw-r--r--compiler/driver/compiler_driver.cc28
-rw-r--r--compiler/image_test.cc10
-rw-r--r--compiler/leb128_encoder.h80
-rw-r--r--compiler/leb128_encoder_test.cc196
-rw-r--r--dex2oat/dex2oat.cc2
-rw-r--r--disassembler/disassembler_x86.cc7
-rw-r--r--runtime/Android.mk6
-rw-r--r--runtime/base/timing_logger.cc4
-rw-r--r--runtime/base/timing_logger.h7
-rw-r--r--runtime/class_linker.cc334
-rw-r--r--runtime/class_linker.h102
-rw-r--r--runtime/class_linker_test.cc103
-rw-r--r--runtime/debugger.cc23
-rw-r--r--runtime/dex_file.cc12
-rw-r--r--runtime/dex_file_verifier.cc3
-rw-r--r--runtime/dex_method_iterator_test.cc2
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc2
-rw-r--r--runtime/entrypoints/entrypoint_utils.h22
-rw-r--r--runtime/entrypoints/interpreter/interpreter_entrypoints.cc11
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc2
-rw-r--r--runtime/entrypoints/portable/portable_thread_entrypoints.cc6
-rw-r--r--runtime/entrypoints/portable/portable_trampoline_entrypoints.cc6
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc6
-rw-r--r--runtime/exception_test.cc28
-rw-r--r--runtime/gc/accounting/card_table.cc4
-rw-r--r--runtime/gc/accounting/mod_union_table.cc2
-rw-r--r--runtime/gc/collector/mark_sweep-inl.h7
-rw-r--r--runtime/gc/collector/mark_sweep.h8
-rw-r--r--runtime/gc/collector/semi_space.cc73
-rw-r--r--runtime/gc/collector/semi_space.h9
-rw-r--r--runtime/gc/collector_type.h2
-rw-r--r--runtime/gc/heap-inl.h52
-rw-r--r--runtime/gc/heap.cc228
-rw-r--r--runtime/gc/heap.h46
-rw-r--r--runtime/gc/space/space_test.cc254
-rw-r--r--runtime/globals.h2
-rw-r--r--runtime/interpreter/interpreter.cc7
-rw-r--r--runtime/interpreter/interpreter_common.cc14
-rw-r--r--runtime/interpreter/interpreter_common.h7
-rw-r--r--runtime/jdwp/object_registry.cc3
-rw-r--r--runtime/jni_internal.cc56
-rw-r--r--runtime/leb128.h21
-rw-r--r--runtime/mapping_table.h16
-rw-r--r--runtime/mirror/array-inl.h7
-rw-r--r--runtime/mirror/array.h3
-rw-r--r--runtime/mirror/art_field.cc7
-rw-r--r--runtime/mirror/art_field.h2
-rw-r--r--runtime/mirror/art_method.cc7
-rw-r--r--runtime/mirror/art_method.h4
-rw-r--r--runtime/mirror/class.cc6
-rw-r--r--runtime/mirror/class.h2
-rw-r--r--runtime/mirror/object.h10
-rw-r--r--runtime/mirror/object_test.cc4
-rw-r--r--runtime/mirror/stack_trace_element.cc7
-rw-r--r--runtime/mirror/stack_trace_element.h3
-rw-r--r--runtime/mirror/string.cc27
-rw-r--r--runtime/mirror/string.h15
-rw-r--r--runtime/mirror/throwable.cc6
-rw-r--r--runtime/mirror/throwable.h3
-rw-r--r--runtime/monitor.cc3
-rw-r--r--runtime/native/dalvik_system_DexFile.cc19
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc5
-rw-r--r--runtime/native/java_lang_Class.cc14
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc2
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc12
-rw-r--r--runtime/native/java_lang_reflect_Field.cc22
-rw-r--r--runtime/oat.cc2
-rw-r--r--runtime/object_utils.h18
-rw-r--r--runtime/reflection.cc8
-rw-r--r--runtime/runtime.cc78
-rw-r--r--runtime/runtime.h18
-rw-r--r--runtime/stack.cc1
-rw-r--r--runtime/thread-inl.h19
-rw-r--r--runtime/thread.cc95
-rw-r--r--runtime/thread.h11
-rw-r--r--runtime/thread_list.cc102
-rw-r--r--runtime/throw_location.cc7
-rw-r--r--runtime/verifier/dex_gc_map.h10
-rw-r--r--runtime/verifier/method_verifier.cc30
-rw-r--r--runtime/verifier/method_verifier.h6
-rw-r--r--runtime/verifier/reg_type.cc6
-rw-r--r--runtime/verifier/reg_type.h5
-rw-r--r--runtime/verifier/reg_type_cache.cc6
-rw-r--r--runtime/verifier/reg_type_cache.h3
-rw-r--r--runtime/zip_archive.cc524
-rw-r--r--runtime/zip_archive.h87
-rw-r--r--runtime/zip_archive_test.cc4
-rw-r--r--test/044-proxy/expected.txt5
-rw-r--r--test/044-proxy/src/BasicTest.java22
-rw-r--r--test/JniTest/JniTest.java12
-rw-r--r--test/JniTest/jni_test.cc36
-rw-r--r--test/ThreadStress/ThreadStress.java10
-rwxr-xr-xtools/cpplint.py2
-rwxr-xr-xtools/generate-operator-out.py2
130 files changed, 2146 insertions, 2498 deletions
diff --git a/Android.mk b/Android.mk
index 76fb411..0492d3c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -93,9 +93,9 @@ include $(art_path)/jdwpspy/Android.mk
include $(art_build_path)/Android.oat.mk
# ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES
-ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-hostdex.jar
+ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-libart-hostdex.jar
ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
-ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
+ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
########################################################################
# test targets
diff --git a/compiler/Android.mk b/compiler/Android.mk
index b7dc9f6..a2419d5 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -23,7 +23,6 @@ LIBART_COMPILER_SRC_FILES := \
dex/local_value_numbering.cc \
dex/arena_allocator.cc \
dex/arena_bit_vector.cc \
- dex/quick/arm/arm_dex_file_method_inliner.cc \
dex/quick/arm/assemble_arm.cc \
dex/quick/arm/call_arm.cc \
dex/quick/arm/fp_arm.cc \
@@ -41,7 +40,6 @@ LIBART_COMPILER_SRC_FILES := \
dex/quick/mips/call_mips.cc \
dex/quick/mips/fp_mips.cc \
dex/quick/mips/int_mips.cc \
- dex/quick/mips/mips_dex_file_method_inliner.cc \
dex/quick/mips/target_mips.cc \
dex/quick/mips/utility_mips.cc \
dex/quick/mir_to_lir.cc \
@@ -52,7 +50,6 @@ LIBART_COMPILER_SRC_FILES := \
dex/quick/x86/int_x86.cc \
dex/quick/x86/target_x86.cc \
dex/quick/x86/utility_x86.cc \
- dex/quick/x86/x86_dex_file_method_inliner.cc \
dex/portable/mir_to_gbc.cc \
dex/dex_to_dex_compiler.cc \
dex/mir_dataflow.cc \
diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc
index 95e44b3..132831c 100644
--- a/compiler/dex/arena_allocator.cc
+++ b/compiler/dex/arena_allocator.cc
@@ -28,6 +28,7 @@ namespace art {
static constexpr bool kUseMemMap = false;
static constexpr bool kUseMemSet = true && kUseMemMap;
static constexpr size_t kValgrindRedZoneBytes = 8;
+constexpr size_t Arena::kDefaultSize;
static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = {
"Misc ",
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index 56facfd..d73f148 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -374,6 +374,7 @@ enum OpFeatureFlags {
kRegUseA,
kRegUseC,
kRegUseD,
+ kRegUseB,
kRegUseFPCSList0,
kRegUseFPCSList2,
kRegUseList0,
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index abafbc5..3368132 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -52,12 +52,6 @@ class DexCompiler {
return *unit_.GetDexFile();
}
- // TODO: since the whole compilation pipeline uses a "const DexFile", we need
- // to "unconst" here. The DEX-to-DEX compiler should work on a non-const DexFile.
- DexFile& GetModifiableDexFile() {
- return *const_cast<DexFile*>(unit_.GetDexFile());
- }
-
bool PerformOptimizations() const {
return dex_to_dex_compilation_level_ >= kOptimize;
}
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 197bba5..6aabb2a 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -63,21 +63,21 @@ LLVMInfo::LLVMInfo() {
LLVMInfo::~LLVMInfo() {
}
-QuickCompilerContext::QuickCompilerContext(CompilerDriver& compiler)
- : inliner_map_(new DexFileToMethodInlinerMap(&compiler)) {
+QuickCompilerContext::QuickCompilerContext()
+ : inliner_map_(new DexFileToMethodInlinerMap()) {
}
QuickCompilerContext::~QuickCompilerContext() {
}
-extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) {
- CHECK(compiler.GetCompilerContext() == NULL);
- compiler.SetCompilerContext(new QuickCompilerContext(compiler));
+extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver) {
+ CHECK(driver.GetCompilerContext() == NULL);
+ driver.SetCompilerContext(new QuickCompilerContext());
}
-extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) {
- delete reinterpret_cast<QuickCompilerContext*>(compiler.GetCompilerContext());
- compiler.SetCompilerContext(NULL);
+extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver) {
+ delete reinterpret_cast<QuickCompilerContext*>(driver.GetCompilerContext());
+ driver.SetCompilerContext(NULL);
}
/* Default optimizer/debug setting for the compiler. */
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 4a863f5..bcb8bf0 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -115,7 +115,7 @@ class LLVMInfo {
class QuickCompilerContext {
public:
- explicit QuickCompilerContext(CompilerDriver& compiler);
+ QuickCompilerContext();
~QuickCompilerContext();
DexFileToMethodInlinerMap* GetInlinerMap() {
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 6353937..5d83991 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -923,11 +923,11 @@ void MIRGraph::BasicBlockOptimization() {
for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) {
BasicBlockOpt(GetBasicBlock(extended_basic_blocks_[i]));
}
- }
- } else {
- PreOrderDfsIterator iter(this);
- for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
- BasicBlockOpt(bb);
+ } else {
+ PreOrderDfsIterator iter(this);
+ for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
+ BasicBlockOpt(bb);
+ }
}
}
if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc b/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc
deleted file mode 100644
index 59f7202..0000000
--- a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc
+++ /dev/null
@@ -1,105 +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/logging.h"
-#include "base/macros.h"
-#include "dex/compiler_enums.h"
-
-#include "arm_dex_file_method_inliner.h"
-
-namespace art {
-
-const DexFileMethodInliner::IntrinsicDef ArmDexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
-
- INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
- INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
- INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
- INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
-
- INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
- INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
- INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-
- INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
- INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
- INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
- INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
- INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
- INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
- INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
- INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
- INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
- INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
- INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
- INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
- INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
- INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
- INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
- INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
- INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
- INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
- INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
- INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
- INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
- INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
- kIntrinsicFlagNone),
- INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
- kIntrinsicFlagIsLong),
- INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
- kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
- INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- type_flags & ~kIntrinsicFlagIsObject), \
- INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
- INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags), \
- INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags | kIntrinsicFlagIsVolatile), \
- INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags | kIntrinsicFlagIsOrdered)
-
- UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
- UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
- UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-#undef UNSAFE_GET_PUT
-
-#undef INTRINSIC
-};
-
-ArmDexFileMethodInliner::ArmDexFileMethodInliner() {
-}
-
-ArmDexFileMethodInliner::~ArmDexFileMethodInliner() {
-}
-
-void ArmDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
- IndexCache cache;
- DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
-}
-
-} // namespace art
diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h b/compiler/dex/quick/arm/arm_dex_file_method_inliner.h
deleted file mode 100644
index 3428391..0000000
--- a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h
+++ /dev/null
@@ -1,37 +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_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class ArmDexFileMethodInliner : public DexFileMethodInliner {
- public:
- ArmDexFileMethodInliner();
- ~ArmDexFileMethodInliner();
-
- void FindIntrinsics(const DexFile* dex_file);
-
- private:
- static const IntrinsicDef kIntrinsicMethods[];
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 51aca85..23ea407 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -434,7 +434,7 @@ void ArmMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) {
rARM_LR);
// Materialize a pointer to the fill data image
NewLIR3(kThumb2Adr, r1, 0, WrapPointer(tab_rec));
- ClobberCalleeSave();
+ ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx, rARM_LR);
MarkSafepointPC(call_inst);
}
@@ -471,7 +471,7 @@ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
// TODO: move to a slow path.
// Go expensive route - artLockObjectFromCode(obj);
LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR);
- ClobberCalleeSave();
+ ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx, rARM_LR);
MarkSafepointPC(call_inst);
@@ -490,7 +490,7 @@ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
OpIT(kCondNe, "T");
// Go expensive route - artLockObjectFromCode(self, obj);
LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR);
- ClobberCalleeSave();
+ ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR);
MarkSafepointPC(call_inst);
GenMemBarrier(kLoadLoad);
@@ -530,7 +530,7 @@ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
// TODO: move to a slow path.
// Go expensive route - artUnlockObjectFromCode(obj);
LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR);
- ClobberCalleeSave();
+ ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx, rARM_LR);
MarkSafepointPC(call_inst);
@@ -549,7 +549,7 @@ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
StoreWordDisp/*eq*/(r0, mirror::Object::MonitorOffset().Int32Value(), r3);
// Go expensive route - UnlockObjectFromCode(obj);
LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR);
- ClobberCalleeSave();
+ ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR);
MarkSafepointPC(call_inst);
GenMemBarrier(kStoreLoad);
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index de3223a..25ddc94 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -60,7 +60,7 @@ class ArmMir2Lir : public Mir2Lir {
uint32_t FpRegMask();
uint64_t GetRegMaskCommon(int reg);
void AdjustSpillMask();
- void ClobberCalleeSave();
+ void ClobberCallerSave();
void FlushReg(int reg);
void FlushRegWide(int reg1, int reg2);
void FreeCallTemps();
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index 1575ece..dc2e0d0 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -315,7 +315,7 @@ bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
S2d(rl_result.low_reg, rl_result.high_reg));
NewLIR0(kThumb2Fmstat);
branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
- ClobberCalleeSave();
+ ClobberCallerSave();
LockCallTemps(); // Using fixed registers
int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt));
NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 52aba9b..48c9af5 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -653,7 +653,7 @@ bool ArmMir2Lir::IsFpReg(int reg) {
}
/* Clobber all regs that might be used by an external C call */
-void ArmMir2Lir::ClobberCalleeSave() {
+void ArmMir2Lir::ClobberCallerSave() {
Clobber(r0);
Clobber(r1);
Clobber(r2);
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 4bc0b35..5d78ed5 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -24,6 +24,28 @@
namespace art {
+namespace {
+
+/* Dump a mapping table */
+template <typename It>
+void DumpMappingTable(const char* table_name, const char* descriptor, const char* name,
+ const Signature& signature, uint32_t size, It first) {
+ if (size != 0) {
+ std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name,
+ descriptor, name, signature.ToString().c_str(), size));
+ std::replace(line.begin(), line.end(), ';', '_');
+ LOG(INFO) << line;
+ for (uint32_t i = 0; i != size; ++i) {
+ line = StringPrintf(" {0x%05x, 0x%04x},", first.NativePcOffset(), first.DexPc());
+ ++first;
+ LOG(INFO) << line;
+ }
+ LOG(INFO) <<" };\n\n";
+ }
+}
+
+} // anonymous namespace
+
bool Mir2Lir::IsInexpensiveConstant(RegLocation rl_src) {
bool res = false;
if (rl_src.is_const) {
@@ -251,23 +273,6 @@ void Mir2Lir::DumpPromotionMap() {
}
}
-/* Dump a mapping table */
-void Mir2Lir::DumpMappingTable(const char* table_name, const char* descriptor,
- const char* name, const Signature& signature,
- const std::vector<uint32_t>& v) {
- if (v.size() > 0) {
- std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name,
- descriptor, name, signature.ToString().c_str(), v.size()));
- std::replace(line.begin(), line.end(), ';', '_');
- LOG(INFO) << line;
- for (uint32_t i = 0; i < v.size(); i+=2) {
- line = StringPrintf(" {0x%05x, 0x%04x},", v[i], v[i+1]);
- LOG(INFO) << line;
- }
- LOG(INFO) <<" };\n\n";
- }
-}
-
/* Dump instructions and constant pool contents */
void Mir2Lir::CodegenDump() {
LOG(INFO) << "Dumping LIR insns for "
@@ -302,8 +307,13 @@ void Mir2Lir::CodegenDump() {
const char* descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id));
// Dump mapping tables
- DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, pc2dex_mapping_table_);
- DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, dex2pc_mapping_table_);
+ if (!encoded_mapping_table_.empty()) {
+ MappingTable table(&encoded_mapping_table_[0]);
+ DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature,
+ table.PcToDexSize(), table.PcToDexBegin());
+ DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature,
+ table.DexToPcSize(), table.DexToPcBegin());
+ }
}
/*
@@ -522,79 +532,128 @@ static int AssignLiteralPointerOffsetCommon(LIR* lir, CodeOffset offset) {
// Make sure we have a code address for every declared catch entry
bool Mir2Lir::VerifyCatchEntries() {
+ MappingTable table(&encoded_mapping_table_[0]);
+ std::vector<uint32_t> dex_pcs;
+ dex_pcs.reserve(table.DexToPcSize());
+ for (auto it = table.DexToPcBegin(), end = table.DexToPcEnd(); it != end; ++it) {
+ dex_pcs.push_back(it.DexPc());
+ }
+ // Sort dex_pcs, so that we can quickly check it against the ordered mir_graph_->catches_.
+ std::sort(dex_pcs.begin(), dex_pcs.end());
+
bool success = true;
- for (std::set<uint32_t>::const_iterator it = mir_graph_->catches_.begin();
- it != mir_graph_->catches_.end(); ++it) {
- uint32_t dex_pc = *it;
- bool found = false;
- for (size_t i = 0; i < dex2pc_mapping_table_.size(); i += 2) {
- if (dex_pc == dex2pc_mapping_table_[i+1]) {
- found = true;
- break;
- }
- }
- if (!found) {
- LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dex_pc;
+ auto it = dex_pcs.begin(), end = dex_pcs.end();
+ for (uint32_t dex_pc : mir_graph_->catches_) {
+ while (it != end && *it < dex_pc) {
+ LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << *it;
+ ++it;
success = false;
}
- }
- // Now, try in the other direction
- for (size_t i = 0; i < dex2pc_mapping_table_.size(); i += 2) {
- uint32_t dex_pc = dex2pc_mapping_table_[i+1];
- if (mir_graph_->catches_.find(dex_pc) == mir_graph_->catches_.end()) {
- LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << dex_pc;
+ if (it == end || *it > dex_pc) {
+ LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dex_pc;
success = false;
+ } else {
+ ++it;
}
}
if (!success) {
LOG(INFO) << "Bad dex2pcMapping table in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
LOG(INFO) << "Entries @ decode: " << mir_graph_->catches_.size() << ", Entries in table: "
- << dex2pc_mapping_table_.size()/2;
+ << table.DexToPcSize();
}
return success;
}
void Mir2Lir::CreateMappingTables() {
+ uint32_t pc2dex_data_size = 0u;
+ uint32_t pc2dex_entries = 0u;
+ uint32_t pc2dex_offset = 0u;
+ uint32_t pc2dex_dalvik_offset = 0u;
+ uint32_t dex2pc_data_size = 0u;
+ uint32_t dex2pc_entries = 0u;
+ uint32_t dex2pc_offset = 0u;
+ uint32_t dex2pc_dalvik_offset = 0u;
for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
- pc2dex_mapping_table_.push_back(tgt_lir->offset);
- pc2dex_mapping_table_.push_back(tgt_lir->dalvik_offset);
+ pc2dex_entries += 1;
+ DCHECK(pc2dex_offset <= tgt_lir->offset);
+ pc2dex_data_size += UnsignedLeb128Size(tgt_lir->offset - pc2dex_offset);
+ pc2dex_data_size += SignedLeb128Size(static_cast<int32_t>(tgt_lir->dalvik_offset) -
+ static_cast<int32_t>(pc2dex_dalvik_offset));
+ pc2dex_offset = tgt_lir->offset;
+ pc2dex_dalvik_offset = tgt_lir->dalvik_offset;
}
if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) {
- dex2pc_mapping_table_.push_back(tgt_lir->offset);
- dex2pc_mapping_table_.push_back(tgt_lir->dalvik_offset);
+ dex2pc_entries += 1;
+ DCHECK(dex2pc_offset <= tgt_lir->offset);
+ dex2pc_data_size += UnsignedLeb128Size(tgt_lir->offset - dex2pc_offset);
+ dex2pc_data_size += SignedLeb128Size(static_cast<int32_t>(tgt_lir->dalvik_offset) -
+ static_cast<int32_t>(dex2pc_dalvik_offset));
+ dex2pc_offset = tgt_lir->offset;
+ dex2pc_dalvik_offset = tgt_lir->dalvik_offset;
}
}
- if (kIsDebugBuild) {
- CHECK(VerifyCatchEntries());
+
+ uint32_t total_entries = pc2dex_entries + dex2pc_entries;
+ uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
+ uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
+ encoded_mapping_table_.resize(data_size);
+ uint8_t* write_pos = &encoded_mapping_table_[0];
+ write_pos = EncodeUnsignedLeb128(write_pos, total_entries);
+ write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries);
+ DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]), hdr_data_size);
+ uint8_t* write_pos2 = write_pos + pc2dex_data_size;
+
+ pc2dex_offset = 0u;
+ pc2dex_dalvik_offset = 0u;
+ dex2pc_offset = 0u;
+ dex2pc_dalvik_offset = 0u;
+ for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+ if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
+ DCHECK(pc2dex_offset <= tgt_lir->offset);
+ write_pos = EncodeUnsignedLeb128(write_pos, tgt_lir->offset - pc2dex_offset);
+ write_pos = EncodeSignedLeb128(write_pos, static_cast<int32_t>(tgt_lir->dalvik_offset) -
+ static_cast<int32_t>(pc2dex_dalvik_offset));
+ pc2dex_offset = tgt_lir->offset;
+ pc2dex_dalvik_offset = tgt_lir->dalvik_offset;
+ }
+ if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) {
+ DCHECK(dex2pc_offset <= tgt_lir->offset);
+ write_pos2 = EncodeUnsignedLeb128(write_pos2, tgt_lir->offset - dex2pc_offset);
+ write_pos2 = EncodeSignedLeb128(write_pos2, static_cast<int32_t>(tgt_lir->dalvik_offset) -
+ static_cast<int32_t>(dex2pc_dalvik_offset));
+ dex2pc_offset = tgt_lir->offset;
+ dex2pc_dalvik_offset = tgt_lir->dalvik_offset;
+ }
}
- CHECK_EQ(pc2dex_mapping_table_.size() & 1, 0U);
- CHECK_EQ(dex2pc_mapping_table_.size() & 1, 0U);
- uint32_t total_entries = (pc2dex_mapping_table_.size() + dex2pc_mapping_table_.size()) / 2;
- uint32_t pc2dex_entries = pc2dex_mapping_table_.size() / 2;
- encoded_mapping_table_.PushBack(total_entries);
- encoded_mapping_table_.PushBack(pc2dex_entries);
- encoded_mapping_table_.InsertBack(pc2dex_mapping_table_.begin(), pc2dex_mapping_table_.end());
- encoded_mapping_table_.InsertBack(dex2pc_mapping_table_.begin(), dex2pc_mapping_table_.end());
+ DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]),
+ hdr_data_size + pc2dex_data_size);
+ DCHECK_EQ(static_cast<size_t>(write_pos2 - &encoded_mapping_table_[0]), data_size);
+
if (kIsDebugBuild) {
+ CHECK(VerifyCatchEntries());
+
// Verify the encoded table holds the expected data.
- MappingTable table(&encoded_mapping_table_.GetData()[0]);
+ MappingTable table(&encoded_mapping_table_[0]);
CHECK_EQ(table.TotalSize(), total_entries);
CHECK_EQ(table.PcToDexSize(), pc2dex_entries);
- CHECK_EQ(table.DexToPcSize(), dex2pc_mapping_table_.size() / 2);
- MappingTable::PcToDexIterator it = table.PcToDexBegin();
- for (uint32_t i = 0; i < pc2dex_mapping_table_.size(); ++i, ++it) {
- CHECK_EQ(pc2dex_mapping_table_.at(i), it.NativePcOffset());
- ++i;
- CHECK_EQ(pc2dex_mapping_table_.at(i), it.DexPc());
- }
- MappingTable::DexToPcIterator it2 = table.DexToPcBegin();
- for (uint32_t i = 0; i < dex2pc_mapping_table_.size(); ++i, ++it2) {
- CHECK_EQ(dex2pc_mapping_table_.at(i), it2.NativePcOffset());
- ++i;
- CHECK_EQ(dex2pc_mapping_table_.at(i), it2.DexPc());
+ auto it = table.PcToDexBegin();
+ auto it2 = table.DexToPcBegin();
+ for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+ if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
+ CHECK_EQ(tgt_lir->offset, it.NativePcOffset());
+ CHECK_EQ(tgt_lir->dalvik_offset, it.DexPc());
+ ++it;
+ }
+ if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) {
+ CHECK_EQ(tgt_lir->offset, it2.NativePcOffset());
+ CHECK_EQ(tgt_lir->dalvik_offset, it2.DexPc());
+ ++it2;
+ }
}
+ CHECK(it == table.PcToDexEnd());
+ CHECK(it2 == table.DexToPcEnd());
}
}
@@ -677,25 +736,27 @@ class NativePcToReferenceMapBuilder {
};
void Mir2Lir::CreateNativeGcMap() {
- const std::vector<uint32_t>& mapping_table = pc2dex_mapping_table_;
+ DCHECK(!encoded_mapping_table_.empty());
+ MappingTable mapping_table(&encoded_mapping_table_[0]);
uint32_t max_native_offset = 0;
- for (size_t i = 0; i < mapping_table.size(); i += 2) {
- uint32_t native_offset = mapping_table[i + 0];
+ for (auto it = mapping_table.PcToDexBegin(), end = mapping_table.PcToDexEnd(); it != end; ++it) {
+ uint32_t native_offset = it.NativePcOffset();
if (native_offset > max_native_offset) {
max_native_offset = native_offset;
}
}
MethodReference method_ref(cu_->dex_file, cu_->method_idx);
const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref);
- verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4);
+ 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.size() / 2, max_native_offset,
- dex_gc_map.RegWidth());
+ mapping_table.PcToDexSize(),
+ max_native_offset, dex_gc_map.RegWidth());
- for (size_t i = 0; i < mapping_table.size(); i += 2) {
- uint32_t native_offset = mapping_table[i + 0];
- uint32_t dex_pc = mapping_table[i + 1];
+ for (auto it = mapping_table.PcToDexBegin(), end = mapping_table.PcToDexEnd(); it != end; ++it) {
+ uint32_t native_offset = it.NativePcOffset();
+ uint32_t dex_pc = it.DexPc();
const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc;
native_gc_map_builder.AddEntry(native_offset, references);
@@ -986,15 +1047,15 @@ CompiledMethod* Mir2Lir::GetCompiledMethod() {
for (uint32_t i = 0; i < fp_vmap_table_.size(); i++) {
raw_vmap_table.push_back(fp_vmap_table_[i]);
}
- UnsignedLeb128EncodingVector vmap_encoder;
+ Leb128EncodingVector vmap_encoder;
// Prefix the encoded data with its size.
- vmap_encoder.PushBack(raw_vmap_table.size());
+ vmap_encoder.PushBackUnsigned(raw_vmap_table.size());
for (uint16_t cur : raw_vmap_table) {
- vmap_encoder.PushBack(cur);
+ vmap_encoder.PushBackUnsigned(cur);
}
CompiledMethod* result =
new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
- core_spill_mask_, fp_spill_mask_, encoded_mapping_table_.GetData(),
+ core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
vmap_encoder.GetData(), native_gc_map_);
return result;
}
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 6c0328e..b21e37e 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -22,6 +22,7 @@
namespace art {
+const uint32_t DexFileMethodInliner::kIndexUnresolved;
const char* DexFileMethodInliner::kClassCacheNames[] = {
"Z", // kClassCacheBoolean
"B", // kClassCacheByte
@@ -157,8 +158,74 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
kClassCacheJavaLangObject } },
};
-DexFileMethodInliner::~DexFileMethodInliner() {
-}
+const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
+#define INTRINSIC(c, n, p, o, d) \
+ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
+
+ INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
+ INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
+ INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
+ INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
+
+ INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
+ INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
+ INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
+
+ INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+ INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+
+ INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
+ INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
+ INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
+ INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
+ INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
+ INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
+
+ INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
+
+ INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
+ INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
+ INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
+ INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
+ INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
+ INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
+ INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
+ INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
+
+ INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
+ kIntrinsicFlagNone),
+ INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
+ kIntrinsicFlagIsLong),
+ INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
+ kIntrinsicFlagIsObject),
+
+#define UNSAFE_GET_PUT(type, code, type_flags) \
+ INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ type_flags & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags), \
+ INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsVolatile), \
+ INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsOrdered)
+
+ UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
+ UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
+ UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
+#undef UNSAFE_GET_PUT
+
+#undef INTRINSIC
+};
DexFileMethodInliner::DexFileMethodInliner()
: dex_file_(NULL) {
@@ -170,6 +237,9 @@ DexFileMethodInliner::DexFileMethodInliner()
COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
}
+DexFileMethodInliner::~DexFileMethodInliner() {
+}
+
bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) const {
return intrinsics_.find(method_index) != intrinsics_.end();
}
@@ -333,15 +403,15 @@ DexFileMethodInliner::IndexCache::IndexCache() {
std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
}
-void DexFileMethodInliner::DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
- const IntrinsicDef* defs, uint32_t def_count) {
+void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
DCHECK(dex_file != nullptr);
DCHECK(dex_file_ == nullptr);
- for (uint32_t i = 0u; i != def_count; ++i) {
- uint32_t method_id = FindMethodIndex(dex_file, cache, defs[i].method_def);
+ IndexCache cache;
+ for (const IntrinsicDef& def : kIntrinsicMethods) {
+ uint32_t method_id = FindMethodIndex(dex_file, &cache, def.method_def);
if (method_id != kIndexNotFound) {
DCHECK(intrinsics_.find(method_id) == intrinsics_.end());
- intrinsics_[method_id] = defs[i].intrinsic;
+ intrinsics_[method_id] = def.intrinsic;
}
}
dex_file_ = dex_file;
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index bc00513..948f4bb 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -89,12 +89,8 @@ struct Intrinsic {
*/
class DexFileMethodInliner {
public:
- virtual ~DexFileMethodInliner();
-
- /**
- * Find all known intrinsic methods in the dex_file and cache their indices.
- */
- virtual void FindIntrinsics(const DexFile* dex_file) = 0;
+ DexFileMethodInliner();
+ ~DexFileMethodInliner();
/**
* Check whether a particular method index corresponds to an intrinsic function.
@@ -103,15 +99,10 @@ class DexFileMethodInliner {
/**
* Generate code for an intrinsic function invocation.
- *
- * TODO: This should be target-specific. For the time being,
- * it's shared since it dispatches everything to backend.
*/
bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const;
- protected:
- DexFileMethodInliner();
-
+ private:
/**
* To avoid multiple lookups of a class by its descriptor, we cache its
* type index in the IndexCache. These are the indexes into the IndexCache
@@ -290,6 +281,7 @@ class DexFileMethodInliner {
static const char* kClassCacheNames[];
static const char* kNameCacheNames[];
static const ProtoDef kProtoCacheDefs[];
+ static const IntrinsicDef kIntrinsicMethods[];
static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
@@ -303,14 +295,22 @@ class DexFileMethodInliner {
static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
const MethodDef& method_def);
- void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
- const IntrinsicDef* defs, uint32_t def_count);
+ /**
+ * Find all known intrinsic methods in the dex_file and cache their indices.
+ *
+ * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
+ */
+ void FindIntrinsics(const DexFile* dex_file);
+
+ friend class DexFileToMethodInlinerMap;
/*
* Maps method indexes (for the particular DexFile) to Intrinsic defintions.
*/
std::map<uint32_t, Intrinsic> intrinsics_;
const DexFile* dex_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
};
} // namespace art
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.cc b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
index 56a42bc..0107ed3 100644
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.cc
+++ b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
@@ -22,17 +22,13 @@
#include "base/mutex-inl.h"
#include "base/logging.h"
#include "driver/compiler_driver.h"
-#include "dex/quick/arm/arm_dex_file_method_inliner.h"
-#include "dex/quick/mips/mips_dex_file_method_inliner.h"
-#include "dex/quick/x86/x86_dex_file_method_inliner.h"
#include "dex_file_to_method_inliner_map.h"
namespace art {
-DexFileToMethodInlinerMap::DexFileToMethodInlinerMap(const CompilerDriver* compiler)
- : compiler_(compiler),
- mutex_("inline_helper_mutex") {
+DexFileToMethodInlinerMap::DexFileToMethodInlinerMap()
+ : lock_("inline_helper_mutex") {
}
DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() {
@@ -44,31 +40,19 @@ DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() {
const DexFileMethodInliner& DexFileToMethodInlinerMap::GetMethodInliner(const DexFile* dex_file) {
Thread* self = Thread::Current();
{
- ReaderMutexLock lock(self, mutex_);
+ ReaderMutexLock lock(self, lock_);
auto it = inliners_.find(dex_file);
if (it != inliners_.end()) {
return *it->second;
}
}
- WriterMutexLock lock(self, mutex_);
+ WriterMutexLock lock(self, lock_);
DexFileMethodInliner** inliner = &inliners_[dex_file]; // inserts new entry if not found
if (*inliner) {
return **inliner;
}
- switch (compiler_->GetInstructionSet()) {
- case kThumb2:
- *inliner = new ArmDexFileMethodInliner;
- break;
- case kX86:
- *inliner = new X86DexFileMethodInliner;
- break;
- case kMips:
- *inliner = new MipsDexFileMethodInliner;
- break;
- default:
- LOG(FATAL) << "Unexpected instruction set: " << compiler_->GetInstructionSet();
- }
+ *inliner = new DexFileMethodInliner();
DCHECK(*inliner != nullptr);
// TODO: per-dex file locking for the intrinsics container filling.
(*inliner)->FindIntrinsics(dex_file);
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.h b/compiler/dex/quick/dex_file_to_method_inliner_map.h
index 77f2648..476f002 100644
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.h
+++ b/compiler/dex/quick/dex_file_to_method_inliner_map.h
@@ -37,15 +37,16 @@ class DexFile;
*/
class DexFileToMethodInlinerMap {
public:
- explicit DexFileToMethodInlinerMap(const CompilerDriver* compiler);
+ DexFileToMethodInlinerMap();
~DexFileToMethodInlinerMap();
- const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(mutex_);
+ const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(lock_);
private:
- const CompilerDriver* const compiler_;
- ReaderWriterMutex mutex_;
- std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(mutex_);
+ ReaderWriterMutex lock_;
+ std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(lock_);
+
+ DISALLOW_COPY_AND_ASSIGN(DexFileToMethodInlinerMap);
};
} // namespace art
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index df6493d..a426cc7 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -611,7 +611,7 @@ void Mir2Lir::HandleThrowLaunchPads() {
default:
LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
}
- ClobberCalleeSave();
+ ClobberCallerSave();
int r_tgt = CallHelperSetup(func_offset);
CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */);
}
@@ -1026,7 +1026,7 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know
}
}
// TODO: only clobber when type isn't final?
- ClobberCalleeSave();
+ ClobberCallerSave();
/* branch targets here */
LIR* target = NewLIR0(kPseudoTargetLabel);
StoreValue(rl_dest, rl_result);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 469c577..e66d4ea 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -62,14 +62,14 @@ LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_p
void Mir2Lir::CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
int r_tgt = CallHelperSetup(helper_offset);
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
void Mir2Lir::CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
int r_tgt = CallHelperSetup(helper_offset);
OpRegCopy(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -81,7 +81,7 @@ void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset helper_offset, RegLocati
} else {
LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
}
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -90,7 +90,7 @@ void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset helper_offset, int arg0, int
int r_tgt = CallHelperSetup(helper_offset);
LoadConstant(TargetReg(kArg0), arg0);
LoadConstant(TargetReg(kArg1), arg1);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -103,7 +103,7 @@ void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset helper_offset, int ar
LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
}
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -112,7 +112,7 @@ void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset helper_offset, RegLoc
int r_tgt = CallHelperSetup(helper_offset);
LoadValueDirectFixed(arg0, TargetReg(kArg0));
LoadConstant(TargetReg(kArg1), arg1);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -121,7 +121,7 @@ void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset helper_offset, int arg0, int
int r_tgt = CallHelperSetup(helper_offset);
OpRegCopy(TargetReg(kArg1), arg1);
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -130,7 +130,7 @@ void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset helper_offset, int arg0, int
int r_tgt = CallHelperSetup(helper_offset);
OpRegCopy(TargetReg(kArg0), arg0);
LoadConstant(TargetReg(kArg1), arg1);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -138,7 +138,7 @@ void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, b
int r_tgt = CallHelperSetup(helper_offset);
LoadCurrMethodDirect(TargetReg(kArg1));
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -168,7 +168,7 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset
LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
}
}
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -178,7 +178,7 @@ void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset helper_offset, int arg0, int
DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
OpRegCopy(TargetReg(kArg0), arg0);
OpRegCopy(TargetReg(kArg1), arg1);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -189,7 +189,7 @@ void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset helper_offset, int arg0, i
OpRegCopy(TargetReg(kArg0), arg0);
OpRegCopy(TargetReg(kArg1), arg1);
LoadConstant(TargetReg(kArg2), arg2);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -199,7 +199,7 @@ void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset helper_offset,
LoadValueDirectFixed(arg2, TargetReg(kArg2));
LoadCurrMethodDirect(TargetReg(kArg1));
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -209,7 +209,7 @@ void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset helper_offset, int arg0
LoadCurrMethodDirect(TargetReg(kArg1));
LoadConstant(TargetReg(kArg2), arg2);
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -225,7 +225,7 @@ void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset helper_off
LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
}
LoadConstant(TargetReg(kArg0), arg0);
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -240,7 +240,7 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset he
LoadValueDirectFixed(arg1, TargetReg(kArg1));
DCHECK_EQ(arg1.wide, 0U);
LoadValueDirectFixed(arg2, TargetReg(kArg2));
- ClobberCalleeSave();
+ ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -971,10 +971,17 @@ bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) {
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (size == kLong) {
RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
- int reg_tmp = AllocTemp();
- OpRegCopy(reg_tmp, rl_result.low_reg);
+ int r_i_low = rl_i.low_reg;
+ if (rl_i.low_reg == rl_result.low_reg) {
+ // First REV shall clobber rl_result.low_reg, save the value in a temp for the second REV.
+ r_i_low = AllocTemp();
+ OpRegCopy(r_i_low, rl_i.low_reg);
+ }
OpRegReg(kOpRev, rl_result.low_reg, rl_i.high_reg);
- OpRegReg(kOpRev, rl_result.high_reg, reg_tmp);
+ OpRegReg(kOpRev, rl_result.high_reg, r_i_low);
+ if (rl_i.low_reg == rl_result.low_reg) {
+ FreeTemp(r_i_low);
+ }
StoreValueWide(rl_dest, rl_result);
} else {
DCHECK(size == kWord || size == kSignedHalf);
@@ -1076,7 +1083,7 @@ bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
// TODO - add Mips implementation
return false;
}
- ClobberCalleeSave();
+ ClobberCallerSave();
LockCallTemps(); // Using fixed registers
int reg_ptr = TargetReg(kArg0);
int reg_char = TargetReg(kArg1);
@@ -1119,7 +1126,7 @@ bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) {
// TODO - add Mips implementation
return false;
}
- ClobberCalleeSave();
+ ClobberCallerSave();
LockCallTemps(); // Using fixed registers
int reg_this = TargetReg(kArg0);
int reg_cmp = TargetReg(kArg1);
@@ -1334,7 +1341,7 @@ void Mir2Lir::GenInvoke(CallInfo* info) {
}
MarkSafepointPC(call_inst);
- ClobberCalleeSave();
+ ClobberCallerSave();
if (info->result.location != kLocInvalid) {
// We have a following MOVE_RESULT - do it now.
if (info->result.wide) {
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 18c8cf8..21d5563 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -253,7 +253,7 @@ void MipsMir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) {
NewLIR4(kMipsDelta, rMIPS_ARG1, 0, WrapPointer(base_label), WrapPointer(tab_rec));
// And go...
- ClobberCalleeSave();
+ ClobberCallerSave();
LIR* call_inst = OpReg(kOpBlx, r_tgt); // ( array*, fill_data* )
MarkSafepointPC(call_inst);
}
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 5dda445..450a44f 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -61,7 +61,7 @@ class MipsMir2Lir : public Mir2Lir {
uint32_t FpRegMask();
uint64_t GetRegMaskCommon(int reg);
void AdjustSpillMask();
- void ClobberCalleeSave();
+ void ClobberCallerSave();
void FlushReg(int reg);
void FlushRegWide(int reg1, int reg2);
void FreeCallTemps();
diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc b/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc
deleted file mode 100644
index 05d8ac8..0000000
--- a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc
+++ /dev/null
@@ -1,105 +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/logging.h"
-#include "base/macros.h"
-#include "dex/compiler_enums.h"
-
-#include "mips_dex_file_method_inliner.h"
-
-namespace art {
-
-const DexFileMethodInliner::IntrinsicDef MipsDexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
-
- // INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
- // INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
- // INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
- // INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
-
- // INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
- // INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
- // INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-
- // INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
- // INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
- // INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
- // INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
- // INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- // INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- // INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- // INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- // INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
- // INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
- // INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
- // INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
- // INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
- // INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
- // INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
- // INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
- INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
- INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
- // INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
- // INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
- // INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
- INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
- // INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
- // INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
- // INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
- // INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
- // kIntrinsicFlagNone),
- // INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
- // kIntrinsicFlagIsLong),
- // INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
- // kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
- INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- type_flags & ~kIntrinsicFlagIsObject), \
- INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
- INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags), \
- INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags | kIntrinsicFlagIsVolatile), \
- INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags | kIntrinsicFlagIsOrdered)
-
- // UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
- // UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
- // UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-#undef UNSAFE_GET_PUT
-
-#undef INTRINSIC
-};
-
-MipsDexFileMethodInliner::MipsDexFileMethodInliner() {
-}
-
-MipsDexFileMethodInliner::~MipsDexFileMethodInliner() {
-}
-
-void MipsDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
- IndexCache cache;
- DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
-}
-
-} // namespace art
diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h b/compiler/dex/quick/mips/mips_dex_file_method_inliner.h
deleted file mode 100644
index 8fe7ec7..0000000
--- a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h
+++ /dev/null
@@ -1,37 +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_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class MipsDexFileMethodInliner : public DexFileMethodInliner {
- public:
- MipsDexFileMethodInliner();
- ~MipsDexFileMethodInliner();
-
- void FindIntrinsics(const DexFile* dex_file);
-
- private:
- static const IntrinsicDef kIntrinsicMethods[];
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 9c598e6..869706f 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -346,7 +346,7 @@ bool MipsMir2Lir::IsFpReg(int reg) {
}
/* Clobber all regs that might be used by an external C call */
-void MipsMir2Lir::ClobberCalleeSave() {
+void MipsMir2Lir::ClobberCallerSave() {
Clobber(r_ZERO);
Clobber(r_AT);
Clobber(r_V0);
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 2ba2c84..65c82c0 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -504,13 +504,13 @@ LIR* MipsMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest,
}
} else {
if (pair) {
- int r_tmp = AllocFreeTemp();
+ int r_tmp = AllocTemp();
res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp);
load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp);
FreeTemp(r_tmp);
} else {
- int r_tmp = (rBase == r_dest) ? AllocFreeTemp() : r_dest;
+ int r_tmp = (rBase == r_dest) ? AllocTemp() : r_dest;
res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
load = NewLIR3(opcode, r_dest, 0, r_tmp);
if (r_tmp != r_dest)
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index f8a2d03..2a54eb3 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -71,6 +71,7 @@ typedef uint32_t CodeOffset; // Native code offset in bytes.
#define REG_USEA (1ULL << kRegUseA)
#define REG_USEC (1ULL << kRegUseC)
#define REG_USED (1ULL << kRegUseD)
+#define REG_USEB (1ULL << kRegUseB)
#define REG_USE_FPCS_LIST0 (1ULL << kRegUseFPCSList0)
#define REG_USE_FPCS_LIST2 (1ULL << kRegUseFPCSList2)
#define REG_USE_LIST0 (1ULL << kRegUseList0)
@@ -341,9 +342,6 @@ class Mir2Lir : public Backend {
bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
bool IsInexpensiveConstant(RegLocation rl_src);
ConditionCode FlipComparisonOrder(ConditionCode before);
- void DumpMappingTable(const char* table_name, const char* descriptor,
- const char* name, const Signature& signature,
- const std::vector<uint32_t>& v);
void InstallLiteralPools();
void InstallSwitchTables();
void InstallFillArrayData();
@@ -624,7 +622,7 @@ class Mir2Lir : public Backend {
virtual uint32_t FpRegMask() = 0;
virtual uint64_t GetRegMaskCommon(int reg) = 0;
virtual void AdjustSpillMask() = 0;
- virtual void ClobberCalleeSave() = 0;
+ virtual void ClobberCallerSave() = 0;
virtual void FlushReg(int reg) = 0;
virtual void FlushRegWide(int reg1, int reg2) = 0;
virtual void FreeCallTemps() = 0;
@@ -792,17 +790,6 @@ class Mir2Lir : public Backend {
GrowableArray<RegisterInfo*> tempreg_info_;
GrowableArray<RegisterInfo*> reginfo_map_;
GrowableArray<void*> pointer_storage_;
- /*
- * Holds mapping from native PC to dex PC for safepoints where we may deoptimize.
- * Native PC is on the return address of the safepointed operation. Dex PC is for
- * the instruction being executed at the safepoint.
- */
- std::vector<uint32_t> pc2dex_mapping_table_;
- /*
- * Holds mapping from Dex PC to native PC for catch entry points. Native PC and Dex PC
- * immediately preceed the instruction.
- */
- std::vector<uint32_t> dex2pc_mapping_table_;
CodeOffset current_code_offset_; // Working byte offset of machine instructons.
CodeOffset data_offset_; // starting offset of literal pool.
size_t total_size_; // header + code size.
@@ -828,7 +815,7 @@ class Mir2Lir : public Backend {
int live_sreg_;
CodeBuffer code_buffer_;
// The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix.
- UnsignedLeb128EncodingVector encoded_mapping_table_;
+ std::vector<uint8_t> encoded_mapping_table_;
std::vector<uint32_t> core_vmap_table_;
std::vector<uint32_t> fp_vmap_table_;
std::vector<uint8_t> native_gc_map_;
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 41a57af..cef013e 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -338,7 +338,7 @@ int Mir2Lir::AllocTempDouble() {
int Mir2Lir::AllocFreeTemp() {
return AllocTempBody(reg_pool_->core_regs,
reg_pool_->num_core_regs,
- &reg_pool_->next_core_reg, true);
+ &reg_pool_->next_core_reg, false);
}
int Mir2Lir::AllocTemp() {
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 191c9c7..96dc6ee 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -246,7 +246,9 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),
#undef UNARY_ENCODING_MAP
- { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" },
+ { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" },
+ { kX86Push32R, kRegOpcode, IS_UNARY_OP | REG_USE0 | IS_STORE, { 0, 0, 0x50, 0, 0, 0, 0, 0 }, "Push32R", "!0r" },
+ { kX86Pop32R, kRegOpcode, IS_UNARY_OP | REG_DEF0 | IS_LOAD, { 0, 0, 0x58, 0, 0, 0, 0, 0 }, "Pop32R", "!0r" },
#define EXT_0F_ENCODING_MAP(opname, prefix, opcode, reg_def) \
{ kX86 ## opname ## RR, kRegReg, IS_BINARY_OP | reg_def | REG_USE01, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \
@@ -306,9 +308,10 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
{ kX86CmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "!0r,!1r" },
{ kX86CmpxchgMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1d],!2r" },
{ kX86CmpxchgAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1r<<!2d+!3d],!4r" },
- { kX86LockCmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "!0r,!1r" },
{ kX86LockCmpxchgMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "[!0r+!1d],!2r" },
{ kX86LockCmpxchgAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "[!0r+!1r<<!2d+!3d],!4r" },
+ { kX86LockCmpxchg8bM, kMem, IS_STORE | IS_BINARY_OP | REG_USE0 | REG_DEFAD_USEAD | REG_USEC | REG_USEB | SETS_CCODES, { 0xF0, 0, 0x0F, 0xC7, 0, 1, 0, 0 }, "Lock Cmpxchg8b", "[!0r+!1d]" },
+ { kX86LockCmpxchg8bA, kArray, IS_STORE | IS_QUAD_OP | REG_USE01 | REG_DEFAD_USEAD | REG_USEC | REG_USEB | SETS_CCODES, { 0xF0, 0, 0x0F, 0xC7, 0, 1, 0, 0 }, "Lock Cmpxchg8b", "[!0r+!1r<<!2d+!3d]" },
EXT_0F_ENCODING_MAP(Movzx8, 0x00, 0xB6, REG_DEF0),
EXT_0F_ENCODING_MAP(Movzx16, 0x00, 0xB7, REG_DEF0),
@@ -493,6 +496,37 @@ int X86Mir2Lir::GetInsnSize(LIR* lir) {
return 0;
}
+void X86Mir2Lir::EmitPrefix(const X86EncodingMap* entry) {
+ if (entry->skeleton.prefix1 != 0) {
+ code_buffer_.push_back(entry->skeleton.prefix1);
+ if (entry->skeleton.prefix2 != 0) {
+ code_buffer_.push_back(entry->skeleton.prefix2);
+ }
+ } else {
+ DCHECK_EQ(0, entry->skeleton.prefix2);
+ }
+}
+
+void X86Mir2Lir::EmitOpcode(const X86EncodingMap* entry) {
+ code_buffer_.push_back(entry->skeleton.opcode);
+ if (entry->skeleton.opcode == 0x0F) {
+ code_buffer_.push_back(entry->skeleton.extra_opcode1);
+ if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
+ code_buffer_.push_back(entry->skeleton.extra_opcode2);
+ } else {
+ DCHECK_EQ(0, entry->skeleton.extra_opcode2);
+ }
+ } else {
+ DCHECK_EQ(0, entry->skeleton.extra_opcode1);
+ DCHECK_EQ(0, entry->skeleton.extra_opcode2);
+ }
+}
+
+void X86Mir2Lir::EmitPrefixAndOpcode(const X86EncodingMap* entry) {
+ EmitPrefix(entry);
+ EmitOpcode(entry);
+}
+
static uint8_t ModrmForDisp(int base, int disp) {
// BP requires an explicit disp, so do not omit it in the 0 case
if (disp == 0 && base != rBP) {
@@ -504,7 +538,7 @@ static uint8_t ModrmForDisp(int base, int disp) {
}
}
-void X86Mir2Lir::EmitDisp(int base, int disp) {
+void X86Mir2Lir::EmitDisp(uint8_t base, int disp) {
// BP requires an explicit disp, so do not omit it in the 0 case
if (disp == 0 && base != rBP) {
return;
@@ -518,26 +552,60 @@ void X86Mir2Lir::EmitDisp(int base, int disp) {
}
}
-void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
+void X86Mir2Lir::EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp) {
+ DCHECK_LT(reg_or_opcode, 8);
+ DCHECK_LT(base, 8);
+ uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base;
+ code_buffer_.push_back(modrm);
+ if (base == rX86_SP) {
+ // Special SIB for SP base
+ code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
}
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- // There's no 3-byte instruction with +rd
- DCHECK_NE(0x38, entry->skeleton.extra_opcode1);
- DCHECK_NE(0x3A, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
+ EmitDisp(base, disp);
+}
+
+void X86Mir2Lir::EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index,
+ int scale, int disp) {
+ DCHECK_LT(reg_or_opcode, 8);
+ uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | rX86_SP;
+ code_buffer_.push_back(modrm);
+ DCHECK_LT(scale, 4);
+ DCHECK_LT(index, 8);
+ DCHECK_LT(base, 8);
+ uint8_t sib = (scale << 6) | (index << 3) | base;
+ code_buffer_.push_back(sib);
+ EmitDisp(base, disp);
+}
+
+void X86Mir2Lir::EmitImm(const X86EncodingMap* entry, int imm) {
+ switch (entry->skeleton.immediate_bytes) {
+ case 1:
+ DCHECK(IS_SIMM8(imm));
+ code_buffer_.push_back(imm & 0xFF);
+ break;
+ case 2:
+ DCHECK(IS_SIMM16(imm));
+ code_buffer_.push_back(imm & 0xFF);
+ code_buffer_.push_back((imm >> 8) & 0xFF);
+ break;
+ case 4:
+ code_buffer_.push_back(imm & 0xFF);
+ code_buffer_.push_back((imm >> 8) & 0xFF);
+ code_buffer_.push_back((imm >> 16) & 0xFF);
+ code_buffer_.push_back((imm >> 24) & 0xFF);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
+ << ") for instruction: " << entry->name;
+ break;
}
+}
+
+void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) {
+ EmitPrefixAndOpcode(entry);
+ // There's no 3-byte instruction with +rd
+ DCHECK(entry->skeleton.opcode != 0x0F ||
+ (entry->skeleton.extra_opcode1 != 0x38 && entry->skeleton.extra_opcode1 != 0x3A));
DCHECK(!X86_FPREG(reg));
DCHECK_LT(reg, 8);
code_buffer_.back() += reg;
@@ -546,26 +614,7 @@ void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) {
}
void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
if (X86_FPREG(reg)) {
reg = reg & X86_FP_REG_MASK;
}
@@ -581,48 +630,28 @@ void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) {
}
void X86Mir2Lir::EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
+ EmitPrefix(entry);
code_buffer_.push_back(entry->skeleton.opcode);
+ DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- DCHECK_LT(entry->skeleton.modrm_opcode, 8);
- DCHECK_LT(base, 8);
- uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
- code_buffer_.push_back(modrm);
- EmitDisp(base, disp);
+ DCHECK_NE(rX86_SP, base);
+ EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp);
+ DCHECK_EQ(0, entry->skeleton.ax_opcode);
+ DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index,
+ int scale, int disp) {
+ EmitPrefixAndOpcode(entry);
+ EmitModrmSibDisp(entry->skeleton.modrm_opcode, base, index, scale, disp);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
}
void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry,
uint8_t base, int disp, uint8_t reg) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
if (X86_FPREG(reg)) {
reg = reg & X86_FP_REG_MASK;
}
@@ -632,15 +661,7 @@ void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry,
<< entry->name << " " << static_cast<int>(reg)
<< " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
}
- DCHECK_LT(reg, 8);
- DCHECK_LT(base, 8);
- uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg << 3) | base;
- code_buffer_.push_back(modrm);
- if (base == rX86_SP) {
- // Special SIB for SP base
- code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
- }
- EmitDisp(base, disp);
+ EmitModrmDisp(reg, base, disp);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -653,39 +674,12 @@ void X86Mir2Lir::EmitRegMem(const X86EncodingMap* entry,
}
void X86Mir2Lir::EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
- int scale, int disp) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ int scale, int disp) {
+ EmitPrefixAndOpcode(entry);
if (X86_FPREG(reg)) {
reg = reg & X86_FP_REG_MASK;
}
- DCHECK_LT(reg, 8);
- uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg << 3) | rX86_SP;
- code_buffer_.push_back(modrm);
- DCHECK_LT(scale, 4);
- DCHECK_LT(index, 8);
- DCHECK_LT(base, 8);
- uint8_t sib = (scale << 6) | (index << 3) | base;
- code_buffer_.push_back(sib);
- EmitDisp(base, disp);
+ EmitModrmSibDisp(reg, base, index, scale, disp);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -699,22 +693,7 @@ void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t
void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp) {
DCHECK_NE(entry->skeleton.prefix1, 0);
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
if (X86_FPREG(reg)) {
reg = reg & X86_FP_REG_MASK;
}
@@ -735,26 +714,7 @@ void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int dis
}
void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
if (X86_FPREG(reg1)) {
reg1 = reg1 & X86_FP_REG_MASK;
}
@@ -772,26 +732,7 @@ void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t r
void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
uint8_t reg1, uint8_t reg2, int32_t imm) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
if (X86_FPREG(reg1)) {
reg1 = reg1 & X86_FP_REG_MASK;
}
@@ -804,27 +745,7 @@ void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
code_buffer_.push_back(modrm);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
- switch (entry->skeleton.immediate_bytes) {
- case 1:
- DCHECK(IS_SIMM8(imm));
- code_buffer_.push_back(imm & 0xFF);
- break;
- case 2:
- DCHECK(IS_SIMM16(imm));
- code_buffer_.push_back(imm & 0xFF);
- code_buffer_.push_back((imm >> 8) & 0xFF);
- break;
- case 4:
- code_buffer_.push_back(imm & 0xFF);
- code_buffer_.push_back((imm >> 8) & 0xFF);
- code_buffer_.push_back((imm >> 16) & 0xFF);
- code_buffer_.push_back((imm >> 24) & 0xFF);
- break;
- default:
- LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
- << ") for instruction: " << entry->name;
- break;
- }
+ EmitImm(entry, imm);
}
void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
@@ -839,95 +760,25 @@ void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
if (reg == rAX && entry->skeleton.ax_opcode != 0) {
code_buffer_.push_back(entry->skeleton.ax_opcode);
} else {
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitOpcode(entry);
if (X86_FPREG(reg)) {
reg = reg & X86_FP_REG_MASK;
}
uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
code_buffer_.push_back(modrm);
}
- switch (entry->skeleton.immediate_bytes) {
- case 1:
- DCHECK(IS_SIMM8(imm));
- code_buffer_.push_back(imm & 0xFF);
- break;
- case 2:
- DCHECK(IS_SIMM16(imm));
- code_buffer_.push_back(imm & 0xFF);
- code_buffer_.push_back((imm >> 8) & 0xFF);
- break;
- case 4:
- code_buffer_.push_back(imm & 0xFF);
- code_buffer_.push_back((imm >> 8) & 0xFF);
- code_buffer_.push_back((imm >> 16) & 0xFF);
- code_buffer_.push_back((imm >> 24) & 0xFF);
- break;
- default:
- LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
- << ") for instruction: " << entry->name;
- break;
- }
+ EmitImm(entry, imm);
}
void X86Mir2Lir::EmitThreadImm(const X86EncodingMap* entry, int disp, int imm) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
code_buffer_.push_back(modrm);
code_buffer_.push_back(disp & 0xFF);
code_buffer_.push_back((disp >> 8) & 0xFF);
code_buffer_.push_back((disp >> 16) & 0xFF);
code_buffer_.push_back((disp >> 24) & 0xFF);
- switch (entry->skeleton.immediate_bytes) {
- case 1:
- DCHECK(IS_SIMM8(imm));
- code_buffer_.push_back(imm & 0xFF);
- break;
- case 2:
- DCHECK(IS_SIMM16(imm));
- code_buffer_.push_back(imm & 0xFF);
- code_buffer_.push_back((imm >> 8) & 0xFF);
- break;
- case 4:
- code_buffer_.push_back(imm & 0xFF);
- code_buffer_.push_back((imm >> 8) & 0xFF);
- code_buffer_.push_back((imm >> 16) & 0xFF);
- code_buffer_.push_back((imm >> 24) & 0xFF);
- break;
- default:
- LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
- << ") for instruction: " << entry->name;
- break;
- }
+ EmitImm(entry, imm);
DCHECK_EQ(entry->skeleton.ax_opcode, 0);
}
@@ -941,31 +792,16 @@ void X86Mir2Lir::EmitMovRegImm(const X86EncodingMap* entry, uint8_t reg, int imm
}
void X86Mir2Lir::EmitShiftRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
+ EmitPrefix(entry);
if (imm != 1) {
code_buffer_.push_back(entry->skeleton.opcode);
} else {
// Shorter encoding for 1 bit shift
code_buffer_.push_back(entry->skeleton.ax_opcode);
}
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ DCHECK_NE(0x0F, entry->skeleton.opcode);
+ DCHECK_EQ(0, entry->skeleton.extra_opcode1);
+ DCHECK_EQ(0, entry->skeleton.extra_opcode2);
if (reg >= 4) {
DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
<< " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
@@ -982,15 +818,9 @@ void X86Mir2Lir::EmitShiftRegImm(const X86EncodingMap* entry, uint8_t reg, int i
void X86Mir2Lir::EmitShiftRegCl(const X86EncodingMap* entry, uint8_t reg, uint8_t cl) {
DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
+ EmitPrefix(entry);
code_buffer_.push_back(entry->skeleton.opcode);
+ DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
DCHECK_LT(reg, 8);
@@ -1060,55 +890,15 @@ void X86Mir2Lir::EmitJcc(const X86EncodingMap* entry, int rel, uint8_t cc) {
}
void X86Mir2Lir::EmitCallMem(const X86EncodingMap* entry, uint8_t base, int disp) {
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
- code_buffer_.push_back(modrm);
- if (base == rX86_SP) {
- // Special SIB for SP base
- code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
- }
- EmitDisp(base, disp);
+ EmitPrefixAndOpcode(entry);
+ EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
}
void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) {
DCHECK_NE(entry->skeleton.prefix1, 0);
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.opcode == 0x0F) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode1);
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitPrefixAndOpcode(entry);
uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
code_buffer_.push_back(modrm);
code_buffer_.push_back(disp & 0xFF);
@@ -1132,20 +922,14 @@ void X86Mir2Lir::EmitPcRel(const X86EncodingMap* entry, uint8_t reg,
reinterpret_cast<Mir2Lir::EmbeddedData*>(UnwrapPointer(base_or_table));
disp = tab_rec->offset;
}
- if (entry->skeleton.prefix1 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix1);
- if (entry->skeleton.prefix2 != 0) {
- code_buffer_.push_back(entry->skeleton.prefix2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.prefix2);
- }
+ EmitPrefix(entry);
if (X86_FPREG(reg)) {
reg = reg & X86_FP_REG_MASK;
}
DCHECK_LT(reg, 8);
if (entry->opcode == kX86PcRelLoadRA) {
code_buffer_.push_back(entry->skeleton.opcode);
+ DCHECK_NE(0x0F, entry->skeleton.opcode);
DCHECK_EQ(0, entry->skeleton.extra_opcode1);
DCHECK_EQ(0, entry->skeleton.extra_opcode2);
uint8_t modrm = (2 << 6) | (reg << 3) | rX86_SP;
@@ -1321,15 +1105,7 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) {
case kNullary: // 1 byte of opcode
DCHECK_EQ(0, entry->skeleton.prefix1);
DCHECK_EQ(0, entry->skeleton.prefix2);
- code_buffer_.push_back(entry->skeleton.opcode);
- if (entry->skeleton.extra_opcode1 != 0) {
- code_buffer_.push_back(entry->skeleton.extra_opcode1);
- if (entry->skeleton.extra_opcode2 != 0) {
- code_buffer_.push_back(entry->skeleton.extra_opcode2);
- }
- } else {
- DCHECK_EQ(0, entry->skeleton.extra_opcode2);
- }
+ EmitOpcode(entry);
DCHECK_EQ(0, entry->skeleton.modrm_opcode);
DCHECK_EQ(0, entry->skeleton.ax_opcode);
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -1343,6 +1119,9 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) {
case kMem: // lir operands - 0: base, 1: disp
EmitOpMem(entry, lir->operands[0], lir->operands[1]);
break;
+ case kArray: // lir operands - 0: base, 1: index, 2: scale, 3: disp
+ EmitOpArray(entry, lir->operands[0], lir->operands[1], lir->operands[2], lir->operands[3]);
+ break;
case kMemReg: // lir operands - 0: base, 1: disp, 2: reg
EmitMemReg(entry, lir->operands[0], lir->operands[1], lir->operands[2]);
break;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index ffe2d67..6552607 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -61,7 +61,7 @@ class X86Mir2Lir : public Mir2Lir {
uint32_t FpRegMask();
uint64_t GetRegMaskCommon(int reg);
void AdjustSpillMask();
- void ClobberCalleeSave();
+ void ClobberCallerSave();
void FlushReg(int reg);
void FlushRegWide(int reg1, int reg2);
void FreeCallTemps();
@@ -171,10 +171,18 @@ class X86Mir2Lir : public Mir2Lir {
bool InexpensiveConstantDouble(int64_t value);
private:
- void EmitDisp(int base, int disp);
+ void EmitPrefix(const X86EncodingMap* entry);
+ void EmitOpcode(const X86EncodingMap* entry);
+ void EmitPrefixAndOpcode(const X86EncodingMap* entry);
+ void EmitDisp(uint8_t base, int disp);
+ void EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp);
+ void EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index, int scale, int disp);
+ void EmitImm(const X86EncodingMap* entry, int imm);
void EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg);
void EmitOpReg(const X86EncodingMap* entry, uint8_t reg);
void EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp);
+ void EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index,
+ int scale, int disp);
void EmitMemReg(const X86EncodingMap* entry, uint8_t base, int disp, uint8_t reg);
void EmitRegMem(const X86EncodingMap* entry, uint8_t reg, uint8_t base, int disp);
void EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 01d5c17..0133a0a 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -282,8 +282,69 @@ void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
}
bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
- DCHECK_NE(cu_->instruction_set, kThumb2);
- return false;
+ DCHECK_EQ(cu_->instruction_set, kX86);
+ // Unused - RegLocation rl_src_unsafe = info->args[0];
+ RegLocation rl_src_obj = info->args[1]; // Object - known non-null
+ RegLocation rl_src_offset = info->args[2]; // long low
+ rl_src_offset.wide = 0; // ignore high half in info->args[3]
+ RegLocation rl_src_expected = info->args[4]; // int, long or Object
+ // If is_long, high half is in info->args[5]
+ RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object
+ // If is_long, high half is in info->args[7]
+
+ if (is_long) {
+ FlushAllRegs();
+ LockCallTemps();
+ NewLIR1(kX86Push32R, rDI);
+ MarkTemp(rDI);
+ LockTemp(rDI);
+ NewLIR1(kX86Push32R, rSI);
+ MarkTemp(rSI);
+ LockTemp(rSI);
+ LoadValueDirectFixed(rl_src_obj, rDI);
+ LoadValueDirectFixed(rl_src_offset, rSI);
+ LoadValueDirectWideFixed(rl_src_expected, rAX, rDX);
+ LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX);
+ NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
+ FreeTemp(rSI);
+ UnmarkTemp(rSI);
+ NewLIR1(kX86Pop32R, rSI);
+ FreeTemp(rDI);
+ UnmarkTemp(rDI);
+ NewLIR1(kX86Pop32R, rDI);
+ FreeCallTemps();
+ } else {
+ // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
+ FlushReg(r0);
+ LockTemp(r0);
+
+ // Release store semantics, get the barrier out of the way. TODO: revisit
+ GenMemBarrier(kStoreLoad);
+
+ RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
+ RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
+
+ if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
+ // Mark card for object assuming new value is stored.
+ FreeTemp(r0); // Temporarily release EAX for MarkGCCard().
+ MarkGCCard(rl_new_value.low_reg, rl_object.low_reg);
+ LockTemp(r0);
+ }
+
+ RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
+ LoadValueDirect(rl_src_expected, r0);
+ NewLIR5(kX86LockCmpxchgAR, rl_object.low_reg, rl_offset.low_reg, 0, 0, rl_new_value.low_reg);
+
+ FreeTemp(r0);
+ }
+
+ // Convert ZF to boolean
+ RegLocation rl_dest = InlineTarget(info); // boolean place for result
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+ NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondZ);
+ NewLIR2(kX86Movzx8RR, rl_result.low_reg, rl_result.low_reg);
+ StoreValue(rl_dest, rl_result);
+ return true;
}
LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 878fa76..0b8c07e 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -165,6 +165,10 @@ void X86Mir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
if (flags & REG_USED) {
SetupRegMask(&lir->u.m.use_mask, rDX);
}
+
+ if (flags & REG_USEB) {
+ SetupRegMask(&lir->u.m.use_mask, rBX);
+ }
}
/* For dumping instructions */
@@ -350,10 +354,11 @@ bool X86Mir2Lir::IsFpReg(int reg) {
}
/* Clobber all regs that might be used by an external C call */
-void X86Mir2Lir::ClobberCalleeSave() {
+void X86Mir2Lir::ClobberCallerSave() {
Clobber(rAX);
Clobber(rCX);
Clobber(rDX);
+ Clobber(rBX);
}
RegLocation X86Mir2Lir::GetReturnWideAlt() {
diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc b/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc
deleted file mode 100644
index b788c3c..0000000
--- a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc
+++ /dev/null
@@ -1,111 +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/logging.h"
-#include "base/macros.h"
-#include "dex/compiler_enums.h"
-
-#include "x86_dex_file_method_inliner.h"
-
-namespace art {
-
-const DexFileMethodInliner::IntrinsicDef X86DexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
-
- INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
- INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
- INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
- INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
-
- INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
- INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
- INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-
- INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
- INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
- INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
- INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
- INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- // INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
- // INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
- INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
- INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
- INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
- INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
- INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
- INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
- INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
- INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
- INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
- INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
- INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
- INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
- INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
- INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
- INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
- // INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
- // kIntrinsicFlagNone),
- // INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
- // kIntrinsicFlagIsLong),
- // INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
- // kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
- INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- type_flags & ~kIntrinsicFlagIsObject), \
- INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
- INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags), \
- INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags | kIntrinsicFlagIsVolatile), \
- INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags | kIntrinsicFlagIsOrdered)
-
- UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
- UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
-
- // UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
- // PutObject: "TODO: fix X86, it exhausts registers for card marking."
- INTRINSIC(SunMiscUnsafe, GetObject, ObjectJ_Object, kIntrinsicUnsafeGet,
- kIntrinsicFlagNone),
- INTRINSIC(SunMiscUnsafe, GetObjectVolatile, ObjectJ_Object, kIntrinsicUnsafeGet,
- kIntrinsicFlagIsVolatile),
-#undef UNSAFE_GET_PUT
-
-#undef INTRINSIC
-};
-
-X86DexFileMethodInliner::X86DexFileMethodInliner() {
-}
-
-X86DexFileMethodInliner::~X86DexFileMethodInliner() {
-}
-
-void X86DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
- IndexCache cache;
- DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
-}
-
-} // namespace art
diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h b/compiler/dex/quick/x86/x86_dex_file_method_inliner.h
deleted file mode 100644
index 7813e44..0000000
--- a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h
+++ /dev/null
@@ -1,37 +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_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class X86DexFileMethodInliner : public DexFileMethodInliner {
- public:
- X86DexFileMethodInliner();
- ~X86DexFileMethodInliner();
-
- void FindIntrinsics(const DexFile* dex_file);
-
- private:
- static const IntrinsicDef kIntrinsicMethods[];
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 3518131..5fe76fe 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -314,6 +314,7 @@ enum X86OpCode {
UnaryOpcode(kX86Divmod, DaR, DaM, DaA),
UnaryOpcode(kX86Idivmod, DaR, DaM, DaA),
kX86Bswap32R,
+ kX86Push32R, kX86Pop32R,
#undef UnaryOpcode
#define Binary0fOpCode(opcode) \
opcode ## RR, opcode ## RM, opcode ## RA
@@ -354,7 +355,8 @@ enum X86OpCode {
Binary0fOpCode(kX86Imul16), // 16bit multiply
Binary0fOpCode(kX86Imul32), // 32bit multiply
kX86CmpxchgRR, kX86CmpxchgMR, kX86CmpxchgAR, // compare and exchange
- kX86LockCmpxchgRR, kX86LockCmpxchgMR, kX86LockCmpxchgAR, // locked compare and exchange
+ kX86LockCmpxchgMR, kX86LockCmpxchgAR, // locked compare and exchange
+ kX86LockCmpxchg8bM, kX86LockCmpxchg8bA, // locked compare and exchange
Binary0fOpCode(kX86Movzx8), // zero-extend 8-bit value
Binary0fOpCode(kX86Movzx16), // zero-extend 16-bit value
Binary0fOpCode(kX86Movsx8), // sign-extend 8-bit value
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 7b42879..8e666dd 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1596,7 +1596,8 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i
ClassLinker* class_linker = manager->GetClassLinker();
const DexFile& dex_file = *manager->GetDexFile();
SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(dex_file));
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()));
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()));
mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
if (klass == NULL) {
@@ -1651,8 +1652,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
jobject jclass_loader = manager->GetClassLoader();
SirtRef<mirror::ClassLoader> class_loader(
soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
- mirror::Class* klass = class_linker->FindClass(descriptor, class_loader);
- if (klass == NULL) {
+ SirtRef<mirror::Class> klass(soa.Self(), class_linker->FindClass(descriptor, class_loader));
+ if (klass.get() == nullptr) {
CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
@@ -1669,8 +1670,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor)
<< " because: " << error_msg;
}
- } else if (!SkipClass(jclass_loader, dex_file, klass)) {
- CHECK(klass->IsResolved()) << PrettyClass(klass);
+ } else if (!SkipClass(jclass_loader, dex_file, klass.get())) {
+ CHECK(klass->IsResolved()) << PrettyClass(klass.get());
class_linker->VerifyClass(klass);
if (klass->IsErroneous()) {
@@ -1680,7 +1681,7 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
}
CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
- << PrettyDescriptor(klass) << ": state=" << klass->GetStatus();
+ << PrettyDescriptor(klass.get()) << ": state=" << klass->GetStatus();
}
soa.Self()->AssertNoPendingException();
}
@@ -2123,9 +2124,10 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
soa.Decode<mirror::ClassLoader*>(jclass_loader));
- mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader);
+ SirtRef<mirror::Class> klass(soa.Self(),
+ manager->GetClassLinker()->FindClass(descriptor, class_loader));
- if (klass != NULL && !SkipClass(jclass_loader, dex_file, klass)) {
+ if (klass.get() != nullptr && !SkipClass(jclass_loader, dex_file, klass.get())) {
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
// Attempt to initialize the class but bail if we either need to initialize the super-class
@@ -2140,7 +2142,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
// parent-to-child and a child-to-parent lock ordering and consequent potential deadlock.
// We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
// than use a special Object for the purpose we use the Class of java.lang.Class.
- ObjectLock lock(soa.Self(), klass->GetClass());
+ SirtRef<mirror::Class> sirt_klass(soa.Self(), klass->GetClass());
+ ObjectLock<mirror::Class> lock(soa.Self(), &sirt_klass);
// Attempt to initialize allowing initialization of parent classes but still not static
// fields.
manager->GetClassLinker()->EnsureInitialized(klass, false, true);
@@ -2164,10 +2167,11 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
VLOG(compiler) << "Initializing: " << descriptor;
if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
// Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
- ObjectLock lock(soa.Self(), klass);
+ ObjectLock<mirror::Class> lock(soa.Self(), &klass);
mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
CHECK_EQ(fields->GetLength(), 1);
- fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
+ fields->Get(0)->SetObj(klass.get(),
+ manager->GetClassLinker()->FindPrimitiveClass('V'));
klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
} else {
manager->GetClassLinker()->EnsureInitialized(klass, true, true);
@@ -2180,7 +2184,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
// If successfully initialized place in SSB array.
if (klass->IsInitialized()) {
int32_t ssb_index = klass->GetDexTypeIndex();
- klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass);
+ klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass.get());
}
}
// Record the final class status if necessary.
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index c71cc97..3406fe6 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -152,14 +152,14 @@ TEST_F(ImageTest, WriteRead) {
const DexFile::ClassDef& class_def = dex->GetClassDef(i);
const char* descriptor = dex->GetClassDescriptor(class_def);
mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
- EXPECT_TRUE(klass != NULL) << descriptor;
- EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
+ EXPECT_TRUE(klass != nullptr) << descriptor;
if (image_classes.find(descriptor) != image_classes.end()) {
- // image classes should be located before the end of the image.
+ // Image classes should be located inside the image.
+ EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
} else {
- // non image classes should be in a space after the image.
- EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+ EXPECT_TRUE(reinterpret_cast<byte*>(klass) >= image_end ||
+ reinterpret_cast<byte*>(klass) < image_begin) << descriptor;
}
EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord()));
}
diff --git a/compiler/leb128_encoder.h b/compiler/leb128_encoder.h
index e9a1c32..6766683 100644
--- a/compiler/leb128_encoder.h
+++ b/compiler/leb128_encoder.h
@@ -18,33 +18,79 @@
#define ART_COMPILER_LEB128_ENCODER_H_
#include "base/macros.h"
+#include "leb128.h"
namespace art {
+static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) {
+ uint8_t out = value & 0x7f;
+ value >>= 7;
+ while (value != 0) {
+ *dest++ = out | 0x80;
+ out = value & 0x7f;
+ value >>= 7;
+ }
+ *dest++ = out;
+ return dest;
+}
+
+static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) {
+ uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
+ uint8_t out = value & 0x7f;
+ while (extra_bits != 0u) {
+ *dest++ = out | 0x80;
+ value >>= 7;
+ out = value & 0x7f;
+ extra_bits >>= 7;
+ }
+ *dest++ = out;
+ return dest;
+}
+
// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
-class UnsignedLeb128EncodingVector {
+class Leb128EncodingVector {
public:
- UnsignedLeb128EncodingVector() {
+ Leb128EncodingVector() {
}
- void PushBack(uint32_t value) {
- bool done = false;
- do {
- uint8_t out = value & 0x7f;
- if (out != value) {
- data_.push_back(out | 0x80);
- value >>= 7;
- } else {
- data_.push_back(out);
- done = true;
- }
- } while (!done);
+ void Reserve(uint32_t size) {
+ data_.reserve(size);
+ }
+
+ void PushBackUnsigned(uint32_t value) {
+ uint8_t out = value & 0x7f;
+ value >>= 7;
+ while (value != 0) {
+ data_.push_back(out | 0x80);
+ out = value & 0x7f;
+ value >>= 7;
+ }
+ data_.push_back(out);
+ }
+
+ template<typename It>
+ void InsertBackUnsigned(It cur, It end) {
+ for (; cur != end; ++cur) {
+ PushBackUnsigned(*cur);
+ }
+ }
+
+ void PushBackSigned(int32_t value) {
+ uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
+ uint8_t out = value & 0x7f;
+ while (extra_bits != 0u) {
+ data_.push_back(out | 0x80);
+ value >>= 7;
+ out = value & 0x7f;
+ extra_bits >>= 7;
+ }
+ data_.push_back(out);
}
template<typename It>
- void InsertBack(It cur, It end) {
+ void InsertBackSigned(It cur, It end) {
for (; cur != end; ++cur) {
- PushBack(*cur);
+ PushBackSigned(*cur);
}
}
@@ -55,7 +101,7 @@ class UnsignedLeb128EncodingVector {
private:
std::vector<uint8_t> data_;
- DISALLOW_COPY_AND_ASSIGN(UnsignedLeb128EncodingVector);
+ DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector);
};
} // namespace art
diff --git a/compiler/leb128_encoder_test.cc b/compiler/leb128_encoder_test.cc
index 4fa8075..c63dfa2 100644
--- a/compiler/leb128_encoder_test.cc
+++ b/compiler/leb128_encoder_test.cc
@@ -42,11 +42,62 @@ static DecodeUnsignedLeb128TestCase uleb128_tests[] = {
{0xFFFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xF}},
};
-TEST_F(Leb128Test, Singles) {
+struct DecodeSignedLeb128TestCase {
+ int32_t decoded;
+ uint8_t leb128_data[5];
+};
+
+static DecodeSignedLeb128TestCase sleb128_tests[] = {
+ {0, {0, 0, 0, 0, 0}},
+ {1, {1, 0, 0, 0, 0}},
+ {0x3F, {0x3F, 0, 0, 0, 0}},
+ {0x40, {0xC0, 0 /* sign bit */, 0, 0, 0}},
+ {0x41, {0xC1, 0 /* sign bit */, 0, 0, 0}},
+ {0x80, {0x80, 1, 0, 0, 0}},
+ {0xFF, {0xFF, 1, 0, 0, 0}},
+ {0x1FFF, {0xFF, 0x3F, 0, 0, 0}},
+ {0x2000, {0x80, 0xC0, 0 /* sign bit */, 0, 0}},
+ {0x2001, {0x81, 0xC0, 0 /* sign bit */, 0, 0}},
+ {0x2081, {0x81, 0xC1, 0 /* sign bit */, 0, 0}},
+ {0x4000, {0x80, 0x80, 1, 0, 0}},
+ {0x0FFFFF, {0xFF, 0xFF, 0x3F, 0, 0}},
+ {0x100000, {0x80, 0x80, 0xC0, 0 /* sign bit */, 0}},
+ {0x100001, {0x81, 0x80, 0xC0, 0 /* sign bit */, 0}},
+ {0x100081, {0x81, 0x81, 0xC0, 0 /* sign bit */, 0}},
+ {0x104081, {0x81, 0x81, 0xC1, 0 /* sign bit */, 0}},
+ {0x200000, {0x80, 0x80, 0x80, 1, 0}},
+ {0x7FFFFFF, {0xFF, 0xFF, 0xFF, 0x3F, 0}},
+ {0x8000000, {0x80, 0x80, 0x80, 0xC0, 0 /* sign bit */}},
+ {0x8000001, {0x81, 0x80, 0x80, 0xC0, 0 /* sign bit */}},
+ {0x8000081, {0x81, 0x81, 0x80, 0xC0, 0 /* sign bit */}},
+ {0x8004081, {0x81, 0x81, 0x81, 0xC0, 0 /* sign bit */}},
+ {0x8204081, {0x81, 0x81, 0x81, 0xC1, 0 /* sign bit */}},
+ {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0 /* sign bit */}},
+ {0x10000000, {0x80, 0x80, 0x80, 0x80, 1}},
+ {0x7FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0x7}},
+ {-1, {0x7F, 0, 0, 0, 0}},
+ {-2, {0x7E, 0, 0, 0, 0}},
+ {-0x3F, {0x41, 0, 0, 0, 0}},
+ {-0x40, {0x40, 0, 0, 0, 0}},
+ {-0x41, {0xBF, 0x7F, 0, 0, 0}},
+ {-0x80, {0x80, 0x7F, 0, 0, 0}},
+ {-0x81, {0xFF, 0x7E, 0, 0, 0}},
+ {-0x00002000, {0x80, 0x40, 0, 0, 0}},
+ {-0x00002001, {0xFF, 0xBF, 0x7F, 0, 0}},
+ {-0x00100000, {0x80, 0x80, 0x40, 0, 0}},
+ {-0x00100001, {0xFF, 0xFF, 0xBF, 0x7F, 0}},
+ {-0x08000000, {0x80, 0x80, 0x80, 0x40, 0}},
+ {-0x08000001, {0xFF, 0xFF, 0xFF, 0xBF, 0x7F}},
+ {-0x20000000, {0x80, 0x80, 0x80, 0x80, 0x7E}},
+ {(-1) << 31, {0x80, 0x80, 0x80, 0x80, 0x78}},
+};
+
+TEST_F(Leb128Test, UnsignedSinglesVector) {
// Test individual encodings.
for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- UnsignedLeb128EncodingVector builder;
- builder.PushBack(uleb128_tests[i].decoded);
+ Leb128EncodingVector builder;
+ builder.PushBackUnsigned(uleb128_tests[i].decoded);
+ EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), builder.GetData().size());
const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
const uint8_t* encoded_data_ptr = &builder.GetData()[0];
for (size_t j = 0; j < 5; ++j) {
@@ -60,33 +111,158 @@ TEST_F(Leb128Test, Singles) {
}
}
-TEST_F(Leb128Test, Stream) {
+TEST_F(Leb128Test, UnsignedSingles) {
+ // Test individual encodings.
+ for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+ uint8_t encoded_data[5];
+ uint8_t* end = EncodeUnsignedLeb128(encoded_data, uleb128_tests[i].decoded);
+ size_t data_size = static_cast<size_t>(end - encoded_data);
+ EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), data_size);
+ const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
+ for (size_t j = 0; j < 5; ++j) {
+ if (j < data_size) {
+ EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j;
+ } else {
+ EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
+ }
+ }
+ EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i;
+ }
+}
+
+TEST_F(Leb128Test, UnsignedStreamVector) {
// Encode a number of entries.
- UnsignedLeb128EncodingVector builder;
+ Leb128EncodingVector builder;
for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
- builder.PushBack(uleb128_tests[i].decoded);
+ builder.PushBackUnsigned(uleb128_tests[i].decoded);
}
const uint8_t* encoded_data_ptr = &builder.GetData()[0];
for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
+ for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) {
+ EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+ }
+ for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) {
+ EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+ }
+ EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
+ }
+ EXPECT_EQ(builder.GetData().size(),
+ static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0]));
+}
+
+TEST_F(Leb128Test, UnsignedStream) {
+ // Encode a number of entries.
+ uint8_t encoded_data[5 * arraysize(uleb128_tests)];
+ uint8_t* end = encoded_data;
+ for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+ end = EncodeUnsignedLeb128(end, uleb128_tests[i].decoded);
+ }
+ size_t data_size = static_cast<size_t>(end - encoded_data);
+ const uint8_t* encoded_data_ptr = encoded_data;
+ for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+ const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
+ for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) {
+ EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+ }
+ for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) {
+ EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+ }
+ EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
+ }
+ EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
+}
+
+TEST_F(Leb128Test, SignedSinglesVector) {
+ // Test individual encodings.
+ for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+ Leb128EncodingVector builder;
+ builder.PushBackSigned(sleb128_tests[i].decoded);
+ EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), builder.GetData().size());
+ const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+ const uint8_t* encoded_data_ptr = &builder.GetData()[0];
for (size_t j = 0; j < 5; ++j) {
- if (data_ptr[j] != 0) {
+ if (j < builder.GetData().size()) {
EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+ } else {
+ EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
}
}
- EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
+ EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+ }
+}
+
+TEST_F(Leb128Test, SignedSingles) {
+ // Test individual encodings.
+ for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+ uint8_t encoded_data[5];
+ uint8_t* end = EncodeSignedLeb128(encoded_data, sleb128_tests[i].decoded);
+ size_t data_size = static_cast<size_t>(end - encoded_data);
+ EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), data_size);
+ const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+ for (size_t j = 0; j < 5; ++j) {
+ if (j < data_size) {
+ EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j;
+ } else {
+ EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
+ }
+ }
+ EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+ }
+}
+
+TEST_F(Leb128Test, SignedStreamVector) {
+ // Encode a number of entries.
+ Leb128EncodingVector builder;
+ for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+ builder.PushBackSigned(sleb128_tests[i].decoded);
+ }
+ const uint8_t* encoded_data_ptr = &builder.GetData()[0];
+ for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+ const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+ for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) {
+ EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+ }
+ for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) {
+ EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+ }
+ EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+ }
+ EXPECT_EQ(builder.GetData().size(),
+ static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0]));
+}
+
+TEST_F(Leb128Test, SignedStream) {
+ // Encode a number of entries.
+ uint8_t encoded_data[5 * arraysize(sleb128_tests)];
+ uint8_t* end = encoded_data;
+ for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+ end = EncodeSignedLeb128(end, sleb128_tests[i].decoded);
+ }
+ size_t data_size = static_cast<size_t>(end - encoded_data);
+ const uint8_t* encoded_data_ptr = encoded_data;
+ for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+ const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+ for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) {
+ EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+ }
+ for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) {
+ EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+ }
+ EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i;
}
+ EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
}
TEST_F(Leb128Test, Speed) {
UniquePtr<Histogram<uint64_t> > enc_hist(new Histogram<uint64_t>("Leb128EncodeSpeedTest", 5));
UniquePtr<Histogram<uint64_t> > dec_hist(new Histogram<uint64_t>("Leb128DecodeSpeedTest", 5));
- UnsignedLeb128EncodingVector builder;
+ Leb128EncodingVector builder;
// Push back 1024 chunks of 1024 values measuring encoding speed.
uint64_t last_time = NanoTime();
for (size_t i = 0; i < 1024; i++) {
for (size_t j = 0; j < 1024; j++) {
- builder.PushBack((i * 1024) + j);
+ builder.PushBackUnsigned((i * 1024) + j);
}
uint64_t cur_time = NanoTime();
enc_hist->AddValue(cur_time - last_time);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 8b23270..28d6649 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -213,7 +213,7 @@ class Dex2Oat {
if (zip_archive.get() == NULL) {
return NULL;
}
- UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename));
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
if (zip_entry.get() == NULL) {
*error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
zip_filename, error_msg->c_str());
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 9ed65cd..8781c7a 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -520,6 +520,13 @@ DISASSEMBLER_ENTRY(cmp,
case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break;
case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break;
case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break;
+ case 0xC7:
+ static const char* x0FxC7_opcodes[] = { "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7" };
+ modrm_opcodes = x0FxC7_opcodes;
+ has_modrm = true;
+ reg_is_opcode = true;
+ store = true;
+ break;
case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
opcode << "bswap";
reg_in_opcode = true;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 16f11c6..2c13284 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -344,10 +344,10 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
LOCAL_SHARED_LIBRARIES += liblog libnativehelper
LOCAL_SHARED_LIBRARIES += libbacktrace # native stack trace support
ifeq ($$(art_target_or_host),target)
- LOCAL_SHARED_LIBRARIES += libcutils libz libdl libselinux
+ LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils
+ LOCAL_STATIC_LIBRARIES := libziparchive libz
else # host
- LOCAL_STATIC_LIBRARIES += libcutils
- LOCAL_SHARED_LIBRARIES += libz-host
+ LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
LOCAL_LDLIBS += -ldl -lpthread
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index c8dee6d..fe18f66 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -31,6 +31,8 @@
namespace art {
+constexpr size_t CumulativeLogger::kLowMemoryBucketCount;
+constexpr size_t CumulativeLogger::kDefaultBucketCount;
CumulativeLogger::CumulativeLogger(const std::string& name)
: name_(name),
lock_name_("CumulativeLoggerLock" + name),
@@ -43,6 +45,7 @@ CumulativeLogger::~CumulativeLogger() {
}
void CumulativeLogger::SetName(const std::string& name) {
+ MutexLock mu(Thread::Current(), lock_);
name_.assign(name);
}
@@ -61,6 +64,7 @@ void CumulativeLogger::Reset() {
}
uint64_t CumulativeLogger::GetTotalNs() const {
+ MutexLock mu(Thread::Current(), lock_);
return GetTotalTime() * kAdjust;
}
diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h
index c1ff0a3..b0bcf10 100644
--- a/runtime/base/timing_logger.h
+++ b/runtime/base/timing_logger.h
@@ -31,16 +31,15 @@ class TimingLogger;
class CumulativeLogger {
public:
explicit CumulativeLogger(const std::string& name);
- void prepare_stats();
~CumulativeLogger();
void Start();
- void End();
- void Reset();
+ void End() LOCKS_EXCLUDED(lock_);
+ void Reset() LOCKS_EXCLUDED(lock_);
void Dump(std::ostream& os) LOCKS_EXCLUDED(lock_);
uint64_t GetTotalNs() const;
// Allow the name to be modified, particularly when the cumulative logger is a field within a
// parent class that is unable to determine the "name" of a sub-class.
- void SetName(const std::string& name);
+ void SetName(const std::string& name) LOCKS_EXCLUDED(lock_);
void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_);
size_t GetIterations() const;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 500cb59..a98673d 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -530,7 +530,8 @@ void ClassLinker::RunRootClinits() {
for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) {
mirror::Class* c = GetClassRoot(ClassRoot(i));
if (!c->IsArrayClass() && !c->IsPrimitive()) {
- EnsureInitialized(GetClassRoot(ClassRoot(i)), true, true);
+ SirtRef<mirror::Class> sirt_class(self, GetClassRoot(ClassRoot(i)));
+ EnsureInitialized(sirt_class, true, true);
self->AssertNoPendingException();
}
}
@@ -673,18 +674,19 @@ OatFile& ClassLinker::GetImageOatFile(gc::space::ImageSpace* space) {
}
const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
- return FindOpenedOatFileFromDexLocation(dex_file.GetLocation().c_str(),
- dex_file.GetLocationChecksum());
+ const char* dex_location = dex_file.GetLocation().c_str();
+ uint32_t dex_location_checksum = dex_file.GetLocationChecksum();
+ return FindOpenedOatFileFromDexLocation(dex_location, &dex_location_checksum);
}
const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const char* dex_location,
- uint32_t dex_location_checksum) {
+ const uint32_t* const dex_location_checksum) {
ReaderMutexLock mu(Thread::Current(), dex_lock_);
for (size_t i = 0; i < oat_files_.size(); i++) {
const OatFile* oat_file = oat_files_[i];
DCHECK(oat_file != NULL);
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
- &dex_location_checksum,
+ dex_location_checksum,
false);
if (oat_dex_file != NULL) {
return oat_file;
@@ -943,13 +945,13 @@ const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& o
}
const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_location,
- uint32_t dex_location_checksum,
+ const uint32_t* const dex_location_checksum,
std::string* error_msg) {
const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location,
dex_location_checksum);
if (open_oat_file != nullptr) {
const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location,
- &dex_location_checksum);
+ dex_location_checksum);
return oat_dex_file->OpenDexFile(error_msg);
}
@@ -962,6 +964,12 @@ const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_
if (dex_file != nullptr) {
return dex_file;
}
+ if (dex_location_checksum == nullptr) {
+ *error_msg = StringPrintf("Failed to open oat file from %s and no classes.dex found in %s: %s",
+ odex_filename.c_str(), dex_location, error_msg->c_str());
+ return nullptr;
+ }
+
std::string cache_error_msg;
std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location));
dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg,
@@ -978,7 +986,7 @@ const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_
// Try to generate oat file if it wasn't found or was obsolete.
error_msg->clear();
- return FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum,
+ return FindOrCreateOatFileForDexLocation(dex_location, *dex_location_checksum,
cache_location.c_str(), error_msg);
}
@@ -1133,7 +1141,7 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, b
}
{
- ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
if (!only_dirty || class_table_dirty_) {
for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
it.second = down_cast<mirror::Class*>(visitor(it.second, arg));
@@ -1156,7 +1164,7 @@ void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) {
if (dex_cache_image_class_lookup_required_) {
MoveImageClassesToClassTable();
}
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
if (!visitor(it.second, arg)) {
return;
@@ -1249,7 +1257,10 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl
size_t class_size) {
DCHECK_GE(class_size, sizeof(mirror::Class));
gc::Heap* heap = Runtime::Current()->GetHeap();
- mirror::Object* k = heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size);
+ mirror::Object* k =
+ kMovingClasses ?
+ heap->AllocObject<true>(self, java_lang_Class, class_size) :
+ heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size);
if (UNLIKELY(k == NULL)) {
CHECK(self->IsExceptionPending()); // OOME.
return NULL;
@@ -1287,21 +1298,23 @@ static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass)
DCHECK(klass != NULL);
// Wait for the class if it has not already been linked.
if (!klass->IsResolved() && !klass->IsErroneous()) {
- ObjectLock lock(self, klass);
+ SirtRef<mirror::Class> sirt_class(self, klass);
+ ObjectLock<mirror::Class> lock(self, &sirt_class);
// Check for circular dependencies between classes.
- if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) {
- ThrowClassCircularityError(klass);
- klass->SetStatus(mirror::Class::kStatusError, self);
- return NULL;
+ if (!sirt_class->IsResolved() && sirt_class->GetClinitThreadId() == self->GetTid()) {
+ ThrowClassCircularityError(sirt_class.get());
+ sirt_class->SetStatus(mirror::Class::kStatusError, self);
+ return nullptr;
}
// Wait for the pending initialization to complete.
- while (!klass->IsResolved() && !klass->IsErroneous()) {
+ while (!sirt_class->IsResolved() && !sirt_class->IsErroneous()) {
lock.WaitIgnoringInterrupts();
}
+ klass = sirt_class.get();
}
if (klass->IsErroneous()) {
ThrowEarlierClassFailure(klass);
- return NULL;
+ return nullptr;
}
// Return the loaded class. No exceptions should be pending.
CHECK(klass->IsResolved()) << PrettyClass(klass);
@@ -1320,7 +1333,7 @@ mirror::Class* ClassLinker::FindSystemClass(const char* descriptor) {
}
mirror::Class* ClassLinker::FindClass(const char* descriptor,
- SirtRef<mirror::ClassLoader>& class_loader) {
+ const SirtRef<mirror::ClassLoader>& class_loader) {
DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
Thread* self = Thread::Current();
DCHECK(self != NULL);
@@ -1403,7 +1416,7 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor,
}
mirror::Class* ClassLinker::DefineClass(const char* descriptor,
- SirtRef<mirror::ClassLoader>& class_loader,
+ const SirtRef<mirror::ClassLoader>& class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
Thread* self = Thread::Current();
@@ -1440,7 +1453,7 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor,
klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
- ObjectLock lock(self, klass.get());
+ ObjectLock<mirror::Class> lock(self, &klass);
klass->SetClinitThreadId(self->GetTid());
// Add the newly loaded class to the loaded classes table.
mirror::Class* existing = InsertClass(descriptor, klass.get(), Hash(descriptor));
@@ -1695,7 +1708,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
// Ignore virtual methods on the iterator.
}
-static void LinkCode(SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
+static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
uint32_t method_index)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Method shouldn't have already been linked.
@@ -1741,7 +1754,7 @@ static void LinkCode(SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass
void ClassLinker::LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
- SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::Class>& klass,
mirror::ClassLoader* class_loader) {
CHECK(klass.get() != NULL);
CHECK(klass->GetDexCache() != NULL);
@@ -1861,7 +1874,8 @@ void ClassLinker::LoadClass(const DexFile& dex_file,
}
void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it,
- SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtField>& dst) {
+ const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ArtField>& dst) {
uint32_t field_idx = it.GetMemberIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.get());
@@ -1870,7 +1884,7 @@ void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIter
mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
const ClassDataItemIterator& it,
- SirtRef<mirror::Class>& klass) {
+ const SirtRef<mirror::Class>& klass) {
uint32_t dex_method_idx = it.GetMemberIndex();
const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
@@ -1941,7 +1955,8 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) {
AppendToBootClassPath(dex_file, dex_cache);
}
-void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
+void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
+ const SirtRef<mirror::DexCache>& dex_cache) {
CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
boot_class_path_.push_back(&dex_file);
RegisterDexFile(dex_file, dex_cache);
@@ -1962,7 +1977,8 @@ bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
return IsDexFileRegisteredLocked(dex_file);
}
-void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
+void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
+ const SirtRef<mirror::DexCache>& dex_cache) {
dex_lock_.AssertExclusiveHeld(Thread::Current());
CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
@@ -1994,7 +2010,8 @@ void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
}
}
-void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
+void ClassLinker::RegisterDexFile(const DexFile& dex_file,
+ const SirtRef<mirror::DexCache>& dex_cache) {
WriterMutexLock mu(Thread::Current(), dex_lock_);
RegisterDexFileLocked(dex_file, dex_cache);
}
@@ -2040,11 +2057,13 @@ mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type t
return InitializePrimitiveClass(klass, type);
}
-mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) {
+mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class,
+ Primitive::Type type) {
CHECK(primitive_class != NULL);
// Must hold lock on object when initializing.
Thread* self = Thread::Current();
- ObjectLock lock(self, primitive_class);
+ SirtRef<mirror::Class> sirt_class(self, primitive_class);
+ ObjectLock<mirror::Class> lock(self, &sirt_class);
primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
primitive_class->SetPrimitiveType(type);
primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
@@ -2068,7 +2087,7 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_cl
//
// Returns NULL with an exception raised on failure.
mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor,
- SirtRef<mirror::ClassLoader>& class_loader) {
+ const SirtRef<mirror::ClassLoader>& class_loader) {
// Identify the underlying component type
CHECK_EQ('[', descriptor[0]);
mirror::Class* component_type = FindClass(descriptor + 1, class_loader);
@@ -2138,7 +2157,7 @@ mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor,
}
new_class->SetComponentType(component_type);
}
- ObjectLock lock(self, new_class.get()); // Must hold lock on object when initializing.
+ ObjectLock<mirror::Class> lock(self, &new_class); // Must hold lock on object when initializing.
DCHECK(new_class->GetComponentType() != NULL);
mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
new_class->SetSuperClass(java_lang_Object);
@@ -2421,10 +2440,10 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Clas
}
}
-void ClassLinker::VerifyClass(mirror::Class* klass) {
+void ClassLinker::VerifyClass(const SirtRef<mirror::Class>& klass) {
// TODO: assert that the monitor on the Class is held
Thread* self = Thread::Current();
- ObjectLock lock(self, klass);
+ ObjectLock<mirror::Class> lock(self, &klass);
// Don't attempt to re-verify if already sufficiently verified.
if (klass->IsVerified() ||
@@ -2435,7 +2454,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
// The class might already be erroneous, for example at compile time if we attempted to verify
// this class as a parent to another.
if (klass->IsErroneous()) {
- ThrowEarlierClassFailure(klass);
+ ThrowEarlierClassFailure(klass.get());
return;
}
@@ -2443,7 +2462,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
klass->SetStatus(mirror::Class::kStatusVerifying, self);
} else {
CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
- << PrettyClass(klass);
+ << PrettyClass(klass.get());
CHECK(!Runtime::Current()->IsCompiler());
klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self);
}
@@ -2452,23 +2471,23 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
SirtRef<mirror::Class> super(self, klass->GetSuperClass());
if (super.get() != NULL) {
// Acquire lock to prevent races on verifying the super class.
- ObjectLock lock(self, super.get());
+ ObjectLock<mirror::Class> lock(self, &super);
if (!super->IsVerified() && !super->IsErroneous()) {
- VerifyClass(super.get());
+ VerifyClass(super);
}
if (!super->IsCompileTimeVerified()) {
std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s",
- PrettyDescriptor(klass).c_str(),
+ PrettyDescriptor(klass.get()).c_str(),
PrettyDescriptor(super.get()).c_str()));
LOG(ERROR) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
- if (cause.get() != NULL) {
+ if (cause.get() != nullptr) {
self->ClearException();
}
- ThrowVerifyError(klass, "%s", error_msg.c_str());
- if (cause.get() != NULL) {
- self->GetException(NULL)->SetCause(cause.get());
+ ThrowVerifyError(klass.get(), "%s", error_msg.c_str());
+ if (cause.get() != nullptr) {
+ self->GetException(nullptr)->SetCause(cause.get());
}
klass->SetStatus(mirror::Class::kStatusError, self);
return;
@@ -2478,26 +2497,26 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
// Try to use verification information from the oat file, otherwise do runtime verification.
const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
- bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
+ bool preverified = VerifyClassUsingOatFile(dex_file, klass.get(), oat_file_class_status);
if (oat_file_class_status == mirror::Class::kStatusError) {
VLOG(class_linker) << "Skipping runtime verification of erroneous class "
- << PrettyDescriptor(klass) << " in "
+ << PrettyDescriptor(klass.get()) << " in "
<< klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
- ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification",
- PrettyDescriptor(klass).c_str());
+ ThrowVerifyError(klass.get(), "Rejecting class %s because it failed compile-time verification",
+ PrettyDescriptor(klass.get()).c_str());
klass->SetStatus(mirror::Class::kStatusError, self);
return;
}
verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
std::string error_msg;
if (!preverified) {
- verifier_failure = verifier::MethodVerifier::VerifyClass(klass,
+ verifier_failure = verifier::MethodVerifier::VerifyClass(klass.get(),
Runtime::Current()->IsCompiler(),
&error_msg);
}
if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
- VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass)
+ VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.get())
<< " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
<< " because: " << error_msg;
}
@@ -2527,11 +2546,11 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
}
}
} else {
- LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass)
+ LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass.get())
<< " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
<< " because: " << error_msg;
self->AssertNoPendingException();
- ThrowVerifyError(klass, "%s", error_msg.c_str());
+ ThrowVerifyError(klass.get(), "%s", error_msg.c_str());
klass->SetStatus(mirror::Class::kStatusError, self);
}
if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
@@ -2625,7 +2644,8 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class
return false;
}
-void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, mirror::Class* klass) {
+void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
+ const SirtRef<mirror::Class>& klass) {
for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
}
@@ -2763,13 +2783,13 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccess& soa, jstring na
self->AssertNoPendingException();
{
- ObjectLock lock(self, klass.get()); // Must hold lock on object when resolved.
+ ObjectLock<mirror::Class> lock(self, &klass); // Must hold lock on object when resolved.
// Link the fields and virtual methods, creating vtable and iftables
SirtRef<mirror::ObjectArray<mirror::Class> > sirt_interfaces(
self, soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
if (!LinkClass(self, klass, sirt_interfaces)) {
klass->SetStatus(mirror::Class::kStatusError, self);
- return NULL;
+ return nullptr;
}
interfaces_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
@@ -2840,7 +2860,7 @@ mirror::ArtMethod* ClassLinker::FindMethodForProxy(const mirror::Class* proxy_cl
mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self,
- SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::Class>& klass,
mirror::Class* proxy_class) {
// Create constructor for Proxy that must initialize h
mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods =
@@ -2870,8 +2890,9 @@ static void CheckProxyConstructor(mirror::ArtMethod* constructor)
DCHECK(constructor->IsPublic());
}
-mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ArtMethod>& prototype) {
+mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self,
+ const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ArtMethod>& prototype) {
// Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
// prototype method
prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(),
@@ -2966,7 +2987,7 @@ bool ClassLinker::IsInitialized() const {
return init_done_;
}
-bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
+bool ClassLinker::InitializeClass(const SirtRef<mirror::Class>& klass, bool can_init_statics,
bool can_init_parents) {
// see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
@@ -2978,14 +2999,14 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
}
// Fast fail if initialization requires a full runtime. Not part of the JLS.
- if (!CanWeInitializeClass(klass, can_init_statics, can_init_parents)) {
+ if (!CanWeInitializeClass(klass.get(), can_init_statics, can_init_parents)) {
return false;
}
Thread* self = Thread::Current();
uint64_t t0;
{
- ObjectLock lock(self, klass);
+ ObjectLock<mirror::Class> lock(self, &klass);
// Re-check under the lock in case another thread initialized ahead of us.
if (klass->IsInitialized()) {
@@ -2994,11 +3015,11 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
// Was the class already found to be erroneous? Done under the lock to match the JLS.
if (klass->IsErroneous()) {
- ThrowEarlierClassFailure(klass);
+ ThrowEarlierClassFailure(klass.get());
return false;
}
- CHECK(klass->IsResolved()) << PrettyClass(klass) << ": state=" << klass->GetStatus();
+ CHECK(klass->IsResolved()) << PrettyClass(klass.get()) << ": state=" << klass->GetStatus();
if (!klass->IsVerified()) {
VerifyClass(klass);
@@ -3035,7 +3056,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
return false;
}
- CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass);
+ CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.get());
// From here out other threads may observe that we're initializing and so changes of state
// require the a notification.
@@ -3051,16 +3072,17 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
if (!super_class->IsInitialized()) {
CHECK(!super_class->IsInterface());
CHECK(can_init_parents);
- bool super_initialized = InitializeClass(super_class, can_init_statics, true);
+ SirtRef<mirror::Class> sirt_super(self, super_class);
+ bool super_initialized = InitializeClass(sirt_super, can_init_statics, true);
if (!super_initialized) {
// The super class was verified ahead of entering initializing, we should only be here if
// the super class became erroneous due to initialization.
- CHECK(super_class->IsErroneous() && self->IsExceptionPending())
- << "Super class initialization failed for " << PrettyDescriptor(super_class)
- << " that has unexpected status " << super_class->GetStatus()
+ CHECK(sirt_super->IsErroneous() && self->IsExceptionPending())
+ << "Super class initialization failed for " << PrettyDescriptor(sirt_super.get())
+ << " that has unexpected status " << sirt_super->GetStatus()
<< "\nPending exception:\n"
<< (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
- ObjectLock lock(self, klass);
+ ObjectLock<mirror::Class> lock(self, &klass);
// Initialization failed because the super-class is erroneous.
klass->SetStatus(mirror::Class::kStatusError, self);
return false;
@@ -3069,7 +3091,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
}
if (klass->NumStaticFields() > 0) {
- ClassHelper kh(klass);
+ ClassHelper kh(klass.get());
const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
CHECK(dex_class_def != NULL);
const DexFile& dex_file = kh.GetDexFile();
@@ -3081,7 +3103,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
CHECK(can_init_statics);
// We reordered the fields, so we need to be able to map the field indexes to the right fields.
SafeMap<uint32_t, mirror::ArtField*> field_map;
- ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
+ ConstructFieldMap(dex_file, *dex_class_def, klass.get(), field_map);
for (size_t i = 0; it.HasNext(); i++, it.Next()) {
it.ReadValueToField(field_map.Get(i));
}
@@ -3100,13 +3122,13 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
}
// Opportunistically set static method trampolines to their destination.
- FixupStaticTrampolines(klass);
+ FixupStaticTrampolines(klass.get());
uint64_t t1 = NanoTime();
bool success = true;
{
- ObjectLock lock(self, klass);
+ ObjectLock<mirror::Class> lock(self, &klass);
if (self->IsExceptionPending()) {
WrapExceptionInInitializer();
@@ -3122,7 +3144,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
// Set the class as initialized except if failed to initialize static fields.
klass->SetStatus(mirror::Class::kStatusInitialized, self);
if (VLOG_IS_ON(class_linker)) {
- ClassHelper kh(klass);
+ ClassHelper kh(klass.get());
LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
}
}
@@ -3130,7 +3152,8 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
return success;
}
-bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock)
+bool ClassLinker::WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self,
+ ObjectLock<mirror::Class>& lock)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
while (true) {
self->AssertNoPendingException();
@@ -3157,47 +3180,49 @@ bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, Obj
// The caller wants an exception, but it was thrown in a
// different thread. Synthesize one here.
ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread",
- PrettyDescriptor(klass).c_str());
+ PrettyDescriptor(klass.get()).c_str());
return false;
}
if (klass->IsInitialized()) {
return true;
}
- LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass) << " is " << klass->GetStatus();
+ LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass.get()) << " is "
+ << klass->GetStatus();
}
- LOG(FATAL) << "Not Reached" << PrettyClass(klass);
+ LOG(FATAL) << "Not Reached" << PrettyClass(klass.get());
}
-bool ClassLinker::ValidateSuperClassDescriptors(const mirror::Class* klass) {
+bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass) {
if (klass->IsInterface()) {
return true;
}
+ Thread* self = Thread::Current();
// begin with the methods local to the superclass
if (klass->HasSuperClass() &&
klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
- const mirror::Class* super = klass->GetSuperClass();
+ SirtRef<mirror::Class> super(self, klass->GetSuperClass());
for (int i = super->GetVTable()->GetLength() - 1; i >= 0; --i) {
const mirror::ArtMethod* method = klass->GetVTable()->Get(i);
if (method != super->GetVTable()->Get(i) &&
- !IsSameMethodSignatureInDifferentClassContexts(method, super, klass)) {
- ThrowLinkageError(klass, "Class %s method %s resolves differently in superclass %s",
- PrettyDescriptor(klass).c_str(), PrettyMethod(method).c_str(),
- PrettyDescriptor(super).c_str());
+ !IsSameMethodSignatureInDifferentClassContexts(method, super.get(), klass.get())) {
+ ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in superclass %s",
+ PrettyDescriptor(klass.get()).c_str(), PrettyMethod(method).c_str(),
+ PrettyDescriptor(super.get()).c_str());
return false;
}
}
}
for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
- mirror::Class* interface = klass->GetIfTable()->GetInterface(i);
+ SirtRef<mirror::Class> interface(self, klass->GetIfTable()->GetInterface(i));
if (klass->GetClassLoader() != interface->GetClassLoader()) {
for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
const mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j);
- if (!IsSameMethodSignatureInDifferentClassContexts(method, interface,
+ if (!IsSameMethodSignatureInDifferentClassContexts(method, interface.get(),
method->GetDeclaringClass())) {
- ThrowLinkageError(klass, "Class %s method %s resolves differently in interface %s",
+ ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in interface %s",
PrettyDescriptor(method->GetDeclaringClass()).c_str(),
PrettyMethod(method).c_str(),
- PrettyDescriptor(interface).c_str());
+ PrettyDescriptor(interface.get()).c_str());
return false;
}
}
@@ -3214,17 +3239,22 @@ bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(const mirror::Ar
if (klass1 == klass2) {
return true;
}
+ Thread* self = Thread::Current();
+ CHECK(klass1 != nullptr);
+ CHECK(klass2 != nullptr);
+ SirtRef<mirror::ClassLoader> loader1(self, klass1->GetClassLoader());
+ SirtRef<mirror::ClassLoader> loader2(self, klass2->GetClassLoader());
const DexFile& dex_file = *method->GetDeclaringClass()->GetDexCache()->GetDexFile();
const DexFile::ProtoId& proto_id =
dex_file.GetMethodPrototype(dex_file.GetMethodId(method->GetDexMethodIndex()));
for (DexFileParameterIterator it(dex_file, proto_id); it.HasNext(); it.Next()) {
const char* descriptor = it.GetDescriptor();
- if (descriptor == NULL) {
+ if (descriptor == nullptr) {
break;
}
if (descriptor[0] == 'L' || descriptor[0] == '[') {
// Found a non-primitive type.
- if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) {
+ if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) {
return false;
}
}
@@ -3232,47 +3262,42 @@ bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(const mirror::Ar
// Check the return type
const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id);
if (descriptor[0] == 'L' || descriptor[0] == '[') {
- if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) {
+ if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) {
return false;
}
}
return true;
}
-// Returns true if the descriptor resolves to the same class in the context of klass1 and klass2.
+// Returns true if the descriptor resolves to the same class in the context of loader1 and loader2.
bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descriptor,
- const mirror::Class* klass1,
- const mirror::Class* klass2) {
- CHECK(descriptor != NULL);
- CHECK(klass1 != NULL);
- CHECK(klass2 != NULL);
- if (klass1 == klass2) {
- return true;
- }
+ SirtRef<mirror::ClassLoader>& loader1,
+ SirtRef<mirror::ClassLoader>& loader2) {
+ CHECK(descriptor != nullptr);
Thread* self = Thread::Current();
- SirtRef<mirror::ClassLoader> class_loader1(self, klass1->GetClassLoader());
- mirror::Class* found1 = FindClass(descriptor, class_loader1);
- if (found1 == NULL) {
- Thread::Current()->ClearException();
+ SirtRef<mirror::Class> found1(self, FindClass(descriptor, loader1));
+ if (found1.get() == nullptr) {
+ self->ClearException();
}
- SirtRef<mirror::ClassLoader> class_loader2(self, klass2->GetClassLoader());
- mirror::Class* found2 = FindClass(descriptor, class_loader2);
- if (found2 == NULL) {
- Thread::Current()->ClearException();
+ mirror::Class* found2 = FindClass(descriptor, loader2);
+ if (found2 == nullptr) {
+ self->ClearException();
}
- return found1 == found2;
+ return found1.get() == found2;
}
-bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_init_fields, bool can_init_parents) {
- DCHECK(c != NULL);
+bool ClassLinker::EnsureInitialized(const SirtRef<mirror::Class>& c, bool can_init_fields,
+ bool can_init_parents) {
+ DCHECK(c.get() != NULL);
if (c->IsInitialized()) {
return true;
}
bool success = InitializeClass(c, can_init_fields, can_init_parents);
if (!success) {
- Thread* self = Thread::Current();
- CHECK(self->IsExceptionPending() || !can_init_fields || !can_init_parents) << PrettyClass(c);
+ if (can_init_fields && can_init_parents) {
+ CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.get());
+ }
}
return success;
}
@@ -3285,13 +3310,14 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas
Thread* self = Thread::Current();
SirtRef<mirror::DexCache> dex_cache(self, c->GetDexCache());
SirtRef<mirror::ClassLoader> class_loader(self, c->GetClassLoader());
+ CHECK(!kMovingFields);
for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) {
field_map.Put(i, ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, true));
}
}
-bool ClassLinker::LinkClass(Thread* self, SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkClass(Thread* self, const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
@@ -3312,7 +3338,8 @@ bool ClassLinker::LinkClass(Thread* self, SirtRef<mirror::Class>& klass,
return true;
}
-bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file) {
+bool ClassLinker::LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass,
+ const DexFile& dex_file) {
CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
uint16_t super_class_idx = class_def.superclass_idx_;
@@ -3355,7 +3382,7 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const De
return true;
}
-bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkSuperClass(const SirtRef<mirror::Class>& klass) {
CHECK(!klass->IsPrimitive());
mirror::Class* super = klass->GetSuperClass();
if (klass.get() == GetClassRoot(kJavaLangObject)) {
@@ -3414,8 +3441,8 @@ bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) {
}
// Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkMethods(const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
if (klass->IsInterface()) {
// No vtable.
size_t count = klass->NumVirtualMethods();
@@ -3435,7 +3462,7 @@ bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass,
return true;
}
-bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkVirtualMethods(const SirtRef<mirror::Class>& klass) {
Thread* self = Thread::Current();
if (klass->HasSuperClass()) {
uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->GetVTable()->GetLength();
@@ -3518,8 +3545,8 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) {
return true;
}
-bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkInterfaceMethods(const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
// Set the imt table to be all conflicts by default.
klass->SetImTable(Runtime::Current()->GetDefaultImt());
size_t super_ifcount;
@@ -3529,14 +3556,17 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
super_ifcount = 0;
}
size_t ifcount = super_ifcount;
- ClassHelper kh(klass.get());
- uint32_t num_interfaces =
- interfaces.get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength();
- ifcount += num_interfaces;
- for (size_t i = 0; i < num_interfaces; i++) {
- mirror::Class* interface =
- interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
- ifcount += interface->GetIfTableCount();
+ uint32_t num_interfaces;
+ {
+ ClassHelper kh(klass.get());
+ num_interfaces =
+ interfaces.get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength();
+ ifcount += num_interfaces;
+ for (size_t i = 0; i < num_interfaces; i++) {
+ mirror::Class* interface =
+ interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
+ ifcount += interface->GetIfTableCount();
+ }
}
if (ifcount == 0) {
// Class implements no interfaces.
@@ -3576,6 +3606,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
// Flatten the interface inheritance hierarchy.
size_t idx = super_ifcount;
for (size_t i = 0; i < num_interfaces; i++) {
+ ClassHelper kh(klass.get());
mirror::Class* interface =
interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
DCHECK(interface != NULL);
@@ -3640,11 +3671,8 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
return false;
}
std::vector<mirror::ArtMethod*> miranda_list;
- MethodHelper vtable_mh(NULL);
- MethodHelper interface_mh(NULL);
for (size_t i = 0; i < ifcount; ++i) {
- mirror::Class* interface = iftable->GetInterface(i);
- size_t num_methods = interface->NumVirtualMethods();
+ size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
if (num_methods > 0) {
SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
method_array(self, AllocArtMethodArray(self, num_methods));
@@ -3656,8 +3684,8 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
SirtRef<mirror::ObjectArray<mirror::ArtMethod> > vtable(self,
klass->GetVTableDuringLinking());
for (size_t j = 0; j < num_methods; ++j) {
- mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j);
- interface_mh.ChangeMethod(interface_method);
+ mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j);
+ MethodHelper interface_mh(interface_method);
int32_t k;
// For each method listed in the interface's method list, find the
// matching method in our class's method list. We want to favor the
@@ -3669,7 +3697,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
// matter which direction we go. We walk it backward anyway.)
for (k = vtable->GetLength() - 1; k >= 0; --k) {
mirror::ArtMethod* vtable_method = vtable->Get(k);
- vtable_mh.ChangeMethod(vtable_method);
+ MethodHelper vtable_mh(vtable_method);
if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
ThrowIllegalAccessError(klass.get(),
@@ -3694,7 +3722,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
SirtRef<mirror::ArtMethod> miranda_method(self, NULL);
for (size_t mir = 0; mir < miranda_list.size(); mir++) {
mirror::ArtMethod* mir_method = miranda_list[mir];
- vtable_mh.ChangeMethod(mir_method);
+ MethodHelper vtable_mh(mir_method);
if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
miranda_method.reset(miranda_list[mir]);
break;
@@ -3772,12 +3800,12 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
return true;
}
-bool ClassLinker::LinkInstanceFields(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkInstanceFields(const SirtRef<mirror::Class>& klass) {
CHECK(klass.get() != NULL);
return LinkFields(klass, false);
}
-bool ClassLinker::LinkStaticFields(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkStaticFields(const SirtRef<mirror::Class>& klass) {
CHECK(klass.get() != NULL);
size_t allocated_class_size = klass->GetClassSize();
bool success = LinkFields(klass, true);
@@ -3813,7 +3841,7 @@ struct LinkFieldsComparator {
}
};
-bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) {
+bool ClassLinker::LinkFields(const SirtRef<mirror::Class>& klass, bool is_static) {
size_t num_fields =
is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
@@ -3972,7 +4000,7 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) {
// Set the bitmap of reference offsets, refOffsets, from the ifields
// list.
-void ClassLinker::CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass) {
uint32_t reference_offsets = 0;
mirror::Class* super_class = klass->GetSuperClass();
if (super_class != NULL) {
@@ -3986,11 +4014,11 @@ void ClassLinker::CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass)
CreateReferenceOffsets(klass, false, reference_offsets);
}
-void ClassLinker::CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass) {
CreateReferenceOffsets(klass, true, 0);
}
-void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static,
+void ClassLinker::CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static,
uint32_t reference_offsets) {
size_t num_reference_fields =
is_static ? klass->NumReferenceStaticFieldsDuringLinking()
@@ -4023,7 +4051,7 @@ void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_
}
mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx,
- SirtRef<mirror::DexCache>& dex_cache) {
+ const SirtRef<mirror::DexCache>& dex_cache) {
DCHECK(dex_cache.get() != nullptr);
mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
if (resolved != NULL) {
@@ -4045,8 +4073,8 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i
}
mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader) {
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader) {
DCHECK(dex_cache.get() != NULL);
mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
if (resolved == NULL) {
@@ -4064,9 +4092,11 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i
// Convert a ClassNotFoundException to a NoClassDefFoundError.
SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+ SirtRef<mirror::Class> sirt_resolved(self, resolved);
Thread::Current()->ClearException();
ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
self->GetException(NULL)->SetCause(cause.get());
+ resolved = sirt_resolved.get();
}
}
}
@@ -4077,8 +4107,8 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i
mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
uint32_t method_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader,
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader,
const mirror::ArtMethod* referrer,
InvokeType type) {
DCHECK(dex_cache.get() != NULL);
@@ -4223,8 +4253,8 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
}
mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader,
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader,
bool is_static) {
DCHECK(dex_cache.get() != nullptr);
mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
@@ -4263,8 +4293,8 @@ mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t fi
mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
uint32_t field_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader) {
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader) {
DCHECK(dex_cache.get() != nullptr);
mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
if (resolved != NULL) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 4e2cc06..d468e1e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -45,7 +45,7 @@ namespace mirror {
} // namespace mirror
class InternTable;
-class ObjectLock;
+template<class T> class ObjectLock;
class ScopedObjectAccess;
template<class T> class SirtRef;
@@ -72,7 +72,7 @@ class ClassLinker {
// Finds a class by its descriptor, loading it if necessary.
// If class_loader is null, searches boot_class_path_.
- mirror::Class* FindClass(const char* descriptor, SirtRef<mirror::ClassLoader>& class_loader)
+ mirror::Class* FindClass(const char* descriptor, const SirtRef<mirror::ClassLoader>& class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::Class* FindSystemClass(const char* descriptor)
@@ -82,7 +82,8 @@ class ClassLinker {
bool IsInitialized() const;
// Define a new a class based on a ClassDef from a DexFile
- mirror::Class* DefineClass(const char* descriptor, SirtRef<mirror::ClassLoader>& class_loader,
+ mirror::Class* DefineClass(const char* descriptor,
+ const SirtRef<mirror::ClassLoader>& class_loader,
const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -126,7 +127,7 @@ class ClassLinker {
// Resolve a String with the given index from the DexFile, storing the
// result in the DexCache.
mirror::String* ResolveString(const DexFile& dex_file, uint32_t string_idx,
- SirtRef<mirror::DexCache>& dex_cache)
+ const SirtRef<mirror::DexCache>& dex_cache)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolve a Type with the given index from the DexFile, storing the
@@ -150,8 +151,8 @@ class ClassLinker {
// type, since it may be referenced from but not contained within
// the given DexFile.
mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader)
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolve a method with a given ID from the DexFile, storing the
@@ -161,8 +162,8 @@ class ClassLinker {
// virtual method.
mirror::ArtMethod* ResolveMethod(const DexFile& dex_file,
uint32_t method_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader,
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader,
const mirror::ArtMethod* referrer,
InvokeType type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -182,8 +183,8 @@ class ClassLinker {
// field.
mirror::ArtField* ResolveField(const DexFile& dex_file,
uint32_t field_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader,
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader,
bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -193,8 +194,8 @@ class ClassLinker {
// field resolution semantics are followed.
mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file,
uint32_t field_idx,
- SirtRef<mirror::DexCache>& dex_cache,
- SirtRef<mirror::ClassLoader>& class_loader)
+ const SirtRef<mirror::DexCache>& dex_cache,
+ const SirtRef<mirror::ClassLoader>& class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Get shorty from method index without resolution. Used to do handlerization.
@@ -204,7 +205,8 @@ class ClassLinker {
// Returns true on success, false if there's an exception pending.
// can_run_clinit=false allows the compiler to attempt to init a class,
// given the restriction that no <clinit> execution is possible.
- bool EnsureInitialized(mirror::Class* c, bool can_run_clinit, bool can_init_fields)
+ bool EnsureInitialized(const SirtRef<mirror::Class>& c,
+ bool can_init_fields, bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Initializes classes that have instances in the image but that have
@@ -214,7 +216,7 @@ class ClassLinker {
void RegisterDexFile(const DexFile& dex_file)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
+ void RegisterDexFile(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -268,7 +270,7 @@ class ClassLinker {
// that this returns null if the location checksum of the DexFile
// does not match the OatFile.
const DexFile* FindDexFileInOatFileFromDexLocation(const char* location,
- uint32_t location_checksum,
+ const uint32_t* const location_checksum,
std::string* error_msg)
LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
@@ -303,11 +305,12 @@ class ClassLinker {
size_t length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void VerifyClass(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VerifyClass(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
mirror::Class::Status& oat_file_class_status)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, mirror::Class* klass)
+ void ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
+ const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -380,7 +383,8 @@ class ClassLinker {
// Alloc* convenience functions to avoid needing to pass in mirror::Class*
// values that are known to the ClassLinker such as
// kObjectArrayClass and kJavaLangString etc.
- mirror::Class* AllocClass(Thread* self, size_t class_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::Class* AllocClass(Thread* self, size_t class_size)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::ArtField* AllocArtField(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -392,12 +396,12 @@ class ClassLinker {
mirror::Class* CreateArrayClass(const char* descriptor,
- SirtRef<mirror::ClassLoader>& class_loader)
+ const SirtRef<mirror::ClassLoader>& class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void AppendToBootClassPath(const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
+ void AppendToBootClassPath(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
@@ -409,17 +413,17 @@ class ClassLinker {
void LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
- SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::Class>& klass,
mirror::ClassLoader* class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
- SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtField>& dst)
+ const SirtRef<mirror::Class>& klass, const SirtRef<mirror::ArtField>& dst)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::ArtMethod* LoadMethod(Thread* self, const DexFile& dex_file,
const ClassDataItemIterator& dex_method,
- SirtRef<mirror::Class>& klass)
+ const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -428,20 +432,22 @@ class ClassLinker {
const OatFile::OatClass* GetOatClass(const DexFile& dex_file, uint16_t class_def_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
+ void RegisterDexFileLocked(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_);
- bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents)
+ bool InitializeClass(const SirtRef<mirror::Class>& klass, bool can_run_clinit,
+ bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock);
- bool ValidateSuperClassDescriptors(const mirror::Class* klass)
+ bool WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self,
+ ObjectLock<mirror::Class>& lock);
+ bool ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsSameDescriptorInDifferentClassContexts(const char* descriptor,
- const mirror::Class* klass1,
- const mirror::Class* klass2)
+ SirtRef<mirror::ClassLoader>& class_loader1,
+ SirtRef<mirror::ClassLoader>& class_loader2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsSameMethodSignatureInDifferentClassContexts(const mirror::ArtMethod* method,
@@ -449,40 +455,40 @@ class ClassLinker {
const mirror::Class* klass2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkClass(Thread* self, SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+ bool LinkClass(Thread* self, const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkSuperClass(SirtRef<mirror::Class>& klass)
+ bool LinkSuperClass(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file)
+ bool LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass, const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkMethods(SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+ bool LinkMethods(const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkVirtualMethods(SirtRef<mirror::Class>& klass)
+ bool LinkVirtualMethods(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+ bool LinkInterfaceMethods(const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkStaticFields(SirtRef<mirror::Class>& klass)
+ bool LinkStaticFields(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkInstanceFields(SirtRef<mirror::Class>& klass)
+ bool LinkInstanceFields(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkFields(SirtRef<mirror::Class>& klass, bool is_static)
+ bool LinkFields(const SirtRef<mirror::Class>& klass, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass)
+ void CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass)
+ void CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static,
+ void CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static,
uint32_t reference_offsets)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -495,7 +501,7 @@ class ClassLinker {
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location,
- uint32_t dex_location_checksum)
+ const uint32_t* const dex_location_checksum)
LOCKS_EXCLUDED(dex_lock);
const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
LOCKS_EXCLUDED(dex_lock_);
@@ -511,11 +517,11 @@ class ClassLinker {
bool* open_failed)
LOCKS_EXCLUDED(dex_lock_);
- mirror::ArtMethod* CreateProxyConstructor(Thread* self, SirtRef<mirror::Class>& klass,
+ mirror::ArtMethod* CreateProxyConstructor(Thread* self, const SirtRef<mirror::Class>& klass,
mirror::Class* proxy_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::ArtMethod* CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass,
- SirtRef<mirror::ArtMethod>& prototype)
+ mirror::ArtMethod* CreateProxyMethod(Thread* self, const SirtRef<mirror::Class>& klass,
+ const SirtRef<mirror::ArtMethod>& prototype)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
std::vector<const DexFile*> boot_class_path_;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index b8bc474..34134fa 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -95,8 +95,10 @@ class ClassLinkerTest : public CommonTest {
const std::string& component_type,
mirror::ClassLoader* class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SirtRef<mirror::ClassLoader> loader(Thread::Current(), class_loader);
- mirror::Class* array = class_linker_->FindClass(array_descriptor.c_str(), loader);
+ Thread* self = Thread::Current();
+ SirtRef<mirror::ClassLoader> loader(self, class_loader);
+ SirtRef<mirror::Class> array(self,
+ class_linker_->FindClass(array_descriptor.c_str(), loader));
ClassHelper array_component_ch(array->GetComponentType());
EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
EXPECT_EQ(class_loader, array->GetClassLoader());
@@ -104,10 +106,10 @@ class ClassLinkerTest : public CommonTest {
AssertArrayClass(array_descriptor, array);
}
- void AssertArrayClass(const std::string& array_descriptor, mirror::Class* array)
+ void AssertArrayClass(const std::string& array_descriptor, const SirtRef<mirror::Class>& array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ClassHelper kh(array);
- ASSERT_TRUE(array != NULL);
+ ClassHelper kh(array.get());
+ ASSERT_TRUE(array.get() != NULL);
ASSERT_TRUE(array->GetClass() != NULL);
ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
@@ -135,15 +137,14 @@ class ClassLinkerTest : public CommonTest {
EXPECT_EQ(0U, array->NumVirtualMethods());
EXPECT_EQ(0U, array->NumInstanceFields());
EXPECT_EQ(0U, array->NumStaticFields());
- kh.ChangeClass(array);
+ kh.ChangeClass(array.get());
EXPECT_EQ(2U, kh.NumDirectInterfaces());
EXPECT_TRUE(array->GetVTable() != NULL);
EXPECT_EQ(2, array->GetIfTableCount());
- mirror::IfTable* iftable = array->GetIfTable();
- ASSERT_TRUE(iftable != NULL);
+ ASSERT_TRUE(array->GetIfTable() != NULL);
kh.ChangeClass(kh.GetDirectInterface(0));
EXPECT_STREQ(kh.GetDescriptor(), "Ljava/lang/Cloneable;");
- kh.ChangeClass(array);
+ kh.ChangeClass(array.get());
kh.ChangeClass(kh.GetDirectInterface(1));
EXPECT_STREQ(kh.GetDescriptor(), "Ljava/io/Serializable;");
}
@@ -179,9 +180,9 @@ class ClassLinkerTest : public CommonTest {
EXPECT_TRUE(fh.GetType() != NULL);
}
- void AssertClass(const std::string& descriptor, mirror::Class* klass)
+ void AssertClass(const std::string& descriptor, const SirtRef<mirror::Class>& klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ClassHelper kh(klass);
+ ClassHelper kh(klass.get());
EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor());
if (descriptor == "Ljava/lang/Object;") {
EXPECT_FALSE(klass->HasSuperClass());
@@ -197,7 +198,7 @@ class ClassLinkerTest : public CommonTest {
EXPECT_FALSE(klass->IsErroneous());
EXPECT_FALSE(klass->IsArrayClass());
EXPECT_TRUE(klass->GetComponentType() == NULL);
- EXPECT_TRUE(klass->IsInSamePackage(klass));
+ EXPECT_TRUE(klass->IsInSamePackage(klass.get()));
EXPECT_TRUE(mirror::Class::IsInSamePackage(kh.GetDescriptor(), kh.GetDescriptor()));
if (klass->IsInterface()) {
EXPECT_TRUE(klass->IsAbstract());
@@ -239,31 +240,31 @@ class ClassLinkerTest : public CommonTest {
}
EXPECT_FALSE(klass->IsPrimitive());
- EXPECT_TRUE(klass->CanAccess(klass));
+ EXPECT_TRUE(klass->CanAccess(klass.get()));
for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
mirror::ArtMethod* method = klass->GetDirectMethod(i);
AssertMethod(method);
EXPECT_TRUE(method->IsDirect());
- EXPECT_EQ(klass, method->GetDeclaringClass());
+ EXPECT_EQ(klass.get(), method->GetDeclaringClass());
}
for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
mirror::ArtMethod* method = klass->GetVirtualMethod(i);
AssertMethod(method);
EXPECT_FALSE(method->IsDirect());
- EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass));
+ EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass.get()));
}
for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
mirror::ArtField* field = klass->GetInstanceField(i);
- AssertField(klass, field);
+ AssertField(klass.get(), field);
EXPECT_FALSE(field->IsStatic());
}
for (size_t i = 0; i < klass->NumStaticFields(); i++) {
mirror::ArtField* field = klass->GetStaticField(i);
- AssertField(klass, field);
+ AssertField(klass.get(), field);
EXPECT_TRUE(field->IsStatic());
}
@@ -291,24 +292,24 @@ class ClassLinkerTest : public CommonTest {
}
size_t total_num_reference_instance_fields = 0;
- mirror::Class* k = klass;
+ mirror::Class* k = klass.get();
while (k != NULL) {
total_num_reference_instance_fields += k->NumReferenceInstanceFields();
k = k->GetSuperClass();
}
- EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0,
- total_num_reference_instance_fields == 0);
+ EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0, total_num_reference_instance_fields == 0);
}
void AssertDexFileClass(mirror::ClassLoader* class_loader, const std::string& descriptor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ASSERT_TRUE(descriptor != NULL);
- mirror::Class* klass = class_linker_->FindSystemClass(descriptor.c_str());
- ASSERT_TRUE(klass != NULL);
- EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass).GetDescriptor());
+ SirtRef<mirror::Class> klass(Thread::Current(),
+ class_linker_->FindSystemClass(descriptor.c_str()));
+ ASSERT_TRUE(klass.get() != nullptr);
+ EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass.get()).GetDescriptor());
EXPECT_EQ(class_loader, klass->GetClassLoader());
if (klass->IsPrimitive()) {
- AssertPrimitiveClass(descriptor, klass);
+ AssertPrimitiveClass(descriptor, klass.get());
} else if (klass->IsArrayClass()) {
AssertArrayClass(descriptor, klass);
} else {
@@ -852,7 +853,7 @@ TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
TEST_F(ClassLinkerTest, StaticFields) {
ScopedObjectAccess soa(Thread::Current());
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")));
- mirror::Class* statics = class_linker_->FindClass("LStatics;", class_loader);
+ SirtRef<mirror::Class> statics(soa.Self(), class_linker_->FindClass("LStatics;", class_loader));
class_linker_->EnsureInitialized(statics, true, true);
// Static final primitives that are initialized by a compile-time constant
@@ -867,68 +868,68 @@ TEST_F(ClassLinkerTest, StaticFields) {
FieldHelper fh(s0);
EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/ArtField;");
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean);
- EXPECT_EQ(true, s0->GetBoolean(statics));
- s0->SetBoolean(statics, false);
+ EXPECT_EQ(true, s0->GetBoolean(statics.get()));
+ s0->SetBoolean(statics.get(), false);
mirror::ArtField* s1 = statics->FindStaticField("s1", "B");
fh.ChangeField(s1);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte);
- EXPECT_EQ(5, s1->GetByte(statics));
- s1->SetByte(statics, 6);
+ EXPECT_EQ(5, s1->GetByte(statics.get()));
+ s1->SetByte(statics.get(), 6);
mirror::ArtField* s2 = statics->FindStaticField("s2", "C");
fh.ChangeField(s2);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar);
- EXPECT_EQ('a', s2->GetChar(statics));
- s2->SetChar(statics, 'b');
+ EXPECT_EQ('a', s2->GetChar(statics.get()));
+ s2->SetChar(statics.get(), 'b');
mirror::ArtField* s3 = statics->FindStaticField("s3", "S");
fh.ChangeField(s3);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort);
- EXPECT_EQ(-536, s3->GetShort(statics));
- s3->SetShort(statics, -535);
+ EXPECT_EQ(-536, s3->GetShort(statics.get()));
+ s3->SetShort(statics.get(), -535);
mirror::ArtField* s4 = statics->FindStaticField("s4", "I");
fh.ChangeField(s4);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt);
- EXPECT_EQ(2000000000, s4->GetInt(statics));
- s4->SetInt(statics, 2000000001);
+ EXPECT_EQ(2000000000, s4->GetInt(statics.get()));
+ s4->SetInt(statics.get(), 2000000001);
mirror::ArtField* s5 = statics->FindStaticField("s5", "J");
fh.ChangeField(s5);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong);
- EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics));
- s5->SetLong(statics, 0x34567890abcdef12LL);
+ EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.get()));
+ s5->SetLong(statics.get(), 0x34567890abcdef12LL);
mirror::ArtField* s6 = statics->FindStaticField("s6", "F");
fh.ChangeField(s6);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat);
- EXPECT_EQ(0.5, s6->GetFloat(statics));
- s6->SetFloat(statics, 0.75);
+ EXPECT_EQ(0.5, s6->GetFloat(statics.get()));
+ s6->SetFloat(statics.get(), 0.75);
mirror::ArtField* s7 = statics->FindStaticField("s7", "D");
fh.ChangeField(s7);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble);
- EXPECT_EQ(16777217, s7->GetDouble(statics));
- s7->SetDouble(statics, 16777219);
+ EXPECT_EQ(16777217, s7->GetDouble(statics.get()));
+ s7->SetDouble(statics.get(), 16777219);
mirror::ArtField* s8 = statics->FindStaticField("s8", "Ljava/lang/String;");
fh.ChangeField(s8);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot);
- EXPECT_TRUE(s8->GetObject(statics)->AsString()->Equals("android"));
+ EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("android"));
s8->SetObject(s8->GetDeclaringClass(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
// TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ
// http://code.google.com/p/googletest/issues/detail?id=322
- EXPECT_FALSE(s0->GetBoolean(statics));
- EXPECT_EQ(6, s1->GetByte(statics));
- EXPECT_EQ('b', s2->GetChar(statics));
- EXPECT_EQ(-535, s3->GetShort(statics));
- EXPECT_EQ(2000000001, s4->GetInt(statics));
- EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(statics));
- EXPECT_EQ(0.75, s6->GetFloat(statics));
- EXPECT_EQ(16777219, s7->GetDouble(statics));
- EXPECT_TRUE(s8->GetObject(statics)->AsString()->Equals("robot"));
+ EXPECT_FALSE(s0->GetBoolean(statics.get()));
+ EXPECT_EQ(6, s1->GetByte(statics.get()));
+ EXPECT_EQ('b', s2->GetChar(statics.get()));
+ EXPECT_EQ(-535, s3->GetShort(statics.get()));
+ EXPECT_EQ(2000000001, s4->GetInt(statics.get()));
+ EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(statics.get()));
+ EXPECT_EQ(0.75, s6->GetFloat(statics.get()));
+ EXPECT_EQ(16777219, s7->GetDouble(statics.get()));
+ EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("robot"));
}
TEST_F(ClassLinkerTest, Interfaces) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index edfd21f..bcf7267 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -452,6 +452,7 @@ void Dbg::StartJdwp() {
void Dbg::StopJdwp() {
delete gJdwpState;
+ gJdwpState = NULL;
delete gRegistry;
gRegistry = NULL;
}
@@ -1132,7 +1133,7 @@ bool Dbg::MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id)
CHECK(c1 != NULL);
mirror::Class* c2 = DecodeClass(class_id, status);
CHECK(c2 != NULL);
- return c1->IsAssignableFrom(c2);
+ return c2->IsAssignableFrom(c1);
}
static JDWP::FieldId ToFieldId(const mirror::ArtField* f)
@@ -2731,7 +2732,7 @@ JDWP::JdwpError Dbg::InvokeMethod(JDWP::ObjectId thread_id, JDWP::ObjectId objec
if (argument == ObjectRegistry::kInvalidObject) {
return JDWP::ERR_INVALID_OBJECT;
}
- if (!argument->InstanceOf(parameter_type)) {
+ if (argument != NULL && !argument->InstanceOf(parameter_type)) {
return JDWP::ERR_ILLEGAL_ARGUMENT;
}
@@ -2835,30 +2836,30 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) {
}
// Translate the method through the vtable, unless the debugger wants to suppress it.
- mirror::ArtMethod* m = pReq->method;
+ SirtRef<mirror::ArtMethod> m(soa.Self(), pReq->method);
if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != NULL) {
mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(pReq->method);
- if (actual_method != m) {
- VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m) << " to " << PrettyMethod(actual_method);
- m = actual_method;
+ if (actual_method != m.get()) {
+ VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m.get()) << " to " << PrettyMethod(actual_method);
+ m.reset(actual_method);
}
}
- VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m)
+ VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m.get())
<< " receiver=" << pReq->receiver
<< " arg_count=" << pReq->arg_count;
- CHECK(m != NULL);
+ CHECK(m.get() != nullptr);
CHECK_EQ(sizeof(jvalue), sizeof(uint64_t));
- MethodHelper mh(m);
+ MethodHelper mh(m.get());
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
arg_array.BuildArgArray(soa, pReq->receiver, reinterpret_cast<jvalue*>(pReq->arg_values));
- InvokeWithArgArray(soa, m, &arg_array, &pReq->result_value, mh.GetShorty()[0]);
+ InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty()[0]);
mirror::Throwable* exception = soa.Self()->GetException(NULL);
soa.Self()->ClearException();
pReq->exception = gRegistry->Add(exception);
- pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m).GetShorty());
+ pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m.get()).GetShorty());
if (pReq->exception != 0) {
VLOG(jdwp) << " JDWP invocation returning with exception=" << exception
<< " " << exception->Dump();
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 517f96c..429c516 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -98,9 +98,10 @@ bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string*
*error_msg = StringPrintf("Failed to open zip archive '%s'", filename);
return false;
}
- UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex, error_msg));
if (zip_entry.get() == NULL) {
- *error_msg = StringPrintf("Zip archive '%s' doesn\'t contain %s", filename, kClassesDex);
+ *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+ kClassesDex, error_msg->c_str());
return false;
}
*checksum = zip_entry->GetCrc32();
@@ -176,7 +177,7 @@ const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify,
struct stat sbuf;
memset(&sbuf, 0, sizeof(sbuf));
if (fstat(fd, &sbuf) == -1) {
- *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno));
+ *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location, strerror(errno));
return nullptr;
}
if (S_ISDIR(sbuf.st_mode)) {
@@ -193,7 +194,7 @@ const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify,
if (map->Size() < sizeof(DexFile::Header)) {
*error_msg = StringPrintf(
- "DexFile: failed to open dex file \'%s\' that is too short to have a header", location);
+ "DexFile: failed to open dex file '%s' that is too short to have a header", location);
return nullptr;
}
@@ -240,9 +241,8 @@ const DexFile* DexFile::OpenMemory(const std::string& location,
const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location,
std::string* error_msg) {
CHECK(!location.empty());
- UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex));
+ UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex, error_msg));
if (zip_entry.get() == NULL) {
- *error_msg = StringPrintf("Failed to find classes.dex within '%s'", location.c_str());
return nullptr;
}
UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex, error_msg));
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 56bf21d..dc9d337 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -16,6 +16,8 @@
#include "dex_file_verifier.h"
+#include <zlib.h>
+
#include "base/stringprintf.h"
#include "dex_file-inl.h"
#include "leb128.h"
@@ -23,7 +25,6 @@
#include "UniquePtr.h"
#include "utf-inl.h"
#include "utils.h"
-#include "zip_archive.h"
namespace art {
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 9961df9..2941db6 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -36,7 +36,7 @@ class DexMethodIteratorTest : public CommonTest {
TEST_F(DexMethodIteratorTest, Basic) {
ScopedObjectAccess soa(Thread::Current());
std::vector<const DexFile*> dex_files;
- dex_files.push_back(OpenDexFile("core"));
+ dex_files.push_back(OpenDexFile("core-libart"));
dex_files.push_back(OpenDexFile("conscrypt"));
dex_files.push_back(OpenDexFile("okhttp"));
dex_files.push_back(OpenDexFile("core-junit"));
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 2806f94..3ab8888 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -57,7 +57,7 @@ static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, mirror:
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
DCHECK(throw_location.GetMethod() == referrer);
self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but \'int\'",
+ "Found type %s; filled-new-array not implemented for anything but 'int'",
PrettyDescriptor(klass).c_str());
}
return nullptr; // Failure
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 747dd56..bfdbd74 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -72,7 +72,7 @@ ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
if (UNLIKELY(!klass->IsInitialized())) {
SirtRef<mirror::Class> sirt_klass(self, klass);
// The class initializer might cause a GC.
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(klass, true, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
DCHECK(self->IsExceptionPending());
return nullptr; // Failure
}
@@ -246,12 +246,15 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr
// If the class is initialized we're done.
if (LIKELY(fields_class->IsInitialized())) {
return resolved_field;
- } else if (LIKELY(class_linker->EnsureInitialized(fields_class, true, true))) {
- // Otherwise let's ensure the class is initialized before resolving the field.
- return resolved_field;
} else {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return nullptr; // failure
+ SirtRef<mirror::Class> sirt_class(self, fields_class);
+ if (LIKELY(class_linker->EnsureInitialized(sirt_class, true, true))) {
+ // Otherwise let's ensure the class is initialized before resolving the field.
+ return resolved_field;
+ } else {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return nullptr; // failure
+ }
}
}
}
@@ -535,12 +538,13 @@ static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
return klass;
}
- if (!class_linker->EnsureInitialized(klass, true, true)) {
+ SirtRef<mirror::Class> sirt_class(self, klass);
+ if (!class_linker->EnsureInitialized(sirt_class, true, true)) {
CHECK(self->IsExceptionPending());
return NULL; // Failure - Indicate to caller to deliver exception
}
- referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
- return klass;
+ referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, sirt_class.get());
+ return sirt_class.get();
}
extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 05c02f2..0df00c2 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -33,12 +33,15 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m
if (method->IsStatic()) {
mirror::Class* declaringClass = method->GetDeclaringClass();
if (UNLIKELY(!declaringClass->IsInitializing())) {
- if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass,
- true, true))) {
- DCHECK(Thread::Current()->IsExceptionPending());
+ self->PushShadowFrame(shadow_frame);
+ SirtRef<mirror::Class> sirt_c(self, declaringClass);
+ if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true))) {
+ self->PopShadowFrame();
+ DCHECK(self->IsExceptionPending());
return;
}
- CHECK(declaringClass->IsInitializing());
+ self->PopShadowFrame();
+ CHECK(sirt_c->IsInitializing());
}
}
uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 16364fc..4d1e531 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -50,7 +50,7 @@ static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
intptr_t value = *arg_ptr;
mirror::Object** value_as_jni_rep = reinterpret_cast<mirror::Object**>(value);
mirror::Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
- CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep))
+ CHECK(Runtime::Current()->GetHeap()->IsValidObjectAddress(value_as_work_around_rep))
<< value_as_work_around_rep;
*arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
}
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
index 8a2c899..4f19964 100644
--- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
@@ -36,11 +36,7 @@ class ShadowFrameCopyVisitor : public StackVisitor {
ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
const uint8_t* gc_map = method->GetNativeGcMap();
- uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
- (gc_map[1] << 16) |
- (gc_map[2] << 8) |
- (gc_map[3] << 0));
- verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
+ verifier::DexPcToReferenceMap dex_gc_map(gc_map);
const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
for (size_t reg = 0; reg < num_regs; ++reg) {
if (TestBitmap(reg, reg_bitmap)) {
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 61f7440..2162dcc 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -208,8 +208,8 @@ extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Th
if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
// Ensure static method's class is initialized.
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
- true, true)) {
+ SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
DCHECK(Thread::Current()->IsExceptionPending());
self->PopManagedStackFragment(fragment);
return 0;
@@ -390,7 +390,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called
const void* code = NULL;
if (LIKELY(!thread->IsExceptionPending())) {
// Ensure that the called method's class is initialized.
- mirror::Class* called_class = called->GetDeclaringClass();
+ SirtRef<mirror::Class> called_class(thread, called->GetDeclaringClass());
linker->EnsureInitialized(called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
code = called->GetEntryPointFromCompiledCode();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 8ba08ee..b589384 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -298,8 +298,8 @@ extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Threa
if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
// Ensure static method's class is initialized.
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
- true, true)) {
+ SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
DCHECK(Thread::Current()->IsExceptionPending());
self->PopManagedStackFragment(fragment);
return 0;
@@ -564,7 +564,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
}
}
// Ensure that the called method's class is initialized.
- mirror::Class* called_class = called->GetDeclaringClass();
+ SirtRef<mirror::Class> called_class(soa.Self(), called->GetDeclaringClass());
linker->EnsureInitialized(called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
code = called->GetEntryPointFromCompiledCode();
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index e9a6e4f..978faeb 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -37,11 +37,13 @@ class ExceptionTest : public CommonTest {
CommonTest::SetUp();
ScopedObjectAccess soa(Thread::Current());
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
- soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader);
ASSERT_TRUE(my_klass_ != NULL);
- class_linker_->EnsureInitialized(my_klass_, true, true);
+ SirtRef<mirror::Class> sirt_klass(soa.Self(), my_klass_);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ my_klass_ = sirt_klass.get();
dex_ = my_klass_->GetDexCache()->GetDexFile();
@@ -54,17 +56,17 @@ class ExceptionTest : public CommonTest {
fake_code_.push_back(0x70 | i);
}
- fake_mapping_data_.PushBack(4); // first element is count
- fake_mapping_data_.PushBack(4); // total (non-length) elements
- fake_mapping_data_.PushBack(2); // count of pc to dex elements
+ fake_mapping_data_.PushBackUnsigned(4); // first element is count
+ fake_mapping_data_.PushBackUnsigned(4); // total (non-length) elements
+ fake_mapping_data_.PushBackUnsigned(2); // count of pc to dex elements
// --- pc to dex table
- fake_mapping_data_.PushBack(3); // offset 3
- fake_mapping_data_.PushBack(3); // maps to dex offset 3
+ fake_mapping_data_.PushBackUnsigned(3 - 0); // offset 3
+ fake_mapping_data_.PushBackSigned(3 - 0); // maps to dex offset 3
// --- dex to pc table
- fake_mapping_data_.PushBack(3); // offset 3
- fake_mapping_data_.PushBack(3); // maps to dex offset 3
+ fake_mapping_data_.PushBackUnsigned(3 - 0); // offset 3
+ fake_mapping_data_.PushBackSigned(3 - 0); // maps to dex offset 3
- fake_vmap_table_data_.PushBack(0);
+ fake_vmap_table_data_.PushBackUnsigned(0);
fake_gc_map_.push_back(0); // 0 bytes to encode references and native pc offsets.
fake_gc_map_.push_back(0);
@@ -91,8 +93,8 @@ class ExceptionTest : public CommonTest {
const DexFile* dex_;
std::vector<uint8_t> fake_code_;
- UnsignedLeb128EncodingVector fake_mapping_data_;
- UnsignedLeb128EncodingVector fake_vmap_table_data_;
+ Leb128EncodingVector fake_mapping_data_;
+ Leb128EncodingVector fake_vmap_table_data_;
std::vector<uint8_t> fake_gc_map_;
mirror::ArtMethod* method_f_;
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 7818bc8..e099137 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -95,8 +95,8 @@ void CardTable::ClearSpaceCards(space::ContinuousSpace* space) {
}
void CardTable::ClearCardTable() {
- // TODO: clear just the range of the table that has been modified
- memset(mem_map_->Begin(), kCardClean, mem_map_->Size());
+ COMPILE_ASSERT(kCardClean == 0, clean_card_must_be_0);
+ madvise(mem_map_->Begin(), mem_map_->Size(), MADV_DONTNEED);
}
bool CardTable::AddrIsInCardTable(const void* addr) const {
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index faa198a..b428e74 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -82,7 +82,7 @@ class ModUnionUpdateObjectReferencesVisitor {
if (ref != nullptr) {
Object* new_ref = visitor_(ref, arg_);
if (new_ref != ref) {
- obj->SetFieldObject(offset, new_ref, true);
+ obj->SetFieldPtr(offset, new_ref, true);
}
}
}
diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h
index 7a51553..9c1c5dc 100644
--- a/runtime/gc/collector/mark_sweep-inl.h
+++ b/runtime/gc/collector/mark_sweep-inl.h
@@ -69,15 +69,14 @@ inline void MarkSweep::VisitObjectReferences(mirror::Object* obj, const Visitor&
DCHECK(obj->GetClass() != NULL);
mirror::Class* klass = obj->GetClass();
DCHECK(klass != NULL);
- if (visit_class) {
- visitor(obj, klass, mirror::Object::ClassOffset(), false);
- }
if (klass == mirror::Class::GetJavaLangClass()) {
DCHECK_EQ(klass->GetClass(), mirror::Class::GetJavaLangClass());
VisitClassReferences(klass, obj, visitor);
} else {
if (klass->IsArrayClass()) {
- visitor(obj, klass, mirror::Object::ClassOffset(), false);
+ if (visit_class) {
+ visitor(obj, klass, mirror::Object::ClassOffset(), false);
+ }
if (klass->IsObjectArrayClass()) {
VisitObjectArrayReferences(obj->AsObjectArray<mirror::Object>(), visitor);
}
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 53d85b0..62991bb 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -89,10 +89,12 @@ class MarkSweep : public GarbageCollector {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void MarkNonThreadRoots()
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void MarkConcurrentRoots();
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+ void MarkConcurrentRoots()
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void MarkRootsCheckpoint(Thread* self)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 3939354..b75b493 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -78,6 +78,8 @@ namespace collector {
static constexpr bool kProtectFromSpace = true;
static constexpr bool kResetFromSpace = true;
+// TODO: move this to a new file as a new garbage collector?
+static constexpr bool kEnableSimplePromo = false;
// TODO: Unduplicate logic.
void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) {
@@ -134,7 +136,9 @@ SemiSpace::SemiSpace(Heap* heap, const std::string& name_prefix)
finalizer_reference_list_(nullptr),
phantom_reference_list_(nullptr),
cleared_reference_list_(nullptr),
- self_(nullptr) {
+ self_(nullptr),
+ last_gc_to_space_end_(nullptr),
+ bytes_promoted_(0) {
}
void SemiSpace::InitializePhase() {
@@ -169,10 +173,25 @@ void SemiSpace::MarkingPhase() {
// Need to do this with mutators paused so that somebody doesn't accidentally allocate into the
// wrong space.
heap_->SwapSemiSpaces();
+ if (kEnableSimplePromo) {
+ // If last_gc_to_space_end_ is out of the bounds of the from-space
+ // (the to-space from last GC), then point it to the beginning of
+ // the from-space. For example, the very first GC or the
+ // pre-zygote compaction.
+ if (!from_space_->HasAddress(reinterpret_cast<mirror::Object*>(last_gc_to_space_end_))) {
+ last_gc_to_space_end_ = from_space_->Begin();
+ }
+ // Reset this before the marking starts below.
+ bytes_promoted_ = 0;
+ }
// Assume the cleared space is already empty.
BindBitmaps();
// Process dirty cards and add dirty cards to mod-union tables.
heap_->ProcessCards(timings_);
+ // Clear the whole card table since we can not get any additional dirty cards during the
+ // paused GC. This saves memory but only works for pause the world collectors.
+ timings_.NewSplit("ClearCardTable");
+ heap_->GetCardTable()->ClearCardTable();
// Need to do this before the checkpoint since we don't want any threads to add references to
// the live stack during the recursive mark.
timings_.NewSplit("SwapStacks");
@@ -268,6 +287,13 @@ void SemiSpace::ReclaimPhase() {
} else {
mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ);
}
+
+ if (kEnableSimplePromo) {
+ // Record the end (top) of the to space so we can distinguish
+ // between objects that were allocated since the last GC and the
+ // older objects.
+ last_gc_to_space_end_ = to_space_->End();
+ }
}
void SemiSpace::ResizeMarkStack(size_t new_size) {
@@ -308,20 +334,48 @@ Object* SemiSpace::MarkObject(Object* obj) {
if (from_space_->HasAddress(obj)) {
mirror::Object* forward_address = GetForwardingAddressInFromSpace(obj);
// If the object has already been moved, return the new forward address.
- if (!to_space_->HasAddress(forward_address)) {
+ if (forward_address == nullptr) {
// Otherwise, we need to move the object and add it to the markstack for processing.
size_t object_size = obj->SizeOf();
size_t dummy = 0;
- forward_address = to_space_->Alloc(self_, object_size, &dummy);
+ if (kEnableSimplePromo && reinterpret_cast<byte*>(obj) < last_gc_to_space_end_) {
+ // If it's allocated before the last GC (older), move (pseudo-promote) it to
+ // the non-moving space (as sort of an old generation.)
+ size_t bytes_promoted;
+ space::MallocSpace* non_moving_space = GetHeap()->GetNonMovingSpace();
+ forward_address = non_moving_space->Alloc(self_, object_size, &bytes_promoted);
+ if (forward_address == nullptr) {
+ // If out of space, fall back to the to-space.
+ forward_address = to_space_->Alloc(self_, object_size, &dummy);
+ } else {
+ GetHeap()->num_bytes_allocated_.fetch_add(bytes_promoted);
+ bytes_promoted_ += bytes_promoted;
+ // Mark forward_address on the live bit map.
+ accounting::SpaceBitmap* live_bitmap = non_moving_space->GetLiveBitmap();
+ DCHECK(live_bitmap != nullptr);
+ DCHECK(!live_bitmap->Test(forward_address));
+ live_bitmap->Set(forward_address);
+ // Mark forward_address on the mark bit map.
+ accounting::SpaceBitmap* mark_bitmap = non_moving_space->GetMarkBitmap();
+ DCHECK(mark_bitmap != nullptr);
+ DCHECK(!mark_bitmap->Test(forward_address));
+ mark_bitmap->Set(forward_address);
+ }
+ DCHECK(forward_address != nullptr);
+ } else {
+ // If it's allocated after the last GC (younger), copy it to the to-space.
+ forward_address = to_space_->Alloc(self_, object_size, &dummy);
+ }
// Copy over the object and add it to the mark stack since we still need to update it's
// references.
memcpy(reinterpret_cast<void*>(forward_address), obj, object_size);
// Make sure to only update the forwarding address AFTER you copy the object so that the
// monitor word doesn't get stomped over.
- COMPILE_ASSERT(sizeof(uint32_t) == sizeof(mirror::Object*),
- monitor_size_must_be_same_as_object);
obj->SetLockWord(LockWord::FromForwardingAddress(reinterpret_cast<size_t>(forward_address)));
MarkStackPush(forward_address);
+ } else {
+ DCHECK(to_space_->HasAddress(forward_address) ||
+ (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forward_address)));
}
ret = forward_address;
// TODO: Do we need this if in the else statement?
@@ -508,7 +562,10 @@ void SemiSpace::ScanObject(Object* obj) {
mirror::Object* new_address = MarkObject(ref);
if (new_address != ref) {
DCHECK(new_address != nullptr);
- obj->SetFieldObject(offset, new_address, false);
+ // Don't need to mark the card since we updating the object address and not changing the
+ // actual objects its pointing to. Using SetFieldPtr is better in this case since it does not
+ // dirty cards and use additional memory.
+ obj->SetFieldPtr(offset, new_address, false);
}
}, kMovingClasses);
mirror::Class* klass = obj->GetClass();
@@ -535,7 +592,9 @@ inline Object* SemiSpace::GetMarkedForwardAddress(mirror::Object* obj) const
if (from_space_->HasAddress(obj)) {
mirror::Object* forwarding_address = GetForwardingAddressInFromSpace(const_cast<Object*>(obj));
// If the object is forwarded then it MUST be marked.
- if (to_space_->HasAddress(forwarding_address)) {
+ DCHECK(forwarding_address == nullptr || to_space_->HasAddress(forwarding_address) ||
+ (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forwarding_address)));
+ if (forwarding_address != nullptr) {
return forwarding_address;
}
// Must not be marked, return nullptr;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 0f0cae1..b0724f9 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -281,6 +281,15 @@ class SemiSpace : public GarbageCollector {
Thread* self_;
+ // Used for kEnableSimplePromo. The end/top of the bump pointer
+ // space at the end of the last collection.
+ byte* last_gc_to_space_end_;
+
+ // Used for kEnableSimplePromo. During a collection, keeps track of
+ // how many bytes of objects have been copied so far from the bump
+ // pointer space to the non-moving space.
+ uint64_t bytes_promoted_;
+
private:
DISALLOW_COPY_AND_ASSIGN(SemiSpace);
};
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index ba3cad6..06395cf 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -24,6 +24,8 @@ namespace gc {
// Which types of collections are able to be performed.
enum CollectorType {
+ // No collector selected.
+ kCollectorTypeNone,
// Non concurrent mark-sweep.
kCollectorTypeMS,
// Concurrent mark-sweep.
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 5eda0b9..99f084a 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -41,24 +41,20 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas
// done in the runnable state where suspension is expected.
DCHECK_EQ(self->GetState(), kRunnable);
self->AssertThreadSuspensionIsAllowable();
+ // Need to check that we arent the large object allocator since the large object allocation code
+ // path this function. If we didn't check we would have an infinite loop.
+ if (allocator != kAllocatorTypeLOS && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
+ return AllocLargeObject<kInstrumented, PreFenceVisitor>(self, klass, byte_count,
+ pre_fence_visitor);
+ }
mirror::Object* obj;
size_t bytes_allocated;
AllocationTimer alloc_timer(this, &obj);
- if (UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
- obj = TryToAllocate<kInstrumented>(self, kAllocatorTypeLOS, byte_count, false,
- &bytes_allocated);
- allocator = kAllocatorTypeLOS;
- } else {
- obj = TryToAllocate<kInstrumented>(self, allocator, byte_count, false, &bytes_allocated);
- }
-
+ obj = TryToAllocate<kInstrumented, false>(self, allocator, byte_count, &bytes_allocated);
if (UNLIKELY(obj == nullptr)) {
- SirtRef<mirror::Class> sirt_c(self, klass);
- obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated);
+ obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated, &klass);
if (obj == nullptr) {
return nullptr;
- } else {
- klass = sirt_c.get();
}
}
obj->SetClass(klass);
@@ -93,7 +89,7 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas
} else {
DCHECK(!Dbg::IsAllocTrackingEnabled());
}
- if (AllocatorHasConcurrentGC(allocator)) {
+ if (concurrent_gc_) {
CheckConcurrentGC(self, new_num_bytes_allocated, obj);
}
if (kIsDebugBuild) {
@@ -105,17 +101,28 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas
return obj;
}
-template <const bool kInstrumented>
+template <bool kInstrumented, typename PreFenceVisitor>
+inline mirror::Object* Heap::AllocLargeObject(Thread* self, mirror::Class* klass,
+ size_t byte_count,
+ const PreFenceVisitor& pre_fence_visitor) {
+ return AllocObjectWithAllocator<kInstrumented, PreFenceVisitor>(self, klass, byte_count,
+ kAllocatorTypeLOS,
+ pre_fence_visitor);
+}
+
+template <const bool kInstrumented, const bool kGrow>
inline mirror::Object* Heap::TryToAllocate(Thread* self, AllocatorType allocator_type,
- size_t alloc_size, bool grow,
- size_t* bytes_allocated) {
- if (UNLIKELY(IsOutOfMemoryOnAllocation(alloc_size, grow))) {
+ size_t alloc_size, size_t* bytes_allocated) {
+ if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(alloc_size))) {
return nullptr;
}
if (kInstrumented) {
if (UNLIKELY(running_on_valgrind_ && allocator_type == kAllocatorTypeFreeList)) {
return non_moving_space_->Alloc(self, alloc_size, bytes_allocated);
}
+ } else {
+ // If running on valgrind, we should be using the instrumented path.
+ DCHECK(!running_on_valgrind_);
}
mirror::Object* ret;
switch (allocator_type) {
@@ -187,18 +194,21 @@ inline bool Heap::ShouldAllocLargeObject(mirror::Class* c, size_t byte_count) co
return byte_count >= kLargeObjectThreshold && have_zygote_space_ && c->IsPrimitiveArray();
}
-inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow) {
+template <const bool kGrow>
+inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size) {
size_t new_footprint = num_bytes_allocated_ + alloc_size;
if (UNLIKELY(new_footprint > max_allowed_footprint_)) {
if (UNLIKELY(new_footprint > growth_limit_)) {
return true;
}
if (!concurrent_gc_) {
- if (!grow) {
+ if (!kGrow) {
return true;
- } else {
- max_allowed_footprint_ = new_footprint;
}
+ // TODO: Grow for allocation is racy, fix it.
+ VLOG(heap) << "Growing heap from " << PrettySize(max_allowed_footprint_) << " to "
+ << PrettySize(new_footprint) << " for a " << PrettySize(alloc_size) << " allocation";
+ max_allowed_footprint_ = new_footprint;
}
}
return false;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5e62729..11acd33 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -75,12 +75,13 @@ static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB;
Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
double target_utilization, size_t capacity, const std::string& image_file_name,
- CollectorType collector_type, size_t parallel_gc_threads, size_t conc_gc_threads,
- bool low_memory_mode, size_t long_pause_log_threshold, size_t long_gc_log_threshold,
- bool ignore_max_footprint)
+ CollectorType post_zygote_collector_type, size_t parallel_gc_threads,
+ size_t conc_gc_threads, bool low_memory_mode, size_t long_pause_log_threshold,
+ size_t long_gc_log_threshold, bool ignore_max_footprint)
: non_moving_space_(nullptr),
- concurrent_gc_(collector_type == gc::kCollectorTypeCMS),
- collector_type_(collector_type),
+ concurrent_gc_(false),
+ collector_type_(kCollectorTypeNone),
+ post_zygote_collector_type_(post_zygote_collector_type),
parallel_gc_threads_(parallel_gc_threads),
conc_gc_threads_(conc_gc_threads),
low_memory_mode_(low_memory_mode),
@@ -107,11 +108,9 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
activity_thread_(NULL),
application_thread_(NULL),
last_process_state_id_(NULL),
- // Initially care about pauses in case we never get notified of process states, or if the JNI
- // code becomes broken.
- care_about_pause_times_(true),
- concurrent_start_bytes_(concurrent_gc_ ? initial_size - kMinConcurrentRemainingBytes
- : std::numeric_limits<size_t>::max()),
+ // Initially assume we perceive jank in case the process state is never updated.
+ process_state_(kProcessStateJankPerceptible),
+ concurrent_start_bytes_(std::numeric_limits<size_t>::max()),
total_bytes_freed_ever_(0),
total_objects_freed_ever_(0),
num_bytes_allocated_(0),
@@ -156,8 +155,12 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
// If we aren't the zygote, switch to the default non zygote allocator. This may update the
// entrypoints.
if (!Runtime::Current()->IsZygote()) {
- ChangeCollector(collector_type_);
+ ChangeCollector(post_zygote_collector_type_);
+ } else {
+ // We are the zygote, use bump pointer allocation + semi space collector.
+ ChangeCollector(kCollectorTypeSS);
}
+
live_bitmap_.reset(new accounting::HeapBitmap(this));
mark_bitmap_.reset(new accounting::HeapBitmap(this));
// Requested begin for the alloc space, to follow the mapped image and oat files
@@ -263,9 +266,6 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
garbage_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));
garbage_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));
}
- gc_plan_.push_back(collector::kGcTypeSticky);
- gc_plan_.push_back(collector::kGcTypePartial);
- gc_plan_.push_back(collector::kGcTypeFull);
if (kMovingCollector) {
// TODO: Clean this up.
semi_space_collector_ = new collector::SemiSpace(this);
@@ -325,6 +325,10 @@ void Heap::DecrementDisableGC(Thread* self) {
--gc_disable_count_;
}
+void Heap::UpdateProcessState(ProcessState process_state) {
+ process_state_ = process_state;
+}
+
void Heap::CreateThreadPool() {
const size_t num_threads = std::max(parallel_gc_threads_, conc_gc_threads_);
if (num_threads != 0) {
@@ -373,124 +377,6 @@ void Heap::DeleteThreadPool() {
thread_pool_.reset(nullptr);
}
-static bool ReadStaticInt(JNIEnvExt* env, jclass clz, const char* name, int* out_value) {
- DCHECK(out_value != NULL);
- jfieldID field = env->GetStaticFieldID(clz, name, "I");
- if (field == NULL) {
- env->ExceptionClear();
- return false;
- }
- *out_value = env->GetStaticIntField(clz, field);
- return true;
-}
-
-void Heap::ListenForProcessStateChange() {
- VLOG(heap) << "Heap notified of process state change";
-
- Thread* self = Thread::Current();
- JNIEnvExt* env = self->GetJniEnv();
-
- if (!have_zygote_space_) {
- return;
- }
-
- if (activity_thread_class_ == NULL) {
- jclass clz = env->FindClass("android/app/ActivityThread");
- if (clz == NULL) {
- env->ExceptionClear();
- LOG(WARNING) << "Could not find activity thread class in process state change";
- return;
- }
- activity_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
- }
-
- if (activity_thread_class_ != NULL && activity_thread_ == NULL) {
- jmethodID current_activity_method = env->GetStaticMethodID(activity_thread_class_,
- "currentActivityThread",
- "()Landroid/app/ActivityThread;");
- if (current_activity_method == NULL) {
- env->ExceptionClear();
- LOG(WARNING) << "Could not get method for currentActivityThread";
- return;
- }
-
- jobject obj = env->CallStaticObjectMethod(activity_thread_class_, current_activity_method);
- if (obj == NULL) {
- env->ExceptionClear();
- LOG(WARNING) << "Could not get current activity";
- return;
- }
- activity_thread_ = env->NewGlobalRef(obj);
- }
-
- if (process_state_cares_about_pause_time_.empty()) {
- // Just attempt to do this the first time.
- jclass clz = env->FindClass("android/app/ActivityManager");
- if (clz == NULL) {
- LOG(WARNING) << "Activity manager class is null";
- return;
- }
- ScopedLocalRef<jclass> activity_manager(env, clz);
- std::vector<const char*> care_about_pauses;
- care_about_pauses.push_back("PROCESS_STATE_TOP");
- care_about_pauses.push_back("PROCESS_STATE_IMPORTANT_BACKGROUND");
- // Attempt to read the constants and classify them as whether or not we care about pause times.
- for (size_t i = 0; i < care_about_pauses.size(); ++i) {
- int process_state = 0;
- if (ReadStaticInt(env, activity_manager.get(), care_about_pauses[i], &process_state)) {
- process_state_cares_about_pause_time_.insert(process_state);
- VLOG(heap) << "Adding process state " << process_state
- << " to set of states which care about pause time";
- }
- }
- }
-
- if (application_thread_class_ == NULL) {
- jclass clz = env->FindClass("android/app/ActivityThread$ApplicationThread");
- if (clz == NULL) {
- env->ExceptionClear();
- LOG(WARNING) << "Could not get application thread class";
- return;
- }
- application_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
- last_process_state_id_ = env->GetFieldID(application_thread_class_, "mLastProcessState", "I");
- if (last_process_state_id_ == NULL) {
- env->ExceptionClear();
- LOG(WARNING) << "Could not get last process state member";
- return;
- }
- }
-
- if (application_thread_class_ != NULL && application_thread_ == NULL) {
- jmethodID get_application_thread =
- env->GetMethodID(activity_thread_class_, "getApplicationThread",
- "()Landroid/app/ActivityThread$ApplicationThread;");
- if (get_application_thread == NULL) {
- LOG(WARNING) << "Could not get method ID for get application thread";
- return;
- }
-
- jobject obj = env->CallObjectMethod(activity_thread_, get_application_thread);
- if (obj == NULL) {
- LOG(WARNING) << "Could not get application thread";
- return;
- }
-
- application_thread_ = env->NewGlobalRef(obj);
- }
-
- if (application_thread_ != NULL && last_process_state_id_ != NULL) {
- int process_state = env->GetIntField(application_thread_, last_process_state_id_);
- env->ExceptionClear();
-
- care_about_pause_times_ = process_state_cares_about_pause_time_.find(process_state) !=
- process_state_cares_about_pause_time_.end();
-
- VLOG(heap) << "New process state " << process_state
- << " care about pauses " << care_about_pause_times_;
- }
-}
-
void Heap::AddSpace(space::Space* space) {
DCHECK(space != NULL);
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
@@ -995,14 +881,17 @@ void Heap::RecordFree(size_t freed_objects, size_t freed_bytes) {
}
mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocator,
- size_t alloc_size, size_t* bytes_allocated) {
+ size_t alloc_size, size_t* bytes_allocated,
+ mirror::Class** klass) {
mirror::Object* ptr = nullptr;
+ DCHECK(klass != nullptr);
+ SirtRef<mirror::Class> sirt_klass(self, *klass);
// The allocation failed. If the GC is running, block until it completes, and then retry the
// allocation.
collector::GcType last_gc = WaitForGcToComplete(self);
if (last_gc != collector::kGcTypeNone) {
// A GC was in progress and we blocked, retry allocation now that memory has been freed.
- ptr = TryToAllocate<true>(self, allocator, alloc_size, false, bytes_allocated);
+ ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated);
}
// Loop through our different Gc types and try to Gc until we get enough free memory.
@@ -1013,13 +902,13 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocat
// Attempt to run the collector, if we succeed, re-try the allocation.
if (CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone) {
// Did we free sufficient memory for the allocation to succeed?
- ptr = TryToAllocate<true>(self, allocator, alloc_size, false, bytes_allocated);
+ ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated);
}
}
// Allocations have failed after GCs; this is an exceptional state.
if (ptr == nullptr) {
// Try harder, growing the heap if necessary.
- ptr = TryToAllocate<true>(self, allocator, alloc_size, true, bytes_allocated);
+ ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated);
}
if (ptr == nullptr) {
// Most allocations should have succeeded by now, so the heap is really full, really fragmented,
@@ -1032,11 +921,12 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocat
// We don't need a WaitForGcToComplete here either.
DCHECK(!gc_plan_.empty());
CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true);
- ptr = TryToAllocate<true>(self, allocator, alloc_size, true, bytes_allocated);
+ ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated);
if (ptr == nullptr) {
ThrowOutOfMemoryError(self, alloc_size, false);
}
}
+ *klass = sirt_klass.get();
return ptr;
}
@@ -1200,22 +1090,46 @@ void Heap::GetReferringObjects(mirror::Object* o, int32_t max_count,
void Heap::CollectGarbage(bool clear_soft_references) {
// Even if we waited for a GC we still need to do another GC since weaks allocated during the
// last GC will not have necessarily been cleared.
- CollectGarbageInternal(collector::kGcTypeFull, kGcCauseExplicit, clear_soft_references);
+ CollectGarbageInternal(gc_plan_.back(), kGcCauseExplicit, clear_soft_references);
}
void Heap::ChangeCollector(CollectorType collector_type) {
- switch (collector_type) {
- case kCollectorTypeSS: {
- ChangeAllocator(kAllocatorTypeBumpPointer);
- break;
+ // TODO: Only do this with all mutators suspended to avoid races.
+ if (collector_type != collector_type_) {
+ collector_type_ = collector_type;
+ gc_plan_.clear();
+ switch (collector_type_) {
+ case kCollectorTypeSS: {
+ concurrent_gc_ = false;
+ gc_plan_.push_back(collector::kGcTypeFull);
+ ChangeAllocator(kAllocatorTypeBumpPointer);
+ break;
+ }
+ case kCollectorTypeMS: {
+ concurrent_gc_ = false;
+ gc_plan_.push_back(collector::kGcTypeSticky);
+ gc_plan_.push_back(collector::kGcTypePartial);
+ gc_plan_.push_back(collector::kGcTypeFull);
+ ChangeAllocator(kAllocatorTypeFreeList);
+ break;
+ }
+ case kCollectorTypeCMS: {
+ concurrent_gc_ = true;
+ gc_plan_.push_back(collector::kGcTypeSticky);
+ gc_plan_.push_back(collector::kGcTypePartial);
+ gc_plan_.push_back(collector::kGcTypeFull);
+ ChangeAllocator(kAllocatorTypeFreeList);
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unimplemented";
+ }
}
- case kCollectorTypeMS:
- // Fall-through.
- case kCollectorTypeCMS: {
- ChangeAllocator(kAllocatorTypeFreeList);
- break;
- default:
- LOG(FATAL) << "Unimplemented";
+ if (concurrent_gc_) {
+ concurrent_start_bytes_ =
+ std::max(max_allowed_footprint_, kMinConcurrentRemainingBytes) - kMinConcurrentRemainingBytes;
+ } else {
+ concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
}
}
}
@@ -1234,8 +1148,8 @@ void Heap::PreZygoteFork() {
// Trim the pages at the end of the non moving space.
non_moving_space_->Trim();
non_moving_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
- // Change the allocator to the post zygote one.
- ChangeCollector(collector_type_);
+ // Change the collector to the post zygote one.
+ ChangeCollector(post_zygote_collector_type_);
// TODO: Delete bump_pointer_space_ and temp_pointer_space_?
if (semi_space_collector_ != nullptr) {
// Create a new bump pointer space which we will compact into.
@@ -1410,7 +1324,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus
} else {
LOG(FATAL) << "Invalid current allocator " << current_allocator_;
}
- CHECK(collector != NULL)
+ CHECK(collector != nullptr)
<< "Could not find garbage collector with concurrent=" << concurrent_gc_
<< " and type=" << gc_type;
@@ -1426,7 +1340,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus
// Grow the heap so that we know when to perform the next GC.
GrowForUtilization(gc_type, collector->GetDurationNs());
- if (care_about_pause_times_) {
+ if (CareAboutPauseTimes()) {
const size_t duration = collector->GetDurationNs();
std::vector<uint64_t> pauses = collector->GetPauseTimes();
// GC for alloc pauses the allocating thread, so consider it as a pause.
@@ -1991,7 +1905,7 @@ void Heap::GrowForUtilization(collector::GcType gc_type, uint64_t gc_duration) {
}
if (!ignore_max_footprint_) {
SetIdealFootprint(target_size);
- if (concurrent_gc_ && AllocatorHasConcurrentGC(current_allocator_)) {
+ if (concurrent_gc_) {
// Calculate when to perform the next ConcurrentGC.
// Calculate the estimated GC duration.
double gc_duration_seconds = NsToMs(gc_duration) / 1000.0;
@@ -2077,7 +1991,6 @@ void Heap::EnqueueClearedReferences() {
void Heap::RequestConcurrentGC(Thread* self) {
// Make sure that we can do a concurrent GC.
Runtime* runtime = Runtime::Current();
- DCHECK(concurrent_gc_);
if (runtime == NULL || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self) ||
self->IsHandlingStackOverflow()) {
return;
@@ -2143,10 +2056,9 @@ void Heap::RequestHeapTrim() {
}
last_trim_time_ms_ = ms_time;
- ListenForProcessStateChange();
// Trim only if we do not currently care about pause times.
- if (!care_about_pause_times_) {
+ if (!CareAboutPauseTimes()) {
JNIEnv* env = self->GetJniEnv();
DCHECK(WellKnownClasses::java_lang_Daemons != NULL);
DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL);
@@ -2212,7 +2124,7 @@ void Heap::RegisterNativeAllocation(JNIEnv* env, int bytes) {
// finalizers released native managed allocations.
UpdateMaxNativeFootprint();
} else if (!IsGCRequestPending()) {
- if (concurrent_gc_ && AllocatorHasConcurrentGC(current_allocator_)) {
+ if (concurrent_gc_) {
RequestConcurrentGC(self);
} else {
CollectGarbageInternal(gc_type, kGcCauseForAlloc, false);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 8c5746d..9788064 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -119,6 +119,13 @@ static constexpr HeapVerificationMode kDesiredHeapVerification = kNoHeapVerifica
// If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace
static constexpr bool kUseRosAlloc = true;
+// The process state passed in from the activity manager, used to determine when to do trimming
+// and compaction.
+enum ProcessState {
+ kProcessStateJankPerceptible = 0,
+ kProcessStateJankImperceptible = 1,
+};
+
class Heap {
public:
// If true, measure the total allocation time.
@@ -287,6 +294,9 @@ class Heap {
// waited for.
collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+ // Update the heap's process state to a new value, may cause compaction to occur.
+ void UpdateProcessState(ProcessState process_state);
+
const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const {
return continuous_spaces_;
}
@@ -451,10 +461,7 @@ class Heap {
// Mark the specified allocation stack as live.
void MarkAllocStackAsLive(accounting::ObjectStack* stack)
- EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
- // Gets called when we get notified by ActivityThread that the process state has changed.
- void ListenForProcessStateChange();
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
// DEPRECATED: Should remove in "near" future when support for multiple image spaces is added.
// Assumes there is only one image space.
@@ -475,7 +482,7 @@ class Heap {
// Returns true if we currently care about pause times.
bool CareAboutPauseTimes() const {
- return care_about_pause_times_;
+ return process_state_ == kProcessStateJankPerceptible;
}
// Thread pool.
@@ -510,10 +517,16 @@ class Heap {
ALWAYS_INLINE void CheckConcurrentGC(Thread* self, size_t new_num_bytes_allocated,
mirror::Object* obj);
+ // We don't force this to be inline since it is a slow path.
+ template <bool kInstrumented, typename PreFenceVisitor>
+ mirror::Object* AllocLargeObject(Thread* self, mirror::Class* klass, size_t byte_count,
+ const PreFenceVisitor& pre_fence_visitor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Handles Allocate()'s slow allocation path with GC involved after
// an initial allocation attempt failed.
mirror::Object* AllocateInternalWithGc(Thread* self, AllocatorType allocator, size_t num_bytes,
- size_t* bytes_allocated)
+ size_t* bytes_allocated, mirror::Class** klass)
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -524,15 +537,15 @@ class Heap {
// Try to allocate a number of bytes, this function never does any GCs. Needs to be inlined so
// that the switch statement is constant optimized in the entrypoints.
- template <const bool kInstrumented>
+ template <const bool kInstrumented, const bool kGrow>
ALWAYS_INLINE mirror::Object* TryToAllocate(Thread* self, AllocatorType allocator_type,
- size_t alloc_size, bool grow,
- size_t* bytes_allocated)
+ size_t alloc_size, size_t* bytes_allocated)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ThrowOutOfMemoryError(Thread* self, size_t byte_count, bool large_object_allocation)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow);
+ template <const bool kGrow>
+ bool IsOutOfMemoryOnAllocation(size_t alloc_size);
// Pushes a list of cleared references out to the managed heap.
void SetReferenceReferent(mirror::Object* reference, mirror::Object* referent)
@@ -632,12 +645,14 @@ class Heap {
// A mod-union table remembers all of the references from the it's space to other spaces.
SafeMap<space::Space*, accounting::ModUnionTable*> mod_union_tables_;
- // What kind of concurrency behavior is the runtime after? True for concurrent mark sweep GC,
- // false for stop-the-world mark sweep.
- const bool concurrent_gc_;
+ // What kind of concurrency behavior is the runtime after? Currently true for concurrent mark
+ // sweep GC, false for other GC types.
+ bool concurrent_gc_;
// The current collector type.
CollectorType collector_type_;
+ // Which collector we will switch to after zygote fork.
+ CollectorType post_zygote_collector_type_;
// How many GC threads we may use for paused parts of garbage collection.
const size_t parallel_gc_threads_;
@@ -713,11 +728,8 @@ class Heap {
jobject application_thread_;
jfieldID last_process_state_id_;
- // Process states which care about pause times.
- std::set<int> process_state_cares_about_pause_time_;
-
// Whether or not we currently care about pause times.
- bool care_about_pause_times_;
+ ProcessState process_state_;
// When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that
// it completes ahead of an allocation failing.
diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc
index 6b597ae..60c3b1c 100644
--- a/runtime/gc/space/space_test.cc
+++ b/runtime/gc/space/space_test.cc
@@ -31,10 +31,6 @@ namespace space {
class SpaceTest : public CommonTest {
public:
- void SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size,
- int round, size_t growth_limit);
- void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size);
-
void AddSpace(ContinuousSpace* space) {
// For RosAlloc, revoke the thread local runs before moving onto a
// new alloc space.
@@ -55,6 +51,26 @@ class SpaceTest : public CommonTest {
arr->SetLength(length);
EXPECT_EQ(arr->SizeOf(), size);
}
+
+ static MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
+ size_t capacity, byte* requested_begin) {
+ return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin);
+ }
+ static MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
+ size_t capacity, byte* requested_begin) {
+ return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin);
+ }
+
+ typedef MallocSpace* (*CreateSpaceFn)(const std::string& name, size_t initial_size, size_t growth_limit,
+ size_t capacity, byte* requested_begin);
+ void InitTestBody(CreateSpaceFn create_space);
+ void ZygoteSpaceTestBody(CreateSpaceFn create_space);
+ void AllocAndFreeTestBody(CreateSpaceFn create_space);
+ void AllocAndFreeListTestBody(CreateSpaceFn create_space);
+
+ void SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
+ int round, size_t growth_limit);
+ void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space);
};
static size_t test_rand(size_t* seed) {
@@ -62,128 +78,143 @@ static size_t test_rand(size_t* seed) {
return *seed;
}
-TEST_F(SpaceTest, Init) {
+void SpaceTest::InitTestBody(CreateSpaceFn create_space) {
{
// Init < max == growth
- UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 32 * MB, 32 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 16 * MB, 32 * MB, 32 * MB, NULL));
EXPECT_TRUE(space.get() != NULL);
}
{
// Init == max == growth
- UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 16 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 16 * MB, 16 * MB, 16 * MB, NULL));
EXPECT_TRUE(space.get() != NULL);
}
{
// Init > max == growth
- UniquePtr<Space> space(DlMallocSpace::Create("test", 32 * MB, 16 * MB, 16 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 32 * MB, 16 * MB, 16 * MB, NULL));
EXPECT_TRUE(space.get() == NULL);
}
{
// Growth == init < max
- UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 32 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 16 * MB, 16 * MB, 32 * MB, NULL));
EXPECT_TRUE(space.get() != NULL);
}
{
// Growth < init < max
- UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 8 * MB, 32 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 16 * MB, 8 * MB, 32 * MB, NULL));
EXPECT_TRUE(space.get() == NULL);
}
{
// Init < growth < max
- UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 16 * MB, 32 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 8 * MB, 16 * MB, 32 * MB, NULL));
EXPECT_TRUE(space.get() != NULL);
}
{
// Init < max < growth
- UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 32 * MB, 16 * MB, NULL));
+ UniquePtr<Space> space(create_space("test", 8 * MB, 32 * MB, 16 * MB, NULL));
EXPECT_TRUE(space.get() == NULL);
}
}
+TEST_F(SpaceTest, Init_DlMallocSpace) {
+ InitTestBody(SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, Init_RosAllocSpace) {
+ InitTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
// TODO: This test is not very good, we should improve it.
// The test should do more allocations before the creation of the ZygoteSpace, and then do
// allocations after the ZygoteSpace is created. The test should also do some GCs to ensure that
// the GC works with the ZygoteSpace.
-TEST_F(SpaceTest, ZygoteSpace) {
- size_t dummy = 0;
- MallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL));
- ASSERT_TRUE(space != NULL);
-
- // Make space findable to the heap, will also delete space when runtime is cleaned up
- AddSpace(space);
- Thread* self = Thread::Current();
-
- // Succeeds, fits without adjusting the footprint limit.
- mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy);
- EXPECT_TRUE(ptr1 != NULL);
- InstallClass(ptr1, 1 * MB);
-
- // Fails, requires a higher footprint limit.
- mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy);
- EXPECT_TRUE(ptr2 == NULL);
-
- // Succeeds, adjusts the footprint.
- size_t ptr3_bytes_allocated;
- mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated);
- EXPECT_TRUE(ptr3 != NULL);
- EXPECT_LE(8U * MB, ptr3_bytes_allocated);
- InstallClass(ptr3, 8 * MB);
-
- // Fails, requires a higher footprint limit.
- mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy);
- EXPECT_TRUE(ptr4 == NULL);
-
- // Also fails, requires a higher allowed footprint.
- mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy);
- EXPECT_TRUE(ptr5 == NULL);
-
- // Release some memory.
- size_t free3 = space->AllocationSize(ptr3);
- EXPECT_EQ(free3, ptr3_bytes_allocated);
- EXPECT_EQ(free3, space->Free(self, ptr3));
- EXPECT_LE(8U * MB, free3);
-
- // Succeeds, now that memory has been freed.
- mirror::Object* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy);
- EXPECT_TRUE(ptr6 != NULL);
- InstallClass(ptr6, 9 * MB);
-
- // Final clean up.
- size_t free1 = space->AllocationSize(ptr1);
- space->Free(self, ptr1);
- EXPECT_LE(1U * MB, free1);
-
- // Make sure that the zygote space isn't directly at the start of the space.
- space->Alloc(self, 1U * MB, &dummy);
- space = space->CreateZygoteSpace("alloc space");
-
- // Make space findable to the heap, will also delete space when runtime is cleaned up
- AddSpace(space);
-
- // Succeeds, fits without adjusting the footprint limit.
- ptr1 = space->Alloc(self, 1 * MB, &dummy);
- EXPECT_TRUE(ptr1 != NULL);
- InstallClass(ptr1, 1 * MB);
-
- // Fails, requires a higher footprint limit.
- ptr2 = space->Alloc(self, 8 * MB, &dummy);
- EXPECT_TRUE(ptr2 == NULL);
-
- // Succeeds, adjusts the footprint.
- ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy);
- EXPECT_TRUE(ptr3 != NULL);
- InstallClass(ptr3, 2 * MB);
- space->Free(self, ptr3);
-
- // Final clean up.
- free1 = space->AllocationSize(ptr1);
- space->Free(self, ptr1);
- EXPECT_LE(1U * MB, free1);
+void SpaceTest::ZygoteSpaceTestBody(CreateSpaceFn create_space) {
+ size_t dummy = 0;
+ MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL));
+ ASSERT_TRUE(space != NULL);
+
+ // Make space findable to the heap, will also delete space when runtime is cleaned up
+ AddSpace(space);
+ Thread* self = Thread::Current();
+
+ // Succeeds, fits without adjusting the footprint limit.
+ mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy);
+ EXPECT_TRUE(ptr1 != NULL);
+ InstallClass(ptr1, 1 * MB);
+
+ // Fails, requires a higher footprint limit.
+ mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy);
+ EXPECT_TRUE(ptr2 == NULL);
+
+ // Succeeds, adjusts the footprint.
+ size_t ptr3_bytes_allocated;
+ mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated);
+ EXPECT_TRUE(ptr3 != NULL);
+ EXPECT_LE(8U * MB, ptr3_bytes_allocated);
+ InstallClass(ptr3, 8 * MB);
+
+ // Fails, requires a higher footprint limit.
+ mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy);
+ EXPECT_TRUE(ptr4 == NULL);
+
+ // Also fails, requires a higher allowed footprint.
+ mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy);
+ EXPECT_TRUE(ptr5 == NULL);
+
+ // Release some memory.
+ size_t free3 = space->AllocationSize(ptr3);
+ EXPECT_EQ(free3, ptr3_bytes_allocated);
+ EXPECT_EQ(free3, space->Free(self, ptr3));
+ EXPECT_LE(8U * MB, free3);
+
+ // Succeeds, now that memory has been freed.
+ mirror::Object* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy);
+ EXPECT_TRUE(ptr6 != NULL);
+ InstallClass(ptr6, 9 * MB);
+
+ // Final clean up.
+ size_t free1 = space->AllocationSize(ptr1);
+ space->Free(self, ptr1);
+ EXPECT_LE(1U * MB, free1);
+
+ // Make sure that the zygote space isn't directly at the start of the space.
+ space->Alloc(self, 1U * MB, &dummy);
+ space = space->CreateZygoteSpace("alloc space");
+
+ // Make space findable to the heap, will also delete space when runtime is cleaned up
+ AddSpace(space);
+
+ // Succeeds, fits without adjusting the footprint limit.
+ ptr1 = space->Alloc(self, 1 * MB, &dummy);
+ EXPECT_TRUE(ptr1 != NULL);
+ InstallClass(ptr1, 1 * MB);
+
+ // Fails, requires a higher footprint limit.
+ ptr2 = space->Alloc(self, 8 * MB, &dummy);
+ EXPECT_TRUE(ptr2 == NULL);
+
+ // Succeeds, adjusts the footprint.
+ ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy);
+ EXPECT_TRUE(ptr3 != NULL);
+ InstallClass(ptr3, 2 * MB);
+ space->Free(self, ptr3);
+
+ // Final clean up.
+ free1 = space->AllocationSize(ptr1);
+ space->Free(self, ptr1);
+ EXPECT_LE(1U * MB, free1);
+}
+
+TEST_F(SpaceTest, ZygoteSpace_DlMallocSpace) {
+ ZygoteSpaceTestBody(SpaceTest::CreateDlMallocSpace);
}
-TEST_F(SpaceTest, AllocAndFree) {
+TEST_F(SpaceTest, ZygoteSpace_RosAllocSpace) {
+ ZygoteSpaceTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
+void SpaceTest::AllocAndFreeTestBody(CreateSpaceFn create_space) {
size_t dummy = 0;
- DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL));
+ MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL));
ASSERT_TRUE(space != NULL);
Thread* self = Thread::Current();
@@ -231,6 +262,13 @@ TEST_F(SpaceTest, AllocAndFree) {
EXPECT_LE(1U * MB, free1);
}
+TEST_F(SpaceTest, AllocAndFree_DlMallocSpace) {
+ AllocAndFreeTestBody(SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, AllocAndFree_RosAllocSpace) {
+ AllocAndFreeTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
TEST_F(SpaceTest, LargeObjectTest) {
size_t rand_seed = 0;
for (size_t i = 0; i < 2; ++i) {
@@ -292,8 +330,8 @@ TEST_F(SpaceTest, LargeObjectTest) {
}
}
-TEST_F(SpaceTest, AllocAndFreeList) {
- DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL));
+void SpaceTest::AllocAndFreeListTestBody(CreateSpaceFn create_space) {
+ MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL));
ASSERT_TRUE(space != NULL);
// Make space findable to the heap, will also delete space when runtime is cleaned up
@@ -332,7 +370,14 @@ TEST_F(SpaceTest, AllocAndFreeList) {
}
}
-void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size,
+TEST_F(SpaceTest, AllocAndFreeList_DlMallocSpace) {
+ AllocAndFreeListTestBody(SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, AllocAndFreeList_RosAllocSpace) {
+ AllocAndFreeListTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
+void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
int round, size_t growth_limit) {
if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) {
@@ -493,11 +538,11 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr
EXPECT_LE(space->Size(), growth_limit);
}
-void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
+void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space) {
size_t initial_size = 4 * MB;
size_t growth_limit = 8 * MB;
size_t capacity = 16 * MB;
- DlMallocSpace* space(DlMallocSpace::Create("test", initial_size, growth_limit, capacity, NULL));
+ MallocSpace* space(create_space("test", initial_size, growth_limit, capacity, NULL));
ASSERT_TRUE(space != NULL);
// Basic sanity
@@ -518,16 +563,25 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
}
#define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \
- TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \
- SizeFootPrintGrowthLimitAndTrimDriver(size); \
+ TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name##_DlMallocSpace) { \
+ SizeFootPrintGrowthLimitAndTrimDriver(size, SpaceTest::CreateDlMallocSpace); \
+ } \
+ TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name##_DlMallocSpace) { \
+ SizeFootPrintGrowthLimitAndTrimDriver(-size, SpaceTest::CreateDlMallocSpace); \
} \
- TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
- SizeFootPrintGrowthLimitAndTrimDriver(-size); \
+ TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name##_RosAllocSpace) { \
+ SizeFootPrintGrowthLimitAndTrimDriver(size, SpaceTest::CreateRosAllocSpace); \
+ } \
+ TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name##_RosAllocSpace) { \
+ SizeFootPrintGrowthLimitAndTrimDriver(-size, SpaceTest::CreateRosAllocSpace); \
}
// Each size test is its own test so that we get a fresh heap each time
-TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B) {
- SizeFootPrintGrowthLimitAndTrimDriver(12);
+TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B_DlMallocSpace) {
+ SizeFootPrintGrowthLimitAndTrimDriver(12, SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B_RosAllocSpace) {
+ SizeFootPrintGrowthLimitAndTrimDriver(12, SpaceTest::CreateRosAllocSpace);
}
TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16)
TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24)
diff --git a/runtime/globals.h b/runtime/globals.h
index c2fe67e..a0d7e48 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -82,7 +82,7 @@ static constexpr bool kUsePortableCompiler = false;
// Garbage collector constants.
static constexpr bool kMovingCollector = true && !kUsePortableCompiler;
// True if we allow moving classes.
-static constexpr bool kMovingClasses = false;
+static constexpr bool kMovingClasses = true;
// True if we allow moving fields.
static constexpr bool kMovingFields = false;
// True if we allow moving methods.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 9938478..02c9012 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -343,12 +343,13 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive
++cur_reg;
} else if (UNLIKELY(!method->GetDeclaringClass()->IsInitializing())) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (UNLIKELY(!class_linker->EnsureInitialized(method->GetDeclaringClass(), true, true))) {
+ SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
+ if (UNLIKELY(!class_linker->EnsureInitialized(sirt_c, true, true))) {
CHECK(self->IsExceptionPending());
self->PopShadowFrame();
return;
}
- CHECK(method->GetDeclaringClass()->IsInitializing());
+ CHECK(sirt_c->IsInitializing());
}
const char* shorty = mh.GetShorty();
for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) {
@@ -428,7 +429,7 @@ extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh
ArtMethod* method = shadow_frame->GetMethod();
// Ensure static methods are initialized.
if (method->IsStatic()) {
- Class* declaringClass = method->GetDeclaringClass();
+ SirtRef<Class> declaringClass(self, method->GetDeclaringClass());
if (UNLIKELY(!declaringClass->IsInitializing())) {
if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass, true,
true))) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index c9756ac..5b9e55f 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -188,7 +188,7 @@ bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
} else {
self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
"Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but \'int\'",
+ "Found type %s; filled-new-array not implemented for anything but 'int'",
PrettyDescriptor(componentClass).c_str());
}
return false;
@@ -231,7 +231,10 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
std::string name(PrettyMethod(shadow_frame->GetMethod()));
- if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
+ if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)"
+ || name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
+ // TODO Class#forName should actually call Class::EnsureInitialized always. Support for the
+ // other variants that take more arguments should also be added.
std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
SirtRef<ClassLoader> class_loader(self, nullptr); // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
@@ -240,6 +243,13 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
<< PrettyDescriptor(descriptor);
result->SetL(found);
+ } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") {
+ SirtRef<ClassLoader> class_loader(self, down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset)));
+ std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
+
+ Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(),
+ class_loader);
+ result->SetL(found);
} else if (name == "java.lang.Object java.lang.Class.newInstance()") {
Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0bc834c..3b8d50b 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -334,13 +334,14 @@ static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instructio
// java.lang.String class is initialized.
static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CHECK(!kMovingMethods);
Class* java_lang_string_class = String::GetJavaLangString();
if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
- true, true))) {
+ SirtRef<mirror::Class> sirt_class(self, java_lang_string_class);
+ if (UNLIKELY(!class_linker->EnsureInitialized(sirt_class, true, true))) {
DCHECK(self->IsExceptionPending());
- return NULL;
+ return nullptr;
}
}
return mh.ResolveString(string_idx);
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index b2371e8..369eddd 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -118,6 +118,9 @@ mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id) {
}
jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) {
+ if (id == 0) {
+ return NULL;
+ }
Thread* self = Thread::Current();
MutexLock mu(self, lock_);
id_iterator it = id_to_entry_.find(id);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 466edeb..6690519 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -225,13 +225,24 @@ static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, Class* c,
kind, ClassHelper(c).GetDescriptor(), name, sig);
}
+static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (LIKELY(klass->IsInitialized())) {
+ return klass;
+ }
+ SirtRef<mirror::Class> sirt_klass(self, klass);
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
+ return nullptr;
+ }
+ return sirt_klass.get();
+}
+
static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
const char* name, const char* sig, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Class* c = soa.Decode<Class*>(jni_class);
- DCHECK(c != nullptr);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
+ Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
+ if (c == nullptr) {
+ return nullptr;
}
ArtMethod* method = NULL;
@@ -284,16 +295,16 @@ static ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name,
const char* sig, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Class* c = soa.Decode<Class*>(jni_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
+ Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
+ if (c == nullptr) {
+ return nullptr;
}
ArtField* field = NULL;
Class* field_type;
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (sig[1] != '\0') {
- SirtRef<mirror::ClassLoader> class_loader(soa.Self(), GetClassLoader(soa));
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader());
field_type = class_linker->FindClass(sig, class_loader);
} else {
field_type = class_linker->FindPrimitiveClass(*sig);
@@ -910,9 +921,9 @@ class JNI {
static jobject AllocObject(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(AllocObject, java_class);
ScopedObjectAccess soa(env);
- Class* c = soa.Decode<Class*>(java_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
+ Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+ if (c == nullptr) {
+ return nullptr;
}
return soa.AddLocalReference<jobject>(c->AllocObject(soa.Self()));
}
@@ -931,20 +942,20 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(NewObjectV, java_class);
CHECK_NON_NULL_ARGUMENT(NewObjectV, mid);
ScopedObjectAccess soa(env);
- Class* c = soa.Decode<Class*>(java_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
+ Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+ if (c == nullptr) {
+ return nullptr;
}
Object* result = c->AllocObject(soa.Self());
- if (result == NULL) {
- return NULL;
+ if (result == nullptr) {
+ return nullptr;
}
jobject local_result = soa.AddLocalReference<jobject>(result);
CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
if (!soa.Self()->IsExceptionPending()) {
return local_result;
} else {
- return NULL;
+ return nullptr;
}
}
@@ -952,9 +963,9 @@ class JNI {
CHECK_NON_NULL_ARGUMENT(NewObjectA, java_class);
CHECK_NON_NULL_ARGUMENT(NewObjectA, mid);
ScopedObjectAccess soa(env);
- Class* c = soa.Decode<Class*>(java_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
+ Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+ if (c == nullptr) {
+ return nullptr;
}
Object* result = c->AllocObject(soa.Self());
if (result == NULL) {
@@ -3303,8 +3314,9 @@ void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) {
// If this is a static method, it could be called before the class
// has been initialized.
if (m->IsStatic()) {
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
- return NULL;
+ c = EnsureInitialized(Thread::Current(), c);
+ if (c == nullptr) {
+ return nullptr;
}
} else {
CHECK(c->IsInitializing()) << c->GetStatus() << " " << PrettyMethod(m);
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 6041f8c..7a7d38d 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_LEB128_H_
#include "globals.h"
+#include "utils.h"
namespace art {
@@ -95,12 +96,20 @@ static inline int32_t DecodeSignedLeb128(const uint8_t** data) {
// Returns the number of bytes needed to encode the value in unsigned LEB128.
static inline uint32_t UnsignedLeb128Size(uint32_t data) {
- uint32_t count = 0;
- do {
- data >>= 7;
- count++;
- } while (data != 0);
- return count;
+ // bits_to_encode = (data != 0) ? 32 - CLZ(x) : 1 // 32 - CLZ(data | 1)
+ // bytes = ceil(bits_to_encode / 7.0); // (6 + bits_to_encode) / 7
+ uint32_t x = 6 + 32 - CLZ(data | 1);
+ // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7).
+ // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85.
+ return (x * 37) >> 8;
+}
+
+// Returns the number of bytes needed to encode the value in unsigned LEB128.
+static inline uint32_t SignedLeb128Size(int32_t data) {
+ // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign.
+ data = data ^ (data >> 31);
+ uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1);
+ return (x * 37) >> 8;
}
} // namespace art
diff --git a/runtime/mapping_table.h b/runtime/mapping_table.h
index c468c1e..a82bc1c 100644
--- a/runtime/mapping_table.h
+++ b/runtime/mapping_table.h
@@ -72,7 +72,8 @@ class MappingTable {
if (end_ > 0) {
encoded_table_ptr_ = table_->FirstDexToPcPtr();
native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
- dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+ // First delta is always positive.
+ dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
}
} else { // An iterator wanted from the end.
DCHECK_EQ(table_->DexToPcSize(), element);
@@ -87,8 +88,9 @@ class MappingTable {
void operator++() {
++element_;
if (element_ != end_) { // Avoid reading beyond the end of the table.
- native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
- dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+ native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
+ // For negative delta, unsigned overflow after static_cast does exactly what we need.
+ dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
}
}
bool operator==(const DexToPcIterator& rhs) const {
@@ -147,7 +149,8 @@ class MappingTable {
if (end_ > 0) {
encoded_table_ptr_ = table_->FirstPcToDexPtr();
native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
- dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+ // First delta is always positive.
+ dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
}
} else { // An iterator wanted from the end.
DCHECK_EQ(table_->PcToDexSize(), element);
@@ -162,8 +165,9 @@ class MappingTable {
void operator++() {
++element_;
if (element_ != end_) { // Avoid reading beyond the end of the table.
- native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
- dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+ native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
+ // For negative delta, unsigned overflow after static_cast does exactly what we need.
+ dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
}
}
bool operator==(const PcToDexIterator& rhs) const {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index a754b69..cf4b48c 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -108,6 +108,13 @@ inline Array* Array::Alloc(Thread* self, Class* array_class, int32_t component_c
Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
+template<class T>
+inline void PrimitiveArray<T>::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (array_class_ != nullptr) {
+ array_class_ = down_cast<Class*>(visitor(array_class_, arg));
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index a332f97..5265946 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -149,6 +149,9 @@ class MANAGED PrimitiveArray : public Array {
array_class_ = NULL;
}
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
static Class* array_class_;
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index a8bbe4b..c3a4efb 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -52,5 +52,12 @@ void ArtField::SetOffset(MemberOffset num_bytes) {
SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false);
}
+void ArtField::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (java_lang_reflect_ArtField_ != nullptr) {
+ java_lang_reflect_ArtField_ = down_cast<mirror::Class*>(
+ visitor(java_lang_reflect_ArtField_, arg));
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index ae34cb1..62bcf06 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -130,6 +130,8 @@ class MANAGED ArtField : public Object {
static void SetClass(Class* java_lang_reflect_ArtField);
static void ResetClass();
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsVolatile() const {
return (GetAccessFlags() & kAccVolatile) != 0;
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index f5c0e9f..a4f6b3b 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -40,6 +40,13 @@ extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*,
// TODO: get global references for these
Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL;
+void ArtMethod::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (java_lang_reflect_ArtMethod_ != nullptr) {
+ java_lang_reflect_ArtMethod_ = down_cast<mirror::Class*>(
+ visitor(java_lang_reflect_ArtMethod_, arg));
+ }
+}
+
InvokeType ArtMethod::GetInvokeType() const {
// TODO: kSuper?
if (GetDeclaringClass()->IsInterface()) {
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f396fbe..d5524ec 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -23,6 +23,7 @@
#include "locks.h"
#include "modifiers.h"
#include "object.h"
+#include "root_visitor.h"
namespace art {
@@ -381,6 +382,9 @@ class MANAGED ArtMethod : public Object {
static void ResetClass();
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
protected:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
// The class we are a part of
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index cdc5ab2..2746e1e 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -50,6 +50,12 @@ void Class::ResetClass() {
java_lang_Class_ = NULL;
}
+void Class::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (java_lang_Class_ != nullptr) {
+ java_lang_Class_ = down_cast<Class*>(visitor(java_lang_Class_, arg));
+ }
+}
+
void Class::SetStatus(Status new_status, Thread* self) {
Status old_status = GetStatus();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 5f64bb4..50ede66 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -787,6 +787,8 @@ class MANAGED Class : public StaticStorageBase {
// Can't call this SetClass or else gets called instead of Object::SetClass in places.
static void SetClassClass(Class* java_lang_Class);
static void ResetClass();
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// When class is verified, set the kAccPreverified flag on each method.
void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 0fb2039..fe89b7e 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -225,6 +225,11 @@ class MANAGED Object {
void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile);
+ template<typename T>
+ void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) {
+ SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid);
+ }
+
protected:
// Accessors for non-Java type fields
template<class T>
@@ -232,11 +237,6 @@ class MANAGED Object {
return reinterpret_cast<T>(GetField32(field_offset, is_volatile));
}
- template<typename T>
- void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) {
- SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid);
- }
-
private:
static void VerifyObject(const Object* obj) ALWAYS_INLINE;
// Verify the type correctness of stores to fields.
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 8272ff8..3637181 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -221,8 +221,8 @@ TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
java_lang_dex_file_->GetIndexForStringId(*string_id));
ASSERT_TRUE(type_id != NULL);
uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
- Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current(), false,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ Object* array = CheckAndAllocArrayFromCodeInstrumented(type_idx, sort, 3, Thread::Current(), false,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
EXPECT_TRUE(array->IsArrayInstance());
EXPECT_EQ(3, array->AsArray()->GetLength());
EXPECT_TRUE(array->GetClass()->IsArrayClass());
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index 32a50fe..a7ebe07 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -58,5 +58,12 @@ StackTraceElement* StackTraceElement::Alloc(Thread* self,
return trace;
}
+void StackTraceElement::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (java_lang_StackTraceElement_ != nullptr) {
+ java_lang_StackTraceElement_ = down_cast<Class*>(visitor(java_lang_StackTraceElement_, arg));
+ }
+}
+
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 2af5128..d1be4dc 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -57,8 +57,9 @@ class MANAGED StackTraceElement : public Object {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void SetClass(Class* java_lang_StackTraceElement);
-
static void ResetClass();
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index b372fe7..d6e509d 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -122,7 +122,7 @@ String* String::AllocFromUtf16(Thread* self,
const uint16_t* utf16_data_in,
int32_t hash_code) {
CHECK(utf16_data_in != NULL || utf16_length == 0);
- String* string = Alloc(self, GetJavaLangString(), utf16_length);
+ String* string = Alloc(self, utf16_length);
if (UNLIKELY(string == nullptr)) {
return nullptr;
}
@@ -152,7 +152,7 @@ String* String::AllocFromModifiedUtf8(Thread* self, const char* utf) {
String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length,
const char* utf8_data_in) {
- String* string = Alloc(self, GetJavaLangString(), utf16_length);
+ String* string = Alloc(self, utf16_length);
if (UNLIKELY(string == nullptr)) {
return nullptr;
}
@@ -163,21 +163,20 @@ String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length,
return string;
}
-String* String::Alloc(Thread* self, Class* java_lang_String, int32_t utf16_length) {
- CharArray* array = CharArray::Alloc(self, utf16_length);
- if (UNLIKELY(array == nullptr)) {
+String* String::Alloc(Thread* self, int32_t utf16_length) {
+ SirtRef<CharArray> array(self, CharArray::Alloc(self, utf16_length));
+ if (UNLIKELY(array.get() == nullptr)) {
return nullptr;
}
- return Alloc(self, java_lang_String, array);
+ return Alloc(self, array);
}
-String* String::Alloc(Thread* self, Class* java_lang_String, CharArray* array) {
+String* String::Alloc(Thread* self, const SirtRef<CharArray>& array) {
// Hold reference in case AllocObject causes GC.
- SirtRef<CharArray> array_ref(self, array);
- String* string = down_cast<String*>(java_lang_String->AllocObject(self));
+ String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self));
if (LIKELY(string != nullptr)) {
- string->SetArray(array_ref.get());
- string->SetCount(array_ref->GetLength());
+ string->SetArray(array.get());
+ string->SetCount(array->GetLength());
}
return string;
}
@@ -287,5 +286,11 @@ int32_t String::CompareTo(String* rhs) const {
return countDiff;
}
+void String::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (java_lang_String_ != nullptr) {
+ java_lang_String_ = down_cast<Class*>(visitor(java_lang_String_, arg));
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 7520c4d..4bbcb9c 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -19,6 +19,7 @@
#include "class.h"
#include "gtest/gtest.h"
+#include "root_visitor.h"
namespace art {
@@ -77,12 +78,6 @@ class MANAGED String : public Object {
const char* utf8_data_in)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static String* Alloc(Thread* self, Class* java_lang_String, int32_t utf16_length)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
- static String* Alloc(Thread* self, Class* java_lang_String, CharArray* array)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
bool Equals(const char* modified_utf8) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -114,6 +109,8 @@ class MANAGED String : public Object {
static void SetClass(Class* java_lang_String);
static void ResetClass();
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
void SetHashCode(int32_t new_hash_code) {
@@ -132,6 +129,12 @@ class MANAGED String : public Object {
SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
}
+ static String* Alloc(Thread* self, int32_t utf16_length)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static String* Alloc(Thread* self, const SirtRef<CharArray>& array)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 961f6de..b55db72 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -93,5 +93,11 @@ void Throwable::ResetClass() {
java_lang_Throwable_ = NULL;
}
+void Throwable::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (java_lang_Throwable_ != nullptr) {
+ java_lang_Throwable_ = down_cast<Class*>(visitor(java_lang_Throwable_, arg));
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 27f6e12..5a90599 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_MIRROR_THROWABLE_H_
#include "object.h"
+#include "root_visitor.h"
#include "string.h"
namespace art {
@@ -50,6 +51,8 @@ class MANAGED Throwable : public Object {
static void SetClass(Class* java_lang_Throwable);
static void ResetClass();
+ static void VisitRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
Object* GetStackState() const {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index af93a56..ef9a9ce 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -633,8 +633,7 @@ void Monitor::InflateThinLocked(Thread* self, SirtRef<mirror::Object>& obj, Lock
ScopedThreadStateChange tsc(self, kBlocked);
if (lock_word == obj->GetLockWord()) { // If lock word hasn't changed.
bool timed_out;
- Thread* owner = thread_list->SuspendThreadByThreadId(lock_word.ThinLockOwner(), false,
- &timed_out);
+ Thread* owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
if (owner != nullptr) {
// We succeeded in suspending the thread, check the lock's status didn't change.
lock_word = obj->GetLockWord();
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index c9e0e83..600045f 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -95,20 +95,27 @@ static jint DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceNam
}
uint32_t dex_location_checksum;
+ uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
std::string error_msg;
- if (!DexFile::GetChecksum(sourceName.c_str(), &dex_location_checksum, &error_msg)) {
- ScopedObjectAccess soa(env);
- DCHECK(!error_msg.empty());
- ThrowIOException("%s", error_msg.c_str());
- return 0;
+ if (!DexFile::GetChecksum(sourceName.c_str(), dex_location_checksum_pointer, &error_msg)) {
+ dex_location_checksum_pointer = NULL;
}
ClassLinker* linker = Runtime::Current()->GetClassLinker();
const DexFile* dex_file;
if (outputName.c_str() == nullptr) {
+ // FindOrCreateOatFileForDexLocation can tolerate a missing dex_location_checksum
+ error_msg.clear();
dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(),
- dex_location_checksum, &error_msg);
+ dex_location_checksum_pointer, &error_msg);
} else {
+ // FindOrCreateOatFileForDexLocation requires the dex_location_checksum
+ if (dex_location_checksum_pointer == NULL) {
+ ScopedObjectAccess soa(env);
+ DCHECK(!error_msg.empty());
+ ThrowIOException("%s", error_msg.c_str());
+ return 0;
+ }
dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum,
outputName.c_str(), &error_msg);
}
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index fd3d91e..726a8f1 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -166,6 +166,10 @@ static void VMRuntime_registerNativeFree(JNIEnv* env, jobject, jint bytes) {
Runtime::Current()->GetHeap()->RegisterNativeFree(env, bytes);
}
+static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) {
+ Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
+}
+
static void VMRuntime_trimHeap(JNIEnv*, jobject) {
Runtime::Current()->GetHeap()->Trim();
}
@@ -496,6 +500,7 @@ static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"),
+ NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"),
NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 3389107..3e3f608 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -46,8 +46,8 @@ static mirror::Class* DecodeClass(const ScopedFastNativeObjectAccess& soa, jobje
static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
ScopedObjectAccess soa(env);
ScopedUtfChars name(env, javaName);
- if (name.c_str() == NULL) {
- return NULL;
+ if (name.c_str() == nullptr) {
+ return nullptr;
}
// We need to validate and convert the name (from x.y.z to x/y/z). This
@@ -57,27 +57,27 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ClassNotFoundException;",
"Invalid name: %s", name.c_str());
- return NULL;
+ return nullptr;
}
std::string descriptor(DotToDescriptor(name.c_str()));
SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
soa.Decode<mirror::ClassLoader*>(javaLoader));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- mirror::Class* c = class_linker->FindClass(descriptor.c_str(), class_loader);
- if (c == NULL) {
+ SirtRef<mirror::Class> c(soa.Self(), class_linker->FindClass(descriptor.c_str(), class_loader));
+ if (c.get() == nullptr) {
ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
env->ExceptionClear();
jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
WellKnownClasses::java_lang_ClassNotFoundException_init,
javaName, cause.get()));
env->Throw(cnfe);
- return NULL;
+ return nullptr;
}
if (initialize) {
class_linker->EnsureInitialized(c, true, true);
}
- return soa.AddLocalReference<jclass>(c);
+ return soa.AddLocalReference<jclass>(c.get());
}
static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index af1b548..314cdb1 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -78,7 +78,7 @@ static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstri
LOG(WARNING) << "Failed to open zip archive '" << location << "': " << error_msg;
return NULL;
}
- UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str()));
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str(), &error_msg));
if (zip_entry.get() == NULL) {
return NULL;
}
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 04dfcb5..5811992 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -41,24 +41,24 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA
javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
mirror::ArtMethod* m = soa.Decode<mirror::Object*>(art_method)->AsArtMethod();
- mirror::Class* c = m->GetDeclaringClass();
+ SirtRef<mirror::Class> c(soa.Self(), m->GetDeclaringClass());
if (UNLIKELY(c->IsAbstract())) {
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/InstantiationException;",
"Can't instantiate %s %s",
c->IsInterface() ? "interface" : "abstract class",
- PrettyDescriptor(c).c_str());
- return NULL;
+ PrettyDescriptor(c.get()).c_str());
+ return nullptr;
}
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
DCHECK(soa.Self()->IsExceptionPending());
- return NULL;
+ return nullptr;
}
mirror::Object* receiver = c->AllocNonMovableObject(soa.Self());
- if (receiver == NULL) {
- return NULL;
+ if (receiver == nullptr) {
+ return nullptr;
}
jobject javaReceiver = soa.AddLocalReference<jobject>(receiver);
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 4d69a68..553aeb8 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -31,10 +31,13 @@ static bool GetFieldValue(const ScopedFastNativeObjectAccess& soa, mirror::Objec
mirror::ArtField* f, JValue& value, bool allow_references)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_EQ(value.GetJ(), 0LL);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(),
- true, true)) {
+ CHECK(!kMovingFields);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
+ SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
return false;
}
+ o = sirt_obj.get();
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
case Primitive::kPrimBoolean:
value.SetZ(f->GetBoolean(o));
@@ -168,13 +171,16 @@ static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) {
return GetPrimitiveField(env, javaField, javaObj, 'S').GetS();
}
-static void SetFieldValue(mirror::Object* o, mirror::ArtField* f, const JValue& new_value,
- bool allow_references)
+static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o,
+ mirror::ArtField* f, const JValue& new_value, bool allow_references)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(),
- true, true)) {
+ CHECK(!kMovingFields);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
+ SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
return;
}
+ o = sirt_obj.get();
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
case Primitive::kPrimBoolean:
f->SetBoolean(o, new_value.GetZ());
@@ -237,7 +243,7 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j
return;
}
- SetFieldValue(o, f, unboxed_value, true);
+ SetFieldValue(soa, o, f, unboxed_value, true);
}
static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor,
@@ -264,7 +270,7 @@ static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, c
}
// Write the value.
- SetFieldValue(o, f, wide_value, false);
+ SetFieldValue(soa, o, f, wide_value, false);
}
static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) {
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 50069b2..52e74ab 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', '1', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '1', '2', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index e37510c..cc996bc 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -34,34 +34,36 @@
namespace art {
+template <typename T>
class ObjectLock {
public:
- explicit ObjectLock(Thread* self, mirror::Object* object)
+ explicit ObjectLock(Thread* self, const SirtRef<T>* object)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: self_(self), obj_(object) {
- CHECK(object != NULL);
- obj_->MonitorEnter(self_);
+ CHECK(object != nullptr);
+ CHECK(object->get() != nullptr);
+ obj_->get()->MonitorEnter(self_);
}
~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- obj_->MonitorExit(self_);
+ obj_->get()->MonitorExit(self_);
}
void WaitIgnoringInterrupts() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Monitor::Wait(self_, obj_, 0, 0, false, kWaiting);
+ Monitor::Wait(self_, obj_->get(), 0, 0, false, kWaiting);
}
void Notify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- obj_->Notify(self_);
+ obj_->get()->Notify(self_);
}
void NotifyAll() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- obj_->NotifyAll(self_);
+ obj_->get()->NotifyAll(self_);
}
private:
Thread* const self_;
- mirror::Object* obj_;
+ const SirtRef<T>* obj_;
DISALLOW_COPY_AND_ASSIGN(ObjectLock);
};
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 80e16aa..ac8f5ef 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -39,8 +39,12 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject
mirror::ArtMethod* m = soa.DecodeMethod(mid);
mirror::Class* declaring_class = m->GetDeclaringClass();
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true, true)) {
- return NULL;
+ if (UNLIKELY(!declaring_class->IsInitialized())) {
+ SirtRef<mirror::Class> sirt_c(soa.Self(), declaring_class);
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
+ return nullptr;
+ }
+ declaring_class = sirt_c.get();
}
mirror::Object* receiver = NULL;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6bd2560..e1b4d7e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -47,6 +47,7 @@
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
+#include "mirror/stack_trace_element.h"
#include "mirror/throwable.h"
#include "monitor.h"
#include "oat_file.h"
@@ -86,6 +87,7 @@ Runtime::Runtime()
resolution_method_(NULL),
imt_conflict_method_(NULL),
default_imt_(NULL),
+ method_verifiers_lock_("Method verifiers lock"),
threads_being_born_(0),
shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)),
shutting_down_(false),
@@ -131,11 +133,6 @@ Runtime::~Runtime() {
heap_->WaitForGcToComplete(self);
heap_->DeleteThreadPool();
- // For RosAlloc, revoke thread local runs. Note that in tests
- // (common_test.h) we repeat allocating and deleting Runtime
- // objects.
- heap_->RevokeAllThreadLocalBuffers();
-
// Make sure our internal threads are dead before we start tearing down things they're using.
Dbg::StopJdwp();
delete signal_catcher_;
@@ -704,35 +701,38 @@ jobject CreateSystemClassLoader() {
}
ScopedObjectAccess soa(Thread::Current());
+ ClassLinker* cl = Runtime::Current()->GetClassLinker();
- mirror::Class* class_loader_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader);
- CHECK(Runtime::Current()->GetClassLinker()->EnsureInitialized(class_loader_class, true, true));
+ SirtRef<mirror::Class> class_loader_class(
+ soa.Self(), soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader));
+ CHECK(cl->EnsureInitialized(class_loader_class, true, true));
mirror::ArtMethod* getSystemClassLoader =
class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
CHECK(getSystemClassLoader != NULL);
JValue result;
- ArgArray arg_array(NULL, 0);
+ ArgArray arg_array(nullptr, 0);
InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, 'L');
- mirror::ClassLoader* class_loader = down_cast<mirror::ClassLoader*>(result.GetL());
- CHECK(class_loader != NULL);
-
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+ down_cast<mirror::ClassLoader*>(result.GetL()));
+ CHECK(class_loader.get() != nullptr);
JNIEnv* env = soa.Self()->GetJniEnv();
- ScopedLocalRef<jobject> system_class_loader(env, soa.AddLocalReference<jobject>(class_loader));
- CHECK(system_class_loader.get() != NULL);
+ ScopedLocalRef<jobject> system_class_loader(env,
+ soa.AddLocalReference<jobject>(class_loader.get()));
+ CHECK(system_class_loader.get() != nullptr);
- soa.Self()->SetClassLoaderOverride(class_loader);
+ soa.Self()->SetClassLoaderOverride(class_loader.get());
- mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
- CHECK(Runtime::Current()->GetClassLinker()->EnsureInitialized(thread_class, true, true));
+ SirtRef<mirror::Class> thread_class(soa.Self(),
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread));
+ CHECK(cl->EnsureInitialized(thread_class, true, true));
- mirror::ArtField* contextClassLoader = thread_class->FindDeclaredInstanceField("contextClassLoader",
- "Ljava/lang/ClassLoader;");
+ mirror::ArtField* contextClassLoader =
+ thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;");
CHECK(contextClassLoader != NULL);
- contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader);
+ contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader.get());
return env->NewGlobalRef(system_class_loader.get());
}
@@ -1193,9 +1193,25 @@ void Runtime::VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_di
}
void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) {
+ // Visit the classes held as static in mirror classes.
+ mirror::ArtField::VisitRoots(visitor, arg);
+ mirror::ArtMethod::VisitRoots(visitor, arg);
+ mirror::Class::VisitRoots(visitor, arg);
+ mirror::StackTraceElement::VisitRoots(visitor, arg);
+ mirror::String::VisitRoots(visitor, arg);
+ mirror::Throwable::VisitRoots(visitor, arg);
+ // Visit all the primitive array types classes.
+ mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor, arg); // BooleanArray
+ mirror::PrimitiveArray<int8_t>::VisitRoots(visitor, arg); // ByteArray
+ mirror::PrimitiveArray<uint16_t>::VisitRoots(visitor, arg); // CharArray
+ mirror::PrimitiveArray<double>::VisitRoots(visitor, arg); // DoubleArray
+ mirror::PrimitiveArray<float>::VisitRoots(visitor, arg); // FloatArray
+ mirror::PrimitiveArray<int32_t>::VisitRoots(visitor, arg); // IntArray
+ mirror::PrimitiveArray<int64_t>::VisitRoots(visitor, arg); // LongArray
+ mirror::PrimitiveArray<int16_t>::VisitRoots(visitor, arg); // ShortArray
java_vm_->VisitRoots(visitor, arg);
if (pre_allocated_OutOfMemoryError_ != nullptr) {
- pre_allocated_OutOfMemoryError_ = reinterpret_cast<mirror::Throwable*>(
+ pre_allocated_OutOfMemoryError_ = down_cast<mirror::Throwable*>(
visitor(pre_allocated_OutOfMemoryError_, arg));
DCHECK(pre_allocated_OutOfMemoryError_ != nullptr);
}
@@ -1214,6 +1230,12 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) {
visitor(callee_save_methods_[i], arg));
}
}
+ {
+ MutexLock mu(Thread::Current(), method_verifiers_lock_);
+ for (verifier::MethodVerifier* verifier : method_verifiers_) {
+ verifier->VisitRoots(visitor, arg);
+ }
+ }
}
void Runtime::VisitNonConcurrentRoots(RootVisitor* visitor, void* arg) {
@@ -1360,4 +1382,18 @@ void Runtime::SetCompileTimeClassPath(jobject class_loader, std::vector<const De
compile_time_class_paths_.Put(class_loader, class_path);
}
+void Runtime::AddMethodVerifier(verifier::MethodVerifier* verifier) {
+ DCHECK(verifier != nullptr);
+ MutexLock mu(Thread::Current(), method_verifiers_lock_);
+ method_verifiers_.insert(verifier);
+}
+
+void Runtime::RemoveMethodVerifier(verifier::MethodVerifier* verifier) {
+ DCHECK(verifier != nullptr);
+ MutexLock mu(Thread::Current(), method_verifiers_lock_);
+ auto it = method_verifiers_.find(verifier);
+ CHECK(it != method_verifiers_.end());
+ method_verifiers_.erase(it);
+}
+
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index e6951d9..01a605a 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -52,6 +52,9 @@ namespace mirror {
class String;
class Throwable;
} // namespace mirror
+namespace verifier {
+class MethodVerifier;
+}
class ClassLinker;
class DexFile;
class InternTable;
@@ -320,14 +323,16 @@ class Runtime {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Visit all of the roots we can do safely do concurrently.
- void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty);
+ void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Visit all of the non thread roots, we can do this with mutators unpaused.
- void VisitNonThreadRoots(RootVisitor* visitor, void* arg);
+ void VisitNonThreadRoots(RootVisitor* visitor, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Visit all other roots which must be done with mutators suspended.
void VisitNonConcurrentRoots(RootVisitor* visitor, void* arg)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Sweep system weaks, the system weak is deleted if the visitor return nullptr. Otherwise, the
// system weak is updated to be the visitor's returned value.
@@ -438,6 +443,9 @@ class Runtime {
return use_compile_time_class_path_;
}
+ void AddMethodVerifier(verifier::MethodVerifier* verifier);
+ void RemoveMethodVerifier(verifier::MethodVerifier* verifier);
+
const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader);
void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path);
@@ -520,6 +528,10 @@ class Runtime {
mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
+ // Method verifier set, used so that we can update their GC roots.
+ Mutex method_verifiers_lock_;
+ std::set<verifier::MethodVerifier*> method_verifiers_;
+
// A non-zero value indicates that a thread has been created but not yet initialized. Guarded by
// the shutdown lock so that threads aren't born while we're shutting down.
size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_);
diff --git a/runtime/stack.cc b/runtime/stack.cc
index a505383..4e3fb4a 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -259,6 +259,7 @@ std::string StackVisitor::DescribeLocation() const {
}
instrumentation::InstrumentationStackFrame& StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
+ CHECK_LT(depth, thread_->GetInstrumentationStack()->size());
return thread_->GetInstrumentationStack()->at(depth);
}
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 8449607..e47fd37 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -50,7 +50,8 @@ inline ThreadState Thread::SetState(ThreadState new_state) {
// old_state_and_flags.suspend_request is true.
DCHECK_NE(new_state, kRunnable);
DCHECK_EQ(this, Thread::Current());
- union StateAndFlags old_state_and_flags = state_and_flags_;
+ union StateAndFlags old_state_and_flags;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
state_and_flags_.as_struct.state = new_state;
return static_cast<ThreadState>(old_state_and_flags.as_struct.state);
}
@@ -87,7 +88,7 @@ inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
union StateAndFlags old_state_and_flags;
union StateAndFlags new_state_and_flags;
do {
- old_state_and_flags = state_and_flags_;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) {
RunCheckpointFunction();
continue;
@@ -104,22 +105,23 @@ inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
bool done = false;
- union StateAndFlags old_state_and_flags = state_and_flags_;
+ union StateAndFlags old_state_and_flags;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
int16_t old_state = old_state_and_flags.as_struct.state;
DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable);
do {
Locks::mutator_lock_->AssertNotHeld(this); // Otherwise we starve GC..
- old_state_and_flags = state_and_flags_;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) {
// Wait while our suspend count is non-zero.
MutexLock mu(this, *Locks::thread_suspend_count_lock_);
- old_state_and_flags = state_and_flags_;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
// Re-check when Thread::resume_cond_ is notified.
Thread::resume_cond_->Wait(this);
- old_state_and_flags = state_and_flags_;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
}
DCHECK_EQ(GetSuspendCount(), 0);
@@ -127,10 +129,11 @@ inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
// Re-acquire shared mutator_lock_ access.
Locks::mutator_lock_->SharedLock(this);
// Atomically change from suspended to runnable if no suspend request pending.
- old_state_and_flags = state_and_flags_;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) {
- union StateAndFlags new_state_and_flags = old_state_and_flags;
+ union StateAndFlags new_state_and_flags;
+ new_state_and_flags.as_int = old_state_and_flags.as_int;
new_state_and_flags.as_struct.state = kRunnable;
// CAS the value without a memory barrier, that occurred in the lock above.
done = android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 1add507..2861213 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -579,19 +579,21 @@ void Thread::RunCheckpointFunction() {
}
bool Thread::RequestCheckpoint(Closure* function) {
- union StateAndFlags old_state_and_flags = state_and_flags_;
+ union StateAndFlags old_state_and_flags;
+ old_state_and_flags.as_int = state_and_flags_.as_int;
if (old_state_and_flags.as_struct.state != kRunnable) {
return false; // Fail, thread is suspended and so can't run a checkpoint.
}
if ((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0) {
return false; // Fail, already a checkpoint pending.
}
- CHECK(checkpoint_function_ == NULL);
+ CHECK(checkpoint_function_ == nullptr);
checkpoint_function_ = function;
// Checkpoint function installed now install flag bit.
// We must be runnable to request a checkpoint.
- old_state_and_flags.as_struct.state = kRunnable;
- union StateAndFlags new_state_and_flags = old_state_and_flags;
+ DCHECK_EQ(old_state_and_flags.as_struct.state, kRunnable);
+ union StateAndFlags new_state_and_flags;
+ new_state_and_flags.as_int = old_state_and_flags.as_int;
new_state_and_flags.as_struct.flags |= kCheckpointRequest;
int succeeded = android_atomic_cmpxchg(old_state_and_flags.as_int, new_state_and_flags.as_int,
&state_and_flags_.as_int);
@@ -985,8 +987,9 @@ void Thread::Destroy() {
mirror::Object* lock =
soa.DecodeField(WellKnownClasses::java_lang_Thread_lock)->GetObject(opeer_);
// (This conditional is only needed for tests, where Thread.lock won't have been set.)
- if (lock != NULL) {
- ObjectLock locker(self, lock);
+ if (lock != nullptr) {
+ SirtRef<mirror::Object> sirt_obj(self, lock);
+ ObjectLock<mirror::Object> locker(self, &sirt_obj);
locker.Notify();
}
}
@@ -1281,7 +1284,7 @@ class BuildInternalStackTraceVisitor : public StackVisitor {
return true; // Ignore runtime frames (in particular callee save).
}
method_trace_->Set(count_, m);
- dex_pc_trace_->Set(count_, GetDexPc());
+ dex_pc_trace_->Set(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
++count_;
return true;
}
@@ -1363,19 +1366,31 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job
// Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(method_trace->Get(i));
MethodHelper mh(method);
- mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
- uint32_t dex_pc = pc_trace->Get(i);
- int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
- // Allocate element, potentially triggering GC
- // TODO: reuse class_name_object via Class::name_?
- const char* descriptor = mh.GetDeclaringClassDescriptor();
- CHECK(descriptor != NULL);
- std::string class_name(PrettyDescriptor(descriptor));
- SirtRef<mirror::String> class_name_object(soa.Self(),
- mirror::String::AllocFromModifiedUtf8(soa.Self(),
- class_name.c_str()));
- if (class_name_object.get() == NULL) {
- return NULL;
+ int32_t line_number;
+ SirtRef<mirror::String> class_name_object(soa.Self(), NULL);
+ SirtRef<mirror::String> source_name_object(soa.Self(), NULL);
+ if (method->IsProxyMethod()) {
+ line_number = -1;
+ class_name_object.reset(method->GetDeclaringClass()->GetName());
+ // source_name_object intentionally left null for proxy methods
+ } else {
+ mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
+ uint32_t dex_pc = pc_trace->Get(i);
+ line_number = mh.GetLineNumFromDexPC(dex_pc);
+ // Allocate element, potentially triggering GC
+ // TODO: reuse class_name_object via Class::name_?
+ const char* descriptor = mh.GetDeclaringClassDescriptor();
+ CHECK(descriptor != NULL);
+ std::string class_name(PrettyDescriptor(descriptor));
+ class_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
+ if (class_name_object.get() == NULL) {
+ return NULL;
+ }
+ const char* source_file = mh.GetDeclaringClassSourceFile();
+ source_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
+ if (source_name_object.get() == NULL) {
+ return NULL;
+ }
}
const char* method_name = mh.GetName();
CHECK(method_name != NULL);
@@ -1385,10 +1400,6 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job
if (method_name_object.get() == NULL) {
return NULL;
}
- const char* source_file = mh.GetDeclaringClassSourceFile();
- SirtRef<mirror::String> source_name_object(soa.Self(),
- mirror::String::AllocFromModifiedUtf8(soa.Self(),
- source_file));
mirror::StackTraceElement* obj = mirror::StackTraceElement::Alloc(
soa.Self(), class_name_object, method_name_object, source_name_object, line_number);
if (obj == NULL) {
@@ -1434,9 +1445,9 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
ClearException();
Runtime* runtime = Runtime::Current();
- mirror::ClassLoader* cl = NULL;
- if (throw_location.GetMethod() != NULL) {
- cl = throw_location.GetMethod()->GetDeclaringClass()->GetClassLoader();
+ mirror::ClassLoader* cl = nullptr;
+ if (saved_throw_method.get() != nullptr) {
+ cl = saved_throw_method.get()->GetDeclaringClass()->GetClassLoader();
}
SirtRef<mirror::ClassLoader> class_loader(this, cl);
SirtRef<mirror::Class>
@@ -1448,7 +1459,7 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
return;
}
- if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class.get(), true, true))) {
+ if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class, true, true))) {
DCHECK(IsExceptionPending());
return;
}
@@ -1458,7 +1469,9 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location,
// If we couldn't allocate the exception, throw the pre-allocated out of memory exception.
if (exception.get() == nullptr) {
- SetException(throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
+ ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(),
+ throw_location.GetDexPc());
+ SetException(gc_safe_throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
return;
}
@@ -1818,6 +1831,12 @@ class CatchBlockStackVisitor : public StackVisitor {
self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
// Do instrumentation events after allowing thread suspension again.
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+ if (!is_deoptimization_) {
+ // The debugger may suspend this thread and walk its stack. Let's do this before popping
+ // instrumentation frames.
+ instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
+ exception_);
+ }
for (size_t i = 0; i < instrumentation_frames_to_pop_; ++i) {
// We pop the instrumentation stack here so as not to corrupt it during the stack walk.
if (i != instrumentation_frames_to_pop_ - 1 || self_->GetInstrumentationStack()->front().method_ != catch_method) {
@@ -1825,10 +1844,7 @@ class CatchBlockStackVisitor : public StackVisitor {
instrumentation->PopMethodForUnwind(self_, is_deoptimization_);
}
}
- if (!is_deoptimization_) {
- instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
- exception_);
- } else {
+ if (is_deoptimization_) {
// TODO: proper return value.
self_->SetDeoptimizationShadowFrame(top_shadow_frame_);
}
@@ -1984,11 +2000,7 @@ class ReferenceMapVisitor : public StackVisitor {
// Portable path use DexGcMap and store in Method.native_gc_map_.
const uint8_t* gc_map = m->GetNativeGcMap();
CHECK(gc_map != NULL) << PrettyMethod(m);
- uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
- (gc_map[1] << 16) |
- (gc_map[2] << 8) |
- (gc_map[3] << 0));
- verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
+ verifier::DexPcToReferenceMap dex_gc_map(gc_map);
uint32_t dex_pc = GetDexPc();
const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
DCHECK(reg_bitmap != NULL);
@@ -2112,12 +2124,11 @@ void Thread::VisitRoots(RootVisitor* visitor, void* arg) {
opeer_ = visitor(opeer_, arg);
}
if (exception_ != nullptr) {
- exception_ = reinterpret_cast<mirror::Throwable*>(visitor(exception_, arg));
+ exception_ = down_cast<mirror::Throwable*>(visitor(exception_, arg));
}
throw_location_.VisitRoots(visitor, arg);
if (class_loader_override_ != nullptr) {
- class_loader_override_ = reinterpret_cast<mirror::ClassLoader*>(
- visitor(class_loader_override_, arg));
+ class_loader_override_ = down_cast<mirror::ClassLoader*>(visitor(class_loader_override_, arg));
}
jni_env_->locals.VisitRoots(visitor, arg);
jni_env_->monitors.VisitRoots(visitor, arg);
@@ -2136,7 +2147,7 @@ void Thread::VisitRoots(RootVisitor* visitor, void* arg) {
frame.this_object_ = visitor(frame.this_object_, arg);
}
DCHECK(frame.method_ != nullptr);
- frame.method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(frame.method_, arg));
+ frame.method_ = down_cast<mirror::ArtMethod*>(visitor(frame.method_, arg));
}
}
diff --git a/runtime/thread.h b/runtime/thread.h
index db2f7b4..44b2186 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -147,7 +147,8 @@ class PACKED(4) Thread {
}
bool IsSuspended() const {
- union StateAndFlags state_and_flags = state_and_flags_;
+ union StateAndFlags state_and_flags;
+ state_and_flags.as_int = state_and_flags_.as_int;
return state_and_flags.as_struct.state != kRunnable &&
(state_and_flags.as_struct.flags & kSuspendRequest) != 0;
}
@@ -638,7 +639,8 @@ class PACKED(4) Thread {
// 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to
// change from being Suspended to Runnable without a suspend request occurring.
- union StateAndFlags {
+ union PACKED(4) StateAndFlags {
+ StateAndFlags() {}
struct PACKED(4) {
// Bitfield of flag values. Must be changed atomically so that flag values aren't lost. See
// ThreadFlags for bit field meanings.
@@ -650,6 +652,11 @@ class PACKED(4) Thread {
volatile uint16_t state;
} as_struct;
volatile int32_t as_int;
+
+ private:
+ // gcc does not handle struct with volatile member assignments correctly.
+ // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47409
+ DISALLOW_COPY_AND_ASSIGN(StateAndFlags);
};
union StateAndFlags state_and_flags_;
COMPILE_ASSERT(sizeof(union StateAndFlags) == sizeof(int32_t),
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index dd3f11c..aed8c77 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -162,6 +162,35 @@ static void UnsafeLogFatalForThreadSuspendAllTimeout(Thread* self) NO_THREAD_SAF
}
#endif
+// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an
+// individual thread requires polling. delay_us is the requested sleep and total_delay_us
+// accumulates the total time spent sleeping for timeouts. The first sleep is just a yield,
+// subsequently sleeps increase delay_us from 1ms to 500ms by doubling.
+static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us,
+ bool holding_locks) {
+ if (!holding_locks) {
+ for (int i = kLockLevelCount - 1; i >= 0; --i) {
+ BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
+ if (held_mutex != NULL) {
+ LOG(FATAL) << "Holding " << held_mutex->GetName() << " while sleeping for thread suspension";
+ }
+ }
+ }
+ useconds_t new_delay_us = (*delay_us) * 2;
+ CHECK_GE(new_delay_us, *delay_us);
+ if (new_delay_us < 500000) { // Don't allow sleeping to be more than 0.5s.
+ *delay_us = new_delay_us;
+ }
+ if (*delay_us == 0) {
+ sched_yield();
+ // Default to 1 milliseconds (note that this gets multiplied by 2 before the first sleep).
+ *delay_us = 500;
+ } else {
+ usleep(*delay_us);
+ *total_delay_us += *delay_us;
+ }
+}
+
size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) {
Thread* self = Thread::Current();
if (kIsDebugBuild) {
@@ -208,17 +237,15 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) {
for (const auto& thread : suspended_count_modified_threads) {
if (!thread->IsSuspended()) {
// Wait until the thread is suspended.
- uint64_t start = NanoTime();
+ useconds_t total_delay_us = 0;
do {
- // Sleep for 100us.
- usleep(100);
+ useconds_t delay_us = 100;
+ ThreadSuspendSleep(self, &delay_us, &total_delay_us, true);
} while (!thread->IsSuspended());
- uint64_t end = NanoTime();
- // Shouldn't need to wait for longer than 1 millisecond.
- const uint64_t threshold = 1;
- if (NsToMs(end - start) > threshold) {
- LOG(INFO) << "Warning: waited longer than " << threshold
- << " ms for thread suspend\n";
+ // Shouldn't need to wait for longer than 1000 microseconds.
+ constexpr useconds_t kLongWaitThresholdUS = 1000;
+ if (UNLIKELY(total_delay_us > kLongWaitThresholdUS)) {
+ LOG(WARNING) << "Waited " << total_delay_us << " us for thread suspend!";
}
}
// We know for sure that the thread is suspended at this point.
@@ -354,34 +381,6 @@ static void ThreadSuspendByPeerWarning(Thread* self, int level, const char* mess
}
}
-// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an
-// individual thread requires polling. delay_us is the requested sleep and total_delay_us
-// accumulates the total time spent sleeping for timeouts. The first sleep is just a yield,
-// subsequently sleeps increase delay_us from 1ms to 500ms by doubling.
-static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us) {
- for (int i = kLockLevelCount - 1; i >= 0; --i) {
- BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
- if (held_mutex != NULL) {
- LOG(FATAL) << "Holding " << held_mutex->GetName() << " while sleeping for thread suspension";
- }
- }
- {
- useconds_t new_delay_us = (*delay_us) * 2;
- CHECK_GE(new_delay_us, *delay_us);
- if (new_delay_us < 500000) { // Don't allow sleeping to be more than 0.5s.
- *delay_us = new_delay_us;
- }
- }
- if ((*delay_us) == 0) {
- sched_yield();
- // Default to 1 milliseconds (note that this gets multiplied by 2 before the first sleep).
- (*delay_us) = 500;
- } else {
- usleep(*delay_us);
- (*total_delay_us) += (*delay_us);
- }
-}
-
Thread* ThreadList::SuspendThreadByPeer(jobject peer, bool request_suspension,
bool debug_suspension, bool* timed_out) {
static const useconds_t kTimeoutUs = 30 * 1000000; // 30s.
@@ -432,7 +431,7 @@ Thread* ThreadList::SuspendThreadByPeer(jobject peer, bool request_suspension,
}
// Release locks and come out of runnable state.
}
- ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+ ThreadSuspendSleep(self, &delay_us, &total_delay_us, false);
}
}
@@ -445,13 +444,13 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe
static const useconds_t kTimeoutUs = 30 * 1000000; // 30s.
useconds_t total_delay_us = 0;
useconds_t delay_us = 0;
- bool did_suspend_request = false;
*timed_out = false;
+ Thread* suspended_thread = nullptr;
Thread* self = Thread::Current();
CHECK_NE(thread_id, kInvalidThreadId);
while (true) {
- Thread* thread = NULL;
{
+ Thread* thread = NULL;
ScopedObjectAccess soa(self);
MutexLock mu(self, *Locks::thread_list_lock_);
for (const auto& it : list_) {
@@ -460,17 +459,20 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe
break;
}
}
- if (thread == NULL) {
+ if (thread == nullptr) {
+ CHECK(suspended_thread == nullptr) << "Suspended thread " << suspended_thread
+ << " no longer in thread list";
// There's a race in inflating a lock and the owner giving up ownership and then dying.
ThreadSuspendByThreadIdWarning(WARNING, "No such thread id for suspend", thread_id);
return NULL;
}
{
MutexLock mu(self, *Locks::thread_suspend_count_lock_);
- if (!did_suspend_request) {
+ if (suspended_thread == nullptr) {
thread->ModifySuspendCount(self, +1, debug_suspension);
- did_suspend_request = true;
+ suspended_thread = thread;
} else {
+ CHECK_EQ(suspended_thread, thread);
// If the caller isn't requesting suspension, a suspension should have already occurred.
CHECK_GT(thread->GetSuspendCount(), 0);
}
@@ -487,7 +489,7 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe
}
if (total_delay_us >= kTimeoutUs) {
ThreadSuspendByThreadIdWarning(WARNING, "Thread suspension timed out", thread_id);
- if (did_suspend_request) {
+ if (suspended_thread != nullptr) {
thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
}
*timed_out = true;
@@ -496,7 +498,7 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe
}
// Release locks and come out of runnable state.
}
- ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+ ThreadSuspendSleep(self, &delay_us, &total_delay_us, false);
}
}
@@ -719,9 +721,7 @@ void ThreadList::Unregister(Thread* self) {
self->Destroy();
uint32_t thin_lock_id = self->thin_lock_thread_id_;
- self->thin_lock_thread_id_ = 0;
- ReleaseThreadId(self, thin_lock_id);
- while (self != NULL) {
+ while (self != nullptr) {
// Remove and delete the Thread* while holding the thread_list_lock_ and
// thread_suspend_count_lock_ so that the unregistering thread cannot be suspended.
// Note: deliberately not using MutexLock that could hold a stale self pointer.
@@ -732,10 +732,14 @@ void ThreadList::Unregister(Thread* self) {
if (!self->IsSuspended()) {
list_.remove(self);
delete self;
- self = NULL;
+ self = nullptr;
}
Locks::thread_list_lock_->ExclusiveUnlock(self);
}
+ // Release the thread ID after the thread is finished and deleted to avoid cases where we can
+ // temporarily have multiple threads with the same thread id. When this occurs, it causes
+ // problems in FindThreadByThreadId / SuspendThreadByThreadId.
+ ReleaseThreadId(nullptr, thin_lock_id);
// Clear the TLS data, so that the underlying native thread is recognizably detached.
// (It may wish to reattach later.)
diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc
index 01497ef..1cc3e74 100644
--- a/runtime/throw_location.cc
+++ b/runtime/throw_location.cc
@@ -25,7 +25,7 @@
namespace art {
std::string ThrowLocation::Dump() const {
- if (method_ != NULL) {
+ if (method_ != nullptr) {
return StringPrintf("%s:%d", PrettyMethod(method_).c_str(),
MethodHelper(method_).GetLineNumFromDexPC(dex_pc_));
} else {
@@ -35,12 +35,11 @@ std::string ThrowLocation::Dump() const {
void ThrowLocation::VisitRoots(RootVisitor* visitor, void* arg) {
if (this_object_ != nullptr) {
- this_object_ = const_cast<mirror::Object*>(visitor(this_object_, arg));
+ this_object_ = visitor(this_object_, arg);
DCHECK(this_object_ != nullptr);
}
if (method_ != nullptr) {
- method_ = const_cast<mirror::ArtMethod*>(
- reinterpret_cast<const mirror::ArtMethod*>(visitor(method_, arg)));
+ method_ = down_cast<mirror::ArtMethod*>(visitor(method_, arg));
DCHECK(method_ != nullptr);
}
}
diff --git a/runtime/verifier/dex_gc_map.h b/runtime/verifier/dex_gc_map.h
index 2a95ba2..4570ae8 100644
--- a/runtime/verifier/dex_gc_map.h
+++ b/runtime/verifier/dex_gc_map.h
@@ -38,11 +38,13 @@ enum RegisterMapFormat {
// Lightweight wrapper for Dex PC to reference bit maps.
class DexPcToReferenceMap {
public:
- DexPcToReferenceMap(const uint8_t* data, size_t data_length) : data_(data) {
+ explicit DexPcToReferenceMap(const uint8_t* data) : data_(data) {
CHECK(data_ != NULL);
- // Check the size of the table agrees with the number of entries
- size_t data_size = data_length - 4;
- DCHECK_EQ(EntryWidth() * NumEntries(), data_size);
+ }
+
+ // The total size of the reference bit map including header.
+ size_t RawSize() const {
+ return EntryWidth() * NumEntries() + 4u /* header */;
}
// The number of entries in the table
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1e45c60..9183b5f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -319,10 +319,12 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, SirtRef<mirror::DexCache
allow_soft_failures_(allow_soft_failures),
has_check_casts_(false),
has_virtual_or_interface_invokes_(false) {
+ Runtime::Current()->AddMethodVerifier(this);
DCHECK(class_def != nullptr);
}
MethodVerifier::~MethodVerifier() {
+ Runtime::Current()->RemoveMethodVerifier(this);
STLDeleteElements(&failure_messages_);
}
@@ -1068,13 +1070,13 @@ bool MethodVerifier::VerifyCodeFlow() {
bool compile = IsCandidateForCompilation(ref, method_access_flags_);
if (compile) {
/* Generate a register map and add it to the method. */
- const std::vector<uint8_t>* dex_gc_map = GenerateLengthPrefixedGcMap();
+ const std::vector<uint8_t>* dex_gc_map = GenerateGcMap();
if (dex_gc_map == NULL) {
DCHECK_NE(failures_.size(), 0U);
return false; // Not a real failure, but a failure to encode
}
if (kIsDebugBuild) {
- VerifyLengthPrefixedGcMap(*dex_gc_map);
+ VerifyGcMap(*dex_gc_map);
}
verifier::MethodVerifier::SetDexGcMap(ref, dex_gc_map);
}
@@ -4054,7 +4056,7 @@ MethodVerifier::PcToConcreteMethodMap* MethodVerifier::GenerateDevirtMap() {
return pc_to_concrete_method_map.release();
}
-const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() {
+const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
size_t num_entries, ref_bitmap_bits, pc_bits;
ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits);
// There's a single byte to encode the size of each bitmap
@@ -4092,12 +4094,7 @@ const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Failed to encode GC map (size=" << table_size << ")";
return NULL;
}
- table->reserve(table_size + 4); // table_size plus the length prefix
- // Write table size
- table->push_back((table_size & 0xff000000) >> 24);
- table->push_back((table_size & 0x00ff0000) >> 16);
- table->push_back((table_size & 0x0000ff00) >> 8);
- table->push_back((table_size & 0x000000ff) >> 0);
+ table->reserve(table_size);
// Write table header
table->push_back(format | ((ref_bitmap_bytes >> DexPcToReferenceMap::kRegMapFormatShift) &
~DexPcToReferenceMap::kRegMapFormatMask));
@@ -4115,18 +4112,15 @@ const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() {
line->WriteReferenceBitMap(*table, ref_bitmap_bytes);
}
}
- DCHECK_EQ(table->size(), table_size + 4); // table_size plus the length prefix
+ DCHECK_EQ(table->size(), table_size);
return table;
}
-void MethodVerifier::VerifyLengthPrefixedGcMap(const std::vector<uint8_t>& data) {
+void MethodVerifier::VerifyGcMap(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
- DCHECK_GE(data.size(), 4u);
- size_t table_size = data.size() - 4u;
- DCHECK_EQ(table_size, static_cast<size_t>((data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | (data[3] << 0)));
- DexPcToReferenceMap map(&data[4], table_size);
+ DexPcToReferenceMap map(&data[0]);
+ DCHECK_EQ(data.size(), map.RawSize());
size_t map_index = 0;
for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
const uint8_t* reg_bitmap = map.FindBitMap(i, false);
@@ -4393,5 +4387,9 @@ bool MethodVerifier::IsClassRejected(ClassReference ref) {
return (rejected_classes_->find(ref) != rejected_classes_->end());
}
+void MethodVerifier::VisitRoots(RootVisitor* visitor, void* arg) {
+ reg_types_.VisitRoots(visitor, arg);
+}
+
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index f72898e..6b5747b 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -237,6 +237,8 @@ class MethodVerifier {
static bool IsCandidateForCompilation(MethodReference& method_ref,
const uint32_t access_flags);
+ void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
// Adds the given string to the beginning of the last failure message.
void PrependToLastFailMessage(std::string);
@@ -614,10 +616,10 @@ class MethodVerifier {
* encode it in some clever fashion.
* Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
*/
- const std::vector<uint8_t>* GenerateLengthPrefixedGcMap();
+ const std::vector<uint8_t>* GenerateGcMap();
// Verify that the GC map associated with method_ is well formed
- void VerifyLengthPrefixedGcMap(const std::vector<uint8_t>& data);
+ void VerifyGcMap(const std::vector<uint8_t>& data);
// Compute sizes for GC map data
void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index d82e75d..f394bce 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -969,6 +969,12 @@ void RegType::CheckInvariants() const {
}
}
+void RegType::VisitRoots(RootVisitor* visitor, void* arg) {
+ if (klass_ != nullptr) {
+ klass_ = down_cast<mirror::Class*>(visitor(klass_, arg));
+ }
+}
+
void UninitializedThisReferenceType::CheckInvariants() const {
CHECK_EQ(GetAllocationPc(), 0U) << *this;
}
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index f371733..8df481f 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -20,6 +20,7 @@
#include "base/macros.h"
#include "globals.h"
#include "primitive.h"
+#include "root_visitor.h"
#include "jni.h"
@@ -269,6 +270,8 @@ class RegType {
virtual ~RegType() {}
+ void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
protected:
RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -282,7 +285,7 @@ class RegType {
const std::string descriptor_;
- mirror::Class* const klass_;
+ mirror::Class* klass_;
const uint16_t cache_id_;
friend class RegTypeCache;
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 9c9673a..3d24414 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -554,5 +554,11 @@ void RegTypeCache::Dump(std::ostream& os) {
}
}
+void RegTypeCache::VisitRoots(RootVisitor* visitor, void* arg) {
+ for (RegType* entry : entries_) {
+ entry->VisitRoots(visitor, arg);
+ }
+}
+
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index a9f8bff..a811696 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -21,6 +21,7 @@
#include "base/macros.h"
#include "base/stl_util.h"
#include "reg_type.h"
+#include "root_visitor.h"
#include "runtime.h"
#include <stdint.h>
@@ -139,6 +140,8 @@ class RegTypeCache {
void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const RegType& RegTypeFromPrimitiveType(Primitive::Type) const;
+ void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index db273ec..8cb1993 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -30,272 +30,23 @@
namespace art {
-static const size_t kBufSize = 32 * KB;
-
-// Get 2 little-endian bytes.
-static uint32_t Le16ToHost(const byte* src) {
- return ((src[0] << 0) |
- (src[1] << 8));
-}
-
-// Get 4 little-endian bytes.
-static uint32_t Le32ToHost(const byte* src) {
- return ((src[0] << 0) |
- (src[1] << 8) |
- (src[2] << 16) |
- (src[3] << 24));
-}
-
-uint16_t ZipEntry::GetCompressionMethod() {
- return Le16ToHost(ptr_ + ZipArchive::kCDEMethod);
-}
-
-uint32_t ZipEntry::GetCompressedLength() {
- return Le32ToHost(ptr_ + ZipArchive::kCDECompLen);
-}
-
uint32_t ZipEntry::GetUncompressedLength() {
- return Le32ToHost(ptr_ + ZipArchive::kCDEUncompLen);
+ return zip_entry_->uncompressed_length;
}
uint32_t ZipEntry::GetCrc32() {
- return Le32ToHost(ptr_ + ZipArchive::kCDECRC);
+ return zip_entry_->crc32;
}
-off64_t ZipEntry::GetDataOffset() {
- // All we have is the offset to the Local File Header, which is
- // variable size, so we have to read the contents of the struct to
- // figure out where the actual data starts.
-
- // We also need to make sure that the lengths are not so large that
- // somebody trying to map the compressed or uncompressed data runs
- // off the end of the mapped region.
-
- off64_t dir_offset = zip_archive_->dir_offset_;
- int64_t lfh_offset = Le32ToHost(ptr_ + ZipArchive::kCDELocalOffset);
- if (lfh_offset + ZipArchive::kLFHLen >= dir_offset) {
- LOG(WARNING) << "Zip: bad LFH offset in zip";
- return -1;
- }
-
- if (lseek64(zip_archive_->fd_, lfh_offset, SEEK_SET) != lfh_offset) {
- PLOG(WARNING) << "Zip: failed seeking to LFH at offset " << lfh_offset;
- return -1;
- }
-
- uint8_t lfh_buf[ZipArchive::kLFHLen];
- ssize_t actual = TEMP_FAILURE_RETRY(read(zip_archive_->fd_, lfh_buf, sizeof(lfh_buf)));
- if (actual != sizeof(lfh_buf)) {
- LOG(WARNING) << "Zip: failed reading LFH from offset " << lfh_offset;
- return -1;
- }
-
- if (Le32ToHost(lfh_buf) != ZipArchive::kLFHSignature) {
- LOG(WARNING) << "Zip: didn't find signature at start of LFH, offset " << lfh_offset;
- return -1;
- }
-
- uint32_t gpbf = Le16ToHost(lfh_buf + ZipArchive::kLFHGPBFlags);
- if ((gpbf & ZipArchive::kGPFUnsupportedMask) != 0) {
- LOG(WARNING) << "Invalid General Purpose Bit Flag: " << gpbf;
- return -1;
- }
-
- off64_t data_offset = (lfh_offset + ZipArchive::kLFHLen
- + Le16ToHost(lfh_buf + ZipArchive::kLFHNameLen)
- + Le16ToHost(lfh_buf + ZipArchive::kLFHExtraLen));
- if (data_offset >= dir_offset) {
- LOG(WARNING) << "Zip: bad data offset " << data_offset << " in zip";
- return -1;
- }
-
- // check lengths
-
- if (static_cast<off64_t>(data_offset + GetCompressedLength()) > dir_offset) {
- LOG(WARNING) << "Zip: bad compressed length in zip "
- << "(" << data_offset << " + " << GetCompressedLength()
- << " > " << dir_offset << ")";
- return -1;
- }
-
- if (GetCompressionMethod() == kCompressStored
- && static_cast<off64_t>(data_offset + GetUncompressedLength()) > dir_offset) {
- LOG(WARNING) << "Zip: bad uncompressed length in zip "
- << "(" << data_offset << " + " << GetUncompressedLength()
- << " > " << dir_offset << ")";
- return -1;
- }
-
- return data_offset;
-}
-
-static bool CopyFdToMemory(uint8_t* begin, size_t size, int in, size_t count) {
- uint8_t* dst = begin;
- std::vector<uint8_t> buf(kBufSize);
- while (count != 0) {
- size_t bytes_to_read = (count > kBufSize) ? kBufSize : count;
- ssize_t actual = TEMP_FAILURE_RETRY(read(in, &buf[0], bytes_to_read));
- if (actual != static_cast<ssize_t>(bytes_to_read)) {
- PLOG(WARNING) << "Zip: short read";
- return false;
- }
- memcpy(dst, &buf[0], bytes_to_read);
- dst += bytes_to_read;
- count -= bytes_to_read;
- }
- DCHECK_EQ(dst, begin + size);
- return true;
-}
-
-class ZStream {
- public:
- ZStream(byte* write_buf, size_t write_buf_size) {
- // Initialize the zlib stream struct.
- memset(&zstream_, 0, sizeof(zstream_));
- zstream_.zalloc = Z_NULL;
- zstream_.zfree = Z_NULL;
- zstream_.opaque = Z_NULL;
- zstream_.next_in = NULL;
- zstream_.avail_in = 0;
- zstream_.next_out = reinterpret_cast<Bytef*>(write_buf);
- zstream_.avail_out = write_buf_size;
- zstream_.data_type = Z_UNKNOWN;
- }
-
- z_stream& Get() {
- return zstream_;
- }
-
- ~ZStream() {
- inflateEnd(&zstream_);
- }
- private:
- z_stream zstream_;
-};
-
-static bool InflateToMemory(uint8_t* begin, size_t size,
- int in, size_t uncompressed_length, size_t compressed_length) {
- uint8_t* dst = begin;
- UniquePtr<uint8_t[]> read_buf(new uint8_t[kBufSize]);
- UniquePtr<uint8_t[]> write_buf(new uint8_t[kBufSize]);
- if (read_buf.get() == NULL || write_buf.get() == NULL) {
- LOG(WARNING) << "Zip: failed to allocate buffer to inflate";
- return false;
- }
-
- UniquePtr<ZStream> zstream(new ZStream(write_buf.get(), kBufSize));
-
- // Use the undocumented "negative window bits" feature to tell zlib
- // that there's no zlib header waiting for it.
- int zerr = inflateInit2(&zstream->Get(), -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- LOG(ERROR) << "Installed zlib is not compatible with linked version (" << ZLIB_VERSION << ")";
- } else {
- LOG(WARNING) << "Call to inflateInit2 failed (zerr=" << zerr << ")";
- }
- return false;
- }
-
- size_t remaining = compressed_length;
- do {
- // read as much as we can
- if (zstream->Get().avail_in == 0) {
- size_t bytes_to_read = (remaining > kBufSize) ? kBufSize : remaining;
-
- ssize_t actual = TEMP_FAILURE_RETRY(read(in, read_buf.get(), bytes_to_read));
- if (actual != static_cast<ssize_t>(bytes_to_read)) {
- LOG(WARNING) << "Zip: inflate read failed (" << actual << " vs " << bytes_to_read << ")";
- return false;
- }
- remaining -= bytes_to_read;
- zstream->Get().next_in = read_buf.get();
- zstream->Get().avail_in = bytes_to_read;
- }
-
- // uncompress the data
- zerr = inflate(&zstream->Get(), Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- LOG(WARNING) << "Zip: inflate zerr=" << zerr
- << " (next_in=" << zstream->Get().next_in
- << " avail_in=" << zstream->Get().avail_in
- << " next_out=" << zstream->Get().next_out
- << " avail_out=" << zstream->Get().avail_out
- << ")";
- return false;
- }
-
- // write when we're full or when we're done
- if (zstream->Get().avail_out == 0 ||
- (zerr == Z_STREAM_END && zstream->Get().avail_out != kBufSize)) {
- size_t bytes_to_write = zstream->Get().next_out - write_buf.get();
- memcpy(dst, write_buf.get(), bytes_to_write);
- dst += bytes_to_write;
- zstream->Get().next_out = write_buf.get();
- zstream->Get().avail_out = kBufSize;
- }
- } while (zerr == Z_OK);
-
- DCHECK_EQ(zerr, Z_STREAM_END); // other errors should've been caught
-
- // paranoia
- if (zstream->Get().total_out != uncompressed_length) {
- LOG(WARNING) << "Zip: size mismatch on inflated file ("
- << zstream->Get().total_out << " vs " << uncompressed_length << ")";
- return false;
- }
-
- DCHECK_EQ(dst, begin + size);
- return true;
-}
bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) {
- uint32_t length = GetUncompressedLength();
- int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length));
- if (result == -1) {
- *error_msg = StringPrintf("Zip: failed to ftruncate '%s' to length %ud", file.GetPath().c_str(),
- length);
- return false;
- }
-
- UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0,
- file.GetPath().c_str(), error_msg));
- if (map.get() == NULL) {
- *error_msg = StringPrintf("Zip: failed to mmap space for '%s': %s", file.GetPath().c_str(),
- error_msg->c_str());
- return false;
- }
-
- return ExtractToMemory(map->Begin(), map->Size(), error_msg);
-}
-
-bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg) {
- // If size is zero, data offset will be meaningless, so bail out early.
- if (size == 0) {
- return true;
- }
- off64_t data_offset = GetDataOffset();
- if (data_offset == -1) {
- *error_msg = StringPrintf("Zip: data_offset=%lld", data_offset);
- return false;
- }
- if (lseek64(zip_archive_->fd_, data_offset, SEEK_SET) != data_offset) {
- *error_msg = StringPrintf("Zip: lseek to data at %lld failed", data_offset);
+ const int32_t error = ExtractEntryToFile(handle_, zip_entry_, file.Fd());
+ if (error) {
+ *error_msg = std::string(ErrorCodeString(error));
return false;
}
- // TODO: this doesn't verify the data's CRC, but probably should (especially
- // for uncompressed data).
- switch (GetCompressionMethod()) {
- case kCompressStored:
- return CopyFdToMemory(begin, size, zip_archive_->fd_, GetUncompressedLength());
- case kCompressDeflated:
- return InflateToMemory(begin, size, zip_archive_->fd_,
- GetUncompressedLength(), GetCompressedLength());
- default:
- *error_msg = StringPrintf("Zip: unknown compression method 0x%x", GetCompressionMethod());
- return false;
- }
+ return true;
}
MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error_msg) {
@@ -303,18 +54,18 @@ MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error
name += " extracted in memory from ";
name += entry_filename;
UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(),
- NULL,
- GetUncompressedLength(),
+ NULL, GetUncompressedLength(),
PROT_READ | PROT_WRITE, error_msg));
if (map.get() == nullptr) {
DCHECK(!error_msg->empty());
- return NULL;
+ return nullptr;
}
- bool success = ExtractToMemory(map->Begin(), map->Size(), error_msg);
- if (!success) {
- LOG(ERROR) << "Zip: Failed to extract '" << entry_filename << "' to memory";
- return NULL;
+ const int32_t error = ExtractToMemory(handle_, zip_entry_,
+ map->Begin(), map->Size());
+ if (error) {
+ *error_msg = std::string(ErrorCodeString(error));
+ return nullptr;
}
return map.release();
@@ -336,238 +87,47 @@ static void SetCloseOnExec(int fd) {
ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) {
DCHECK(filename != nullptr);
- int fd = open(filename, O_RDONLY, 0);
- if (fd == -1) {
- *error_msg = StringPrintf("Zip: unable to open '%s': %s", filename, strerror(errno));
- return NULL;
- }
- return OpenFromFd(fd, filename, error_msg);
-}
-ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) {
- SetCloseOnExec(fd);
- UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd, filename));
- CHECK(zip_archive.get() != nullptr);
- if (!zip_archive->MapCentralDirectory(error_msg)) {
- zip_archive->Close();
- return NULL;
- }
- if (!zip_archive->Parse(error_msg)) {
- zip_archive->Close();
- return NULL;
+ ZipArchiveHandle handle;
+ const int32_t error = OpenArchive(filename, &handle);
+ if (error) {
+ *error_msg = std::string(ErrorCodeString(error));
+ CloseArchive(handle);
+ return nullptr;
}
- return zip_archive.release();
-}
-
-ZipEntry* ZipArchive::Find(const char* name) const {
- DCHECK(name != NULL);
- DirEntries::const_iterator it = dir_entries_.find(name);
- if (it == dir_entries_.end()) {
- return NULL;
- }
- return new ZipEntry(this, (*it).second);
-}
-void ZipArchive::Close() {
- if (fd_ != -1) {
- close(fd_);
- }
- fd_ = -1;
- num_entries_ = 0;
- dir_offset_ = 0;
-}
-
-std::string ZipArchive::ErrorStringPrintf(const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- std::string result(StringPrintf("Zip '%s' : ", filename_.c_str()));
- StringAppendV(&result, fmt, ap);
- va_end(ap);
- return result;
+ SetCloseOnExec(GetFileDescriptor(handle));
+ return new ZipArchive(handle);
}
-// Find the zip Central Directory and memory-map it.
-//
-// On success, returns true after populating fields from the EOCD area:
-// num_entries_
-// dir_offset_
-// dir_map_
-bool ZipArchive::MapCentralDirectory(std::string* error_msg) {
- /*
- * Get and test file length.
- */
- off64_t file_length = lseek64(fd_, 0, SEEK_END);
- if (file_length < kEOCDLen) {
- *error_msg = ErrorStringPrintf("length %lld is too small to be zip", file_length);
- return false;
- }
-
- size_t read_amount = kMaxEOCDSearch;
- if (file_length < off64_t(read_amount)) {
- read_amount = file_length;
- }
-
- UniquePtr<uint8_t[]> scan_buf(new uint8_t[read_amount]);
- CHECK(scan_buf.get() != nullptr);
-
- /*
- * Make sure this is a Zip archive.
- */
- if (lseek64(fd_, 0, SEEK_SET) != 0) {
- *error_msg = ErrorStringPrintf("seek to start failed: %s", strerror(errno));
- return false;
- }
-
- ssize_t actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), sizeof(int32_t)));
- if (actual != static_cast<ssize_t>(sizeof(int32_t))) {
- *error_msg = ErrorStringPrintf("couldn\'t read first signature from zip archive: %s",
- strerror(errno));
- return false;
- }
-
- unsigned int header = Le32ToHost(scan_buf.get());
- if (header != kLFHSignature) {
- *error_msg = ErrorStringPrintf("not a zip archive (found 0x%x)", header);
- return false;
- }
-
- // Perform the traditional EOCD snipe hunt.
- //
- // We're searching for the End of Central Directory magic number,
- // which appears at the start of the EOCD block. It's followed by
- // 18 bytes of EOCD stuff and up to 64KB of archive comment. We
- // need to read the last part of the file into a buffer, dig through
- // it to find the magic number, parse some values out, and use those
- // to determine the extent of the CD.
- //
- // We start by pulling in the last part of the file.
- off64_t search_start = file_length - read_amount;
-
- if (lseek64(fd_, search_start, SEEK_SET) != search_start) {
- *error_msg = ErrorStringPrintf("seek %lld failed: %s", search_start, strerror(errno));
- return false;
- }
- actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), read_amount));
- if (actual != static_cast<ssize_t>(read_amount)) {
- *error_msg = ErrorStringPrintf("read %lld, expected %zd. %s", search_start, read_amount,
- strerror(errno));
- return false;
- }
-
-
- // Scan backward for the EOCD magic. In an archive without a trailing
- // comment, we'll find it on the first try. (We may want to consider
- // doing an initial minimal read; if we don't find it, retry with a
- // second read as above.)
- int i;
- for (i = read_amount - kEOCDLen; i >= 0; i--) {
- if (scan_buf.get()[i] == 0x50 && Le32ToHost(&(scan_buf.get())[i]) == kEOCDSignature) {
- break;
- }
- }
- if (i < 0) {
- *error_msg = ErrorStringPrintf("EOCD not found, not a zip file");
- return false;
- }
-
- off64_t eocd_offset = search_start + i;
- const byte* eocd_ptr = scan_buf.get() + i;
-
- CHECK(eocd_offset < file_length);
-
- // Grab the CD offset and size, and the number of entries in the
- // archive. Verify that they look reasonable.
- uint16_t disk_number = Le16ToHost(eocd_ptr + kEOCDDiskNumber);
- uint16_t disk_with_central_dir = Le16ToHost(eocd_ptr + kEOCDDiskNumberForCD);
- uint16_t num_entries = Le16ToHost(eocd_ptr + kEOCDNumEntries);
- uint16_t total_num_entries = Le16ToHost(eocd_ptr + kEOCDTotalNumEntries);
- uint32_t dir_size = Le32ToHost(eocd_ptr + kEOCDSize);
- uint32_t dir_offset = Le32ToHost(eocd_ptr + kEOCDFileOffset);
- uint16_t comment_size = Le16ToHost(eocd_ptr + kEOCDCommentSize);
-
- if ((uint64_t) dir_offset + (uint64_t) dir_size > (uint64_t) eocd_offset) {
- *error_msg = ErrorStringPrintf("bad offsets (dir=%ud, size=%ud, eocd=%lld)",
- dir_offset, dir_size, eocd_offset);
- return false;
- }
- if (num_entries == 0) {
- *error_msg = ErrorStringPrintf("empty archive?");
- return false;
- } else if (num_entries != total_num_entries || disk_number != 0 || disk_with_central_dir != 0) {
- *error_msg = ErrorStringPrintf("spanned archives not supported");
- return false;
- }
-
- // Check to see if comment is a sane size
- if ((comment_size > (file_length - kEOCDLen))
- || (eocd_offset > (file_length - kEOCDLen) - comment_size)) {
- *error_msg = ErrorStringPrintf("comment size runs off end of file");
- return false;
- }
+ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) {
+ DCHECK(filename != nullptr);
+ DCHECK_GT(fd, 0);
- // It all looks good. Create a mapping for the CD.
- dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset,
- filename_.c_str(), error_msg));
- if (dir_map_.get() == NULL) {
- return false;
+ ZipArchiveHandle handle;
+ const int32_t error = OpenArchiveFd(fd, filename, &handle);
+ if (error) {
+ *error_msg = std::string(ErrorCodeString(error));
+ CloseArchive(handle);
+ return nullptr;
}
- num_entries_ = num_entries;
- dir_offset_ = dir_offset;
- return true;
+ SetCloseOnExec(GetFileDescriptor(handle));
+ return new ZipArchive(handle);
}
-bool ZipArchive::Parse(std::string* error_msg) {
- const byte* cd_ptr = dir_map_->Begin();
- size_t cd_length = dir_map_->Size();
+ZipEntry* ZipArchive::Find(const char* name, std::string* error_msg) const {
+ DCHECK(name != nullptr);
- // Walk through the central directory, adding entries to the hash
- // table and verifying values.
- const byte* ptr = cd_ptr;
- for (int i = 0; i < num_entries_; i++) {
- if (Le32ToHost(ptr) != kCDESignature) {
- *error_msg = ErrorStringPrintf("missed a central dir sig (at %d)", i);
- return false;
- }
- if (ptr + kCDELen > cd_ptr + cd_length) {
- *error_msg = ErrorStringPrintf("ran off the end (at %d)", i);
- return false;
- }
-
- int64_t local_hdr_offset = Le32ToHost(ptr + kCDELocalOffset);
- if (local_hdr_offset >= dir_offset_) {
- *error_msg = ErrorStringPrintf("bad LFH offset %lld at entry %d", local_hdr_offset, i);
- return false;
- }
-
- uint16_t gpbf = Le16ToHost(ptr + kCDEGPBFlags);
- if ((gpbf & kGPFUnsupportedMask) != 0) {
- *error_msg = ErrorStringPrintf("invalid general purpose bit flag %x", gpbf);
- return false;
- }
-
- uint16_t name_len = Le16ToHost(ptr + kCDENameLen);
- uint16_t extra_len = Le16ToHost(ptr + kCDEExtraLen);
- uint16_t comment_len = Le16ToHost(ptr + kCDECommentLen);
-
- // add the CDE filename to the hash table
- const char* name = reinterpret_cast<const char*>(ptr + kCDELen);
-
- // Check name for NULL characters
- if (memchr(name, 0, name_len) != NULL) {
- *error_msg = ErrorStringPrintf("filename contains NUL byte");
- return false;
- }
-
- dir_entries_.Put(StringPiece(name, name_len), ptr);
- ptr += kCDELen + name_len + extra_len + comment_len;
- if (ptr > cd_ptr + cd_length) {
- *error_msg = ErrorStringPrintf("bad CD advance (%p vs %p) at entry %d",
- ptr, cd_ptr + cd_length, i);
- return false;
- }
+ // Resist the urge to delete the space. <: is a bigraph sequence.
+ UniquePtr< ::ZipEntry> zip_entry(new ::ZipEntry);
+ const int32_t error = FindEntry(handle_, name, zip_entry.get());
+ if (error) {
+ *error_msg = std::string(ErrorCodeString(error));
+ return nullptr;
}
- return true;
+
+ return new ZipEntry(handle_, zip_entry.release());
}
} // namespace art
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index 8ff952b..1f48e0a 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -18,8 +18,8 @@
#define ART_RUNTIME_ZIP_ARCHIVE_H_
#include <stdint.h>
-#include <zlib.h>
#include <string>
+#include <ziparchive/zip_archive.h>
#include "base/logging.h"
#include "base/stringpiece.h"
@@ -38,33 +38,17 @@ class MemMap;
class ZipEntry {
public:
bool ExtractToFile(File& file, std::string* error_msg);
- bool ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg);
MemMap* ExtractToMemMap(const char* entry_filename, std::string* error_msg);
uint32_t GetUncompressedLength();
uint32_t GetCrc32();
private:
- ZipEntry(const ZipArchive* zip_archive, const byte* ptr) : zip_archive_(zip_archive), ptr_(ptr) {}
+ ZipEntry(ZipArchiveHandle handle,
+ ::ZipEntry* zip_entry) : handle_(handle), zip_entry_(zip_entry) {}
- // Zip compression methods
- enum {
- kCompressStored = 0, // no compression
- kCompressDeflated = 8, // standard deflate
- };
-
- // kCompressStored, kCompressDeflated, ...
- uint16_t GetCompressionMethod();
-
- uint32_t GetCompressedLength();
-
- // returns -1 on error
- off64_t GetDataOffset();
-
- const ZipArchive* zip_archive_;
-
- // pointer to zip entry within central directory
- const byte* ptr_;
+ ZipArchiveHandle handle_;
+ ::ZipEntry* const zip_entry_;
friend class ZipArchive;
DISALLOW_COPY_AND_ASSIGN(ZipEntry);
@@ -72,74 +56,23 @@ class ZipEntry {
class ZipArchive {
public:
- // Zip file constants.
- static const uint32_t kEOCDSignature = 0x06054b50;
- static const int32_t kEOCDLen = 22;
- static const int32_t kEOCDDiskNumber = 4; // number of the current disk
- static const int32_t kEOCDDiskNumberForCD = 6; // disk number with the Central Directory
- static const int32_t kEOCDNumEntries = 8; // offset to #of entries in file
- static const int32_t kEOCDTotalNumEntries = 10; // offset to total #of entries in spanned archives
- static const int32_t kEOCDSize = 12; // size of the central directory
- static const int32_t kEOCDFileOffset = 16; // offset to central directory
- static const int32_t kEOCDCommentSize = 20; // offset to the length of the file comment
-
- static const int32_t kMaxCommentLen = 65535; // longest possible in uint16_t
- static const int32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);
-
- static const uint32_t kLFHSignature = 0x04034b50;
- static const int32_t kLFHLen = 30; // excluding variable-len fields
- static const int32_t kLFHGPBFlags = 6; // offset to GPB flags
- static const int32_t kLFHNameLen = 26; // offset to filename length
- static const int32_t kLFHExtraLen = 28; // offset to extra length
-
- static const uint32_t kCDESignature = 0x02014b50;
- static const int32_t kCDELen = 46; // excluding variable-len fields
- static const int32_t kCDEGPBFlags = 8; // offset to GPB flags
- static const int32_t kCDEMethod = 10; // offset to compression method
- static const int32_t kCDEModWhen = 12; // offset to modification timestamp
- static const int32_t kCDECRC = 16; // offset to entry CRC
- static const int32_t kCDECompLen = 20; // offset to compressed length
- static const int32_t kCDEUncompLen = 24; // offset to uncompressed length
- static const int32_t kCDENameLen = 28; // offset to filename length
- static const int32_t kCDEExtraLen = 30; // offset to extra length
- static const int32_t kCDECommentLen = 32; // offset to comment length
- static const int32_t kCDELocalOffset = 42; // offset to local hdr
-
- // General Purpose Bit Flag
- static const int32_t kGPFEncryptedFlag = (1 << 0);
- static const int32_t kGPFUnsupportedMask = (kGPFEncryptedFlag);
-
// return new ZipArchive instance on success, NULL on error.
static ZipArchive* Open(const char* filename, std::string* error_msg);
static ZipArchive* OpenFromFd(int fd, const char* filename, std::string* error_msg);
- ZipEntry* Find(const char* name) const;
+ ZipEntry* Find(const char* name, std::string* error_msg) const;
~ZipArchive() {
- Close();
+ CloseArchive(handle_);
}
private:
- explicit ZipArchive(int fd, const char* filename)
- : fd_(fd), num_entries_(0), dir_offset_(0), filename_(filename) {}
-
- bool MapCentralDirectory(std::string* error_msg);
- bool Parse(std::string* error_msg);
- void Close();
- std::string ErrorStringPrintf(const char* fmt, ...)
- __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
-
- int fd_;
- uint16_t num_entries_;
- off64_t dir_offset_;
- UniquePtr<MemMap> dir_map_;
- typedef SafeMap<StringPiece, const byte*> DirEntries;
- DirEntries dir_entries_;
- // Containing file for error reporting.
- const std::string filename_;
+ explicit ZipArchive(ZipArchiveHandle handle) : handle_(handle) {}
friend class ZipEntry;
+ ZipArchiveHandle handle_;
+
DISALLOW_COPY_AND_ASSIGN(ZipArchive);
};
diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc
index 622dc89..16394b0 100644
--- a/runtime/zip_archive_test.cc
+++ b/runtime/zip_archive_test.cc
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <zlib.h>
#include "UniquePtr.h"
#include "common_test.h"
@@ -33,8 +34,9 @@ TEST_F(ZipArchiveTest, FindAndExtract) {
UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg));
ASSERT_TRUE(zip_archive.get() != false) << error_msg;
ASSERT_TRUE(error_msg.empty());
- UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex"));
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex", &error_msg));
ASSERT_TRUE(zip_entry.get() != false);
+ ASSERT_TRUE(error_msg.empty());
ScratchFile tmp;
ASSERT_NE(-1, tmp.GetFd());
diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt
index 13e3a28..12df250 100644
--- a/test/044-proxy/expected.txt
+++ b/test/044-proxy/expected.txt
@@ -42,6 +42,7 @@ Invoke public abstract java.lang.String Shapes.blob()
(no args)
--- blob
Success: method blob res=mix
+$Proxy1.getTrace null:-1
Invoke public abstract void Shapes.upChuck()
(no args)
Got expected ioobe
@@ -49,8 +50,8 @@ Invoke public abstract void Shapes.upCheck() throws java.lang.InterruptedExcepti
(no args)
Got expected ie
-Proxy interfaces: [interface Quads, interface Colors]
-Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()]
+Proxy interfaces: [interface Quads, interface Colors, interface Trace]
+Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final void $Proxy1.getTrace(), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()]
Decl annos: []
Param annos (0) : []
Dupe threw expected exception
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index 46aa3fe..ea46f49 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -51,6 +51,8 @@ public class BasicTest {
colors.blue(777);
colors.mauve("sorry");
colors.blob();
+ Trace trace = (Trace) proxy;
+ trace.getTrace();
try {
shapes.upChuck();
@@ -96,7 +98,7 @@ public class BasicTest {
/* create the proxy class */
Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
- new Class[] { Quads.class, Colors.class });
+ new Class[] { Quads.class, Colors.class, Trace.class });
/* create a proxy object, passing the handler object in */
Object proxy = null;
@@ -156,6 +158,10 @@ interface Colors {
public R0aa checkMe();
}
+interface Trace {
+ public void getTrace();
+}
+
/*
* Some return types.
*/
@@ -248,6 +254,20 @@ class MyInvocationHandler implements InvocationHandler {
throw new RuntimeException("huh?");
}
+ if (method.getDeclaringClass() == Trace.class) {
+ if (method.getName().equals("getTrace")) {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ for (int i = 0; i < stackTrace.length; i++) {
+ StackTraceElement ste = stackTrace[i];
+ if (ste.getMethodName().equals("getTrace")) {
+ System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " +
+ ste.getFileName() + ":" + ste.getLineNumber());
+ }
+ }
+ return null;
+ }
+ }
+
System.out.println("Invoke " + method);
if (args == null || args.length == 0) {
System.out.println(" (no args)");
diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java
index a1b1f0c..9194da5 100644
--- a/test/JniTest/JniTest.java
+++ b/test/JniTest/JniTest.java
@@ -20,12 +20,24 @@ class JniTest {
public static void main(String[] args) {
System.loadLibrary("arttest");
testFindClassOnAttachedNativeThread();
+ testFindFieldOnAttachedNativeThread();
testCallStaticVoidMethodOnSubClass();
testGetMirandaMethod();
}
private static native void testFindClassOnAttachedNativeThread();
+ private static boolean testFindFieldOnAttachedNativeThreadField;
+
+ private static void testFindFieldOnAttachedNativeThread() {
+ testFindFieldOnAttachedNativeThreadNative();
+ if (!testFindFieldOnAttachedNativeThreadField) {
+ throw new AssertionError();
+ }
+ }
+
+ private static native void testFindFieldOnAttachedNativeThreadNative();
+
private static void testCallStaticVoidMethodOnSubClass() {
testCallStaticVoidMethodOnSubClassNative();
if (!testCallStaticVoidMethodOnSubClass_SuperClass.executed) {
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
index cfcbb64..d15e180 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/JniTest/jni_test.cc
@@ -67,6 +67,42 @@ extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindClassOnAttachedNativeThre
assert(pthread_join_result == 0);
}
+static void* testFindFieldOnAttachedNativeThread(void*) {
+ assert(jvm != NULL);
+
+ JNIEnv* env = NULL;
+ JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL };
+ int attach_result = jvm->AttachCurrentThread(&env, &args);
+ assert(attach_result == 0);
+
+ jclass clazz = env->FindClass("JniTest");
+ assert(clazz != NULL);
+ assert(!env->ExceptionCheck());
+
+ jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z");
+ assert(field != NULL);
+ assert(!env->ExceptionCheck());
+
+ env->SetStaticBooleanField(clazz, field, JNI_TRUE);
+
+ int detach_result = jvm->DetachCurrentThread();
+ assert(detach_result == 0);
+ return NULL;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindFieldOnAttachedNativeThreadNative(JNIEnv*,
+ jclass) {
+ pthread_t pthread;
+ int pthread_create_result = pthread_create(&pthread,
+ NULL,
+ testFindFieldOnAttachedNativeThread,
+ NULL);
+ assert(pthread_create_result == 0);
+ int pthread_join_result = pthread_join(pthread, NULL);
+ assert(pthread_join_result == 0);
+}
+
+
// http://b/11243757
extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
jclass) {
diff --git a/test/ThreadStress/ThreadStress.java b/test/ThreadStress/ThreadStress.java
index 8d8135d..795c790 100644
--- a/test/ThreadStress/ThreadStress.java
+++ b/test/ThreadStress/ThreadStress.java
@@ -128,13 +128,13 @@ class ThreadStress implements Runnable {
Thread[] runners = new Thread[numberOfThreads];
for (int r = 0; r < runners.length; r++) {
final ThreadStress ts = threadStresses[r];
- runners[r] = new Thread() {
+ runners[r] = new Thread("Runner thread " + r) {
final ThreadStress threadStress = ts;
public void run() {
int id = threadStress.id;
- System.out.println("Starting runner for " + id);
+ System.out.println("Starting worker for " + id);
while (threadStress.nextOperation < operationsPerThread) {
- Thread thread = new Thread(ts);
+ Thread thread = new Thread(ts, "Worker thread " + id);
thread.start();
try {
thread.join();
@@ -144,14 +144,14 @@ class ThreadStress implements Runnable {
+ (operationsPerThread - threadStress.nextOperation)
+ " operations remaining.");
}
- System.out.println("Finishing runner for " + id);
+ System.out.println("Finishing worker for " + id);
}
};
}
// The notifier thread is a daemon just loops forever to wake
// up threads in Operation.WAIT
- Thread notifier = new Thread() {
+ Thread notifier = new Thread("Notifier") {
public void run() {
while (true) {
synchronized (lock) {
diff --git a/tools/cpplint.py b/tools/cpplint.py
index 30b5216..c2f6514 100755
--- a/tools/cpplint.py
+++ b/tools/cpplint.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# Copyright (c) 2009 Google Inc. All rights reserved.
#
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index 0c085fb..19266b4 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# Copyright (C) 2012 The Android Open Source Project
#