diff options
author | 2016-12-07 11:35:37 +0000 | |
---|---|---|
committer | 2017-01-06 08:49:07 +0000 | |
commit | 811bd5ff0189122d34e8a1b8ccda889bbba4c0d1 (patch) | |
tree | 278b128c15dc32657e06fd38b7111407edef552f /runtime/common_dex_operations.h | |
parent | b51edffe1c0b331a4d4d5298938c7c1b31ebaf6a (diff) |
ART: Make method handle runtime code callable from compiler.
Most of this change is moving the existing method handles code, but it
also introduces a new header file, common_dex_operations.h, that has
some operations taken from interpreter_common.{h,cc} that are also used
by method handles (perform call, set field, get field).
Bug: 30550796
Test: m test-art-host
Change-Id: I2235e13770a5562950f2767f65a25ca273479150
Diffstat (limited to 'runtime/common_dex_operations.h')
-rw-r--r-- | runtime/common_dex_operations.h | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h new file mode 100644 index 0000000000..6693eefa5a --- /dev/null +++ b/runtime/common_dex_operations.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2016 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_COMMON_DEX_OPERATIONS_H_ +#define ART_RUNTIME_COMMON_DEX_OPERATIONS_H_ + +#include "art_field.h" +#include "art_method.h" +#include "class_linker.h" +#include "interpreter/unstarted_runtime.h" +#include "runtime.h" +#include "stack.h" +#include "thread.h" + +namespace art { + +namespace interpreter { + void ArtInterpreterToInterpreterBridge(Thread* self, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + + void ArtInterpreterToCompiledCodeBridge(Thread* self, + ArtMethod* caller, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, + JValue* result); +} // namespace interpreter + +inline void PerformCall(Thread* self, + const DexFile::CodeItem* code_item, + ArtMethod* caller_method, + const size_t first_dest_reg, + ShadowFrame* callee_frame, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (LIKELY(Runtime::Current()->IsStarted())) { + ArtMethod* target = callee_frame->GetMethod(); + if (ClassLinker::ShouldUseInterpreterEntrypoint( + target, + target->GetEntryPointFromQuickCompiledCode())) { + interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result); + } else { + interpreter::ArtInterpreterToCompiledCodeBridge( + self, caller_method, code_item, callee_frame, result); + } + } else { + interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg); + } +} + +template<Primitive::Type field_type> +static ALWAYS_INLINE void DoFieldGetCommon(Thread* self, + const ShadowFrame& shadow_frame, + ObjPtr<mirror::Object> obj, + ArtField* field, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_) { + field->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self); + + // Report this field access to instrumentation if needed. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldReadListeners())) { + StackHandleScope<1> hs(self); + // Wrap in handle wrapper in case the listener does thread suspension. + HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj)); + ObjPtr<mirror::Object> this_object; + if (!field->IsStatic()) { + this_object = obj; + } + instrumentation->FieldReadEvent(self, + this_object.Ptr(), + shadow_frame.GetMethod(), + shadow_frame.GetDexPC(), + field); + } + + switch (field_type) { + case Primitive::kPrimBoolean: + result->SetZ(field->GetBoolean(obj)); + break; + case Primitive::kPrimByte: + result->SetB(field->GetByte(obj)); + break; + case Primitive::kPrimChar: + result->SetC(field->GetChar(obj)); + break; + case Primitive::kPrimShort: + result->SetS(field->GetShort(obj)); + break; + case Primitive::kPrimInt: + result->SetI(field->GetInt(obj)); + break; + case Primitive::kPrimLong: + result->SetJ(field->GetLong(obj)); + break; + case Primitive::kPrimNot: + result->SetL(field->GetObject(obj)); + break; + case Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable " << field_type; + break; + } +} + +template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active> +ALWAYS_INLINE bool DoFieldPutCommon(Thread* self, + const ShadowFrame& shadow_frame, + ObjPtr<mirror::Object> obj, + ArtField* field, + const JValue& value) + REQUIRES_SHARED(Locks::mutator_lock_) { + field->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self); + + // Report this field access to instrumentation if needed. Since we only have the offset of + // the field from the base of the object, we need to look for it first. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldWriteListeners())) { + StackHandleScope<1> hs(self); + // Wrap in handle wrapper in case the listener does thread suspension. + HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj)); + ObjPtr<mirror::Object> this_object = field->IsStatic() ? nullptr : obj; + instrumentation->FieldWriteEvent(self, this_object.Ptr(), + shadow_frame.GetMethod(), + shadow_frame.GetDexPC(), + field, + value); + } + + switch (field_type) { + case Primitive::kPrimBoolean: + field->SetBoolean<transaction_active>(obj, value.GetZ()); + break; + case Primitive::kPrimByte: + field->SetByte<transaction_active>(obj, value.GetB()); + break; + case Primitive::kPrimChar: + field->SetChar<transaction_active>(obj, value.GetC()); + break; + case Primitive::kPrimShort: + field->SetShort<transaction_active>(obj, value.GetS()); + break; + case Primitive::kPrimInt: + field->SetInt<transaction_active>(obj, value.GetI()); + break; + case Primitive::kPrimLong: + field->SetLong<transaction_active>(obj, value.GetJ()); + break; + case Primitive::kPrimNot: { + ObjPtr<mirror::Object> reg = value.GetL(); + if (do_assignability_check && reg != nullptr) { + // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the + // object in the destructor. + ObjPtr<mirror::Class> field_class; + { + StackHandleScope<2> hs(self); + HandleWrapperObjPtr<mirror::Object> h_reg(hs.NewHandleWrapper(®)); + HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&obj)); + field_class = field->GetType<true>(); + } + if (!reg->VerifierInstanceOf(field_class.Ptr())) { + // This should never happen. + std::string temp1, temp2, temp3; + self->ThrowNewExceptionF("Ljava/lang/InternalError;", + "Put '%s' that is not instance of field '%s' in '%s'", + reg->GetClass()->GetDescriptor(&temp1), + field_class->GetDescriptor(&temp2), + field->GetDeclaringClass()->GetDescriptor(&temp3)); + return false; + } + } + field->SetObj<transaction_active>(obj, reg); + break; + } + case Primitive::kPrimVoid: { + LOG(FATAL) << "Unreachable " << field_type; + break; + } + } + return true; +} + +} // namespace art + +#endif // ART_RUNTIME_COMMON_DEX_OPERATIONS_H_ |