diff options
author | 2016-12-07 11:35:37 +0000 | |
---|---|---|
committer | 2017-01-06 08:49:07 +0000 | |
commit | 811bd5ff0189122d34e8a1b8ccda889bbba4c0d1 (patch) | |
tree | 278b128c15dc32657e06fd38b7111407edef552f /runtime/interpreter/interpreter_common.cc | |
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/interpreter/interpreter_common.cc')
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 801 |
1 files changed, 41 insertions, 760 deletions
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index a09e71b6c0..ca26207093 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -32,7 +32,6 @@ #include "reflection.h" #include "reflection-inl.h" #include "stack.h" -#include "unstarted_runtime.h" #include "verifier/method_verifier.h" #include "well_known_classes.h" @@ -43,60 +42,6 @@ void ThrowNullPointerExceptionFromInterpreter() { ThrowNullPointerExceptionFromDexPC(); } -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; - default: - LOG(FATAL) << "Unreachable: " << field_type; - UNREACHABLE(); - } -} - template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check> bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { @@ -184,48 +129,6 @@ EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticObjectRead, Primitive::kPrimNot) #undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL #undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL -// Helper for getters in invoke-polymorphic. -inline static void DoFieldGetForInvokePolymorphic(Thread* self, - const ShadowFrame& shadow_frame, - ObjPtr<mirror::Object>& obj, - ArtField* field, - Primitive::Type field_type, - JValue* result) - REQUIRES_SHARED(Locks::mutator_lock_) { - switch (field_type) { - case Primitive::kPrimBoolean: - DoFieldGetCommon<Primitive::kPrimBoolean>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimByte: - DoFieldGetCommon<Primitive::kPrimByte>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimChar: - DoFieldGetCommon<Primitive::kPrimChar>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimShort: - DoFieldGetCommon<Primitive::kPrimShort>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimInt: - DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimLong: - DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimFloat: - DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimDouble: - DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimNot: - DoFieldGetCommon<Primitive::kPrimNot>(self, shadow_frame, obj, field, result); - break; - case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable: " << field_type; - UNREACHABLE(); - } -} - // Handles iget-quick, iget-wide-quick and iget-object-quick instructions. // Returns true on success, otherwise throws an exception and returns false. template<Primitive::Type field_type> @@ -300,42 +203,6 @@ EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong); // iget-wide-qui EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-quick. #undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL -static JValue GetFieldValue(const ShadowFrame& shadow_frame, - Primitive::Type field_type, - uint32_t vreg) - REQUIRES_SHARED(Locks::mutator_lock_) { - JValue field_value; - switch (field_type) { - case Primitive::kPrimBoolean: - field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg))); - break; - case Primitive::kPrimByte: - field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg))); - break; - case Primitive::kPrimChar: - field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg))); - break; - case Primitive::kPrimShort: - field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg))); - break; - case Primitive::kPrimInt: - case Primitive::kPrimFloat: - field_value.SetI(shadow_frame.GetVReg(vreg)); - break; - case Primitive::kPrimLong: - case Primitive::kPrimDouble: - field_value.SetJ(shadow_frame.GetVRegLong(vreg)); - break; - case Primitive::kPrimNot: - field_value.SetL(shadow_frame.GetVRegReference(vreg)); - break; - case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable: " << field_type; - UNREACHABLE(); - } - return field_value; -} - template<Primitive::Type field_type> static JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -369,82 +236,6 @@ static JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg) return field_value; } -template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active> -static inline bool DoFieldPutCommon(Thread* self, - const ShadowFrame& shadow_frame, - ObjPtr<mirror::Object>& obj, - ArtField* f, - const JValue& value) - REQUIRES_SHARED(Locks::mutator_lock_) { - f->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 = f->IsStatic() ? nullptr : obj; - instrumentation->FieldWriteEvent(self, this_object.Ptr(), - shadow_frame.GetMethod(), - shadow_frame.GetDexPC(), - f, - value); - } - - switch (field_type) { - case Primitive::kPrimBoolean: - f->SetBoolean<transaction_active>(obj, value.GetZ()); - break; - case Primitive::kPrimByte: - f->SetByte<transaction_active>(obj, value.GetB()); - break; - case Primitive::kPrimChar: - f->SetChar<transaction_active>(obj, value.GetC()); - break; - case Primitive::kPrimShort: - f->SetShort<transaction_active>(obj, value.GetS()); - break; - case Primitive::kPrimInt: - f->SetInt<transaction_active>(obj, value.GetI()); - break; - case Primitive::kPrimLong: - f->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 = f->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), - f->GetDeclaringClass()->GetDescriptor(&temp3)); - return false; - } - } - f->SetObj<transaction_active>(obj, reg); - break; - } - default: - LOG(FATAL) << "Unreachable: " << field_type; - UNREACHABLE(); - } - return true; -} - template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, bool transaction_active> bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst, @@ -511,46 +302,6 @@ EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(StaticObjectWrite, Primitive::kPrimNot) #undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL #undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL -// Helper for setters in invoke-polymorphic. -bool DoFieldPutForInvokePolymorphic(Thread* self, - ShadowFrame& shadow_frame, - ObjPtr<mirror::Object>& obj, - ArtField* field, - Primitive::Type field_type, - const JValue& value) - REQUIRES_SHARED(Locks::mutator_lock_) { - static const bool kDoCheckAssignability = false; - static const bool kTransaction = false; - switch (field_type) { - case Primitive::kPrimBoolean: - return DoFieldPutCommon<Primitive::kPrimBoolean, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimByte: - return DoFieldPutCommon<Primitive::kPrimByte, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimChar: - return DoFieldPutCommon<Primitive::kPrimChar, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimShort: - return DoFieldPutCommon<Primitive::kPrimShort, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimInt: - case Primitive::kPrimFloat: - return DoFieldPutCommon<Primitive::kPrimInt, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimLong: - case Primitive::kPrimDouble: - return DoFieldPutCommon<Primitive::kPrimLong, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimNot: - return DoFieldPutCommon<Primitive::kPrimNot, kDoCheckAssignability, kTransaction>( - self, shadow_frame, obj, field, value); - case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable: " << field_type; - UNREACHABLE(); - } -} - template<Primitive::Type field_type, bool transaction_active> bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) { ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); @@ -697,36 +448,6 @@ static ALWAYS_INLINE bool DoCallCommon(ArtMethod* called_method, uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_); template <bool is_range> -static ALWAYS_INLINE bool DoCallPolymorphic(ArtMethod* called_method, - Handle<mirror::MethodType> callsite_type, - Handle<mirror::MethodType> target_type, - Thread* self, - ShadowFrame& shadow_frame, - JValue* result, - uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t vregC, - const MethodHandleKind handle_kind) - REQUIRES_SHARED(Locks::mutator_lock_); - -template <bool is_range> -static ALWAYS_INLINE bool DoCallTransform(ArtMethod* called_method, - Handle<mirror::MethodType> callsite_type, - Handle<mirror::MethodType> callee_type, - Thread* self, - ShadowFrame& shadow_frame, - Handle<mirror::MethodHandleImpl> receiver, - JValue* result, - uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_); - -ALWAYS_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_); - -template <bool is_range> ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame, ShadowFrame* callee_frame, const uint32_t (&arg)[Instruction::kMaxVarArgRegs], @@ -798,55 +519,12 @@ void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame, } } -inline static bool IsInvokeExact(const DexFile& dex_file, int invoke_method_idx) { - // This check uses string comparison as it needs less code and data - // to do than fetching the associated ArtMethod from the DexCache - // and checking against ArtMethods in the well known classes. The - // verifier needs to perform a more rigorous check. - const char* method_name = dex_file.GetMethodName(dex_file.GetMethodId(invoke_method_idx)); - bool is_invoke_exact = (0 == strcmp(method_name, "invokeExact")); - DCHECK(is_invoke_exact || (0 == strcmp(method_name, "invoke"))); - return is_invoke_exact; -} - -inline static ObjPtr<mirror::Class> GetAndInitializeDeclaringClass(Thread* self, ArtField* field) - REQUIRES_SHARED(Locks::mutator_lock_) { - // Method handle invocations on static fields should ensure class is - // initialized. This usually happens when an instance is constructed - // or class members referenced, but this is not guaranteed when - // looking up method handles. - ObjPtr<mirror::Class> klass = field->GetDeclaringClass(); - if (UNLIKELY(!klass->IsInitialized())) { - StackHandleScope<1> hs(self); - HandleWrapperObjPtr<mirror::Class> h(hs.NewHandleWrapper(&klass)); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h, true, true)) { - DCHECK(self->IsExceptionPending()); - return nullptr; - } - } - return klass; -} - -// Returns true iff. the callsite type for a polymorphic invoke is transformer -// like, i.e that it has a single input argument whose type is -// dalvik.system.EmulatedStackFrame. -static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type) - REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::ObjectArray<mirror::Class>> param_types(callsite_type->GetPTypes()); - if (param_types->GetLength() == 1) { - ObjPtr<mirror::Class> param(param_types->GetWithoutChecks(0)); - return param == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_EmulatedStackFrame); - } - - return false; -} - template<bool is_range, bool do_access_check> -inline bool DoInvokePolymorphic(Thread* self, - ShadowFrame& shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result) +bool DoInvokePolymorphic(Thread* self, + ShadowFrame& shadow_frame, + const Instruction* inst, + uint16_t inst_data, + JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { // Invoke-polymorphic instructions always take a receiver. i.e, they are never static. const uint32_t vRegC = (is_range) ? inst->VRegC_4rcc() : inst->VRegC_45cc(); @@ -857,15 +535,10 @@ inline bool DoInvokePolymorphic(Thread* self, // and provides sane return result in error cases. result->SetJ(0); - // Determine if this invocation is MethodHandle.invoke() or - // MethodHandle.invokeExact(). - bool is_invoke_exact = IsInvokeExact(shadow_frame.GetMethod()->GetDeclaringClass()->GetDexFile(), - invoke_method_idx); - // The invoke_method_idx here is the name of the signature polymorphic method that // was symbolically invoked in bytecode (say MethodHandle.invoke or MethodHandle.invokeExact) // and not the method that we'll dispatch to in the end. - StackHandleScope<6> hs(self); + StackHandleScope<5> hs(self); Handle<mirror::MethodHandleImpl> method_handle(hs.NewHandle( ObjPtr<mirror::MethodHandleImpl>::DownCast( MakeObjPtr(shadow_frame.GetVRegReference(vRegC))))); @@ -877,7 +550,7 @@ inline bool DoInvokePolymorphic(Thread* self, } // The vRegH value gives the index of the proto_id associated with this - // signature polymorphic callsite. + // signature polymorphic call site. const uint32_t callsite_proto_id = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); // Call through to the classlinker and ask it to resolve the static type associated @@ -896,224 +569,43 @@ inline bool DoInvokePolymorphic(Thread* self, return false; } - const MethodHandleKind handle_kind = method_handle->GetHandleKind(); - Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType())); - CHECK(handle_type.Get() != nullptr); - { - // We need to check the nominal type of the handle in addition to the - // real type. The "nominal" type is present when MethodHandle.asType is - // called any handle, and results in the declared type of the handle - // changing. - ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType()); - ObjPtr<mirror::MethodType> check_type(nullptr); - if (LIKELY(nominal_type.Ptr() == nullptr)) { - check_type.Assign(handle_type.Get()); - } else { - check_type.Assign(nominal_type.Ptr()); - } - - if (is_invoke_exact) { - if (UNLIKELY(!callsite_type->IsExactMatch(check_type.Ptr()))) { - ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get()); - return false; - } - } else if (!IsInvokeTransform(handle_kind)) { - if (UNLIKELY(!IsCallerTransformer(callsite_type) && - !callsite_type->IsConvertible(check_type.Ptr()))) { - ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get()); - return false; - } - } - } + ArtMethod* invoke_method = + class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(self, + invoke_method_idx, + shadow_frame.GetMethod(), + kVirtual); - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; - uint32_t first_src_reg = 0; + // There is a common dispatch method for method handles that takes + // arguments either from a range or an array of arguments depending + // on whether the DEX instruction is invoke-polymorphic/range or + // invoke-polymorphic. The array here is for the latter. + uint32_t args[Instruction::kMaxVarArgRegs] = {}; if (is_range) { - first_src_reg = (inst->VRegC_4rcc() + 1); + // VRegC is the register holding the method handle. Arguments passed + // to the method handle's target do not include the method handle. + uint32_t first_arg = inst->VRegC_4rcc() + 1; + return DoInvokePolymorphic<is_range, do_access_check>(self, + invoke_method, + shadow_frame, + method_handle, + callsite_type, + args /* unused */, + first_arg, + result); } else { - inst->GetVarArgs(arg, inst_data); - arg[0] = arg[1]; - arg[1] = arg[2]; - arg[2] = arg[3]; - arg[3] = arg[4]; - arg[4] = 0; - first_src_reg = arg[0]; - } - - if (IsInvoke(handle_kind)) { - // Get the method we're actually invoking along with the kind of - // invoke that is desired. We don't need to perform access checks at this - // point because they would have been performed on our behalf at the point - // of creation of the method handle. - ArtMethod* called_method = method_handle->GetTargetMethod(); - CHECK(called_method != nullptr); - - if (handle_kind == kInvokeVirtual || handle_kind == kInvokeInterface) { - // TODO: Unfortunately, we have to postpone dynamic receiver based checks - // because the receiver might be cast or might come from an emulated stack - // frame, which means that it is unknown at this point. We perform these - // checks inside DoCallPolymorphic right before we do the actual invoke. - } else if (handle_kind == kInvokeDirect) { - // String constructors are a special case, they are replaced with StringFactory - // methods. - if (called_method->IsConstructor() && called_method->GetDeclaringClass()->IsStringClass()) { - DCHECK(handle_type->GetRType()->IsStringClass()); - called_method = WellKnownClasses::StringInitToStringFactory(called_method); - } - } else if (handle_kind == kInvokeSuper) { - ObjPtr<mirror::Class> declaring_class = called_method->GetDeclaringClass(); - - // Note that we're not dynamically dispatching on the type of the receiver - // here. We use the static type of the "receiver" object that we've - // recorded in the method handle's type, which will be the same as the - // special caller that was specified at the point of lookup. - ObjPtr<mirror::Class> referrer_class = handle_type->GetPTypes()->Get(0); - if (!declaring_class->IsInterface()) { - ObjPtr<mirror::Class> super_class = referrer_class->GetSuperClass(); - uint16_t vtable_index = called_method->GetMethodIndex(); - DCHECK(super_class != nullptr); - DCHECK(super_class->HasVTable()); - // Note that super_class is a super of referrer_class and called_method - // will always be declared by super_class (or one of its super classes). - DCHECK_LT(vtable_index, super_class->GetVTableLength()); - called_method = super_class->GetVTableEntry(vtable_index, kRuntimePointerSize); - } else { - called_method = referrer_class->FindVirtualMethodForInterfaceSuper( - called_method, kRuntimePointerSize); - } - - CHECK(called_method != nullptr); - } - - if (IsInvokeTransform(handle_kind)) { - // There are two cases here - method handles representing regular - // transforms and those representing call site transforms. Method - // handles for call site transforms adapt their MethodType to match - // the call site. For these, the |callee_type| is the same as the - // |callsite_type|. The VarargsCollector is such a tranform, its - // method type depends on the call site, ie. x(a) or x(a, b), or - // x(a, b, c). The VarargsCollector invokes a variable arity method - // with the arity arguments in an array. - Handle<mirror::MethodType> callee_type = - (handle_kind == kInvokeCallSiteTransform) ? callsite_type : handle_type; - return DoCallTransform<is_range>(called_method, - callsite_type, - callee_type, - self, - shadow_frame, - method_handle /* receiver */, - result, - arg, - first_src_reg); - } else { - return DoCallPolymorphic<is_range>(called_method, - callsite_type, - handle_type, - self, - shadow_frame, - result, - arg, - first_src_reg, - handle_kind); - } - } else { - DCHECK(!is_range); - ArtField* field = method_handle->GetTargetField(); - Primitive::Type field_type = field->GetTypeAsPrimitiveType(); - - switch (handle_kind) { - case kInstanceGet: { - ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(first_src_reg); - DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result); - if (!ConvertReturnValue(callsite_type, handle_type, result)) { - DCHECK(self->IsExceptionPending()); - return false; - } - return true; - } - case kStaticGet: { - ObjPtr<mirror::Object> obj = GetAndInitializeDeclaringClass(self, field); - if (obj == nullptr) { - DCHECK(self->IsExceptionPending()); - return false; - } - DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result); - if (!ConvertReturnValue(callsite_type, handle_type, result)) { - DCHECK(self->IsExceptionPending()); - return false; - } - return true; - } - case kInstancePut: { - JValue value = GetFieldValue(shadow_frame, field_type, arg[1]); - if (!ConvertArgumentValue(callsite_type, handle_type, 1, &value)) { - DCHECK(self->IsExceptionPending()); - return false; - } - ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(first_src_reg); - return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value); - } - case kStaticPut: { - JValue value = GetFieldValue(shadow_frame, field_type, arg[0]); - if (!ConvertArgumentValue(callsite_type, handle_type, 0, &value)) { - DCHECK(self->IsExceptionPending()); - return false; - } - ObjPtr<mirror::Object> obj = field->GetDeclaringClass(); - return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value); - } - default: - LOG(FATAL) << "Unreachable: " << handle_kind; - UNREACHABLE(); - } - } -} - -// Calculate the number of ins for a proxy or native method, where we -// can't just look at the code item. -static inline size_t GetInsForProxyOrNativeMethod(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(method->IsNative() || method->IsProxyMethod()); - - method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); - size_t num_ins = 0; - // Separate accounting for the receiver, which isn't a part of the - // shorty. - if (!method->IsStatic()) { - ++num_ins; - } - - uint32_t shorty_len = 0; - const char* shorty = method->GetShorty(&shorty_len); - for (size_t i = 1; i < shorty_len; ++i) { - const char c = shorty[i]; - ++num_ins; - if (c == 'J' || c == 'D') { - ++num_ins; - } - } - - return num_ins; -} - -inline void PerformCall(Thread* self, - const DexFile::CodeItem* code_item, - ArtMethod* caller_method, - const size_t first_dest_reg, - ShadowFrame* callee_frame, - JValue* result) { - if (LIKELY(Runtime::Current()->IsStarted())) { - ArtMethod* target = callee_frame->GetMethod(); - if (ClassLinker::ShouldUseInterpreterEntrypoint( - target, - target->GetEntryPointFromQuickCompiledCode())) { - ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result); - } else { - ArtInterpreterToCompiledCodeBridge( - self, caller_method, code_item, callee_frame, result); - } - } else { - UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg); + // Get the register arguments for the invoke. + inst->GetVarArgs(args, inst_data); + // Drop the first register which is the method handle performing the invoke. + memcpy(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1)); + args[Instruction::kMaxVarArgRegs - 1] = 0; + return DoInvokePolymorphic<is_range, do_access_check>(self, + invoke_method, + shadow_frame, + method_handle, + callsite_type, + args, + args[0], + result); } } @@ -1139,217 +631,6 @@ inline void CopyRegisters(ShadowFrame& caller_frame, } } -template <bool is_range> -static inline bool DoCallPolymorphic(ArtMethod* called_method, - Handle<mirror::MethodType> callsite_type, - Handle<mirror::MethodType> target_type, - Thread* self, - ShadowFrame& shadow_frame, - JValue* result, - uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t first_src_reg, - const MethodHandleKind handle_kind) { - // Compute method information. - const DexFile::CodeItem* code_item = called_method->GetCodeItem(); - - // Number of registers for the callee's call frame. Note that for non-exact - // invokes, we always derive this information from the callee method. We - // cannot guarantee during verification that the number of registers encoded - // in the invoke is equal to the number of ins for the callee. This is because - // some transformations (such as boxing a long -> Long or wideining an - // int -> long will change that number. - uint16_t num_regs; - size_t num_input_regs; - size_t first_dest_reg; - if (LIKELY(code_item != nullptr)) { - num_regs = code_item->registers_size_; - first_dest_reg = num_regs - code_item->ins_size_; - num_input_regs = code_item->ins_size_; - // Parameter registers go at the end of the shadow frame. - DCHECK_NE(first_dest_reg, (size_t)-1); - } else { - // No local regs for proxy and native methods. - DCHECK(called_method->IsNative() || called_method->IsProxyMethod()); - num_regs = num_input_regs = GetInsForProxyOrNativeMethod(called_method); - first_dest_reg = 0; - } - - // Allocate shadow frame on the stack. - ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = - CREATE_SHADOW_FRAME(num_regs, &shadow_frame, called_method, /* dex pc */ 0); - ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get(); - - // Whether this polymorphic invoke was issued by a transformer method. - bool is_caller_transformer = false; - // Thread might be suspended during PerformArgumentConversions due to the - // allocations performed during boxing. - { - ScopedStackedShadowFramePusher pusher( - self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction); - if (callsite_type->IsExactMatch(target_type.Get())) { - // This is an exact invoke, we can take the fast path of just copying all - // registers without performing any argument conversions. - CopyRegisters<is_range>(shadow_frame, - new_shadow_frame, - arg, - first_src_reg, - first_dest_reg, - num_input_regs); - } else { - // This includes the case where we're entering this invoke-polymorphic - // from a transformer method. In that case, the callsite_type will contain - // a single argument of type dalvik.system.EmulatedStackFrame. In that - // case, we'll have to unmarshal the EmulatedStackFrame into the - // new_shadow_frame and perform argument conversions on it. - if (IsCallerTransformer(callsite_type)) { - is_caller_transformer = true; - // The emulated stack frame is the first and only argument when we're coming - // through from a transformer. - ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame( - reinterpret_cast<mirror::EmulatedStackFrame*>( - shadow_frame.GetVRegReference(first_src_reg))); - if (!emulated_stack_frame->WriteToShadowFrame(self, - target_type, - first_dest_reg, - new_shadow_frame)) { - DCHECK(self->IsExceptionPending()); - result->SetL(0); - return false; - } - } else if (!ConvertAndCopyArgumentsFromCallerFrame<is_range>(self, - callsite_type, - target_type, - shadow_frame, - first_src_reg, - first_dest_reg, - arg, - new_shadow_frame)) { - DCHECK(self->IsExceptionPending()); - result->SetL(0); - return false; - } - } - } - - // See TODO in DoInvokePolymorphic : We need to perform this dynamic, receiver - // based dispatch right before we perform the actual call, because the - // receiver isn't known very early. - if (handle_kind == kInvokeVirtual || handle_kind == kInvokeInterface) { - ObjPtr<mirror::Object> receiver(new_shadow_frame->GetVRegReference(first_dest_reg)); - ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass()); - // Verify that _vRegC is an object reference and of the type expected by - // the receiver. - if (!VerifyObjectIsClass(receiver, declaring_class)) { - DCHECK(self->IsExceptionPending()); - return false; - } - - called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface( - called_method, kRuntimePointerSize); - } - - PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result); - if (self->IsExceptionPending()) { - return false; - } - - // If the caller of this signature polymorphic method was a transformer, - // we need to copy the result back out to the emulated stack frame. - if (is_caller_transformer) { - StackHandleScope<2> hs(self); - Handle<mirror::EmulatedStackFrame> emulated_stack_frame( - hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>( - shadow_frame.GetVRegReference(first_src_reg)))); - Handle<mirror::MethodType> emulated_stack_type(hs.NewHandle(emulated_stack_frame->GetType())); - JValue local_result; - local_result.SetJ(result->GetJ()); - - if (ConvertReturnValue(emulated_stack_type, target_type, &local_result)) { - emulated_stack_frame->SetReturnValue(self, local_result); - return true; - } else { - DCHECK(self->IsExceptionPending()); - return false; - } - } else { - return ConvertReturnValue(callsite_type, target_type, result); - } -} - -template <bool is_range> -static inline bool DoCallTransform(ArtMethod* called_method, - Handle<mirror::MethodType> callsite_type, - Handle<mirror::MethodType> callee_type, - Thread* self, - ShadowFrame& shadow_frame, - Handle<mirror::MethodHandleImpl> receiver, - JValue* result, - uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t first_src_reg) { - // This can be fixed to two, because the method we're calling here - // (MethodHandle.transformInternal) doesn't have any locals and the signature - // is known : - // - // private MethodHandle.transformInternal(EmulatedStackFrame sf); - // - // This means we need only two vregs : - // - One for the receiver object. - // - One for the only method argument (an EmulatedStackFrame). - static constexpr size_t kNumRegsForTransform = 2; - - const DexFile::CodeItem* code_item = called_method->GetCodeItem(); - DCHECK(code_item != nullptr); - DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_); - DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_); - - ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = - CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0); - ShadowFrame* new_shadow_frame = shadow_frame_unique_ptr.get(); - - StackHandleScope<1> hs(self); - MutableHandle<mirror::EmulatedStackFrame> sf(hs.NewHandle<mirror::EmulatedStackFrame>(nullptr)); - if (IsCallerTransformer(callsite_type)) { - // If we're entering this transformer from another transformer, we can pass - // through the handle directly to the callee, instead of having to - // instantiate a new stack frame based on the shadow frame. - sf.Assign(reinterpret_cast<mirror::EmulatedStackFrame*>( - shadow_frame.GetVRegReference(first_src_reg))); - } else { - sf.Assign(mirror::EmulatedStackFrame::CreateFromShadowFrameAndArgs<is_range>( - self, - callsite_type, - callee_type, - shadow_frame, - first_src_reg, - arg)); - - // Something went wrong while creating the emulated stack frame, we should - // throw the pending exception. - if (sf.Get() == nullptr) { - DCHECK(self->IsExceptionPending()); - return false; - } - } - - new_shadow_frame->SetVRegReference(0, receiver.Get()); - new_shadow_frame->SetVRegReference(1, sf.Get()); - - PerformCall(self, - code_item, - shadow_frame.GetMethod(), - 0 /* first dest reg */, - new_shadow_frame, - result); - if (self->IsExceptionPending()) { - return false; - } - - // If the called transformer method we called has returned a value, then we - // need to copy it back to |result|. - sf->GetReturnValue(self, result); - return ConvertReturnValue(callsite_type, callee_type, result); -} - template <bool is_range, bool do_assignability_check> static inline bool DoCallCommon(ArtMethod* called_method, |