diff options
20 files changed, 258 insertions, 55 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index a8fdecaa4a..e75f75bbd9 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -473,6 +473,11 @@ void ImageWriter::PrepareDexCacheArraySlots() { start + layout.MethodTypesOffset(), dex_cache); } + if (dex_cache->GetResolvedCallSites() != nullptr) { + AddDexCacheArrayRelocation(dex_cache->GetResolvedCallSites(), + start + layout.CallSitesOffset(), + dex_cache); + } } } diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index df0169f7d0..65232bfaa5 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -1582,31 +1582,53 @@ static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) { static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) { const DexFile::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx); + const char* type = nullptr; + bool is_instance = false; bool is_invoke = false; - const char* type; switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) { case DexFile::MethodHandleType::kStaticPut: type = "put-static"; + is_instance = false; + is_invoke = false; break; case DexFile::MethodHandleType::kStaticGet: type = "get-static"; + is_instance = false; + is_invoke = false; break; case DexFile::MethodHandleType::kInstancePut: type = "put-instance"; + is_instance = true; + is_invoke = false; break; case DexFile::MethodHandleType::kInstanceGet: type = "get-instance"; + is_instance = true; + is_invoke = false; break; case DexFile::MethodHandleType::kInvokeStatic: type = "invoke-static"; + is_instance = false; is_invoke = true; break; case DexFile::MethodHandleType::kInvokeInstance: type = "invoke-instance"; + is_instance = true; is_invoke = true; break; case DexFile::MethodHandleType::kInvokeConstructor: type = "invoke-constructor"; + is_instance = true; + is_invoke = true; + break; + case DexFile::MethodHandleType::kInvokeDirect: + type = "invoke-direct"; + is_instance = true; + is_invoke = true; + break; + case DexFile::MethodHandleType::kInvokeInterface: + type = "invoke-interface"; + is_instance = true; is_invoke = true; break; } @@ -1614,16 +1636,26 @@ static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) { const char* declaring_class; const char* member; std::string member_type; - if (is_invoke) { - const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_); - declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id); - member = pDexFile->GetMethodName(method_id); - member_type = pDexFile->GetMethodSignature(method_id).ToString(); + if (type != nullptr) { + if (is_invoke) { + const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_); + declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id); + member = pDexFile->GetMethodName(method_id); + member_type = pDexFile->GetMethodSignature(method_id).ToString(); + } else { + const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_); + declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id); + member = pDexFile->GetFieldName(field_id); + member_type = pDexFile->GetFieldTypeDescriptor(field_id); + } + if (is_instance) { + member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1); + } } else { - const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_); - declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id); - member = pDexFile->GetFieldName(field_id); - member_type = pDexFile->GetFieldTypeDescriptor(field_id); + type = "?"; + declaring_class = "?"; + member = "?"; + member_type = "?"; } if (gOptions.outputFormat == OUTPUT_PLAIN) { diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index a200d8d9c7..5913832f96 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -793,8 +793,10 @@ void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) { static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_); bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic || type == DexFile::MethodHandleType::kInvokeInstance || - type == DexFile::MethodHandleType::kInvokeConstructor; - static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeConstructor, + type == DexFile::MethodHandleType::kInvokeConstructor || + type == DexFile::MethodHandleType::kInvokeDirect || + type == DexFile::MethodHandleType::kInvokeInterface; + static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface, "Unexpected method handle types."); IndexedItem* field_or_method_id; if (is_invoke) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 10e0bd28c3..7aab9de1ed 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -8256,65 +8256,139 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id const DexFile* const dex_file = referrer->GetDexFile(); const DexFile::MethodHandleItem& mh = dex_file->GetMethodHandle(method_handle_idx); - union { - ArtField* field; - ArtMethod* method; - uintptr_t field_or_method; - } target; - uint32_t num_params; - mirror::MethodHandle::Kind kind; + ArtField* target_field = nullptr; + ArtMethod* target_method = nullptr; + DexFile::MethodHandleType handle_type = static_cast<DexFile::MethodHandleType>(mh.method_handle_type_); switch (handle_type) { case DexFile::MethodHandleType::kStaticPut: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); + break; + } + case DexFile::MethodHandleType::kStaticGet: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); + break; + } + case DexFile::MethodHandleType::kInstancePut: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); + break; + } + case DexFile::MethodHandleType::kInstanceGet: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); + break; + } + case DexFile::MethodHandleType::kInvokeStatic: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kStatic); + break; + } + case DexFile::MethodHandleType::kInvokeInstance: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kVirtual); + break; + } + case DexFile::MethodHandleType::kInvokeConstructor: { + UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform."; + break; + } + case DexFile::MethodHandleType::kInvokeDirect: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kDirect); + break; + } + case DexFile::MethodHandleType::kInvokeInterface: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kInterface); + break; + } + } + + if (target_field != nullptr) { + ObjPtr<mirror::Class> target_class = target_field->GetDeclaringClass(); + ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); + if (!referring_class->CanAccessMember(target_class, target_field->GetAccessFlags())) { + ThrowIllegalAccessErrorField(referring_class, target_field); + return nullptr; + } + } else if (target_method != nullptr) { + ObjPtr<mirror::Class> target_class = target_method->GetDeclaringClass(); + ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); + if (!referring_class->CanAccessMember(target_class, target_method->GetAccessFlags())) { + ThrowIllegalAccessErrorMethod(referring_class, target_method); + return nullptr; + } + } else { + // Common check for resolution failure. + DCHECK(Thread::Current()->IsExceptionPending()); + return nullptr; + } + + // Determine the kind and number of parameters after it's safe to + // follow the field or method pointer. + mirror::MethodHandle::Kind kind; + uint32_t num_params; + switch (handle_type) { + case DexFile::MethodHandleType::kStaticPut: { kind = mirror::MethodHandle::Kind::kStaticPut; - target.field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); num_params = 1; break; } case DexFile::MethodHandleType::kStaticGet: { kind = mirror::MethodHandle::Kind::kStaticGet; - target.field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); num_params = 0; break; } case DexFile::MethodHandleType::kInstancePut: { kind = mirror::MethodHandle::Kind::kInstancePut; - target.field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); num_params = 2; break; } case DexFile::MethodHandleType::kInstanceGet: { kind = mirror::MethodHandle::Kind::kInstanceGet; - target.field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); num_params = 1; break; } case DexFile::MethodHandleType::kInvokeStatic: { kind = mirror::MethodHandle::Kind::kInvokeStatic; - target.method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, - referrer, - InvokeType::kStatic); uint32_t shorty_length; - target.method->GetShorty(&shorty_length); - num_params = shorty_length - 1; // Remove 1 for return value. + target_method->GetShorty(&shorty_length); + num_params = shorty_length - 1; // Remove 1 for the return value. break; } case DexFile::MethodHandleType::kInvokeInstance: { kind = mirror::MethodHandle::Kind::kInvokeVirtual; - target.method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, - referrer, - InvokeType::kVirtual); uint32_t shorty_length; - target.method->GetShorty(&shorty_length); - num_params = shorty_length - 1; // Remove 1 for return value. + target_method->GetShorty(&shorty_length); + num_params = shorty_length; // Add 1 for the receiver, remove 1 for the return value. break; } case DexFile::MethodHandleType::kInvokeConstructor: { UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform."; num_params = 0; + break; + } + case DexFile::MethodHandleType::kInvokeDirect: { + kind = mirror::MethodHandle::Kind::kInvokeDirect; + uint32_t shorty_length; + target_method->GetShorty(&shorty_length); + num_params = shorty_length; // Add 1 for the receiver, remove 1 for the return value. + break; + } + case DexFile::MethodHandleType::kInvokeInterface: { + kind = mirror::MethodHandle::Kind::kInvokeInterface; + uint32_t shorty_length; + target_method->GetShorty(&shorty_length); + num_params = shorty_length; // Add 1 for the receiver, remove 1 for the return value. + break; } } @@ -8331,44 +8405,51 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id Handle<mirror::Class> return_type; switch (handle_type) { case DexFile::MethodHandleType::kStaticPut: { - method_params->Set(0, target.field->GetType<true>()); + method_params->Set(0, target_field->GetType<true>()); return_type = hs.NewHandle(FindPrimitiveClass('V')); break; } case DexFile::MethodHandleType::kStaticGet: { - return_type = hs.NewHandle(target.field->GetType<true>()); + return_type = hs.NewHandle(target_field->GetType<true>()); break; } case DexFile::MethodHandleType::kInstancePut: { - method_params->Set(0, target.field->GetDeclaringClass()); - method_params->Set(1, target.field->GetType<true>()); + method_params->Set(0, target_field->GetDeclaringClass()); + method_params->Set(1, target_field->GetType<true>()); return_type = hs.NewHandle(FindPrimitiveClass('V')); break; } case DexFile::MethodHandleType::kInstanceGet: { - method_params->Set(0, target.field->GetDeclaringClass()); - return_type = hs.NewHandle(target.field->GetType<true>()); + method_params->Set(0, target_field->GetDeclaringClass()); + return_type = hs.NewHandle(target_field->GetType<true>()); break; } - case DexFile::MethodHandleType::kInvokeStatic: - case DexFile::MethodHandleType::kInvokeInstance: { + case DexFile::MethodHandleType::kInvokeDirect: + case DexFile::MethodHandleType::kInvokeInstance: + case DexFile::MethodHandleType::kInvokeInterface: + case DexFile::MethodHandleType::kInvokeStatic: { // TODO(oth): This will not work for varargs methods as this // requires instantiating a Transformer. This resolution step // would be best done in managed code rather than in the run // time (b/35235705) Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); - DexFileParameterIterator it(*dex_file, target.method->GetPrototype()); - for (int32_t i = 0; it.HasNext(); i++, it.Next()) { + DexFileParameterIterator it(*dex_file, target_method->GetPrototype()); + int32_t index = 0; + if (handle_type != DexFile::MethodHandleType::kInvokeStatic) { + method_params->Set(index++, target_method->GetDeclaringClass()); + } + while (it.HasNext()) { const dex::TypeIndex type_idx = it.GetTypeIdx(); mirror::Class* klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader); if (nullptr == klass) { DCHECK(self->IsExceptionPending()); return nullptr; } - method_params->Set(i, klass); + method_params->Set(index++, klass); + it.Next(); } - return_type = hs.NewHandle(target.method->GetReturnType(true)); + return_type = hs.NewHandle(target_method->GetReturnType(true)); break; } case DexFile::MethodHandleType::kInvokeConstructor: { @@ -8388,7 +8469,14 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id DCHECK(self->IsExceptionPending()); return nullptr; } - return mirror::MethodHandleImpl::Create(self, target.field_or_method, kind, mt); + + uintptr_t target; + if (target_field != nullptr) { + target = reinterpret_cast<uintptr_t>(target_field); + } else { + target = reinterpret_cast<uintptr_t>(target_method); + } + return mirror::MethodHandleImpl::Create(self, target, kind, mt); } bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const { diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 81a39afbee..eb3b210cd1 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -272,7 +272,9 @@ class DexFile { // can be any non-static method on any class (or interface) except // for “<init>”. kInvokeConstructor = 0x0006, // an invoker for a given constructor. - kLast = kInvokeConstructor + kInvokeDirect = 0x0007, // an invoker for a direct (special) method. + kInvokeInterface = 0x0008, // an invoker for an interface method. + kLast = kInvokeInterface }; // raw method_handle_item diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index c18ab47739..c5c4eda98f 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -2483,7 +2483,9 @@ bool DexFileVerifier::CheckInterMethodHandleItem() { } case DexFile::MethodHandleType::kInvokeStatic: case DexFile::MethodHandleType::kInvokeInstance: - case DexFile::MethodHandleType::kInvokeConstructor: { + case DexFile::MethodHandleType::kInvokeConstructor: + case DexFile::MethodHandleType::kInvokeDirect: + case DexFile::MethodHandleType::kInvokeInterface: { LOAD_METHOD(method, index, "method_handle_item method_idx", return false); break; } diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 1b36c3f12b..b57e2b2b40 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -640,7 +640,7 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self, const DexFile* dex_file = referrer->GetDexFile(); const DexFile::CallSiteIdItem& csi = dex_file->GetCallSiteId(call_site_idx); - StackHandleScope<9> hs(self); + StackHandleScope<10> hs(self); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); @@ -836,9 +836,13 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self, return nullptr; } - // Check the target method type matches the method type requested. - if (UNLIKELY(!target->GetMethodType()->IsExactMatch(method_type.Get()))) { - ThrowWrongMethodTypeException(target->GetMethodType(), method_type.Get()); + // Check the target method type matches the method type requested modulo the receiver + // needs to be compatible rather than exact. + Handle<mirror::MethodType> target_method_type = hs.NewHandle(target->GetMethodType()); + if (UNLIKELY(!target_method_type->IsExactMatch(method_type.Get()) && + !IsParameterTypeConvertible(target_method_type->GetPTypes()->GetWithoutChecks(0), + method_type->GetPTypes()->GetWithoutChecks(0)))) { + ThrowWrongMethodTypeException(target_method_type.Get(), method_type.Get()); return nullptr; } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 9b652553df..efb02f6205 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -4159,7 +4159,8 @@ bool MethodVerifier::CheckCallSite(uint32_t call_site_idx) { const DexFile::MethodHandleItem& mh = dex_file_->GetMethodHandle(method_handle_idx); if (mh.method_handle_type_ != static_cast<uint16_t>(DexFile::MethodHandleType::kInvokeStatic)) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Call site #" << call_site_idx - << " argument 0 method handle type is not InvokeStatic"; + << " argument 0 method handle type is not InvokeStatic: " + << mh.method_handle_type_; return false; } diff --git a/test/952-invoke-custom-kinds/build b/test/952-invoke-custom-kinds/build new file mode 100644 index 0000000000..a02cdc3769 --- /dev/null +++ b/test/952-invoke-custom-kinds/build @@ -0,0 +1,22 @@ +#!/bin/bash +# +# 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. + +# Stop if something fails. +set -e + +${DX} --dex --min-sdk-version=26 --output=classes.dex classes + +zip $TEST_NAME.jar classes.dex diff --git a/test/952-invoke-custom-kinds/classes/Main.class b/test/952-invoke-custom-kinds/classes/Main.class Binary files differnew file mode 100644 index 0000000000..6bc04e326a --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/Main.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class b/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class Binary files differnew file mode 100644 index 0000000000..5dfe958795 --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class b/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class Binary files differnew file mode 100644 index 0000000000..a11ee696bf --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class Binary files differnew file mode 100644 index 0000000000..e233febbf4 --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class Binary files differnew file mode 100644 index 0000000000..41e1d431f2 --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class Binary files differnew file mode 100644 index 0000000000..4f0f497c72 --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/Super.class b/test/952-invoke-custom-kinds/classes/invokecustom/Super.class Binary files differnew file mode 100644 index 0000000000..5990f28d47 --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/Super.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class Binary files differnew file mode 100644 index 0000000000..c3266e49f7 --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class Binary files differnew file mode 100644 index 0000000000..711db2343b --- /dev/null +++ b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class diff --git a/test/952-invoke-custom-kinds/expected.txt b/test/952-invoke-custom-kinds/expected.txt new file mode 100644 index 0000000000..c72da25c99 --- /dev/null +++ b/test/952-invoke-custom-kinds/expected.txt @@ -0,0 +1,38 @@ +bsmLookupStatic [] +Hello World! +bsmLookupStatic [] +true +127 +c +1024 +123456 +1.2 +123456789 +3.5123456789 +String +bsmLookupStaticWithExtraArgs [1, 123456789, 123.456, 123456.789123] +targetMethodTest3 from InvokeCustom +bsmCreateCallSite [MethodHandle(Super)void] +targetMethodTest4 from Super +bsmLookupStatic [] +targetMethodTest5 1000 + -923 = 77 +targetMethodTest5 returned: 77 +bsmLookupStatic [] +targetMethodTest6 8209686820727 + -1172812402961 = 7036874417766 +targetMethodTest6 returned: 7036874417766 +bsmLookupStatic [] +targetMethodTest7 0.50097656 * -0.50097656 = -0.2509775161743164 +targetMethodTest6 returned: -0.2509775161743164 +bsmLookupStatic [] +targetMethodTest8 First invokedynamic invocation +bsmLookupStatic [] +targetMethodTest8 Second invokedynamic invocation +bsmLookupStatic [] +targetMethodTest8 Dupe first invokedynamic invocation +bsmLookupTest9 [MethodHandle()int, MethodHandle(int)void, MethodHandle(InvokeCustom)float, MethodHandle(InvokeCustom,float)void] +targetMethodTest9 ()void +checkStaticFieldTest9: old 0 new 1985229328 expected 1985229328 OK +checkFieldTest9: old 0.0 new 1.99E-19 expected 1.99E-19 OK +helperMethodTest9 in class invokecustom.InvokeCustom +run() for Test9 +targetMethodTest9() diff --git a/test/952-invoke-custom-kinds/info.txt b/test/952-invoke-custom-kinds/info.txt new file mode 100644 index 0000000000..cddb96dcf0 --- /dev/null +++ b/test/952-invoke-custom-kinds/info.txt @@ -0,0 +1,7 @@ +This test checks call sites and constant method handles in DEX files used +by invoke-custom. + +It is derived from a dx test (dalvik/dx/tests/135-invoke-custom) which +generates the invoke-custom using ASM to generate class files. The +test here differs as it not include an instance a constant method +handle with a constructor kind (see b/62774190). |