diff options
Diffstat (limited to 'runtime/lambda/closure.cc')
-rw-r--r-- | runtime/lambda/closure.cc | 414 |
1 files changed, 0 insertions, 414 deletions
diff --git a/runtime/lambda/closure.cc b/runtime/lambda/closure.cc deleted file mode 100644 index 179e4ee7f2..0000000000 --- a/runtime/lambda/closure.cc +++ /dev/null @@ -1,414 +0,0 @@ -/* - * 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 "lambda/closure.h" - -#include "base/logging.h" -#include "lambda/art_lambda_method.h" -#include "runtime/mirror/object_reference.h" - -static constexpr const bool kClosureSupportsReferences = false; -static constexpr const bool kClosureSupportsGarbageCollection = false; - -namespace art { -namespace lambda { - -template <typename T> -// TODO: can I return T __attribute__((__aligned__(1)))* here instead? -const uint8_t* Closure::GetUnsafeAtOffset(size_t offset) const { - // Do not DCHECK here with existing helpers since most of them will call into this function. - return reinterpret_cast<const uint8_t*>(captured_) + offset; -} - -size_t Closure::GetCapturedVariableSize(ShortyFieldType variable_type, size_t offset) const { - switch (variable_type) { - case ShortyFieldType::kLambda: - { - return GetClosureSize(GetUnsafeAtOffset<Closure>(offset)); - } - default: - DCHECK(variable_type.IsStaticSize()); - return variable_type.GetStaticSize(); - } -} - -// Templatize the flags to give the compiler a fighting chance to eliminate -// any unnecessary code through different uses of this function. -template <Closure::VariableInfo::Flags flags> -inline Closure::VariableInfo Closure::ParseTypeDescriptor(const char* type_descriptor, - size_t upto_index) const { - DCHECK(type_descriptor != nullptr); - - VariableInfo result; - - ShortyFieldType last_type; - size_t offset = (flags & VariableInfo::kOffset) ? GetStartingOffset() : 0; - size_t prev_offset = 0; - size_t count = 0; - - while ((type_descriptor = - ShortyFieldType::ParseFromFieldTypeDescriptor(type_descriptor, &last_type)) != nullptr) { - count++; - - if (flags & VariableInfo::kOffset) { - // Accumulate the sizes of all preceding captured variables as the current offset only. - offset += prev_offset; - prev_offset = GetCapturedVariableSize(last_type, offset); - } - - if ((count > upto_index)) { - break; - } - } - - if (flags & VariableInfo::kVariableType) { - result.variable_type_ = last_type; - } - - if (flags & VariableInfo::kIndex) { - result.index_ = count; - } - - if (flags & VariableInfo::kCount) { - result.count_ = count; - } - - if (flags & VariableInfo::kOffset) { - result.offset_ = offset; - } - - // TODO: We should probably store the result of this in the ArtLambdaMethod, - // to avoid re-computing the data every single time for static closures. - return result; -} - -size_t Closure::GetCapturedVariablesSize() const { - const size_t captured_variable_offset = offsetof(Closure, captured_); - DCHECK_GE(GetSize(), captured_variable_offset); // Prevent underflows. - return GetSize() - captured_variable_offset; -} - -size_t Closure::GetSize() const { - const size_t static_closure_size = lambda_info_->GetStaticClosureSize(); - if (LIKELY(lambda_info_->IsStaticSize())) { - return static_closure_size; - } - - DCHECK_GE(static_closure_size, sizeof(captured_[0].dynamic_.size_)); - const size_t dynamic_closure_size = captured_[0].dynamic_.size_; - // The dynamic size better be at least as big as the static size. - DCHECK_GE(dynamic_closure_size, static_closure_size); - - return dynamic_closure_size; -} - -void Closure::CopyTo(void* target, size_t target_size) const { - DCHECK_GE(target_size, GetSize()); - - // TODO: using memcpy is unsafe with read barriers, fix this once we add reference support - static_assert(kClosureSupportsReferences == false, - "Do not use memcpy with readbarrier references"); - memcpy(target, this, GetSize()); -} - -ArtMethod* Closure::GetTargetMethod() const { - return const_cast<ArtMethod*>(lambda_info_->GetArtMethod()); -} - -uint32_t Closure::GetHashCode() const { - // Start with a non-zero constant, a prime number. - uint32_t result = 17; - - // Include the hash with the ArtMethod. - { - uintptr_t method = reinterpret_cast<uintptr_t>(GetTargetMethod()); - result = 31 * result + Low32Bits(method); - if (sizeof(method) == sizeof(uint64_t)) { - result = 31 * result + High32Bits(method); - } - } - - // Include a hash for each captured variable. - for (size_t i = 0; i < GetCapturedVariablesSize(); ++i) { - // TODO: not safe for GC-able values since the address can move and the hash code would change. - uint8_t captured_variable_raw_value; - CopyUnsafeAtOffset<uint8_t>(i, /*out*/&captured_variable_raw_value); // NOLINT: [whitespace/comma] [3] - - result = 31 * result + captured_variable_raw_value; - } - - // TODO: Fix above loop to work for objects and lambdas. - static_assert(kClosureSupportsGarbageCollection == false, - "Need to update above loop to read the hash code from the " - "objects and lambdas recursively"); - - return result; -} - -bool Closure::ReferenceEquals(const Closure* other) const { - DCHECK(other != nullptr); - - // TODO: Need rework to use read barriers once closures have references inside of them that can - // move. Until then, it's safe to just compare the data inside of it directly. - static_assert(kClosureSupportsReferences == false, - "Unsafe to use memcmp in read barrier collector"); - - if (GetSize() != other->GetSize()) { - return false; - } - - return memcmp(this, other, GetSize()); -} - -size_t Closure::GetNumberOfCapturedVariables() const { - // TODO: refactor into art_lambda_method.h. Parsing should only be required here as a DCHECK. - VariableInfo variable_info = - ParseTypeDescriptor<VariableInfo::kCount>(GetCapturedVariablesTypeDescriptor(), - VariableInfo::kUpToIndexMax); - size_t count = variable_info.count_; - // Assuming each variable was 1 byte, the size should always be greater or equal than the count. - DCHECK_LE(count, GetCapturedVariablesSize()); - return count; -} - -const char* Closure::GetCapturedVariablesTypeDescriptor() const { - return lambda_info_->GetCapturedVariablesTypeDescriptor(); -} - -ShortyFieldType Closure::GetCapturedShortyType(size_t index) const { - DCHECK_LT(index, GetNumberOfCapturedVariables()); - - VariableInfo variable_info = - ParseTypeDescriptor<VariableInfo::kVariableType>(GetCapturedVariablesTypeDescriptor(), - index); - - return variable_info.variable_type_; -} - -uint32_t Closure::GetCapturedPrimitiveNarrow(size_t index) const { - DCHECK(GetCapturedShortyType(index).IsPrimitiveNarrow()); - - ShortyFieldType variable_type; - size_t offset; - GetCapturedVariableTypeAndOffset(index, &variable_type, &offset); - - // TODO: Restructure to use template specialization, e.g. GetCapturedPrimitive<T> - // so that we can avoid this nonsense regarding memcpy always overflowing. - // Plus, this additional switching seems redundant since the interpreter - // would've done it already, and knows the exact type. - uint32_t result = 0; - static_assert(ShortyFieldTypeTraits::IsPrimitiveNarrowType<decltype(result)>(), - "result must be a primitive narrow type"); - switch (variable_type) { - case ShortyFieldType::kBoolean: - CopyUnsafeAtOffset<bool>(offset, &result); - break; - case ShortyFieldType::kByte: - CopyUnsafeAtOffset<uint8_t>(offset, &result); - break; - case ShortyFieldType::kChar: - CopyUnsafeAtOffset<uint16_t>(offset, &result); - break; - case ShortyFieldType::kShort: - CopyUnsafeAtOffset<int16_t>(offset, &result); - break; - case ShortyFieldType::kInt: - CopyUnsafeAtOffset<int32_t>(offset, &result); - break; - case ShortyFieldType::kFloat: - // XX: Maybe there should just be a GetCapturedPrimitive<T> to avoid this shuffle? - // The interpreter's invoke seems to only special case references and wides, - // everything else is treated as a generic 32-bit pattern. - CopyUnsafeAtOffset<float>(offset, &result); - break; - default: - LOG(FATAL) - << "expected a valid narrow primitive shorty type but got " - << static_cast<char>(variable_type); - UNREACHABLE(); - } - - return result; -} - -uint64_t Closure::GetCapturedPrimitiveWide(size_t index) const { - DCHECK(GetCapturedShortyType(index).IsPrimitiveWide()); - - ShortyFieldType variable_type; - size_t offset; - GetCapturedVariableTypeAndOffset(index, &variable_type, &offset); - - // TODO: Restructure to use template specialization, e.g. GetCapturedPrimitive<T> - // so that we can avoid this nonsense regarding memcpy always overflowing. - // Plus, this additional switching seems redundant since the interpreter - // would've done it already, and knows the exact type. - uint64_t result = 0; - static_assert(ShortyFieldTypeTraits::IsPrimitiveWideType<decltype(result)>(), - "result must be a primitive wide type"); - switch (variable_type) { - case ShortyFieldType::kLong: - CopyUnsafeAtOffset<int64_t>(offset, &result); - break; - case ShortyFieldType::kDouble: - CopyUnsafeAtOffset<double>(offset, &result); - break; - default: - LOG(FATAL) - << "expected a valid primitive wide shorty type but got " - << static_cast<char>(variable_type); - UNREACHABLE(); - } - - return result; -} - -mirror::Object* Closure::GetCapturedObject(size_t index) const { - DCHECK(GetCapturedShortyType(index).IsObject()); - - ShortyFieldType variable_type; - size_t offset; - GetCapturedVariableTypeAndOffset(index, &variable_type, &offset); - - // TODO: Restructure to use template specialization, e.g. GetCapturedPrimitive<T> - // so that we can avoid this nonsense regarding memcpy always overflowing. - // Plus, this additional switching seems redundant since the interpreter - // would've done it already, and knows the exact type. - mirror::Object* result = nullptr; - static_assert(ShortyFieldTypeTraits::IsObjectType<decltype(result)>(), - "result must be an object type"); - switch (variable_type) { - case ShortyFieldType::kObject: - // TODO: This seems unsafe. This may need to use gcroots. - static_assert(kClosureSupportsGarbageCollection == false, - "May need GcRoots and definitely need mutator locks"); - { - mirror::CompressedReference<mirror::Object> compressed_result; - CopyUnsafeAtOffset<uint32_t>(offset, &compressed_result); - result = compressed_result.AsMirrorPtr(); - } - break; - default: - CHECK(false) - << "expected a valid shorty type but got " << static_cast<char>(variable_type); - UNREACHABLE(); - } - - return result; -} - -size_t Closure::GetCapturedClosureSize(size_t index) const { - DCHECK(GetCapturedShortyType(index).IsLambda()); - size_t offset = GetCapturedVariableOffset(index); - - auto* captured_ptr = reinterpret_cast<const uint8_t*>(&captured_); - size_t closure_size = GetClosureSize(captured_ptr + offset); - - return closure_size; -} - -void Closure::CopyCapturedClosure(size_t index, void* destination, size_t destination_room) const { - DCHECK(GetCapturedShortyType(index).IsLambda()); - size_t offset = GetCapturedVariableOffset(index); - - auto* captured_ptr = reinterpret_cast<const uint8_t*>(&captured_); - size_t closure_size = GetClosureSize(captured_ptr + offset); - - static_assert(ShortyFieldTypeTraits::IsLambdaType<Closure*>(), - "result must be a lambda type"); - - CopyUnsafeAtOffset<Closure>(offset, destination, closure_size, destination_room); -} - -size_t Closure::GetCapturedVariableOffset(size_t index) const { - VariableInfo variable_info = - ParseTypeDescriptor<VariableInfo::kOffset>(GetCapturedVariablesTypeDescriptor(), - index); - - size_t offset = variable_info.offset_; - - return offset; -} - -void Closure::GetCapturedVariableTypeAndOffset(size_t index, - ShortyFieldType* out_type, - size_t* out_offset) const { - DCHECK(out_type != nullptr); - DCHECK(out_offset != nullptr); - - static constexpr const VariableInfo::Flags kVariableTypeAndOffset = - static_cast<VariableInfo::Flags>(VariableInfo::kVariableType | VariableInfo::kOffset); - VariableInfo variable_info = - ParseTypeDescriptor<kVariableTypeAndOffset>(GetCapturedVariablesTypeDescriptor(), - index); - - ShortyFieldType variable_type = variable_info.variable_type_; - size_t offset = variable_info.offset_; - - *out_type = variable_type; - *out_offset = offset; -} - -template <typename T> -void Closure::CopyUnsafeAtOffset(size_t offset, - void* destination, - size_t src_size, - size_t destination_room) const { - DCHECK_GE(destination_room, src_size); - const uint8_t* data_ptr = GetUnsafeAtOffset<T>(offset); - memcpy(destination, data_ptr, sizeof(T)); -} - -// TODO: This is kind of ugly. I would prefer an unaligned_ptr<Closure> here. -// Unfortunately C++ doesn't let you lower the alignment (i.e. alignas(1) Closure*) is not legal. -size_t Closure::GetClosureSize(const uint8_t* closure) { - DCHECK(closure != nullptr); - - static_assert(!std::is_base_of<mirror::Object, Closure>::value, - "It might be unsafe to call memcpy on a managed object"); - - // Safe as long as it's not a mirror Object. - // TODO: Should probably wrap this in like MemCpyNative or some such which statically asserts - // we aren't trying to copy mirror::Object data around. - ArtLambdaMethod* closure_info; - memcpy(&closure_info, closure + offsetof(Closure, lambda_info_), sizeof(closure_info)); - - if (LIKELY(closure_info->IsStaticSize())) { - return closure_info->GetStaticClosureSize(); - } - - // The size is dynamic, so we need to read it from captured_variables_ portion. - size_t dynamic_size; - memcpy(&dynamic_size, - closure + offsetof(Closure, captured_[0].dynamic_.size_), - sizeof(dynamic_size)); - static_assert(sizeof(dynamic_size) == sizeof(captured_[0].dynamic_.size_), - "Dynamic size type must match the structural type of the size"); - - DCHECK_GE(dynamic_size, closure_info->GetStaticClosureSize()); - return dynamic_size; -} - -size_t Closure::GetStartingOffset() const { - static constexpr const size_t captured_offset = offsetof(Closure, captured_); - if (LIKELY(lambda_info_->IsStaticSize())) { - return offsetof(Closure, captured_[0].static_variables_) - captured_offset; - } else { - return offsetof(Closure, captured_[0].dynamic_.variables_) - captured_offset; - } -} - -} // namespace lambda -} // namespace art |