diff options
Diffstat (limited to 'runtime')
36 files changed, 245 insertions, 130 deletions
diff --git a/runtime/CPPLINT.cfg b/runtime/CPPLINT.cfg new file mode 100644 index 0000000000..6f274994a9 --- /dev/null +++ b/runtime/CPPLINT.cfg @@ -0,0 +1,18 @@ +# +# Copyright (C) 2017 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. +# + +# External headers, not subject to our lint rules. +exclude_files=^elf[.]h$ diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h index fba9308e8e..99cdb49984 100644 --- a/runtime/base/allocator.h +++ b/runtime/base/allocator.h @@ -111,7 +111,7 @@ class TrackingAllocatorImpl : public std::allocator<T> { // Used internally by STL data structures. template <class U> - TrackingAllocatorImpl( // NOLINT, implicit + TrackingAllocatorImpl( const TrackingAllocatorImpl<U, kTag>& alloc ATTRIBUTE_UNUSED) noexcept {} // Used internally by STL data structures. diff --git a/runtime/base/arena_containers.h b/runtime/base/arena_containers.h index 2e71156ee8..dcdb92b9d8 100644 --- a/runtime/base/arena_containers.h +++ b/runtime/base/arena_containers.h @@ -143,7 +143,7 @@ class ArenaAllocatorAdapter<void> : private ArenaAllocatorAdapterKind { allocator_(allocator) { } template <typename U> - ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other) // NOLINT, implicit + ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other) : ArenaAllocatorAdapterKind(other), allocator_(other.allocator_) { } @@ -179,7 +179,7 @@ class ArenaAllocatorAdapter : private ArenaAllocatorAdapterKind { allocator_(allocator) { } template <typename U> - ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other) // NOLINT, implicit + ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other) : ArenaAllocatorAdapterKind(other), allocator_(other.allocator_) { } diff --git a/runtime/base/bit_string.h b/runtime/base/bit_string.h index 1cda021017..a2164f335d 100644 --- a/runtime/base/bit_string.h +++ b/runtime/base/bit_string.h @@ -248,7 +248,7 @@ struct BitString { // Does this bitstring contain exactly 0 characters? bool IsEmpty() const { - return (*this) == BitString{}; // NOLINT + return (*this) == BitString{}; } // Remove all BitStringChars starting at end. diff --git a/runtime/base/bit_string_test.cc b/runtime/base/bit_string_test.cc index d5610e7a73..96aa154ef3 100644 --- a/runtime/base/bit_string_test.cc +++ b/runtime/base/bit_string_test.cc @@ -47,7 +47,7 @@ BitStringChar MakeBitStringChar(size_t val) { BitString MakeBitString(std::initializer_list<size_t> values = {}) { CHECK_GE(BitString::kCapacity, values.size()); - BitString bs{}; // NOLINT + BitString bs{}; size_t i = 0; for (size_t val : values) { @@ -68,7 +68,7 @@ size_t AsUint(const T& value) { // Make max bitstring, e.g. BitString[4095,7,255] for {12,3,8} template <size_t kCount = BitString::kCapacity> BitString MakeBitStringMax() { - BitString bs{}; // NOLINT + BitString bs{}; for (size_t i = 0; i < kCount; ++i) { bs.SetAt(i, diff --git a/runtime/base/bit_struct.h b/runtime/base/bit_struct.h index 16b555e1c6..b207459419 100644 --- a/runtime/base/bit_struct.h +++ b/runtime/base/bit_struct.h @@ -288,7 +288,7 @@ using BitStructUint = // // See top of file for usage example. #define BITSTRUCT_DEFINE_END(name) \ - }; /* NOLINT [readability/braces] [4] */ \ + }; \ static_assert(art::detail::ValidateBitStructSize<name>(), \ #name "bitsize incorrect: " \ "did you insert extra fields that weren't BitStructX, " \ diff --git a/runtime/base/bit_struct_detail.h b/runtime/base/bit_struct_detail.h index 49d432e69c..912f51c7b0 100644 --- a/runtime/base/bit_struct_detail.h +++ b/runtime/base/bit_struct_detail.h @@ -79,7 +79,7 @@ struct HasUnderscoreField { using FalseT = std::integral_constant<bool, false>::type; template <typename C> - static constexpr auto Test(void*) -> decltype(std::declval<C>()._, TrueT{}); // NOLINT + static constexpr auto Test(void*) -> decltype(std::declval<C>()._, TrueT{}); template <typename> static constexpr FalseT Test(...); diff --git a/runtime/base/bit_struct_test.cc b/runtime/base/bit_struct_test.cc index a80d39eb91..577682ccce 100644 --- a/runtime/base/bit_struct_test.cc +++ b/runtime/base/bit_struct_test.cc @@ -73,7 +73,7 @@ struct CustomBitStruct { TEST(BitStructs, Custom) { CustomBitStruct expected(0b1111); - BitStructField<CustomBitStruct, /*lsb*/4, /*width*/4> f{}; // NOLINT + BitStructField<CustomBitStruct, /*lsb*/4, /*width*/4> f{}; EXPECT_EQ(1u, sizeof(f)); @@ -95,7 +95,7 @@ TEST(BitStructs, TwoCustom) { VALIDATE_BITSTRUCT_SIZE(TestTwoCustom); - TestTwoCustom cst{}; // NOLINT + TestTwoCustom cst{}; // Test the write to most-significant field doesn't clobber least-significant. cst.f4_a = CustomBitStruct(0b0110); @@ -122,7 +122,7 @@ TEST(BitStructs, TwoCustom) { } TEST(BitStructs, Number) { - BitStructNumber<uint16_t, /*lsb*/4, /*width*/4> bsn{}; // NOLINT + BitStructNumber<uint16_t, /*lsb*/4, /*width*/4> bsn{}; EXPECT_EQ(2u, sizeof(bsn)); bsn = 0b1111; @@ -154,7 +154,7 @@ TEST(BitStructs, Test1) { EXPECT_EQ(1u, sizeof(u4)); EXPECT_EQ(1u, sizeof(alias_all)); } - TestBitStruct tst{}; // NOLINT + TestBitStruct tst{}; // Check minimal size selection is correct. EXPECT_EQ(1u, sizeof(TestBitStruct)); @@ -229,7 +229,7 @@ BITSTRUCT_DEFINE_END(MixedSizeBitStruct); TEST(BitStructs, Mixed) { EXPECT_EQ(4u, sizeof(MixedSizeBitStruct)); - MixedSizeBitStruct tst{}; // NOLINT + MixedSizeBitStruct tst{}; // Check operator assignment. tst.u3 = 0b111u; @@ -263,11 +263,11 @@ BITSTRUCT_DEFINE_START(TestBitStruct_u8, /* size */ 8) BITSTRUCT_DEFINE_END(TestBitStruct_u8); TEST(BitStructs, FieldAssignment) { - TestBitStruct_u8 all_1s{}; // NOLINT + TestBitStruct_u8 all_1s{}; all_1s.alias_all = 0xffu; { - TestBitStruct_u8 tst{}; // NOLINT + TestBitStruct_u8 tst{}; tst.i3 = all_1s.i3; // Copying a single bitfield does not copy all bitfields. @@ -275,7 +275,7 @@ TEST(BitStructs, FieldAssignment) { } { - TestBitStruct_u8 tst{}; // NOLINT + TestBitStruct_u8 tst{}; tst.u4 = all_1s.u4; // Copying a single bitfield does not copy all bitfields. @@ -291,13 +291,13 @@ BITSTRUCT_DEFINE_START(NestedStruct, /* size */ 64) BITSTRUCT_DEFINE_END(NestedStruct); TEST(BitStructs, NestedFieldAssignment) { - MixedSizeBitStruct mixed_all_1s{}; // NOLINT + MixedSizeBitStruct mixed_all_1s{}; mixed_all_1s.alias_all = 0xFFFFFFFFu; { - NestedStruct xyz{}; // NOLINT + NestedStruct xyz{}; - NestedStruct other{}; // NOLINT + NestedStruct other{}; other.mixed_upper = mixed_all_1s; other.mixed_lower = mixed_all_1s; @@ -307,9 +307,9 @@ TEST(BitStructs, NestedFieldAssignment) { } { - NestedStruct xyz{}; // NOLINT + NestedStruct xyz{}; - NestedStruct other{}; // NOLINT + NestedStruct other{}; other.mixed_upper = mixed_all_1s; other.mixed_lower = mixed_all_1s; diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 877f052006..3adebe7e00 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -584,7 +584,7 @@ ReaderWriterMutex::ReaderWriterMutex(const char* name, LockLevel level) #if ART_USE_FUTEXES , state_(0), num_pending_readers_(0), num_pending_writers_(0) #endif -{ // NOLINT(whitespace/braces) +{ #if !ART_USE_FUTEXES CHECK_MUTEX_CALL(pthread_rwlock_init, (&rwlock_, nullptr)); #endif diff --git a/runtime/base/scoped_arena_containers.h b/runtime/base/scoped_arena_containers.h index fccaaeaa42..756089f438 100644 --- a/runtime/base/scoped_arena_containers.h +++ b/runtime/base/scoped_arena_containers.h @@ -110,7 +110,7 @@ class ScopedArenaAllocatorAdapter<void> arena_stack_(allocator->arena_stack_) { } template <typename U> - ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other) // NOLINT, implicit + ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other) : DebugStackReference(other), DebugStackIndirectTopRef(other), ArenaAllocatorAdapterKind(other), @@ -153,7 +153,7 @@ class ScopedArenaAllocatorAdapter arena_stack_(allocator->arena_stack_) { } template <typename U> - ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other) // NOLINT, implicit + ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other) : DebugStackReference(other), DebugStackIndirectTopRef(other), ArenaAllocatorAdapterKind(other), diff --git a/runtime/base/transform_array_ref.h b/runtime/base/transform_array_ref.h index b432f86d77..a4e0bc27ed 100644 --- a/runtime/base/transform_array_ref.h +++ b/runtime/base/transform_array_ref.h @@ -72,7 +72,7 @@ class TransformArrayRef { template <typename OtherBT, typename = typename std::enable_if<std::is_same<BaseType, const OtherBT>::value>::type> - TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other) // NOLINT, implicit + TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other) : TransformArrayRef(other.base(), other.GetFunction()) { } // Assignment operators. diff --git a/runtime/base/transform_array_ref_test.cc b/runtime/base/transform_array_ref_test.cc index 494dbb29aa..da0340d36b 100644 --- a/runtime/base/transform_array_ref_test.cc +++ b/runtime/base/transform_array_ref_test.cc @@ -38,7 +38,7 @@ ATTRIBUTE_UNUSED bool operator==(const ValueHolder& lhs, const ValueHolder& rhs) } // anonymous namespace TEST(TransformArrayRef, ConstRefAdd1) { - auto add1 = [](const ValueHolder& h) { return h.value + 1; }; // NOLINT [readability/braces] + auto add1 = [](const ValueHolder& h) { return h.value + 1; }; std::vector<ValueHolder> input({ 7, 6, 4, 0 }); std::vector<int> output; @@ -79,7 +79,7 @@ TEST(TransformArrayRef, ConstRefAdd1) { } TEST(TransformArrayRef, NonConstRefSub1) { - auto sub1 = [](ValueHolder& h) { return h.value - 1; }; // NOLINT [readability/braces] + auto sub1 = [](ValueHolder& h) { return h.value - 1; }; std::vector<ValueHolder> input({ 4, 4, 5, 7, 10 }); std::vector<int> output; diff --git a/runtime/base/transform_iterator.h b/runtime/base/transform_iterator.h index f1a8a52ceb..9c8f822b71 100644 --- a/runtime/base/transform_iterator.h +++ b/runtime/base/transform_iterator.h @@ -62,7 +62,7 @@ class TransformIterator { : data_(base, fn) { } template <typename OtherBI> - TransformIterator(const TransformIterator<OtherBI, Function>& other) // NOLINT, implicit + TransformIterator(const TransformIterator<OtherBI, Function>& other) : data_(other.base(), other.GetFunction()) { } diff --git a/runtime/base/transform_iterator_test.cc b/runtime/base/transform_iterator_test.cc index a85dda8958..63b6e4f531 100644 --- a/runtime/base/transform_iterator_test.cc +++ b/runtime/base/transform_iterator_test.cc @@ -41,7 +41,7 @@ bool operator==(const ValueHolder& lhs, const ValueHolder& rhs) { } // anonymous namespace TEST(TransformIterator, VectorAdd1) { - auto add1 = [](const ValueHolder& h) { return h.value + 1; }; // NOLINT [readability/braces] + auto add1 = [](const ValueHolder& h) { return h.value + 1; }; std::vector<ValueHolder> input({ 1, 7, 3, 8 }); std::vector<int> output; @@ -144,7 +144,7 @@ TEST(TransformIterator, VectorAdd1) { } TEST(TransformIterator, ListSub1) { - auto sub1 = [](const ValueHolder& h) { return h.value - 1; }; // NOLINT [readability/braces] + auto sub1 = [](const ValueHolder& h) { return h.value - 1; }; std::list<ValueHolder> input({ 2, 3, 5, 7, 11 }); std::vector<int> output; @@ -208,7 +208,7 @@ TEST(TransformIterator, ListSub1) { } TEST(TransformIterator, ForwardListSub1) { - auto mul3 = [](const ValueHolder& h) { return h.value * 3; }; // NOLINT [readability/braces] + auto mul3 = [](const ValueHolder& h) { return h.value * 3; }; std::forward_list<ValueHolder> input({ 1, 1, 2, 3, 5, 8 }); std::vector<int> output; @@ -246,7 +246,7 @@ TEST(TransformIterator, ForwardListSub1) { } TEST(TransformIterator, VectorConstReference) { - auto ref = [](const ValueHolder& h) -> const int& { return h.value; }; // NOLINT [readability/braces] + auto ref = [](const ValueHolder& h) -> const int& { return h.value; }; std::vector<ValueHolder> input({ 7, 3, 1, 2, 4, 8 }); std::vector<int> output; @@ -339,7 +339,7 @@ TEST(TransformIterator, VectorConstReference) { } TEST(TransformIterator, VectorNonConstReference) { - auto ref = [](ValueHolder& h) -> int& { return h.value; }; // NOLINT [readability/braces] + auto ref = [](ValueHolder& h) -> int& { return h.value; }; std::vector<ValueHolder> input({ 7, 3, 1, 2, 4, 8 }); std::vector<int> output; @@ -519,7 +519,7 @@ TEST(TransformIterator, VectorConstAndNonConstReference) { } TEST(TransformIterator, TransformRange) { - auto ref = [](ValueHolder& h) -> int& { return h.value; }; // NOLINT [readability/braces] + auto ref = [](ValueHolder& h) -> int& { return h.value; }; std::vector<ValueHolder> data({ 1, 0, 1, 3, 1, 0 }); for (int& v : MakeTransformRange(data, ref)) { diff --git a/runtime/base/variant_map.h b/runtime/base/variant_map.h index fe332d1e3b..c480b5162d 100644 --- a/runtime/base/variant_map.h +++ b/runtime/base/variant_map.h @@ -139,7 +139,7 @@ struct VariantMapKey : detail::VariantMapKeyRaw { // then that is used. Otherwise, the default value for the type TValue{} is returned. TValue CreateDefaultValue() const { if (default_value_ == nullptr) { - return TValue{}; // NOLINT [readability/braces] [4] + return TValue{}; } else { return TValue(*default_value_); } diff --git a/runtime/base/variant_map_test.cc b/runtime/base/variant_map_test.cc index 9dd29baf48..4677b6d3b3 100644 --- a/runtime/base/variant_map_test.cc +++ b/runtime/base/variant_map_test.cc @@ -107,8 +107,8 @@ TEST(VariantMaps, RuleOfFive) { fmFilled.Set(FruitMap::Orange, 555.0); EXPECT_EQ(size_t(2), fmFilled.Size()); - // Test copy constructor (NOLINT as a reference is suggested, instead) - FruitMap fmEmptyCopy(fmEmpty); // NOLINT + // Test copy constructor + FruitMap fmEmptyCopy(fmEmpty); EXPECT_EQ(size_t(0), fmEmptyCopy.Size()); // Test copy constructor diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 493468bb3d..ef1647caf3 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -78,11 +78,11 @@ static const uint8_t kBase64Map[256] = { 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // NOLINT - 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // NOLINT + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // NOLINT - 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, // NOLINT + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, diff --git a/runtime/debugger.cc b/runtime/debugger.cc index c7f245309f..613e4fe7c7 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -18,6 +18,7 @@ #include <sys/uio.h> +#include <functional> #include <memory> #include <set> #include <vector> @@ -325,6 +326,7 @@ bool Dbg::gDebuggerActive = false; bool Dbg::gDisposed = false; ObjectRegistry* Dbg::gRegistry = nullptr; DebuggerActiveMethodInspectionCallback Dbg::gDebugActiveCallback; +DebuggerDdmCallback Dbg::gDebugDdmCallback; // Deoptimization support. std::vector<DeoptimizationRequest> Dbg::deoptimization_requests_; @@ -342,6 +344,10 @@ uint32_t Dbg::instrumentation_events_ = 0; Dbg::DbgThreadLifecycleCallback Dbg::thread_lifecycle_callback_; Dbg::DbgClassLoadCallback Dbg::class_load_callback_; +void DebuggerDdmCallback::DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) { + Dbg::DdmSendChunk(type, data); +} + bool DebuggerActiveMethodInspectionCallback::IsMethodBeingInspected(ArtMethod* m ATTRIBUTE_UNUSED) { return Dbg::IsDebuggerActive(); } @@ -531,6 +537,12 @@ void Dbg::StartJdwp() { CHECK(gRegistry == nullptr); gRegistry = new ObjectRegistry; + { + // Setup the Ddm listener + ScopedObjectAccess soa(Thread::Current()); + Runtime::Current()->GetRuntimeCallbacks()->AddDdmCallback(&gDebugDdmCallback); + } + // Init JDWP if the debugger is enabled. This may connect out to a // debugger, passively listen for a debugger, or block waiting for a // debugger. @@ -4285,47 +4297,28 @@ void Dbg::FinishInvokeMethod(DebugInvokeReq* pReq) { } } -/* - * "request" contains a full JDWP packet, possibly with multiple chunks. We - * need to process each, accumulate the replies, and ship the whole thing - * back. - * - * Returns "true" if we have a reply. The reply buffer is newly allocated, - * and includes the chunk type/length, followed by the data. - * - * OLD-TODO: we currently assume that the request and reply include a single - * chunk. If this becomes inconvenient we will need to adapt. - */ -bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen) { - Thread* self = Thread::Current(); - JNIEnv* env = self->GetJniEnv(); - - uint32_t type = request->ReadUnsigned32("type"); - uint32_t length = request->ReadUnsigned32("length"); - - // Create a byte[] corresponding to 'request'. - size_t request_length = request->size(); - ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(request_length)); +bool Dbg::DdmHandleChunk(JNIEnv* env, + uint32_t type, + const ArrayRef<const jbyte>& data, + /*out*/uint32_t* out_type, + /*out*/std::vector<uint8_t>* out_data) { + ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(data.size())); if (dataArray.get() == nullptr) { - LOG(WARNING) << "byte[] allocation failed: " << request_length; + LOG(WARNING) << "byte[] allocation failed: " << data.size(); env->ExceptionClear(); return false; } - env->SetByteArrayRegion(dataArray.get(), 0, request_length, - reinterpret_cast<const jbyte*>(request->data())); - request->Skip(request_length); - - // Run through and find all chunks. [Currently just find the first.] - ScopedByteArrayRO contents(env, dataArray.get()); - if (length != request_length) { - LOG(WARNING) << StringPrintf("bad chunk found (len=%u pktLen=%zd)", length, request_length); - return false; - } - + env->SetByteArrayRegion(dataArray.get(), + 0, + data.size(), + reinterpret_cast<const jbyte*>(data.data())); // Call "private static Chunk dispatch(int type, byte[] data, int offset, int length)". - ScopedLocalRef<jobject> chunk(env, env->CallStaticObjectMethod(WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer, - WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch, - type, dataArray.get(), 0, length)); + ScopedLocalRef<jobject> chunk( + env, + env->CallStaticObjectMethod( + WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer, + WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch, + type, dataArray.get(), 0, data.size())); if (env->ExceptionCheck()) { LOG(INFO) << StringPrintf("Exception thrown by dispatcher for 0x%08x", type); env->ExceptionDescribe(); @@ -4349,30 +4342,78 @@ bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pRep * * So we're pretty much stuck with copying data around multiple times. */ - ScopedLocalRef<jbyteArray> replyData(env, reinterpret_cast<jbyteArray>(env->GetObjectField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data))); - jint offset = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset); - length = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length); - type = env->GetIntField(chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type); - - VLOG(jdwp) << StringPrintf("DDM reply: type=0x%08x data=%p offset=%d length=%d", type, replyData.get(), offset, length); + ScopedLocalRef<jbyteArray> replyData( + env, + reinterpret_cast<jbyteArray>( + env->GetObjectField( + chunk.get(), WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data))); + jint offset = env->GetIntField(chunk.get(), + WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset); + jint length = env->GetIntField(chunk.get(), + WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length); + *out_type = env->GetIntField(chunk.get(), + WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_type); + + VLOG(jdwp) << StringPrintf("DDM reply: type=0x%08x data=%p offset=%d length=%d", + type, + replyData.get(), + offset, + length); if (length == 0 || replyData.get() == nullptr) { return false; } - const int kChunkHdrLen = 8; - uint8_t* reply = new uint8_t[length + kChunkHdrLen]; - if (reply == nullptr) { - LOG(WARNING) << "malloc failed: " << (length + kChunkHdrLen); + out_data->resize(length); + env->GetByteArrayRegion(replyData.get(), + offset, + length, + reinterpret_cast<jbyte*>(out_data->data())); + return true; +} + +/* + * "request" contains a full JDWP packet, possibly with multiple chunks. We + * need to process each, accumulate the replies, and ship the whole thing + * back. + * + * Returns "true" if we have a reply. The reply buffer is newly allocated, + * and includes the chunk type/length, followed by the data. + * + * OLD-TODO: we currently assume that the request and reply include a single + * chunk. If this becomes inconvenient we will need to adapt. + */ +bool Dbg::DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen) { + Thread* self = Thread::Current(); + JNIEnv* env = self->GetJniEnv(); + + uint32_t type = request->ReadUnsigned32("type"); + uint32_t length = request->ReadUnsigned32("length"); + + // Create a byte[] corresponding to 'request'. + size_t request_length = request->size(); + // Run through and find all chunks. [Currently just find the first.] + if (length != request_length) { + LOG(WARNING) << StringPrintf("bad chunk found (len=%u pktLen=%zd)", length, request_length); return false; } - JDWP::Set4BE(reply + 0, type); - JDWP::Set4BE(reply + 4, length); - env->GetByteArrayRegion(replyData.get(), offset, length, reinterpret_cast<jbyte*>(reply + kChunkHdrLen)); - *pReplyBuf = reply; - *pReplyLen = length + kChunkHdrLen; - - VLOG(jdwp) << StringPrintf("dvmHandleDdm returning type=%.4s %p len=%d", reinterpret_cast<char*>(reply), reply, length); + ArrayRef<const jbyte> data(reinterpret_cast<const jbyte*>(request->data()), request_length); + std::vector<uint8_t> out_data; + uint32_t out_type = 0; + request->Skip(request_length); + if (!DdmHandleChunk(env, type, data, &out_type, &out_data)) { + return false; + } + const uint32_t kDdmHeaderSize = 8; + *pReplyLen = out_data.size() + kDdmHeaderSize; + *pReplyBuf = new uint8_t[out_data.size() + kDdmHeaderSize]; + memcpy((*pReplyBuf) + kDdmHeaderSize, out_data.data(), out_data.size()); + JDWP::Set4BE(*pReplyBuf, out_type); + JDWP::Set4BE((*pReplyBuf) + 4, static_cast<uint32_t>(out_data.size())); + VLOG(jdwp) + << StringPrintf("dvmHandleDdm returning type=%.4s", reinterpret_cast<char*>(*pReplyBuf)) + << "0x" << std::hex << reinterpret_cast<uintptr_t>(*pReplyBuf) << std::dec + << " len= " << out_data.size(); return true; } @@ -4482,6 +4523,10 @@ void Dbg::PostThreadDeath(Thread* t) { Dbg::PostThreadStartOrStop(t, CHUNK_TYPE("THDE")); } +void Dbg::DdmSendChunk(uint32_t type, const ArrayRef<const uint8_t>& data) { + DdmSendChunk(type, data.size(), data.data()); +} + void Dbg::DdmSendChunk(uint32_t type, size_t byte_count, const uint8_t* buf) { CHECK(buf != nullptr); iovec vec[1]; diff --git a/runtime/debugger.h b/runtime/debugger.h index ec37833f6d..c3184e8374 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -27,6 +27,7 @@ #include <string> #include <vector> +#include "base/array_ref.h" #include "class_linker.h" #include "gc_root.h" #include "handle.h" @@ -52,6 +53,11 @@ class ScopedObjectAccessUnchecked; class StackVisitor; class Thread; +struct DebuggerDdmCallback : public DdmCallback { + void DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); +}; + struct DebuggerActiveMethodInspectionCallback : public MethodInspectionCallback { bool IsMethodBeingInspected(ArtMethod* m ATTRIBUTE_UNUSED) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); @@ -647,9 +653,17 @@ class Dbg { REQUIRES_SHARED(Locks::mutator_lock_); static void DdmSetThreadNotification(bool enable) REQUIRES(!Locks::thread_list_lock_); + static bool DdmHandleChunk( + JNIEnv* env, + uint32_t type, + const ArrayRef<const jbyte>& data, + /*out*/uint32_t* out_type, + /*out*/std::vector<uint8_t>* out_data); static bool DdmHandlePacket(JDWP::Request* request, uint8_t** pReplyBuf, int* pReplyLen); static void DdmConnected() REQUIRES_SHARED(Locks::mutator_lock_); static void DdmDisconnected() REQUIRES_SHARED(Locks::mutator_lock_); + static void DdmSendChunk(uint32_t type, const ArrayRef<const uint8_t>& bytes) + REQUIRES_SHARED(Locks::mutator_lock_); static void DdmSendChunk(uint32_t type, const std::vector<uint8_t>& bytes) REQUIRES_SHARED(Locks::mutator_lock_); static void DdmSendChunk(uint32_t type, size_t len, const uint8_t* buf) @@ -782,6 +796,7 @@ class Dbg { static bool gDebuggerActive; static DebuggerActiveMethodInspectionCallback gDebugActiveCallback; + static DebuggerDdmCallback gDebugDdmCallback; // Indicates whether we should drop the JDWP connection because the runtime stops or the // debugger called VirtualMachine.Dispose. diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 90bc4b8f94..c963f6e111 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -487,52 +487,52 @@ TEST_F(DexFileTest, GetMethodSignature) { "(IDJLjava/lang/Object;)Ljava/lang/Float;", "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)" }, - { // NOLINT [whitespace/braces] [4] + { "m2", "(ZSC)LGetMethodSignature;", "GetMethodSignature GetMethodSignature.m2(boolean, short, char)" }, - { // NOLINT [whitespace/braces] [4] + { "m3", "()V", "void GetMethodSignature.m3()" }, - { // NOLINT [whitespace/braces] [4] + { "m4", "(I)V", "void GetMethodSignature.m4(int)" }, - { // NOLINT [whitespace/braces] [4] + { "m5", "(II)V", "void GetMethodSignature.m5(int, int)" }, - { // NOLINT [whitespace/braces] [4] + { "m6", "(II[[I)V", "void GetMethodSignature.m6(int, int, int[][])" }, - { // NOLINT [whitespace/braces] [4] + { "m7", "(II[[ILjava/lang/Object;)V", "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)" }, - { // NOLINT [whitespace/braces] [4] + { "m8", "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V", "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])" }, - { // NOLINT [whitespace/braces] [4] + { "m9", "()I", "int GetMethodSignature.m9()" }, - { // NOLINT [whitespace/braces] [4] + { "mA", "()[[I", "int[][] GetMethodSignature.mA()" }, - { // NOLINT [whitespace/braces] [4] + { "mB", "()[[Ljava/lang/Object;", "java.lang.Object[][] GetMethodSignature.mB()" diff --git a/runtime/experimental_flags.h b/runtime/experimental_flags.h index b7f40372db..5f1443814a 100644 --- a/runtime/experimental_flags.h +++ b/runtime/experimental_flags.h @@ -30,10 +30,10 @@ struct ExperimentalFlags { }; constexpr ExperimentalFlags() : value_(0x0000) {} - constexpr ExperimentalFlags(decltype(kNone) t) // NOLINT, implicit + constexpr ExperimentalFlags(decltype(kNone) t) // NOLINT [runtime/explicit] : value_(static_cast<uint32_t>(t)) {} - constexpr operator decltype(kNone)() const { // NOLINT, implicit + constexpr operator decltype(kNone)() const { return static_cast<decltype(kNone)>(value_); } diff --git a/runtime/indenter.h b/runtime/indenter.h index cc6d4c4e96..69b973252d 100644 --- a/runtime/indenter.h +++ b/runtime/indenter.h @@ -32,7 +32,7 @@ class Indenter : public std::streambuf { public: Indenter(std::streambuf* out, char text, size_t count) : indent_next_(true), out_sbuf_(out), - text_{text, text, text, text, text, text, text, text}, // NOLINT(whitespace/braces) + text_{text, text, text, text, text, text, text, text}, count_(count) {} private: diff --git a/runtime/mem_map.h b/runtime/mem_map.h index 36a24169d5..5603963eac 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -21,7 +21,7 @@ #include <sys/types.h> #include <map> -#include <mutex> // NOLINT [build/c++11] [5] +#include <mutex> #include <string> #include "android-base/thread_annotations.h" diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc index f8f4b1f0ad..c79f51b51e 100644 --- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc +++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc @@ -16,6 +16,7 @@ #include "org_apache_harmony_dalvik_ddmc_DdmServer.h" +#include "base/array_ref.h" #include "base/logging.h" #include "debugger.h" #include "jni_internal.h" @@ -31,7 +32,9 @@ static void DdmServer_nativeSendChunk(JNIEnv* env, jclass, jint type, ScopedFastNativeObjectAccess soa(env); ScopedByteArrayRO data(env, javaData); DCHECK_LE(offset + length, static_cast<int32_t>(data.size())); - Dbg::DdmSendChunk(type, length, reinterpret_cast<const uint8_t*>(&data[offset])); + ArrayRef<const uint8_t> chunk(reinterpret_cast<const uint8_t*>(&data[offset]), + static_cast<size_t>(length)); + Runtime::Current()->GetRuntimeCallbacks()->DdmPublishChunk(static_cast<uint32_t>(type), chunk); } static JNINativeMethod gMethods[] = { diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h index 9a66983de7..70e767acf6 100644 --- a/runtime/obj_ptr.h +++ b/runtime/obj_ptr.h @@ -49,23 +49,22 @@ class ObjPtr { // Note: The following constructors allow implicit conversion. This simplifies code that uses // them, e.g., for parameter passing. However, in general, implicit-conversion constructors - // are discouraged and detected by cpplint and clang-tidy. So mark these constructors - // as NOLINT (without category, as the categories are different). + // are discouraged and detected by clang-tidy. - ALWAYS_INLINE ObjPtr(std::nullptr_t) // NOLINT + ALWAYS_INLINE ObjPtr(std::nullptr_t) REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {} template <typename Type, typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> - ALWAYS_INLINE ObjPtr(Type* ptr) // NOLINT + ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_) : reference_(Encode(static_cast<MirrorType*>(ptr))) { } template <typename Type, typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> - ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) // NOLINT + ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) REQUIRES_SHARED(Locks::mutator_lock_) : reference_(kObjPtrPoisoningValidateOnCopy ? Encode(static_cast<MirrorType*>(other.Ptr())) diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index cc09a776b8..85af560ce3 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -548,7 +548,7 @@ bool ParsedOptions::DoParse(const RuntimeOptions& options, // If not low memory mode, semispace otherwise. gc::CollectorType background_collector_type_; - gc::CollectorType collector_type_ = (XGcOption{}).collector_type_; // NOLINT [whitespace/braces] [5] + gc::CollectorType collector_type_ = (XGcOption{}).collector_type_; bool low_memory_mode_ = args.Exists(M::LowMemoryMode); background_collector_type_ = args.GetOrDefault(M::BackgroundGc); diff --git a/runtime/prebuilt_tools_test.cc b/runtime/prebuilt_tools_test.cc index 6fa9b3424d..158d9d6e69 100644 --- a/runtime/prebuilt_tools_test.cc +++ b/runtime/prebuilt_tools_test.cc @@ -29,7 +29,7 @@ class PrebuiltToolsTest : public CommonRuntimeTest { }; static void CheckToolsExist(const std::string& tools_dir) { - const char* tools[] { "as", "objcopy", "objdump" }; // NOLINT + const char* tools[] = { "as", "objcopy", "objdump" }; for (const char* tool : tools) { struct stat exec_st; std::string exec_path = tools_dir + tool; @@ -50,7 +50,7 @@ TEST_F(PrebuiltToolsTest, CheckHostTools) { TEST_F(PrebuiltToolsTest, CheckTargetTools) { // Other prebuilts are missing from the build server's repo manifest. - InstructionSet isas[] = { InstructionSet::kThumb2 }; // NOLINT + InstructionSet isas[] = { InstructionSet::kThumb2 }; for (InstructionSet isa : isas) { std::string tools_dir = GetAndroidTargetToolsDir(isa); if (tools_dir.empty()) { diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 720a9d6219..1e7fc3ee92 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -16,7 +16,7 @@ #include "reference_table.h" -#include <regex> // NOLINT [build/c++11] [5] +#include <regex> #include "android-base/stringprintf.h" diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc index 339fe822fd..40d7889565 100644 --- a/runtime/runtime_callbacks.cc +++ b/runtime/runtime_callbacks.cc @@ -35,6 +35,20 @@ static inline void Remove(T* cb, std::vector<T*>* data) { } } +void RuntimeCallbacks::AddDdmCallback(DdmCallback* cb) { + ddm_callbacks_.push_back(cb); +} + +void RuntimeCallbacks::RemoveDdmCallback(DdmCallback* cb) { + Remove(cb, &ddm_callbacks_); +} + +void RuntimeCallbacks::DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) { + for (DdmCallback* cb : ddm_callbacks_) { + cb->DdmPublishChunk(type, data); + } +} + void RuntimeCallbacks::AddMethodInspectionCallback(MethodInspectionCallback* cb) { method_inspection_callbacks_.push_back(cb); } diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h index c1ba9643a7..baf941a8e1 100644 --- a/runtime/runtime_callbacks.h +++ b/runtime/runtime_callbacks.h @@ -19,6 +19,7 @@ #include <vector> +#include "base/array_ref.h" #include "base/macros.h" #include "base/mutex.h" #include "dex_file.h" @@ -54,6 +55,13 @@ class ThreadLifecycleCallback; // any state checking (is the listener enabled) in the listener itself. For an example, see // Dbg. +class DdmCallback { + public: + virtual ~DdmCallback() {} + virtual void DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) + REQUIRES_SHARED(Locks::mutator_lock_) = 0; +}; + class RuntimeSigQuitCallback { public: virtual ~RuntimeSigQuitCallback() {} @@ -182,6 +190,13 @@ class RuntimeCallbacks { void RemoveMethodInspectionCallback(MethodInspectionCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); + // DDMS callbacks + void DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) + REQUIRES_SHARED(Locks::mutator_lock_); + + void AddDdmCallback(DdmCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); + void RemoveDdmCallback(DdmCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); + private: std::vector<ThreadLifecycleCallback*> thread_callbacks_ GUARDED_BY(Locks::mutator_lock_); @@ -197,6 +212,8 @@ class RuntimeCallbacks { GUARDED_BY(Locks::mutator_lock_); std::vector<MethodInspectionCallback*> method_inspection_callbacks_ GUARDED_BY(Locks::mutator_lock_); + std::vector<DdmCallback*> ddm_callbacks_ + GUARDED_BY(Locks::mutator_lock_); }; } // namespace art diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc index d283c79960..0b69851a55 100644 --- a/runtime/runtime_callbacks_test.cc +++ b/runtime/runtime_callbacks_test.cc @@ -22,7 +22,7 @@ #include <initializer_list> #include <memory> -#include <mutex> // NOLINT [build/c++11] [5] +#include <mutex> #include <string> #include "jni.h" diff --git a/runtime/runtime_options.cc b/runtime/runtime_options.cc index b072bb0c37..bce0d81cfb 100644 --- a/runtime/runtime_options.cc +++ b/runtime/runtime_options.cc @@ -30,7 +30,7 @@ namespace art { // Specify storage for the RuntimeOptions keys. -#define RUNTIME_OPTIONS_KEY(Type, Name, ...) const RuntimeArgumentMap::Key<Type> RuntimeArgumentMap::Name {__VA_ARGS__}; // NOLINT [readability/braces] [4] +#define RUNTIME_OPTIONS_KEY(Type, Name, ...) const RuntimeArgumentMap::Key<Type> RuntimeArgumentMap::Name {__VA_ARGS__}; #include "runtime_options.def" } // namespace art diff --git a/runtime/stack_map.h b/runtime/stack_map.h index db776eaa1a..85c734ee4c 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -711,7 +711,11 @@ class StackMapEncoding { total_bit_size_ += MinimumBitsToStore(native_pc_max); dex_pc_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max); + // Note: We're not encoding the dex pc if there is none. That's the case + // for an intrinsified native method, such as String.charAt(). + if (dex_pc_max != dex::kDexNoIndex) { + total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max); + } // We also need +1 for kNoDexRegisterMap, but since the size is strictly // greater than any offset we might try to encode, we already implicitly have it. diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h index 24f07632ce..1556abe67f 100644 --- a/runtime/subtype_check.h +++ b/runtime/subtype_check.h @@ -274,7 +274,7 @@ struct SubtypeCheck { // more complicated (e.g. ObjPtr or Depth call) will fail dchecks. // OK. zero-initializing subtype_check_info_ puts us into the kUninitialized state. - SubtypeCheckBits scb_uninitialized = SubtypeCheckBits{}; // NOLINT + SubtypeCheckBits scb_uninitialized = SubtypeCheckBits{}; WriteSubtypeCheckBits(klass, scb_uninitialized); // Do not use "SubtypeCheckInfo" API here since that requires Depth() diff --git a/runtime/subtype_check_info.h b/runtime/subtype_check_info.h index d10d4728ad..cd579c3a5c 100644 --- a/runtime/subtype_check_info.h +++ b/runtime/subtype_check_info.h @@ -188,7 +188,7 @@ struct SubtypeCheckInfo { // Returns a new root SubtypeCheckInfo with a blank PathToRoot. // Post-condition: The return valued has an Assigned state. static SubtypeCheckInfo CreateRoot() { - SubtypeCheckInfo io{}; // NOLINT + SubtypeCheckInfo io{}; io.depth_ = 0u; io.SetNext(io.GetNext() + 1u); @@ -220,7 +220,7 @@ struct SubtypeCheckInfo { child.MaybeInitNext(); // Always clear the inherited Parent's next Value on the child. - OverwriteNextValueFromParent(/*inout*/&child, BitStringChar{}); // NOLINT + OverwriteNextValueFromParent(/*inout*/&child, BitStringChar{}); // The state is now Initialized | Overflowed. DCHECK_NE(kAssigned, child.GetState()) << child.GetBitString(); @@ -392,7 +392,7 @@ struct SubtypeCheckInfo { // Clearing out the "Next" value like this // is often an intermediate operation which temporarily // violates the invariants. Do not do the extra dchecks. - SetNextUnchecked(BitStringChar{}); // NOLINT + SetNextUnchecked(BitStringChar{}); SetNextUnchecked(GetNext()+1u); } } diff --git a/runtime/subtype_check_info_test.cc b/runtime/subtype_check_info_test.cc index bc2e84e37d..338d75a285 100644 --- a/runtime/subtype_check_info_test.cc +++ b/runtime/subtype_check_info_test.cc @@ -47,7 +47,7 @@ BitStringChar MakeBitStringChar(size_t val) { BitString MakeBitString(std::initializer_list<size_t> values = {}) { CHECK_GE(BitString::kCapacity, values.size()); - BitString bs{}; // NOLINT + BitString bs{}; size_t i = 0; for (size_t val : values) { @@ -68,7 +68,7 @@ size_t AsUint(const T& value) { // Make max bistring, e.g. BitString[4095,7,255] for {12,3,8} template <size_t kCount = BitString::kCapacity> BitString MakeBitStringMax() { - BitString bs{}; // NOLINT + BitString bs{}; for (size_t i = 0; i < kCount; ++i) { bs.SetAt(i, @@ -132,7 +132,7 @@ struct SubtypeCheckInfoTest : public ::testing::Test { // Create an SubtypeCheckInfo with the same depth, but with everything else reset. // Returns: SubtypeCheckInfo in the Uninitialized state. static SubtypeCheckInfo CopyCleared(SubtypeCheckInfo sc) { - SubtypeCheckInfo cleared_copy{}; // NOLINT + SubtypeCheckInfo cleared_copy{}; cleared_copy.depth_ = sc.depth_; DCHECK_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy.GetState()); return cleared_copy; @@ -260,7 +260,7 @@ TEST_F(SubtypeCheckInfoTest, EncodedPathToRoot) { SubtypeCheckInfo io = MakeSubtypeCheckInfo(/*path_to_root*/MakeBitStringMax(), - /*next*/BitStringChar{}, // NOLINT + /*next*/BitStringChar{}, /*overflow*/false, /*depth*/BitString::kCapacity); // 0b11111...000 where MSB == 1, and leading 1s = the maximum bitstring representation. @@ -329,7 +329,7 @@ TEST_F(SubtypeCheckInfoTest, CopyCleared) { // CopyCleared is just a thin wrapper around value-init and providing the depth. SubtypeCheckInfo cleared_copy_value = - SubtypeCheckInfo::Create(SubtypeCheckBits{}, /*depth*/1u); // NOLINT + SubtypeCheckInfo::Create(SubtypeCheckBits{}, /*depth*/1u); EXPECT_EQ(SubtypeCheckInfo::kUninitialized, cleared_copy_value.GetState()); EXPECT_EQ(MakeBitString({}), GetPathToRoot(cleared_copy_value)); } |