diff options
44 files changed, 940 insertions, 276 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 63ad9cf3ff..4850e6c44e 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -165,6 +165,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/base/hex_dump_test.cc \ runtime/base/histogram_test.cc \ runtime/base/mutex_test.cc \ + runtime/base/out_test.cc \ runtime/base/scoped_flock_test.cc \ runtime/base/stringprintf_test.cc \ runtime/base/time_utils_test.cc \ diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index e15eff9056..676b8421cd 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -4535,7 +4535,11 @@ void ParallelMoveResolverX86::EmitSwap(size_t index) { Location destination = move->GetDestination(); if (source.IsRegister() && destination.IsRegister()) { - __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>()); + // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary. + DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>()); + __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>()); + __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>()); + __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>()); } else if (source.IsRegister() && destination.IsStackSlot()) { Exchange(source.AsRegister<Register>(), destination.GetStackIndex()); } else if (source.IsStackSlot() && destination.IsRegister()) { diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 8ef13e125e..bc7da802b1 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -359,7 +359,7 @@ void IntrinsicsRecognizer::Run() { std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) { switch (intrinsic) { case Intrinsics::kNone: - os << "No intrinsic."; + os << "None"; break; #define OPTIMIZING_INTRINSICS(Name, IsStatic) \ case Intrinsics::k ## Name: \ diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 44efc65e3f..a614193c96 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -1523,6 +1523,13 @@ void X86Assembler::repe_cmpsw() { } +void X86Assembler::repe_cmpsl() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0xA7); +} + + X86Assembler* X86Assembler::lock() { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0xF0); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index e2abcde624..ae8d7a1a1d 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -466,6 +466,7 @@ class X86Assembler FINAL : public Assembler { void repne_scasw(); void repe_cmpsw(); + void repe_cmpsl(); X86Assembler* lock(); void cmpxchgl(const Address& address, Register reg); diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index 0e8c4aee0c..7663580793 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -202,4 +202,10 @@ TEST_F(AssemblerX86Test, Repecmpsw) { DriverStr(expected, "Repecmpsw"); } +TEST_F(AssemblerX86Test, Repecmpsl) { + GetAssembler()->repe_cmpsl(); + const char* expected = "repe cmpsl\n"; + DriverStr(expected, "Repecmpsl"); +} + } // namespace art diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index 93c90db5d3..1dd4a2e3e9 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -2081,6 +2081,13 @@ void X86_64Assembler::repe_cmpsw() { } +void X86_64Assembler::repe_cmpsl() { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF3); + EmitUint8(0xA7); +} + + void X86_64Assembler::LoadDoubleConstant(XmmRegister dst, double value) { // TODO: Need to have a code constants table. int64_t constant = bit_cast<int64_t, double>(value); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 0cd31971b4..89a5606399 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -604,6 +604,7 @@ class X86_64Assembler FINAL : public Assembler { void repne_scasw(); void repe_cmpsw(); + void repe_cmpsl(); // // Macros for High-level operations. diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 2c1a6a1f3c..e1e4c32d8f 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -1269,4 +1269,10 @@ TEST_F(AssemblerX86_64Test, Repecmpsw) { DriverStr(expected, "Repecmpsw"); } +TEST_F(AssemblerX86_64Test, Repecmpsl) { + GetAssembler()->repe_cmpsl(); + const char* expected = "repe cmpsl\n"; + DriverStr(expected, "Repecmpsl"); +} + } // namespace art diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc index 2ead4a2af5..44787a7ac8 100644 --- a/disassembler/disassembler_x86.cc +++ b/disassembler/disassembler_x86.cc @@ -1117,6 +1117,9 @@ DISASSEMBLER_ENTRY(cmp, opcode1 = opcode_tmp.c_str(); } break; + case 0xA7: + opcode1 = (prefix[2] == 0x66 ? "cmpsw" : "cmpsl"); + break; case 0xAF: opcode1 = (prefix[2] == 0x66 ? "scasw" : "scasl"); break; diff --git a/runtime/Android.mk b/runtime/Android.mk index 4a944963a2..ce3e6d1f37 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -341,10 +341,13 @@ LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \ LIBART_CFLAGS := -DBUILDING_LIBART=1 +LIBART_TARGET_CFLAGS := +LIBART_HOST_CFLAGS := + ifeq ($(MALLOC_IMPL),dlmalloc) - LIBART_CFLAGS += -DUSE_DLMALLOC + LIBART_TARGET_CFLAGS += -DUSE_DLMALLOC else - LIBART_CFLAGS += -DUSE_JEMALLOC + LIBART_TARGET_CFLAGS += -DUSE_JEMALLOC endif # Default dex2oat instruction set features. @@ -440,8 +443,10 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT LOCAL_CFLAGS := $$(LIBART_CFLAGS) LOCAL_LDFLAGS := $$(LIBART_LDFLAGS) ifeq ($$(art_target_or_host),target) + LOCAL_CFLAGS += $$(LIBART_TARGET_CFLAGS) LOCAL_LDFLAGS += $$(LIBART_TARGET_LDFLAGS) else #host + LOCAL_CFLAGS += $$(LIBART_HOST_CFLAGS) LOCAL_LDFLAGS += $$(LIBART_HOST_LDFLAGS) ifeq ($$(art_static_or_shared),static) LOCAL_LDFLAGS += -static @@ -581,4 +586,6 @@ LIBART_HOST_SRC_FILES_32 := LIBART_HOST_SRC_FILES_64 := LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := LIBART_CFLAGS := +LIBART_TARGET_CFLAGS := +LIBART_HOST_CFLAGS := build-libart := diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index 548ab47f82..8ba3d4392d 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -537,18 +537,18 @@ SAVE_SIZE_AND_METHOD=SAVE_SIZE+8 // W10 - temporary add x9, sp, #8 // Destination address is bottom of stack + null. - // Use \@ to differentiate between macro invocations. -.LcopyParams\@: + // Copy parameters into the stack. Use numeric label as this is a macro and Clang's assembler + // does not have unique-id variables. +1: cmp w2, #0 - beq .LendCopyParams\@ + beq 2f sub w2, w2, #4 // Need 65536 bytes of range. ldr w10, [x1, x2] str w10, [x9, x2] - b .LcopyParams\@ - -.LendCopyParams\@: + b 1b +2: // Store null into ArtMethod* at bottom of frame. str xzr, [sp] .endm @@ -587,26 +587,29 @@ SAVE_SIZE_AND_METHOD=SAVE_SIZE+8 // Store result (w0/x0/s0/d0) appropriately, depending on resultType. ldrb w10, [x5] + // Check the return type and store the correct register into the jvalue in memory. + // Use numeric label as this is a macro and Clang's assembler does not have unique-id variables. + // Don't set anything for a void type. cmp w10, #'V' - beq .Lexit_art_quick_invoke_stub\@ + beq 3f + // Is it a double? cmp w10, #'D' - bne .Lreturn_is_float\@ + bne 1f str d0, [x4] - b .Lexit_art_quick_invoke_stub\@ + b 3f -.Lreturn_is_float\@: +1: // Is it a float? cmp w10, #'F' - bne .Lreturn_is_int\@ + bne 2f str s0, [x4] - b .Lexit_art_quick_invoke_stub\@ + b 3f - // Just store x0. Doesn't matter if it is 64 or 32 bits. -.Lreturn_is_int\@: +2: // Just store x0. Doesn't matter if it is 64 or 32 bits. str x0, [x4] -.Lexit_art_quick_invoke_stub\@: +3: // Finish up. ldp x2, x19, [xFP, #32] // Restore stack pointer and x19. .cfi_restore x19 mov sp, x2 diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 17c9fe4149..f37e0407ca 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -19,6 +19,7 @@ #include "arch/context.h" #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/out.h" #include "base/stringpiece.h" #include "dex_file-inl.h" #include "dex_instruction.h" @@ -565,7 +566,7 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param const uint8_t* ArtMethod::GetQuickenedInfo() { bool found = false; OatFile::OatMethod oat_method = - Runtime::Current()->GetClassLinker()->FindOatMethodFor(this, &found); + Runtime::Current()->GetClassLinker()->FindOatMethodFor(this, outof(found)); if (!found || (oat_method.GetQuickCode() != nullptr)) { return nullptr; } diff --git a/runtime/base/out.h b/runtime/base/out.h new file mode 100644 index 0000000000..7b4bc1216c --- /dev/null +++ b/runtime/base/out.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_OUT_H_ +#define ART_RUNTIME_BASE_OUT_H_ + +#include <base/macros.h> +#include <base/logging.h> + +#include <memory> +// A zero-overhead abstraction marker that means this value is meant to be used as an out +// parameter for functions. It mimics semantics of a pointer that the function will +// dereference and output its value into. +// +// Inspired by the 'out' language keyword in C#. +// +// Declaration example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Use-site example: +// // (1) -- out of a local variable or field +// int res; +// if (do_work(1, outof(res)) { +// cout << "success: " << res; +// } +// // (2) -- out of an iterator +// std::vector<int> list = {1}; +// std::vector<int>::iterator it = list.begin(); +// if (do_work(2, outof_iterator(*it)) { +// cout << "success: " << list[0]; +// } +// // (3) -- out of a pointer +// int* array = &some_other_value; +// if (do_work(3, outof_ptr(array))) { +// cout << "success: " << *array; +// } +// +// The type will also automatically decay into a C-style pointer for compatibility +// with calling legacy code that expect pointers. +// +// Declaration example: +// void write_data(int* res) { *res = 5; } +// +// Use-site example: +// int data; +// write_data(outof(res)); +// // data is now '5' +// (The other outof_* functions can be used analogously when the target is a C-style pointer). +// +// --------------- +// +// Other typical pointer operations such as addition, subtraction, etc are banned +// since there is exactly one value being output. +// +namespace art { + +// Forward declarations. See below for specific functions. +template <typename T> +struct out_convertible; // Implicitly converts to out<T> or T*. + +// Helper function that automatically infers 'T' +// +// Returns a type that is implicitly convertible to either out<T> or T* depending +// on the call site. +// +// Example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Usage: +// int res; +// if (do_work(1, outof(res)) { +// cout << "success: " << res; +// } +template <typename T> +out_convertible<T> outof(T& param) ALWAYS_INLINE; + +// Helper function that automatically infers 'T' from a container<T>::iterator. +// To use when the argument is already inside an iterator. +// +// Returns a type that is implicitly convertible to either out<T> or T* depending +// on the call site. +// +// Example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Usage: +// std::vector<int> list = {1}; +// std::vector<int>::iterator it = list.begin(); +// if (do_work(2, outof_iterator(*it)) { +// cout << "success: " << list[0]; +// } +template <typename It> +auto ALWAYS_INLINE outof_iterator(It iter) + -> out_convertible<typename std::remove_reference<decltype(*iter)>::type>; + +// Helper function that automatically infers 'T'. +// To use when the argument is already a pointer. +// +// ptr must be not-null, else a DCHECK failure will occur. +// +// Returns a type that is implicitly convertible to either out<T> or T* depending +// on the call site. +// +// Example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Usage: +// int* array = &some_other_value; +// if (do_work(3, outof_ptr(array))) { +// cout << "success: " << *array; +// } +template <typename T> +out_convertible<T> outof_ptr(T* ptr) ALWAYS_INLINE; + +// Zero-overhead wrapper around a non-null non-const pointer meant to be used to output +// the result of parameters. There are no other extra guarantees. +// +// The most common use case is to treat this like a typical pointer argument, for example: +// +// void write_out_5(out<int> x) { +// *x = 5; +// } +// +// The following operations are supported: +// operator* -> use like a pointer (guaranteed to be non-null) +// == and != -> compare against other pointers for (in)equality +// begin/end -> use in standard C++ algorithms as if it was an iterator +template <typename T> +struct out { + // Has to be mutable lref. Otherwise how would you write something as output into it? + explicit inline out(T& param) + : param_(param) {} + + // Model a single-element iterator (or pointer) to the parameter. + inline T& operator *() { + return param_; + } + + // Model dereferencing fields/methods on a pointer. + inline T* operator->() { + return std::addressof(param_); + } + + // + // Comparison against this or other pointers. + // + template <typename T2> + inline bool operator==(const T2* other) const { + return std::addressof(param_) == other; + } + + template <typename T2> + inline bool operator==(const out<T>& other) const { + return std::addressof(param_) == std::addressof(other.param_); + } + + // An out-parameter is never null. + inline bool operator==(std::nullptr_t) const { + return false; + } + + template <typename T2> + inline bool operator!=(const T2* other) const { + return std::addressof(param_) != other; + } + + template <typename T2> + inline bool operator!=(const out<T>& other) const { + return std::addressof(param_) != std::addressof(other.param_); + } + + // An out-parameter is never null. + inline bool operator!=(std::nullptr_t) const { + return true; + } + + // + // Iterator interface implementation. Use with standard algorithms. + // TODO: (add items in iterator_traits if this is truly useful). + // + + inline T* begin() { + return std::addressof(param_); + } + + inline const T* begin() const { + return std::addressof(param_); + } + + inline T* end() { + return std::addressof(param_) + 1; + } + + inline const T* end() const { + return std::addressof(param_) + 1; + } + + private: + T& param_; +}; + +// +// IMPLEMENTATION DETAILS +// + +// +// This intermediate type should not be used directly by user code. +// +// It enables 'outof(x)' to be passed into functions that expect either +// an out<T> **or** a regular C-style pointer (T*). +// +template <typename T> +struct out_convertible { + explicit inline out_convertible(T& param) + : param_(param) { + } + + // Implicitly convert into an out<T> for standard usage. + inline operator out<T>() { + return out<T>(param_); + } + + // Implicitly convert into a '*' for legacy usage. + inline operator T*() { + return std::addressof(param_); + } + private: + T& param_; +}; + +// Helper function that automatically infers 'T' +template <typename T> +inline out_convertible<T> outof(T& param) { + return out_convertible<T>(param); +} + +// Helper function that automatically infers 'T'. +// To use when the argument is already inside an iterator. +template <typename It> +inline auto outof_iterator(It iter) + -> out_convertible<typename std::remove_reference<decltype(*iter)>::type> { + return outof(*iter); +} + +// Helper function that automatically infers 'T'. +// To use when the argument is already a pointer. +template <typename T> +inline out_convertible<T> outof_ptr(T* ptr) { + DCHECK(ptr != nullptr); + return outof(*ptr); +} + +// Helper function that automatically infers 'T'. +// Forwards an out parameter from one function into another. +template <typename T> +inline out_convertible<T> outof_forward(out<T>& out_param) { + T& param = *out_param; + return out_convertible<T>(param); +} + +} // namespace art +#endif // ART_RUNTIME_BASE_OUT_H_ diff --git a/runtime/base/out_fwd.h b/runtime/base/out_fwd.h new file mode 100644 index 0000000000..6b2f926429 --- /dev/null +++ b/runtime/base/out_fwd.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_OUT_FWD_H_ +#define ART_RUNTIME_BASE_OUT_FWD_H_ + +// Forward declaration for "out<T>". See <out.h> for more information. +// Other headers use only the forward declaration. + +// Callers of functions that take an out<T> parameter should #include <out.h> to get outof_. +// which constructs out<T> through type inference. +namespace art { +template <typename T> +struct out; +} // namespace art + +#endif // ART_RUNTIME_BASE_OUT_FWD_H_ diff --git a/runtime/base/out_test.cc b/runtime/base/out_test.cc new file mode 100644 index 0000000000..427420035b --- /dev/null +++ b/runtime/base/out_test.cc @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 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 "out.h" + +#include <algorithm> +#include <gtest/gtest.h> + +namespace art { + +struct OutTest : public testing::Test { + // Multiplies values less than 10 by two, stores the result and returns 0. + // Returns -1 if the original value was not multiplied by two. + static int multiply_small_values_by_two(size_t args, out<int> result) { + if (args < 10) { + *result = args * 2; + return 0; + } else { + return -1; + } + } +}; + +extern "C" int multiply_small_values_by_two_legacy(size_t args, int* result) { + if (args < 10) { + *result = args * 2; + return 0; + } else { + return -1; + } +} + +TEST_F(OutTest, TraditionalCall) { + // For calling traditional C++ functions. + int res; + EXPECT_EQ(multiply_small_values_by_two(1, outof(res)), 0); + EXPECT_EQ(2, res); +} + +TEST_F(OutTest, LegacyCall) { + // For calling legacy, e.g. C-style functions. + int res2; + EXPECT_EQ(0, multiply_small_values_by_two_legacy(1, outof(res2))); + EXPECT_EQ(2, res2); +} + +TEST_F(OutTest, CallFromIterator) { + // For calling a function with a parameter originating as an iterator. + std::vector<int> list = {1, 2, 3}; // NOLINT [whitespace/labels] [4] + std::vector<int>::iterator it = list.begin(); + + EXPECT_EQ(0, multiply_small_values_by_two(2, outof_iterator(it))); + EXPECT_EQ(4, list[0]); +} + +TEST_F(OutTest, CallFromPointer) { + // For calling a function with a parameter originating as a C-pointer. + std::vector<int> list = {1, 2, 3}; // NOLINT [whitespace/labels] [4] + + int* list_ptr = &list[2]; // 3 + + EXPECT_EQ(0, multiply_small_values_by_two(2, outof_ptr(list_ptr))); + EXPECT_EQ(4, list[2]); +} + +TEST_F(OutTest, OutAsIterator) { + // For using the out<T> parameter as an iterator inside of the callee. + std::vector<int> list; + int x = 100; + out<int> out_from_x = outof(x); + + for (const int& val : out_from_x) { + list.push_back(val); + } + + ASSERT_EQ(1u, list.size()); + EXPECT_EQ(100, list[0]); + + // A more typical use-case would be to use std algorithms + EXPECT_NE(out_from_x.end(), + std::find(out_from_x.begin(), + out_from_x.end(), + 100)); // Search for '100' in out. +} + +} // namespace art diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 11901b3bef..c08417f542 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -117,8 +117,10 @@ inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* return resolved_method; } -inline ArtMethod* ClassLinker::ResolveMethod(Thread* self, uint32_t method_idx, - ArtMethod* referrer, InvokeType type) { +inline ArtMethod* ClassLinker::ResolveMethod(Thread* self, + uint32_t method_idx, + ArtMethod* referrer, + InvokeType type) { ArtMethod* resolved_method = GetResolvedMethod(method_idx, referrer); if (UNLIKELY(resolved_method == nullptr)) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); @@ -143,7 +145,8 @@ inline ArtField* ClassLinker::GetResolvedField( return GetResolvedField(field_idx, field_declaring_class->GetDexCache()); } -inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, ArtMethod* referrer, +inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, + ArtMethod* referrer, bool is_static) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); ArtField* resolved_field = GetResolvedField(field_idx, declaring_class); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 56fae81512..5f5b42f7df 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -30,6 +30,7 @@ #include "base/arena_allocator.h" #include "base/casts.h" #include "base/logging.h" +#include "base/out.h" #include "base/scoped_arena_containers.h" #include "base/scoped_flock.h" #include "base/stl_util.h" @@ -198,7 +199,7 @@ struct FieldGapsComparator { return lhs.size < rhs.size || (lhs.size == rhs.size && lhs.start_offset > rhs.start_offset); } }; -typedef std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator> FieldGaps; +using FieldGaps = std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator>; // Adds largest aligned gaps to queue of gaps. static void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) { @@ -775,7 +776,8 @@ class DexFileAndClassPair : ValueObject { // be from multidex, which resolves correctly). }; -static void AddDexFilesFromOat(const OatFile* oat_file, bool already_loaded, +static void AddDexFilesFromOat(const OatFile* oat_file, + bool already_loaded, std::priority_queue<DexFileAndClassPair>* heap) { const std::vector<const OatDexFile*>& oat_dex_files = oat_file->GetOatDexFiles(); for (const OatDexFile* oat_dex_file : oat_dex_files) { @@ -836,7 +838,7 @@ const OatFile* ClassLinker::GetPrimaryOatFile() { // against the following top element. If the descriptor is the same, it is now checked whether // the two elements agree on whether their dex file was from an already-loaded oat-file or the // new oat file. Any disagreement indicates a collision. -bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg) { +bool ClassLinker::HasCollisions(const OatFile* oat_file, out<std::string> error_msg) { if (!kDuplicateClassesCheck) { return false; } @@ -901,10 +903,9 @@ bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg) } std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat( - const char* dex_location, const char* oat_location, - std::vector<std::string>* error_msgs) { - CHECK(error_msgs != nullptr); - + const char* dex_location, + const char* oat_location, + out<std::vector<std::string>> error_msgs) { // Verify we aren't holding the mutator lock, which could starve GC if we // have to generate or relocate an oat file. Locks::mutator_lock_->AssertNotHeld(Thread::Current()); @@ -946,7 +947,7 @@ std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat( std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); if (oat_file.get() != nullptr) { // Take the file only if it has no collisions, or we must take it because of preopting. - bool accept_oat_file = !HasCollisions(oat_file.get(), &error_msg); + bool accept_oat_file = !HasCollisions(oat_file.get(), outof(error_msg)); if (!accept_oat_file) { // Failed the collision check. Print warning. if (Runtime::Current()->IsDexFileFallbackEnabled()) { @@ -980,8 +981,7 @@ std::vector<std::unique_ptr<const DexFile>> ClassLinker::OpenDexFilesFromOat( if (source_oat_file != nullptr) { dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); if (dex_files.empty()) { - error_msgs->push_back("Failed to open dex files from " - + source_oat_file->GetLocation()); + error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation()); } } @@ -1017,7 +1017,8 @@ const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& return nullptr; } -static void SanityCheckArtMethod(ArtMethod* m, mirror::Class* expected_class, +static void SanityCheckArtMethod(ArtMethod* m, + mirror::Class* expected_class, gc::space::ImageSpace* space) SHARED_REQUIRES(Locks::mutator_lock_) { if (m->IsRuntimeMethod()) { @@ -1035,9 +1036,11 @@ static void SanityCheckArtMethod(ArtMethod* m, mirror::Class* expected_class, } } -static void SanityCheckArtMethodPointerArray( - mirror::PointerArray* arr, mirror::Class* expected_class, size_t pointer_size, - gc::space::ImageSpace* space) SHARED_REQUIRES(Locks::mutator_lock_) { +static void SanityCheckArtMethodPointerArray(mirror::PointerArray* arr, + mirror::Class* expected_class, + size_t pointer_size, + gc::space::ImageSpace* space) + SHARED_REQUIRES(Locks::mutator_lock_) { CHECK(arr != nullptr); for (int32_t j = 0; j < arr->GetLength(); ++j) { auto* method = arr->GetElementPtrSize<ArtMethod*>(j, pointer_size); @@ -1503,7 +1506,8 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_fi return dex_cache.Get(); } -mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class, +mirror::Class* ClassLinker::AllocClass(Thread* self, + mirror::Class* java_lang_Class, uint32_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); gc::Heap* heap = Runtime::Current()->GetHeap(); @@ -1522,13 +1526,14 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, uint32_t class_size) { return AllocClass(self, GetClassRoot(kJavaLangClass), class_size); } -mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray( - Thread* self, size_t length) { +mirror::ObjectArray<mirror::StackTraceElement>* +ClassLinker::AllocStackTraceElementArray(Thread* self, size_t length) { return mirror::ObjectArray<mirror::StackTraceElement>::Alloc( self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length); } -mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor, +mirror::Class* ClassLinker::EnsureResolved(Thread* self, + const char* descriptor, mirror::Class* klass) { DCHECK(klass != nullptr); @@ -1587,7 +1592,8 @@ typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry; // Search a collection of DexFiles for a descriptor ClassPathEntry FindInClassPath(const char* descriptor, - size_t hash, const std::vector<const DexFile*>& class_path) { + size_t hash, + const std::vector<const DexFile*>& class_path) { for (const DexFile* dex_file : class_path) { const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor, hash); if (dex_class_def != nullptr) { @@ -1606,16 +1612,17 @@ static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, } bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa, - Thread* self, const char* descriptor, + Thread* self, + const char* descriptor, size_t hash, Handle<mirror::ClassLoader> class_loader, - mirror::Class** result) { + out<mirror::Class*> result) { // Termination case: boot class-loader. if (IsBootClassLoader(soa, class_loader.Get())) { // The boot class loader, search the boot class path. ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); if (pair.second != nullptr) { - mirror::Class* klass = LookupClass(self, descriptor, hash, nullptr); + mirror::Class* klass = LookupClass(self, descriptor, hash, nullptr /* no classloader */); if (klass != nullptr) { *result = EnsureResolved(self, descriptor, klass); } else { @@ -1717,7 +1724,8 @@ bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& return true; } -mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, +mirror::Class* ClassLinker::FindClass(Thread* self, + const char* descriptor, Handle<mirror::ClassLoader> class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; DCHECK(self != nullptr); @@ -1753,7 +1761,7 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, } else { ScopedObjectAccessUnchecked soa(self); mirror::Class* cp_klass; - if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) { + if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, outof(cp_klass))) { // The chain was understood. So the value in cp_klass is either the class we were looking // for, or not found. if (cp_klass != nullptr) { @@ -1806,7 +1814,9 @@ mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor, UNREACHABLE(); } -mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash, +mirror::Class* ClassLinker::DefineClass(Thread* self, + const char* descriptor, + size_t hash, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { @@ -1892,7 +1902,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, si auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr); MutableHandle<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(nullptr); - if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) { + if (!LinkClass(self, descriptor, klass, interfaces, outof(h_new_class))) { // Linking failed. if (!klass->IsErroneous()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); @@ -1975,8 +1985,9 @@ uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, image_pointer_size_); } -OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, - bool* found) { +OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, + uint16_t class_def_idx, + out<bool> found) { DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file == nullptr) { @@ -1987,7 +1998,8 @@ OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, uint16_t cl return oat_dex_file->GetOatClass(class_def_idx); } -static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, +static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, + uint16_t class_def_idx, uint32_t method_idx) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); const uint8_t* class_data = dex_file.GetClassData(class_def); @@ -2021,7 +2033,7 @@ static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16 UNREACHABLE(); } -const OatFile::OatMethod ClassLinker::FindOatMethodFor(ArtMethod* method, bool* found) { +const OatFile::OatMethod ClassLinker::FindOatMethodFor(ArtMethod* method, out<bool> found) { // Although we overwrite the trampoline of non-static methods, we may get here via the resolution // method for direct methods (or virtual methods made direct). mirror::Class* declaring_class = method->GetDeclaringClass(); @@ -2053,7 +2065,7 @@ const OatFile::OatMethod ClassLinker::FindOatMethodFor(ArtMethod* method, bool* method->GetDexMethodIndex())); OatFile::OatClass oat_class = FindOatClass(*declaring_class->GetDexCache()->GetDexFile(), declaring_class->GetDexClassDefIndex(), - found); + outof_forward(found)); if (!(*found)) { return OatFile::OatMethod::Invalid(); } @@ -2067,7 +2079,7 @@ const void* ClassLinker::GetQuickOatCodeFor(ArtMethod* method) { return GetQuickProxyInvokeHandler(); } bool found; - OatFile::OatMethod oat_method = FindOatMethodFor(method, &found); + OatFile::OatMethod oat_method = FindOatMethodFor(method, outof(found)); if (found) { auto* code = oat_method.GetQuickCode(); if (code != nullptr) { @@ -2093,7 +2105,7 @@ const void* ClassLinker::GetOatMethodQuickCodeFor(ArtMethod* method) { return nullptr; } bool found; - OatFile::OatMethod oat_method = FindOatMethodFor(method, &found); + OatFile::OatMethod oat_method = FindOatMethodFor(method, outof(found)); if (found) { return oat_method.GetQuickCode(); } @@ -2107,10 +2119,11 @@ const void* ClassLinker::GetOatMethodQuickCodeFor(ArtMethod* method) { return nullptr; } -const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, +const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, + uint16_t class_def_idx, uint32_t method_idx) { bool found; - OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found); + OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, outof(found)); if (!found) { return nullptr; } @@ -2161,7 +2174,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { } bool has_oat_class; OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), - &has_oat_class); + outof(has_oat_class)); // Link the code of methods skipped by LinkCode. for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_); @@ -2189,7 +2202,8 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // Ignore virtual methods on the iterator. } -void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class, +void ClassLinker::LinkCode(ArtMethod* method, + const OatFile::OatClass* oat_class, uint32_t class_def_method_index) { Runtime* const runtime = Runtime::Current(); if (runtime->IsAotCompiler()) { @@ -2241,8 +2255,10 @@ void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class } } -void ClassLinker::SetupClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - Handle<mirror::Class> klass, mirror::ClassLoader* class_loader) { +void ClassLinker::SetupClass(const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def, + Handle<mirror::Class> klass, + mirror::ClassLoader* class_loader) { CHECK(klass.Get() != nullptr); CHECK(klass->GetDexCache() != nullptr); CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus()); @@ -2262,7 +2278,8 @@ void ClassLinker::SetupClass(const DexFile& dex_file, const DexFile::ClassDef& d CHECK(klass->GetDexCacheStrings() != nullptr); } -void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file, +void ClassLinker::LoadClass(Thread* self, + const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, Handle<mirror::Class> klass) { const uint8_t* class_data = dex_file.GetClassData(dex_class_def); @@ -2272,7 +2289,7 @@ void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file, bool has_oat_class = false; if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) { OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), - &has_oat_class); + outof(has_oat_class)); if (has_oat_class) { LoadClassMembers(self, dex_file, class_data, klass, &oat_class); } @@ -2301,7 +2318,8 @@ ArtMethod* ClassLinker::AllocArtMethodArray(Thread* self, size_t length) { return reinterpret_cast<ArtMethod*>(ptr); } -void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file, +void ClassLinker::LoadClassMembers(Thread* self, + const DexFile& dex_file, const uint8_t* class_data, Handle<mirror::Class> klass, const OatFile::OatClass* oat_class) { @@ -2396,7 +2414,8 @@ void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file, self->AllowThreadSuspension(); } -void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, +void ClassLinker::LoadField(const ClassDataItemIterator& it, + Handle<mirror::Class> klass, ArtField* dst) { const uint32_t field_idx = it.GetMemberIndex(); dst->SetDexFieldIndex(field_idx); @@ -2404,8 +2423,11 @@ void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Clas dst->SetAccessFlags(it.GetFieldAccessFlags()); } -void ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it, - Handle<mirror::Class> klass, ArtMethod* dst) { +void ClassLinker::LoadMethod(Thread* self, + const DexFile& dex_file, + const ClassDataItemIterator& it, + Handle<mirror::Class> klass, + ArtMethod* dst) { 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_); @@ -2605,7 +2627,9 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_cl // array class; that always comes from the base element class. // // Returns null with an exception raised on failure. -mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor, size_t hash, +mirror::Class* ClassLinker::CreateArrayClass(Thread* self, + const char* descriptor, + size_t hash, Handle<mirror::ClassLoader> class_loader) { // Identify the underlying component type CHECK_EQ('[', descriptor[0]); @@ -2807,7 +2831,8 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* k return nullptr; } -void ClassLinker::UpdateClassVirtualMethods(mirror::Class* klass, ArtMethod* new_methods, +void ClassLinker::UpdateClassVirtualMethods(mirror::Class* klass, + ArtMethod* new_methods, size_t new_num_methods) { // TODO: Fix the race condition here. b/22832610 klass->SetNumVirtualMethods(new_num_methods); @@ -2822,7 +2847,9 @@ bool ClassLinker::RemoveClass(const char* descriptor, mirror::ClassLoader* class return class_table != nullptr && class_table->Remove(descriptor); } -mirror::Class* ClassLinker::LookupClass(Thread* self, const char* descriptor, size_t hash, +mirror::Class* ClassLinker::LookupClass(Thread* self, + const char* descriptor, + size_t hash, mirror::ClassLoader* class_loader) { { ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); @@ -2926,7 +2953,9 @@ mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) { return nullptr; } -void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& result) { +void ClassLinker::LookupClasses(const char* descriptor, + out<std::vector<mirror::Class*>> out_result) { + std::vector<mirror::Class*>& result = *out_result; result.clear(); if (dex_cache_image_class_lookup_required_) { MoveImageClassesToClassTable(); @@ -3103,7 +3132,8 @@ void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) { } } -bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass, +bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, + mirror::Class* klass, mirror::Class::Status& oat_file_class_status) { // If we're compiling, we can only verify the class using the oat file if // we are not compiling the image or if the class we're verifying is not part of @@ -3225,9 +3255,12 @@ void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, } } -mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, - jobjectArray interfaces, jobject loader, - jobjectArray methods, jobjectArray throws) { +mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, + jstring name, + jobjectArray interfaces, + jobject loader, + jobjectArray methods, + jobjectArray throws) { Thread* self = soa.Self(); StackHandleScope<10> hs(self); MutableHandle<mirror::Class> klass(hs.NewHandle( @@ -3322,7 +3355,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& // The new class will replace the old one in the class table. Handle<mirror::ObjectArray<mirror::Class>> h_interfaces( hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces))); - if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) { + if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, outof(new_class))) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); return nullptr; } @@ -3427,7 +3460,8 @@ void ClassLinker::CheckProxyConstructor(ArtMethod* constructor) const { DCHECK(constructor->IsPublic()); } -void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, +void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, + ArtMethod* prototype, ArtMethod* out) { // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden // prototype method @@ -3473,7 +3507,8 @@ void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) cons CHECK_EQ(np->GetReturnType(), prototype->GetReturnType()); } -bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, +bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, + bool can_init_statics, bool can_init_parents) { if (can_init_statics && can_init_parents) { return true; @@ -3503,8 +3538,10 @@ bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_stati return CanWeInitializeClass(super_class, can_init_statics, can_init_parents); } -bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, - bool can_init_statics, bool can_init_parents) { +bool ClassLinker::InitializeClass(Thread* self, + Handle<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 // Are we already initialized and therefore done? @@ -3573,7 +3610,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, return true; } // No. That's fine. Wait for another thread to finish initializing. - return WaitForInitializeClass(klass, self, lock); + return WaitForInitializeClass(klass, self, &lock); } if (!ValidateSuperClassDescriptors(klass)) { @@ -3707,13 +3744,16 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, return success; } -bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self, - ObjectLock<mirror::Class>& lock) +bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, + Thread* self, + ObjectLock<mirror::Class>* lock) SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(lock != nullptr); + while (true) { self->AssertNoPendingException(); CHECK(!klass->IsInitialized()); - lock.WaitIgnoringInterrupts(); + lock->WaitIgnoringInterrupts(); // When we wake up, repeat the test for init-in-progress. If // there's an exception pending (only possible if @@ -3776,7 +3816,8 @@ static void ThrowSignatureCheckResolveArgException(Handle<mirror::Class> klass, Handle<mirror::Class> super_klass, ArtMethod* method, ArtMethod* m, - uint32_t index, uint32_t arg_type_idx) + uint32_t index, + uint32_t arg_type_idx) SHARED_REQUIRES(Locks::mutator_lock_) { DCHECK(Thread::Current()->IsExceptionPending()); DCHECK(!m->IsProxyMethod()); @@ -3938,7 +3979,8 @@ bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) { return true; } -bool ClassLinker::EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool can_init_fields, +bool ClassLinker::EnsureInitialized(Thread* self, Handle<mirror::Class> c, + bool can_init_fields, bool can_init_parents) { DCHECK(c.Get() != nullptr); if (c->IsInitialized()) { @@ -4012,9 +4054,11 @@ ClassTable* ClassLinker::ClassTableForClassLoader(mirror::ClassLoader* class_loa return nullptr; } -bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass, +bool ClassLinker::LinkClass(Thread* self, + const char* descriptor, + Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - MutableHandle<mirror::Class>* h_new_class_out) { + out<MutableHandle<mirror::Class>> h_new_class_out) { CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); if (!LinkSuperClass(klass)) { @@ -4022,14 +4066,14 @@ bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror: } ArtMethod* imt[mirror::Class::kImtSize]; std::fill_n(imt, arraysize(imt), Runtime::Current()->GetImtUnimplementedMethod()); - if (!LinkMethods(self, klass, interfaces, imt)) { + if (!LinkMethods(self, klass, interfaces, outof(imt))) { return false; } if (!LinkInstanceFields(self, klass)) { return false; } size_t class_size; - if (!LinkStaticFields(self, klass, &class_size)) { + if (!LinkStaticFields(self, klass, outof(class_size))) { return false; } CreateReferenceInstanceOffsets(klass); @@ -4105,30 +4149,31 @@ bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror: return true; } -static void CountMethodsAndFields(ClassDataItemIterator& dex_data, - size_t* virtual_methods, - size_t* direct_methods, - size_t* static_fields, - size_t* instance_fields) { +static void CountMethodsAndFields(ClassDataItemIterator* dex_data, + out<size_t> virtual_methods, + out<size_t> direct_methods, + out<size_t> static_fields, + out<size_t> instance_fields) { + DCHECK(dex_data != nullptr); *virtual_methods = *direct_methods = *static_fields = *instance_fields = 0; - while (dex_data.HasNextStaticField()) { - dex_data.Next(); + while (dex_data->HasNextStaticField()) { + dex_data->Next(); (*static_fields)++; } - while (dex_data.HasNextInstanceField()) { - dex_data.Next(); + while (dex_data->HasNextInstanceField()) { + dex_data->Next(); (*instance_fields)++; } - while (dex_data.HasNextDirectMethod()) { + while (dex_data->HasNextDirectMethod()) { (*direct_methods)++; - dex_data.Next(); + dex_data->Next(); } - while (dex_data.HasNextVirtualMethod()) { + while (dex_data->HasNextVirtualMethod()) { (*virtual_methods)++; - dex_data.Next(); + dex_data->Next(); } - DCHECK(!dex_data.HasNext()); + DCHECK(!dex_data->HasNext()); } static void DumpClass(std::ostream& os, @@ -4162,8 +4207,10 @@ static void DumpClass(std::ostream& os, } } -static std::string DumpClasses(const DexFile& dex_file1, const DexFile::ClassDef& dex_class_def1, - const DexFile& dex_file2, const DexFile::ClassDef& dex_class_def2) { +static std::string DumpClasses(const DexFile& dex_file1, + const DexFile::ClassDef& dex_class_def1, + const DexFile& dex_file2, + const DexFile::ClassDef& dex_class_def2) { std::ostringstream os; DumpClass(os, dex_file1, dex_class_def1, " (Compile time)"); DumpClass(os, dex_file2, dex_class_def2, " (Runtime)"); @@ -4173,20 +4220,28 @@ static std::string DumpClasses(const DexFile& dex_file1, const DexFile::ClassDef // Very simple structural check on whether the classes match. Only compares the number of // methods and fields. -static bool SimpleStructuralCheck(const DexFile& dex_file1, const DexFile::ClassDef& dex_class_def1, - const DexFile& dex_file2, const DexFile::ClassDef& dex_class_def2, +static bool SimpleStructuralCheck(const DexFile& dex_file1, + const DexFile::ClassDef& dex_class_def1, + const DexFile& dex_file2, + const DexFile::ClassDef& dex_class_def2, std::string* error_msg) { ClassDataItemIterator dex_data1(dex_file1, dex_file1.GetClassData(dex_class_def1)); ClassDataItemIterator dex_data2(dex_file2, dex_file2.GetClassData(dex_class_def2)); // Counters for current dex file. size_t dex_virtual_methods1, dex_direct_methods1, dex_static_fields1, dex_instance_fields1; - CountMethodsAndFields(dex_data1, &dex_virtual_methods1, &dex_direct_methods1, &dex_static_fields1, - &dex_instance_fields1); + CountMethodsAndFields(&dex_data1, + outof(dex_virtual_methods1), + outof(dex_direct_methods1), + outof(dex_static_fields1), + outof(dex_instance_fields1)); // Counters for compile-time dex file. size_t dex_virtual_methods2, dex_direct_methods2, dex_static_fields2, dex_instance_fields2; - CountMethodsAndFields(dex_data2, &dex_virtual_methods2, &dex_direct_methods2, &dex_static_fields2, - &dex_instance_fields2); + CountMethodsAndFields(&dex_data2, + outof(dex_virtual_methods2), + outof(dex_direct_methods2), + outof(dex_static_fields2), + outof(dex_instance_fields2)); if (dex_virtual_methods1 != dex_virtual_methods2) { std::string class_dump = DumpClasses(dex_file1, dex_class_def1, dex_file2, dex_class_def2); @@ -4389,9 +4444,10 @@ bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) { } // Populate the class vtable and itable. Compute return type indices. -bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass, +bool ClassLinker::LinkMethods(Thread* self, + Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - ArtMethod** out_imt) { + out<ArtMethod* [mirror::Class::kImtSize]> out_imt) { self->AllowThreadSuspension(); if (klass->IsInterface()) { // No vtable. @@ -4406,7 +4462,10 @@ bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass, } else if (!LinkVirtualMethods(self, klass)) { // Link virtual methods first. return false; } - return LinkInterfaceMethods(self, klass, interfaces, out_imt); // Link interface method last. + return LinkInterfaceMethods(self, + klass, + interfaces, + outof_forward(out_imt)); // Link interface method last. } // Comparator for name and signature of a method, used in finding overriding methods. Implementation @@ -4459,7 +4518,9 @@ class MethodNameAndSignatureComparator FINAL : public ValueObject { class LinkVirtualHashTable { public: - LinkVirtualHashTable(Handle<mirror::Class> klass, size_t hash_size, uint32_t* hash_table, + LinkVirtualHashTable(Handle<mirror::Class> klass, + size_t hash_size, + uint32_t* hash_table, size_t image_pointer_size) : klass_(klass), hash_size_(hash_size), hash_table_(hash_table), image_pointer_size_(image_pointer_size) { @@ -4663,9 +4724,12 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) return true; } -bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass, +bool ClassLinker::LinkInterfaceMethods(Thread* self, + Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - ArtMethod** out_imt) { + out<ArtMethod* [mirror::Class::kImtSize]> out_imt_array) { + auto& out_imt = *out_imt_array; + StackHandleScope<3> hs(self); Runtime* const runtime = Runtime::Current(); const bool has_superclass = klass->HasSuperClass(); @@ -4853,7 +4917,7 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass } } - auto* old_cause = self->StartAssertNoThreadSuspension( + const char* old_cause = self->StartAssertNoThreadSuspension( "Copying ArtMethods for LinkInterfaceMethods"); for (size_t i = 0; i < ifcount; ++i) { size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); @@ -5074,12 +5138,16 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass bool ClassLinker::LinkInstanceFields(Thread* self, Handle<mirror::Class> klass) { CHECK(klass.Get() != nullptr); - return LinkFields(self, klass, false, nullptr); + size_t class_size_dont_care; + UNUSED(class_size_dont_care); // This doesn't get set for instance fields. + return LinkFields(self, klass, false, outof(class_size_dont_care)); } -bool ClassLinker::LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size) { +bool ClassLinker::LinkStaticFields(Thread* self, + Handle<mirror::Class> klass, + out<size_t> class_size) { CHECK(klass.Get() != nullptr); - return LinkFields(self, klass, true, class_size); + return LinkFields(self, klass, true, outof_forward(class_size)); } struct LinkFieldsComparator { @@ -5116,8 +5184,10 @@ struct LinkFieldsComparator { } }; -bool ClassLinker::LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_static, - size_t* class_size) { +bool ClassLinker::LinkFields(Thread* self, + Handle<mirror::Class> klass, + bool is_static, + out<size_t> class_size) { self->AllowThreadSuspension(); const size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields(); ArtField* const fields = is_static ? klass->GetSFields() : klass->GetIFields(); @@ -5288,7 +5358,8 @@ void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) { klass->SetReferenceInstanceOffsets(reference_offsets); } -mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx, +mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, + uint32_t string_idx, Handle<mirror::DexCache> dex_cache) { DCHECK(dex_cache.Get() != nullptr); mirror::String* resolved = dex_cache->GetResolvedString(string_idx); @@ -5302,7 +5373,8 @@ mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t str return string; } -mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx, +mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, + uint16_t type_idx, mirror::Class* referrer) { StackHandleScope<2> hs(Thread::Current()); Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); @@ -5310,7 +5382,8 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i return ResolveType(dex_file, type_idx, dex_cache, class_loader); } -mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx, +mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, + uint16_t type_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { DCHECK(dex_cache.Get() != nullptr); @@ -5343,7 +5416,8 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i return resolved; } -ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx, +ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, + uint32_t method_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer, InvokeType type) { @@ -5500,9 +5574,11 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_i } } -ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx, +ArtField* ClassLinker::ResolveField(const DexFile& dex_file, + uint32_t field_idx, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, bool is_static) { + Handle<mirror::ClassLoader> class_loader, + bool is_static) { DCHECK(dex_cache.Get() != nullptr); ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_); if (resolved != nullptr) { @@ -5541,7 +5617,8 @@ ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx, return resolved; } -ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx, +ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, + uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { DCHECK(dex_cache.Get() != nullptr); @@ -5571,7 +5648,8 @@ ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, uint32_t field_i return resolved; } -const char* ClassLinker::MethodShorty(uint32_t method_idx, ArtMethod* referrer, +const char* ClassLinker::MethodShorty(uint32_t method_idx, + ArtMethod* referrer, uint32_t* length) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); mirror::DexCache* dex_cache = declaring_class->GetDexCache(); @@ -5778,7 +5856,8 @@ bool ClassLinker::MayBeCalledWithDirectCodePointer(ArtMethod* m) { } } -jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFile*>& dex_files) { +jobject ClassLinker::CreatePathClassLoader(Thread* self, + const std::vector<const DexFile*>& dex_files) { // SOAAlreadyRunnable is protected, and we need something to add a global reference. // We could move the jobject to the callers, but all call-sites do this... ScopedObjectAccessUnchecked soa(self); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index c53ff616e5..54f1f3dac8 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -25,6 +25,7 @@ #include "base/hash_set.h" #include "base/macros.h" #include "base/mutex.h" +#include "base/out_fwd.h" #include "class_table.h" #include "dex_file.h" #include "gc_root.h" @@ -108,16 +109,19 @@ class ClassLinker { // Initialize class linker by bootstraping from dex files. void InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Initialize class linker from one or more images. void InitFromImage() SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); // Finds a class by its descriptor, loading it if necessary. // If class_loader is null, searches boot_class_path_. - mirror::Class* FindClass(Thread* self, const char* descriptor, + mirror::Class* FindClass(Thread* self, + const char* descriptor, Handle<mirror::ClassLoader> class_loader) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Finds a class in the path class loader, loading it if necessary without using JNI. Hash // function is supposed to be ComputeModifiedUtf8Hash(descriptor). Returns true if the @@ -125,19 +129,24 @@ class ClassLinker { // was encountered while walking the parent chain (currently only BootClassLoader and // PathClassLoader are supported). bool FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa, - Thread* self, const char* descriptor, size_t hash, + Thread* self, + const char* descriptor, + size_t hash, Handle<mirror::ClassLoader> class_loader, - mirror::Class** result) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + out<mirror::Class*> result) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Finds a class by its descriptor using the "system" class loader, ie by searching the // boot_class_path_. mirror::Class* FindSystemClass(Thread* self, const char* descriptor) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Finds the array class given for the element class. - mirror::Class* FindArrayClass(Thread* self, mirror::Class** element_class) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + mirror::Class* FindArrayClass(Thread* self, /* in parameter */ mirror::Class** element_class) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Returns true if the class linker is initialized. bool IsInitialized() const { @@ -145,20 +154,27 @@ class ClassLinker { } // Define a new a class based on a ClassDef from a DexFile - mirror::Class* DefineClass(Thread* self, const char* descriptor, size_t hash, + mirror::Class* DefineClass(Thread* self, + const char* descriptor, + size_t hash, Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Finds a class by its descriptor, returning null if it isn't wasn't loaded // by the given 'class_loader'. - mirror::Class* LookupClass(Thread* self, const char* descriptor, size_t hash, - mirror::ClassLoader* class_loader) + mirror::Class* LookupClass(Thread* self, + const char* descriptor, + size_t hash, + mirror::ClassLoader* + class_loader) REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Finds all the classes with the given descriptor, regardless of ClassLoader. - void LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) + void LookupClasses(const char* descriptor, out<std::vector<mirror::Class*>> classes) REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); @@ -166,17 +182,21 @@ class ClassLinker { // General class unloading is not supported, this is used to prune // unwanted classes during image writing. - bool RemoveClass(const char* descriptor, mirror::ClassLoader* class_loader) - REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + bool RemoveClass(const char* descriptor, + mirror::ClassLoader* class_loader) + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); void DumpAllClasses(int flags) - REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::classlinker_classes_lock_); size_t NumLoadedClasses() - REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Resolve a String with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identify the @@ -186,75 +206,95 @@ 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, + mirror::String* ResolveString(const DexFile& dex_file, + uint32_t string_idx, Handle<mirror::DexCache> dex_cache) SHARED_REQUIRES(Locks::mutator_lock_); // Resolve a Type with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identity the // target DexCache and ClassLoader to use for resolution. - mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx, mirror::Class* referrer) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + mirror::Class* ResolveType(const DexFile& dex_file, + uint16_t type_idx, + mirror::Class* referrer) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Resolve a Type with the given index from the DexFile, storing the // result in the DexCache. The referrer is used to identify the // target DexCache and ClassLoader to use for resolution. - mirror::Class* ResolveType(uint16_t type_idx, ArtMethod* referrer) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + mirror::Class* ResolveType(uint16_t type_idx, + ArtMethod* referrer) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); - mirror::Class* ResolveType(uint16_t type_idx, ArtField* referrer) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + mirror::Class* ResolveType(uint16_t type_idx, + ArtField* referrer) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Resolve a type with the given ID from the DexFile, storing the // result in DexCache. The ClassLoader is used to search for the // 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, + mirror::Class* ResolveType(const DexFile& dex_file, + uint16_t type_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Resolve a method with a given ID from the DexFile, storing the // result in DexCache. The ClassLinker and ClassLoader are used as // in ResolveType. What is unique is the method type argument which // is used to determine if this method is a direct, static, or // virtual method. - ArtMethod* ResolveMethod(const DexFile& dex_file, uint32_t method_idx, + ArtMethod* ResolveMethod(const DexFile& dex_file, + uint32_t method_idx, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer, + Handle<mirror::ClassLoader> class_loader, + ArtMethod* referrer, InvokeType type) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) SHARED_REQUIRES(Locks::mutator_lock_); ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); ArtField* GetResolvedField(uint32_t field_idx, mirror::Class* field_declaring_class) SHARED_REQUIRES(Locks::mutator_lock_); ArtField* GetResolvedField(uint32_t field_idx, mirror::DexCache* dex_cache) SHARED_REQUIRES(Locks::mutator_lock_); ArtField* ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Resolve a field with a given ID from the DexFile, storing the // result in DexCache. The ClassLinker and ClassLoader are used as // in ResolveType. What is unique is the is_static argument which is // used to determine if we are resolving a static or non-static // field. - ArtField* ResolveField(const DexFile& dex_file, uint32_t field_idx, + ArtField* ResolveField(const DexFile& dex_file, + uint32_t field_idx, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, bool is_static) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + Handle<mirror::ClassLoader> class_loader, + bool is_static) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Resolve a field with a given ID from the DexFile, storing the // result in DexCache. The ClassLinker and ClassLoader are used as // in ResolveType. No is_static argument is provided so that Java // field resolution semantics are followed. - ArtField* ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx, + ArtField* ResolveFieldJLS(const DexFile& dex_file, + uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Get shorty from method index without resolution. Used to do handlerization. const char* MethodShorty(uint32_t method_idx, ArtMethod* referrer, uint32_t* length) @@ -263,9 +303,12 @@ 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(Thread* self, Handle<mirror::Class> c, bool can_init_fields, + bool EnsureInitialized(Thread* self, + Handle<mirror::Class> c, + bool can_init_fields, bool can_init_parents) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); // Initializes classes that have instances in the image but that have // <clinit> methods so they could not be initialized by the compiler. @@ -289,26 +332,33 @@ class ClassLinker { REQUIRES(!dex_lock_); void VisitClasses(ClassVisitor* visitor) - REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Less efficient variant of VisitClasses that copies the class_table_ into secondary storage // so that it can visit individual classes without holding the doesn't hold the // Locks::classlinker_classes_lock_. As the Locks::classlinker_classes_lock_ isn't held this code // can race with insertion and deletion of classes while the visitor is being called. void VisitClassesWithoutClassesLock(ClassVisitor* visitor) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); void VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) - REQUIRES(!Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); void VisitRoots(RootVisitor* visitor, VisitRootFlags flags) - REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!dex_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); mirror::DexCache* FindDexCache(const DexFile& dex_file) - REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!dex_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); bool IsDexFileRegistered(const DexFile& dex_file) - REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!dex_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); void FixupDexCaches(ArtMethod* resolution_method) - REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(!dex_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Finds or creates the oat file holding dex_location. Then loads and returns // all corresponding dex files (there may be more than one dex file loaded @@ -324,58 +374,75 @@ class ClassLinker { // This method should not be called with the mutator_lock_ held, because it // could end up starving GC if we need to generate or relocate any oat // files. - std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat( - const char* dex_location, const char* oat_location, - std::vector<std::string>* error_msgs) + std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat(const char* dex_location, + const char* oat_location, + out<std::vector<std::string>> + error_msgs) REQUIRES(!dex_lock_, !Locks::mutator_lock_); // Allocate an instance of a java.lang.Object. - mirror::Object* AllocObject(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_) + mirror::Object* AllocObject(Thread* self) + SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); // TODO: replace this with multiple methods that allocate the correct managed type. template <class T> mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); mirror::ObjectArray<mirror::Class>* AllocClassArray(Thread* self, size_t length) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); mirror::ObjectArray<mirror::String>* AllocStringArray(Thread* self, size_t length) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); ArtField* AllocArtFieldArray(Thread* self, size_t length); ArtMethod* AllocArtMethodArray(Thread* self, size_t length); mirror::PointerArray* AllocPointerArray(Thread* self, size_t length) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); mirror::IfTable* AllocIfTable(Thread* self, size_t ifcount) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); - mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray( - Thread* self, size_t length) SHARED_REQUIRES(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); + mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(Thread* self, + size_t length) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); void VerifyClass(Thread* self, Handle<mirror::Class> klass) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); - bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass, + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); + bool VerifyClassUsingOatFile(const DexFile& dex_file, + mirror::Class* klass, mirror::Class::Status& oat_file_class_status) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Handle<mirror::Class> klass) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, ArtMethod* klass) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); - mirror::Class* CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, - jobjectArray interfaces, jobject loader, jobjectArray methods, + mirror::Class* CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, + jstring name, + jobjectArray interfaces, + jobject loader, + jobjectArray methods, jobjectArray throws) SHARED_REQUIRES(Locks::mutator_lock_); std::string GetDescriptorForProxy(mirror::Class* proxy_class) SHARED_REQUIRES(Locks::mutator_lock_); - ArtMethod* FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method) + ArtMethod* FindMethodForProxy(mirror::Class* proxy_class, + ArtMethod* proxy_method) REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_); @@ -384,7 +451,8 @@ class ClassLinker { SHARED_REQUIRES(Locks::mutator_lock_); // Get the oat code for a method from a method index. - const void* GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, + const void* GetQuickOatCodeFor(const DexFile& dex_file, + uint16_t class_def_idx, uint32_t method_idx) SHARED_REQUIRES(Locks::mutator_lock_); @@ -394,7 +462,7 @@ class ClassLinker { const void* GetOatMethodQuickCodeFor(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_); - const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, bool* found) + const OatFile::OatMethod FindOatMethodFor(ArtMethod* method, out<bool> found) SHARED_REQUIRES(Locks::mutator_lock_); pid_t GetClassesLockOwner(); // For SignalCatcher. @@ -451,12 +519,14 @@ class ClassLinker { // Returns true if the method can be called with its direct code pointer, false otherwise. bool MayBeCalledWithDirectCodePointer(ArtMethod* m) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Creates a GlobalRef PathClassLoader that can be used to load classes from the given dex files. // Note: the objects are not completely set up. Do not use this outside of tests and the compiler. - jobject CreatePathClassLoader(Thread* self, std::vector<const DexFile*>& dex_files) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + jobject CreatePathClassLoader(Thread* self, const std::vector<const DexFile*>& dex_files) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); size_t GetImagePointerSize() const { DCHECK(ValidPointerSize(image_pointer_size_)) << image_pointer_size_; @@ -503,29 +573,39 @@ class ClassLinker { // For early bootstrapping by Init mirror::Class* AllocClass(Thread* self, mirror::Class* java_lang_Class, uint32_t class_size) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); // 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, uint32_t class_size) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); mirror::Class* InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); - mirror::Class* CreateArrayClass(Thread* self, const char* descriptor, size_t hash, + mirror::Class* CreateArrayClass(Thread* self, + const char* descriptor, + size_t hash, Handle<mirror::ClassLoader> class_loader) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_, !Roles::uninterruptible_); void AppendToBootClassPath(Thread* self, const DexFile& dex_file) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); void AppendToBootClassPath(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); // Precomputes size needed for Class, in the case of a non-temporary class this size must be // sufficient to hold all static fields. @@ -534,30 +614,41 @@ class ClassLinker { // Setup the classloader, class def index, type idx so that we can insert this class in the class // table. - void SetupClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - Handle<mirror::Class> klass, mirror::ClassLoader* class_loader) + void SetupClass(const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def, + Handle<mirror::Class> klass, + mirror::ClassLoader* class_loader) SHARED_REQUIRES(Locks::mutator_lock_); - void LoadClass(Thread* self, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, + void LoadClass(Thread* self, + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def, Handle<mirror::Class> klass) SHARED_REQUIRES(Locks::mutator_lock_); - void LoadClassMembers(Thread* self, const DexFile& dex_file, const uint8_t* class_data, - Handle<mirror::Class> klass, const OatFile::OatClass* oat_class) + void LoadClassMembers(Thread* self, + const DexFile& dex_file, + const uint8_t* class_data, + Handle<mirror::Class> klass, + const OatFile::OatClass* oat_class) SHARED_REQUIRES(Locks::mutator_lock_); - void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, + void LoadField(const ClassDataItemIterator& it, + Handle<mirror::Class> klass, ArtField* dst) SHARED_REQUIRES(Locks::mutator_lock_); - void LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it, - Handle<mirror::Class> klass, ArtMethod* dst) + void LoadMethod(Thread* self, + const DexFile& dex_file, + const ClassDataItemIterator& it, + Handle<mirror::Class> klass, + ArtMethod* dst) SHARED_REQUIRES(Locks::mutator_lock_); void FixupStaticTrampolines(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_); // Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on // error and sets found to false. - OatFile::OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found) + OatFile::OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, out<bool> found) SHARED_REQUIRES(Locks::mutator_lock_); void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) @@ -565,55 +656,70 @@ class ClassLinker { bool IsDexFileRegisteredLocked(const DexFile& dex_file) SHARED_REQUIRES(dex_lock_, Locks::mutator_lock_); - bool InitializeClass(Thread* self, Handle<mirror::Class> klass, bool can_run_clinit, + bool InitializeClass(Thread* self, + Handle<mirror::Class> klass, + bool can_run_clinit, bool can_init_parents) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); - bool WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self, - ObjectLock<mirror::Class>& lock); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); + bool WaitForInitializeClass(Handle<mirror::Class> klass, + Thread* self, + ObjectLock<mirror::Class>* lock); bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass) SHARED_REQUIRES(Locks::mutator_lock_); - bool IsSameDescriptorInDifferentClassContexts(Thread* self, const char* descriptor, + bool IsSameDescriptorInDifferentClassContexts(Thread* self, + const char* descriptor, Handle<mirror::ClassLoader> class_loader1, Handle<mirror::ClassLoader> class_loader2) SHARED_REQUIRES(Locks::mutator_lock_); - bool IsSameMethodSignatureInDifferentClassContexts(Thread* self, ArtMethod* method, - mirror::Class* klass1, mirror::Class* klass2) + bool IsSameMethodSignatureInDifferentClassContexts(Thread* self, + ArtMethod* method, + mirror::Class* klass1, + mirror::Class* klass2) SHARED_REQUIRES(Locks::mutator_lock_); - bool LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass, + bool LinkClass(Thread* self, + const char* descriptor, + Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - MutableHandle<mirror::Class>* h_new_class_out) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::classlinker_classes_lock_); + out<MutableHandle<mirror::Class>> h_new_class_out) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Locks::classlinker_classes_lock_); bool LinkSuperClass(Handle<mirror::Class> klass) SHARED_REQUIRES(Locks::mutator_lock_); bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!dex_lock_); bool LinkMethods(Thread* self, Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - ArtMethod** out_imt) + out<ArtMethod* [mirror::Class::kImtSize]> out_imt) SHARED_REQUIRES(Locks::mutator_lock_); bool LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) SHARED_REQUIRES(Locks::mutator_lock_); - bool LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass, + bool LinkInterfaceMethods(Thread* self, + Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - ArtMethod** out_imt) + out<ArtMethod* [mirror::Class::kImtSize]> out_imt) SHARED_REQUIRES(Locks::mutator_lock_); - bool LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size) + bool LinkStaticFields(Thread* self, + Handle<mirror::Class> klass, + out<size_t> class_size) SHARED_REQUIRES(Locks::mutator_lock_); bool LinkInstanceFields(Thread* self, Handle<mirror::Class> klass) SHARED_REQUIRES(Locks::mutator_lock_); - bool LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_static, size_t* class_size) + bool LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_static, out<size_t> class_size) SHARED_REQUIRES(Locks::mutator_lock_); - void LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class, + void LinkCode(ArtMethod* method, + const OatFile::OatClass* oat_class, uint32_t class_def_method_index) SHARED_REQUIRES(Locks::mutator_lock_); void CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) @@ -686,7 +792,7 @@ class ClassLinker { REQUIRES(!dex_lock_); // Check for duplicate class definitions of the given oat file against all open oat files. - bool HasCollisions(const OatFile* oat_file, std::string* error_msg) REQUIRES(!dex_lock_); + bool HasCollisions(const OatFile* oat_file, out<std::string> error_msg) REQUIRES(!dex_lock_); bool HasInitWithString(Thread* self, const char* descriptor) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); @@ -694,9 +800,11 @@ class ClassLinker { bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, bool can_init_parents) SHARED_REQUIRES(Locks::mutator_lock_); - void UpdateClassVirtualMethods(mirror::Class* klass, ArtMethod* new_methods, + void UpdateClassVirtualMethods(mirror::Class* klass, + ArtMethod* new_methods, size_t new_num_methods) - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::classlinker_classes_lock_); + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!Locks::classlinker_classes_lock_); std::vector<const DexFile*> boot_class_path_; std::vector<std::unique_ptr<const DexFile>> opened_dex_files_; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index c9ae9b8b6e..1865516939 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -24,6 +24,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" #include "base/time_utils.h" +#include "base/out.h" #include "class_linker.h" #include "class_linker-inl.h" #include "dex_file-inl.h" @@ -1000,7 +1001,7 @@ JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* p void Dbg::FindLoadedClassBySignature(const char* descriptor, std::vector<JDWP::RefTypeId>* ids) { std::vector<mirror::Class*> classes; - Runtime::Current()->GetClassLinker()->LookupClasses(descriptor, classes); + Runtime::Current()->GetClassLinker()->LookupClasses(descriptor, outof(classes)); ids->clear(); for (size_t i = 0; i < classes.size(); ++i) { ids->push_back(gRegistry->Add(classes[i])); diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc index 75fc84bd63..c9ba6cfada 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -28,6 +28,8 @@ namespace art { +static constexpr bool kDumpStackOnNonLocalReference = false; + template<typename T> class MutatorLockedDumpable { public: @@ -183,7 +185,9 @@ bool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) { if (env->check_jni) { ScopedObjectAccess soa(self); LOG(WARNING) << "Attempt to remove non-JNI local reference, dumping thread"; - self->Dump(LOG(WARNING)); + if (kDumpStackOnNonLocalReference) { + self->Dump(LOG(WARNING)); + } } return true; } diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 2486a983fd..a6cccef617 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -553,7 +553,7 @@ static inline bool DoUnboxLambda(Thread* self, ArtMethod* unboxed_closure = nullptr; // Raise an exception if unboxing fails. if (!Runtime::Current()->GetLambdaBoxTable()->UnboxLambda(boxed_closure_object, - &unboxed_closure)) { + outof(unboxed_closure))) { CHECK(self->IsExceptionPending()); return false; } diff --git a/runtime/lambda/box_table.cc b/runtime/lambda/box_table.cc index 64a6076aea..22cc820b73 100644 --- a/runtime/lambda/box_table.cc +++ b/runtime/lambda/box_table.cc @@ -94,8 +94,7 @@ mirror::Object* BoxTable::BoxLambda(const ClosureType& closure) { return method_as_object; } -bool BoxTable::UnboxLambda(mirror::Object* object, ClosureType* out_closure) { - DCHECK(object != nullptr); +bool BoxTable::UnboxLambda(mirror::Object* object, out<ClosureType> out_closure) { *out_closure = nullptr; // Note that we do not need to access lambda_table_lock_ here diff --git a/runtime/lambda/box_table.h b/runtime/lambda/box_table.h index 312d811b9b..c6d3d0c0fb 100644 --- a/runtime/lambda/box_table.h +++ b/runtime/lambda/box_table.h @@ -18,6 +18,7 @@ #include "base/allocator.h" #include "base/hash_map.h" +#include "base/out.h" #include "gc_root.h" #include "base/macros.h" #include "base/mutex.h" @@ -51,7 +52,7 @@ class BoxTable FINAL { SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::lambda_table_lock_); // Unboxes an object back into the lambda. Returns false and throws an exception on failure. - bool UnboxLambda(mirror::Object* object, ClosureType* out_closure) + bool UnboxLambda(mirror::Object* object, out<ClosureType> out_closure) SHARED_REQUIRES(Locks::mutator_lock_); // Sweep weak references to lambda boxes. Update the addresses if the objects have been diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 4f97d20d6c..1b210bb4c3 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -17,6 +17,7 @@ #include "dalvik_system_DexFile.h" #include "base/logging.h" +#include "base/out.h" #include "base/stl_util.h" #include "base/stringprintf.h" #include "class_linker.h" @@ -164,7 +165,8 @@ static jobject DexFile_openDexFileNative( std::vector<std::unique_ptr<const DexFile>> dex_files; std::vector<std::string> error_msgs; - dex_files = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs); + dex_files = + linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), outof(error_msgs)); if (!dex_files.empty()) { jlongArray array = ConvertNativeToJavaArray(env, dex_files); diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index 15156301c8..62a0b7653d 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -16,6 +16,7 @@ #include "java_lang_VMClassLoader.h" +#include "base/out.h" #include "class_linker.h" #include "jni_internal.h" #include "mirror/class_loader.h" @@ -45,7 +46,7 @@ static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoa // Try the common case. StackHandleScope<1> hs(soa.Self()); cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), descriptor_hash, - hs.NewHandle(loader), &c); + hs.NewHandle(loader), outof(c)); if (c != nullptr) { return soa.AddLocalReference<jclass>(c); } diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 03ad2d5ac8..65263d0f30 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -26,6 +26,7 @@ #include <gtest/gtest.h> #include "art_field-inl.h" +#include "base/out.h" #include "class_linker-inl.h" #include "common_runtime_test.h" #include "compiler_callbacks.h" @@ -958,7 +959,9 @@ class RaceGenerateTask : public Task { ClassLinker* linker = Runtime::Current()->GetClassLinker(); std::vector<std::unique_ptr<const DexFile>> dex_files; std::vector<std::string> error_msgs; - dex_files = linker->OpenDexFilesFromOat(dex_location_.c_str(), oat_location_.c_str(), &error_msgs); + dex_files = linker->OpenDexFilesFromOat(dex_location_.c_str(), + oat_location_.c_str(), + outof(error_msgs)); CHECK(!dex_files.empty()) << Join(error_msgs, '\n'); CHECK(dex_files[0]->GetOatDexFile() != nullptr) << dex_files[0]->GetLocation(); loaded_oat_file_ = dex_files[0]->GetOatDexFile()->GetOatFile(); diff --git a/runtime/stack.cc b/runtime/stack.cc index b07b244282..2916eaaf5e 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -19,6 +19,7 @@ #include "arch/context.h" #include "art_method-inl.h" #include "base/hex_dump.h" +#include "base/out.h" #include "entrypoints/entrypoint_utils-inl.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "gc_map.h" @@ -180,7 +181,7 @@ mirror::Object* StackVisitor::GetThisObject() const { } else { uint16_t reg = code_item->registers_size_ - code_item->ins_size_; uint32_t value = 0; - bool success = GetVReg(m, reg, kReferenceVReg, &value); + bool success = GetVReg(m, reg, kReferenceVReg, outof(value)); // We currently always guarantee the `this` object is live throughout the method. CHECK(success) << "Failed to read the this object in " << PrettyMethod(m); return reinterpret_cast<mirror::Object*>(value); @@ -375,8 +376,8 @@ bool StackVisitor::GetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKin QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer); uint32_t vmap_offset_lo, vmap_offset_hi; // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && - vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) { + if (vmap_table.IsInContext(vreg, kind_lo, outof(vmap_offset_lo)) && + vmap_table.IsInContext(vreg + 1, kind_hi, outof(vmap_offset_hi))) { bool is_float = (kind_lo == kDoubleLoVReg); uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo); @@ -399,8 +400,8 @@ bool StackVisitor::GetVRegPairFromOptimizedCode(ArtMethod* m, uint16_t vreg, uint64_t* val) const { uint32_t low_32bits; uint32_t high_32bits; - bool success = GetVRegFromOptimizedCode(m, vreg, kind_lo, &low_32bits); - success &= GetVRegFromOptimizedCode(m, vreg + 1, kind_hi, &high_32bits); + bool success = GetVRegFromOptimizedCode(m, vreg, kind_lo, outof(low_32bits)); + success &= GetVRegFromOptimizedCode(m, vreg + 1, kind_hi, outof(high_32bits)); if (success) { *val = (static_cast<uint64_t>(high_32bits) << 32) | static_cast<uint64_t>(low_32bits); } @@ -452,7 +453,7 @@ bool StackVisitor::SetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, uint32_t ne QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer); uint32_t vmap_offset; // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { + if (vmap_table.IsInContext(vreg, kind, outof(vmap_offset))) { bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind); @@ -532,8 +533,8 @@ bool StackVisitor::SetVRegPairFromQuickCode( QuickMethodFrameInfo frame_info = m->GetQuickFrameInfo(code_pointer); uint32_t vmap_offset_lo, vmap_offset_hi; // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && - vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) { + if (vmap_table.IsInContext(vreg, kind_lo, outof(vmap_offset_lo)) && + vmap_table.IsInContext(vreg + 1, kind_hi, outof(vmap_offset_hi))) { bool is_float = (kind_lo == kDoubleLoVReg); uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index d63b455668..0181e5b7cc 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2874,6 +2874,13 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } } } + // Handle this like a RETURN_VOID now. Code is duplicated to separate standard from + // quickened opcodes (otherwise this could be a fall-through). + if (!IsConstructor()) { + if (!GetMethodReturnType().IsConflict()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void not expected"; + } + } break; // Note: the following instructions encode offsets derived from class linking. // As such they use Class*/Field*/AbstractMethod* as these offsets only have diff --git a/test/401-optimizing-compiler/src/Main.java b/test/401-optimizing-compiler/src/Main.java index a1e62b3b39..f2e451854b 100644 --- a/test/401-optimizing-compiler/src/Main.java +++ b/test/401-optimizing-compiler/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/402-optimizing-control-flow/src/Main.java b/test/402-optimizing-control-flow/src/Main.java index c9c24dd568..4c93d266e8 100644 --- a/test/402-optimizing-control-flow/src/Main.java +++ b/test/402-optimizing-control-flow/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/403-optimizing-long/src/Main.java b/test/403-optimizing-long/src/Main.java index 21af4e14aa..5927d1c325 100644 --- a/test/403-optimizing-long/src/Main.java +++ b/test/403-optimizing-long/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/404-optimizing-allocator/src/Main.java b/test/404-optimizing-allocator/src/Main.java index 7b31820470..1ff5475e45 100644 --- a/test/404-optimizing-allocator/src/Main.java +++ b/test/404-optimizing-allocator/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$reg$ is a marker for the optimizing compiler to ensure +// Note that $opt$reg$ is a marker for the optimizing compiler to test // it does use its register allocator. public class Main { diff --git a/test/405-optimizing-long-allocator/src/Main.java b/test/405-optimizing-long-allocator/src/Main.java index 9fd840b543..a0e0bb5355 100644 --- a/test/405-optimizing-long-allocator/src/Main.java +++ b/test/405-optimizing-long-allocator/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it compiles these methods. public class Main { diff --git a/test/411-optimizing-arith-mul/src/Main.java b/test/411-optimizing-arith-mul/src/Main.java index 3a5d7c05c9..60e418e1e5 100644 --- a/test/411-optimizing-arith-mul/src/Main.java +++ b/test/411-optimizing-arith-mul/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/412-new-array/src/Main.java b/test/412-new-array/src/Main.java index e4669b8a96..b9c2a053e0 100644 --- a/test/412-new-array/src/Main.java +++ b/test/412-new-array/src/Main.java @@ -17,7 +17,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main extends TestCase { diff --git a/test/414-optimizing-arith-sub/src/Main.java b/test/414-optimizing-arith-sub/src/Main.java index 30e84368d0..b4531cdfd4 100644 --- a/test/414-optimizing-arith-sub/src/Main.java +++ b/test/414-optimizing-arith-sub/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/415-optimizing-arith-neg/src/Main.java b/test/415-optimizing-arith-neg/src/Main.java index bd8a1583d5..cabf635554 100644 --- a/test/415-optimizing-arith-neg/src/Main.java +++ b/test/415-optimizing-arith-neg/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/417-optimizing-arith-div/src/Main.java b/test/417-optimizing-arith-div/src/Main.java index 909ceb43d6..68e89b3eb2 100644 --- a/test/417-optimizing-arith-div/src/Main.java +++ b/test/417-optimizing-arith-div/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/421-large-frame/src/Main.java b/test/421-large-frame/src/Main.java index 81896abbd8..6717ba0661 100644 --- a/test/421-large-frame/src/Main.java +++ b/test/421-large-frame/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java index 9f8f417cff..146f309c81 100644 --- a/test/422-type-conversion/src/Main.java +++ b/test/422-type-conversion/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/427-bitwise/src/Main.java b/test/427-bitwise/src/Main.java index e9840669dd..aa69554a4f 100644 --- a/test/427-bitwise/src/Main.java +++ b/test/427-bitwise/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/477-long-to-float-conversion-precision/src/Main.java b/test/477-long-to-float-conversion-precision/src/Main.java index cd9703943d..568bc04d6c 100644 --- a/test/477-long-to-float-conversion-precision/src/Main.java +++ b/test/477-long-to-float-conversion-precision/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { diff --git a/test/705-register-conflict/src/Main.java b/test/705-register-conflict/src/Main.java index 42c79fb275..9ae10ecba6 100644 --- a/test/705-register-conflict/src/Main.java +++ b/test/705-register-conflict/src/Main.java @@ -14,7 +14,7 @@ * limitations under the License. */ -// Note that $opt$ is a marker for the optimizing compiler to ensure +// Note that $opt$ is a marker for the optimizing compiler to test // it does compile the method. public class Main { |