summaryrefslogtreecommitdiff
path: root/runtime/lambda/closure.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lambda/closure.cc')
-rw-r--r--runtime/lambda/closure.cc414
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