diff options
Diffstat (limited to 'runtime/interpreter/interpreter_common.cc')
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 605 |
1 files changed, 456 insertions, 149 deletions
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 380a981d09..8a85ee41f8 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -900,171 +900,489 @@ bool DoInvokePolymorphic(Thread* self, } } +static JValue ConvertScalarBootstrapArgument(jvalue value) { + // value either contains a primitive scalar value if it corresponds + // to a primitive type, or it contains an integer value if it + // corresponds to an object instance reference id (e.g. a string id). + return JValue::FromPrimitive(value.j); +} + +static ObjPtr<mirror::Class> GetClassForBootstrapArgument(EncodedArrayValueIterator::ValueType type) + REQUIRES_SHARED(Locks::mutator_lock_) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + switch (type) { + case EncodedArrayValueIterator::ValueType::kBoolean: + case EncodedArrayValueIterator::ValueType::kByte: + case EncodedArrayValueIterator::ValueType::kChar: + case EncodedArrayValueIterator::ValueType::kShort: + // These types are disallowed by JVMS. Treat as integers. This + // will result in CCE's being raised if the BSM has one of these + // types. + case EncodedArrayValueIterator::ValueType::kInt: + return class_linker->FindPrimitiveClass('I'); + case EncodedArrayValueIterator::ValueType::kLong: + return class_linker->FindPrimitiveClass('J'); + case EncodedArrayValueIterator::ValueType::kFloat: + return class_linker->FindPrimitiveClass('F'); + case EncodedArrayValueIterator::ValueType::kDouble: + return class_linker->FindPrimitiveClass('D'); + case EncodedArrayValueIterator::ValueType::kMethodType: + return mirror::MethodType::StaticClass(); + case EncodedArrayValueIterator::ValueType::kMethodHandle: + return mirror::MethodHandle::StaticClass(); + case EncodedArrayValueIterator::ValueType::kString: + return mirror::String::GetJavaLangString(); + case EncodedArrayValueIterator::ValueType::kType: + return mirror::Class::GetJavaLangClass(); + case EncodedArrayValueIterator::ValueType::kField: + case EncodedArrayValueIterator::ValueType::kMethod: + case EncodedArrayValueIterator::ValueType::kEnum: + case EncodedArrayValueIterator::ValueType::kArray: + case EncodedArrayValueIterator::ValueType::kAnnotation: + case EncodedArrayValueIterator::ValueType::kNull: + return nullptr; + } +} + +static bool GetArgumentForBootstrapMethod(Thread* self, + ArtMethod* referrer, + EncodedArrayValueIterator::ValueType type, + const JValue* encoded_value, + JValue* decoded_value) + REQUIRES_SHARED(Locks::mutator_lock_) { + // The encoded_value contains either a scalar value (IJDF) or a + // scalar DEX file index to a reference type to be materialized. + switch (type) { + case EncodedArrayValueIterator::ValueType::kInt: + case EncodedArrayValueIterator::ValueType::kFloat: + decoded_value->SetI(encoded_value->GetI()); + return true; + case EncodedArrayValueIterator::ValueType::kLong: + case EncodedArrayValueIterator::ValueType::kDouble: + decoded_value->SetJ(encoded_value->GetJ()); + return true; + case EncodedArrayValueIterator::ValueType::kMethodType: { + StackHandleScope<2> hs(self); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + uint32_t index = static_cast<uint32_t>(encoded_value->GetI()); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + ObjPtr<mirror::MethodType> o = cl->ResolveMethodType(self, index, dex_cache, class_loader); + if (UNLIKELY(o.IsNull())) { + DCHECK(self->IsExceptionPending()); + return false; + } + decoded_value->SetL(o); + return true; + } + case EncodedArrayValueIterator::ValueType::kMethodHandle: { + uint32_t index = static_cast<uint32_t>(encoded_value->GetI()); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + ObjPtr<mirror::MethodHandle> o = cl->ResolveMethodHandle(self, index, referrer); + if (UNLIKELY(o.IsNull())) { + DCHECK(self->IsExceptionPending()); + return false; + } + decoded_value->SetL(o); + return true; + } + case EncodedArrayValueIterator::ValueType::kString: { + StackHandleScope<1> hs(self); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + dex::StringIndex index(static_cast<uint32_t>(encoded_value->GetI())); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + ObjPtr<mirror::String> o = cl->ResolveString(index, dex_cache); + if (UNLIKELY(o.IsNull())) { + DCHECK(self->IsExceptionPending()); + return false; + } + decoded_value->SetL(o); + return true; + } + case EncodedArrayValueIterator::ValueType::kType: { + StackHandleScope<2> hs(self); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + dex::TypeIndex index(static_cast<uint32_t>(encoded_value->GetI())); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + ObjPtr<mirror::Class> o = cl->ResolveType(index, dex_cache, class_loader); + if (UNLIKELY(o.IsNull())) { + DCHECK(self->IsExceptionPending()); + return false; + } + decoded_value->SetL(o); + return true; + } + case EncodedArrayValueIterator::ValueType::kBoolean: + case EncodedArrayValueIterator::ValueType::kByte: + case EncodedArrayValueIterator::ValueType::kChar: + case EncodedArrayValueIterator::ValueType::kShort: + case EncodedArrayValueIterator::ValueType::kField: + case EncodedArrayValueIterator::ValueType::kMethod: + case EncodedArrayValueIterator::ValueType::kEnum: + case EncodedArrayValueIterator::ValueType::kArray: + case EncodedArrayValueIterator::ValueType::kAnnotation: + case EncodedArrayValueIterator::ValueType::kNull: + // Unreachable - unsupported types that have been checked when + // determining the effect call site type based on the bootstrap + // argument types. + UNREACHABLE(); + } +} + +static bool PackArgumentForBootstrapMethod(Thread* self, + ArtMethod* referrer, + CallSiteArrayValueIterator* it, + ShadowFrameSetter* setter) + REQUIRES_SHARED(Locks::mutator_lock_) { + auto type = it->GetValueType(); + const JValue encoded_value = ConvertScalarBootstrapArgument(it->GetJavaValue()); + JValue decoded_value; + if (!GetArgumentForBootstrapMethod(self, referrer, type, &encoded_value, &decoded_value)) { + return false; + } + switch (it->GetValueType()) { + case EncodedArrayValueIterator::ValueType::kInt: + case EncodedArrayValueIterator::ValueType::kFloat: + setter->Set(static_cast<uint32_t>(decoded_value.GetI())); + return true; + case EncodedArrayValueIterator::ValueType::kLong: + case EncodedArrayValueIterator::ValueType::kDouble: + setter->SetLong(decoded_value.GetJ()); + return true; + case EncodedArrayValueIterator::ValueType::kMethodType: + case EncodedArrayValueIterator::ValueType::kMethodHandle: + case EncodedArrayValueIterator::ValueType::kString: + case EncodedArrayValueIterator::ValueType::kType: + setter->SetReference(decoded_value.GetL()); + return true; + case EncodedArrayValueIterator::ValueType::kBoolean: + case EncodedArrayValueIterator::ValueType::kByte: + case EncodedArrayValueIterator::ValueType::kChar: + case EncodedArrayValueIterator::ValueType::kShort: + case EncodedArrayValueIterator::ValueType::kField: + case EncodedArrayValueIterator::ValueType::kMethod: + case EncodedArrayValueIterator::ValueType::kEnum: + case EncodedArrayValueIterator::ValueType::kArray: + case EncodedArrayValueIterator::ValueType::kAnnotation: + case EncodedArrayValueIterator::ValueType::kNull: + // Unreachable - unsupported types that have been checked when + // determining the effect call site type based on the bootstrap + // argument types. + UNREACHABLE(); + } +} + +static bool PackCollectorArrayForBootstrapMethod(Thread* self, + ArtMethod* referrer, + ObjPtr<mirror::Class> array_type, + int32_t array_length, + CallSiteArrayValueIterator* it, + ShadowFrameSetter* setter) + REQUIRES_SHARED(Locks::mutator_lock_) { + StackHandleScope<1> hs(self); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + JValue decoded_value; + +#define COLLECT_PRIMITIVE_ARRAY(Descriptor, Type) \ + Handle<mirror::Type ## Array> array = \ + hs.NewHandle(mirror::Type ## Array::Alloc(self, array_length)); \ + if (array.IsNull()) { \ + return false; \ + } \ + for (int32_t i = 0; it->HasNext(); it->Next(), ++i) { \ + auto type = it->GetValueType(); \ + DCHECK_EQ(type, EncodedArrayValueIterator::ValueType::k ## Type); \ + const JValue encoded_value = \ + ConvertScalarBootstrapArgument(it->GetJavaValue()); \ + GetArgumentForBootstrapMethod(self, \ + referrer, \ + type, \ + &encoded_value, \ + &decoded_value); \ + array->Set(i, decoded_value.Get ## Descriptor()); \ + } \ + setter->SetReference(array.Get()); \ + return true; + +#define COLLECT_REFERENCE_ARRAY(T, Type) \ + Handle<mirror::ObjectArray<T>> array = \ + hs.NewHandle(mirror::ObjectArray<T>::Alloc(self, \ + array_type, \ + array_length)); \ + if (array.IsNull()) { \ + return false; \ + } \ + for (int32_t i = 0; it->HasNext(); it->Next(), ++i) { \ + auto type = it->GetValueType(); \ + DCHECK_EQ(type, EncodedArrayValueIterator::ValueType::k ## Type); \ + const JValue encoded_value = \ + ConvertScalarBootstrapArgument(it->GetJavaValue()); \ + if (!GetArgumentForBootstrapMethod(self, \ + referrer, \ + type, \ + &encoded_value, \ + &decoded_value)) { \ + return false; \ + } \ + ObjPtr<mirror::Object> o = decoded_value.GetL(); \ + if (Runtime::Current()->IsActiveTransaction()) { \ + array->Set<true>(i, ObjPtr<T>::DownCast(o)); \ + } else { \ + array->Set<false>(i, ObjPtr<T>::DownCast(o)); \ + } \ + } \ + setter->SetReference(array.Get()); \ + return true; + + if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('I')) { + COLLECT_PRIMITIVE_ARRAY(I, Int); + } else if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('J')) { + COLLECT_PRIMITIVE_ARRAY(J, Long); + } else if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('F')) { + COLLECT_PRIMITIVE_ARRAY(F, Float); + } else if (array_type->GetComponentType() == class_linker->FindPrimitiveClass('D')) { + COLLECT_PRIMITIVE_ARRAY(D, Double); + } else if (array_type->GetComponentType() == mirror::MethodType::StaticClass()) { + COLLECT_REFERENCE_ARRAY(mirror::MethodType, MethodType); + } else if (array_type->GetComponentType() == mirror::MethodHandle::StaticClass()) { + COLLECT_REFERENCE_ARRAY(mirror::MethodHandle, MethodHandle); + } else if (array_type->GetComponentType() == mirror::String::GetJavaLangString()) { + COLLECT_REFERENCE_ARRAY(mirror::String, String); + } else if (array_type->GetComponentType() == mirror::Class::GetJavaLangClass()) { + COLLECT_REFERENCE_ARRAY(mirror::Class, Type); + } else { + UNREACHABLE(); + } + #undef COLLECT_PRIMITIVE_ARRAY + #undef COLLECT_REFERENCE_ARRAY +} + +static ObjPtr<mirror::MethodType> BuildCallSiteForBootstrapMethod(Thread* self, + const DexFile* dex_file, + uint32_t call_site_idx) + REQUIRES_SHARED(Locks::mutator_lock_) { + const DexFile::CallSiteIdItem& csi = dex_file->GetCallSiteId(call_site_idx); + CallSiteArrayValueIterator it(*dex_file, csi); + DCHECK_GE(it.Size(), 1u); + + StackHandleScope<2> hs(self); + // Create array for parameter types. + ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); + mirror::Class* class_array_type = + Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_type); + Handle<mirror::ObjectArray<mirror::Class>> ptypes = hs.NewHandle( + mirror::ObjectArray<mirror::Class>::Alloc(self, + class_array_type, + static_cast<int>(it.Size()))); + if (ptypes.IsNull()) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } + + // Populate the first argument with an instance of j.l.i.MethodHandles.Lookup + // that the runtime will construct. + ptypes->Set(0, mirror::MethodHandlesLookup::StaticClass()); + it.Next(); + + // The remaining parameter types are derived from the types of + // arguments present in the DEX file. + int index = 1; + while (it.HasNext()) { + ObjPtr<mirror::Class> ptype = GetClassForBootstrapArgument(it.GetValueType()); + if (ptype.IsNull()) { + ThrowClassCastException("Unsupported bootstrap argument type"); + return nullptr; + } + ptypes->Set(index, ptype); + index++; + it.Next(); + } + DCHECK_EQ(static_cast<size_t>(index), it.Size()); + + // By definition, the return type is always a j.l.i.CallSite. + Handle<mirror::Class> rtype = hs.NewHandle(mirror::CallSite::StaticClass()); + return mirror::MethodType::Create(self, rtype, ptypes); +} + static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self, ShadowFrame& shadow_frame, uint32_t call_site_idx) REQUIRES_SHARED(Locks::mutator_lock_) { + StackHandleScope<7> hs(self); + // There are three mandatory arguments expected from the call site + // value array in the DEX file: the bootstrap method handle, the + // method name to pass to the bootstrap method, and the method type + // to pass to the bootstrap method. + static constexpr size_t kMandatoryArgumentsCount = 3; ArtMethod* referrer = shadow_frame.GetMethod(); const DexFile* dex_file = referrer->GetDexFile(); const DexFile::CallSiteIdItem& csi = dex_file->GetCallSiteId(call_site_idx); + CallSiteArrayValueIterator it(*dex_file, csi); + if (it.Size() < kMandatoryArgumentsCount) { + ThrowBootstrapMethodError("Truncated bootstrap arguments (%zu < %zu)", + it.Size(), kMandatoryArgumentsCount); + return nullptr; + } - StackHandleScope<10> hs(self); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + if (it.GetValueType() != EncodedArrayValueIterator::ValueType::kMethodHandle) { + ThrowBootstrapMethodError("First bootstrap argument is not a method handle"); + return nullptr; + } + + uint32_t bsm_index = static_cast<uint32_t>(it.GetJavaValue().i); + it.Next(); - CallSiteArrayValueIterator it(*dex_file, csi); - uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Handle<mirror::MethodHandle> - bootstrap(hs.NewHandle(class_linker->ResolveMethodHandle(self, method_handle_idx, referrer))); - if (bootstrap.IsNull()) { + Handle<mirror::MethodHandle> bsm = + hs.NewHandle(class_linker->ResolveMethodHandle(self, bsm_index, referrer)); + if (bsm.IsNull()) { DCHECK(self->IsExceptionPending()); return nullptr; } - Handle<mirror::MethodType> bootstrap_method_type = hs.NewHandle(bootstrap->GetMethodType()); - it.Next(); - DCHECK_EQ(static_cast<size_t>(bootstrap->GetMethodType()->GetPTypes()->GetLength()), it.Size()); - const size_t num_bootstrap_vregs = bootstrap->GetMethodType()->NumberOfVRegs(); + if (bsm->GetHandleKind() != mirror::MethodHandle::Kind::kInvokeStatic) { + // JLS suggests also accepting constructors. This is currently + // hard as constructor invocations happen via transformers in ART + // today. The constructor would need to be a class derived from java.lang.invoke.CallSite. + ThrowBootstrapMethodError("Unsupported bootstrap method invocation kind"); + return nullptr; + } - // Set-up a shadow frame for invoking the bootstrap method handle. - ShadowFrameAllocaUniquePtr bootstrap_frame = - CREATE_SHADOW_FRAME(num_bootstrap_vregs, nullptr, referrer, shadow_frame.GetDexPC()); - ScopedStackedShadowFramePusher pusher( - self, bootstrap_frame.get(), StackedShadowFrameType::kShadowFrameUnderConstruction); - size_t vreg = 0; + // Construct the local call site type information based on the 3 + // mandatory arguments provided by the runtime and the static arguments + // in the DEX file. We will use these arguments to build a shadow frame. + MutableHandle<mirror::MethodType> call_site_type = + hs.NewHandle(BuildCallSiteForBootstrapMethod(self, dex_file, call_site_idx)); + if (call_site_type.IsNull()) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } - // The first parameter is a MethodHandles lookup instance. - { - Handle<mirror::Class> lookup_class = - hs.NewHandle(shadow_frame.GetMethod()->GetDeclaringClass()); - ObjPtr<mirror::MethodHandlesLookup> lookup = - mirror::MethodHandlesLookup::Create(self, lookup_class); - if (lookup.IsNull()) { + // Check if this BSM is targeting a variable arity method. If so, + // we'll need to collect the trailing arguments into an array. + Handle<mirror::Array> collector_arguments; + int32_t collector_arguments_length; + if (bsm->GetTargetMethod()->IsVarargs()) { + int number_of_bsm_parameters = bsm->GetMethodType()->GetNumberOfPTypes(); + if (number_of_bsm_parameters == 0) { + ThrowBootstrapMethodError("Variable arity BSM does not have any arguments"); + return nullptr; + } + Handle<mirror::Class> collector_array_class = + hs.NewHandle(bsm->GetMethodType()->GetPTypes()->Get(number_of_bsm_parameters - 1)); + if (!collector_array_class->IsArrayClass()) { + ThrowBootstrapMethodError("Variable arity BSM does not have array as final argument"); + return nullptr; + } + // The call site may include no arguments to be collected. In this + // case the number of arguments must be at least the number of BSM + // parameters less the collector array. + if (call_site_type->GetNumberOfPTypes() < number_of_bsm_parameters - 1) { + ThrowWrongMethodTypeException(bsm->GetMethodType(), call_site_type.Get()); + return nullptr; + } + // Check all the arguments to be collected match the collector array component type. + for (int i = number_of_bsm_parameters - 1; i < call_site_type->GetNumberOfPTypes(); ++i) { + if (call_site_type->GetPTypes()->Get(i) != collector_array_class->GetComponentType()) { + ThrowClassCastException(collector_array_class->GetComponentType(), + call_site_type->GetPTypes()->Get(i)); + return nullptr; + } + } + // Update the call site method type so it now includes the collector array. + int32_t collector_arguments_start = number_of_bsm_parameters - 1; + collector_arguments_length = call_site_type->GetNumberOfPTypes() - number_of_bsm_parameters + 1; + call_site_type.Assign( + mirror::MethodType::CollectTrailingArguments(self, + call_site_type.Get(), + collector_array_class.Get(), + collector_arguments_start)); + if (call_site_type.IsNull()) { DCHECK(self->IsExceptionPending()); return nullptr; } - bootstrap_frame->SetVRegReference(vreg++, lookup.Ptr()); + } else { + collector_arguments_length = 0; } - // The second parameter is the name to lookup. - { - dex::StringIndex name_idx(static_cast<uint32_t>(it.GetJavaValue().i)); - ObjPtr<mirror::String> name = class_linker->ResolveString(name_idx, dex_cache); - if (name.IsNull()) { - DCHECK(self->IsExceptionPending()); + if (call_site_type->GetNumberOfPTypes() != bsm->GetMethodType()->GetNumberOfPTypes()) { + ThrowWrongMethodTypeException(bsm->GetMethodType(), call_site_type.Get()); + return nullptr; + } + + // BSM invocation has a different set of exceptions that + // j.l.i.MethodHandle.invoke(). Scan arguments looking for CCE + // "opportunities". Unfortunately we cannot just leave this to the + // method handle invocation as this might generate a WMTE. + for (int32_t i = 0; i < call_site_type->GetNumberOfPTypes(); ++i) { + ObjPtr<mirror::Class> from = call_site_type->GetPTypes()->Get(i); + ObjPtr<mirror::Class> to = bsm->GetMethodType()->GetPTypes()->Get(i); + if (!IsParameterTypeConvertible(from, to)) { + ThrowClassCastException(from, to); return nullptr; } - bootstrap_frame->SetVRegReference(vreg++, name.Ptr()); } - it.Next(); + if (!IsReturnTypeConvertible(call_site_type->GetRType(), bsm->GetMethodType()->GetRType())) { + ThrowClassCastException(bsm->GetMethodType()->GetRType(), call_site_type->GetRType()); + return nullptr; + } + + // Set-up a shadow frame for invoking the bootstrap method handle. + ShadowFrameAllocaUniquePtr bootstrap_frame = + CREATE_SHADOW_FRAME(call_site_type->NumberOfVRegs(), + nullptr, + referrer, + shadow_frame.GetDexPC()); + ScopedStackedShadowFramePusher pusher( + self, bootstrap_frame.get(), StackedShadowFrameType::kShadowFrameUnderConstruction); + ShadowFrameSetter setter(bootstrap_frame.get(), 0u); - // The third parameter is the method type associated with the name. - uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i); - Handle<mirror::MethodType> method_type(hs.NewHandle( - class_linker->ResolveMethodType(self, method_type_idx, dex_cache, class_loader))); - if (method_type.IsNull()) { + // The first parameter is a MethodHandles lookup instance. + Handle<mirror::Class> lookup_class = + hs.NewHandle(shadow_frame.GetMethod()->GetDeclaringClass()); + ObjPtr<mirror::MethodHandlesLookup> lookup = + mirror::MethodHandlesLookup::Create(self, lookup_class); + if (lookup.IsNull()) { DCHECK(self->IsExceptionPending()); return nullptr; } - bootstrap_frame->SetVRegReference(vreg++, method_type.Get()); - it.Next(); - - // Append remaining arguments (if any). - while (it.HasNext()) { - const jvalue& jvalue = it.GetJavaValue(); - switch (it.GetValueType()) { - case EncodedArrayValueIterator::ValueType::kBoolean: - case EncodedArrayValueIterator::ValueType::kByte: - case EncodedArrayValueIterator::ValueType::kChar: - case EncodedArrayValueIterator::ValueType::kShort: - case EncodedArrayValueIterator::ValueType::kInt: - bootstrap_frame->SetVReg(vreg, jvalue.i); - vreg += 1; - break; - case EncodedArrayValueIterator::ValueType::kLong: - bootstrap_frame->SetVRegLong(vreg, jvalue.j); - vreg += 2; - break; - case EncodedArrayValueIterator::ValueType::kFloat: - bootstrap_frame->SetVRegFloat(vreg, jvalue.f); - vreg += 1; - break; - case EncodedArrayValueIterator::ValueType::kDouble: - bootstrap_frame->SetVRegDouble(vreg, jvalue.d); - vreg += 2; - break; - case EncodedArrayValueIterator::ValueType::kMethodType: { - uint32_t idx = static_cast<uint32_t>(jvalue.i); - ObjPtr<mirror::MethodType> ref = - class_linker->ResolveMethodType(self, idx, dex_cache, class_loader); - if (ref.IsNull()) { - DCHECK(self->IsExceptionPending()); - return nullptr; - } - bootstrap_frame->SetVRegReference(vreg, ref.Ptr()); - vreg += 1; - break; - } - case EncodedArrayValueIterator::ValueType::kMethodHandle: { - uint32_t idx = static_cast<uint32_t>(jvalue.i); - ObjPtr<mirror::MethodHandle> ref = - class_linker->ResolveMethodHandle(self, idx, referrer); - if (ref.IsNull()) { - DCHECK(self->IsExceptionPending()); - return nullptr; - } - bootstrap_frame->SetVRegReference(vreg, ref.Ptr()); - vreg += 1; - break; - } - case EncodedArrayValueIterator::ValueType::kString: { - dex::StringIndex idx(static_cast<uint32_t>(jvalue.i)); - ObjPtr<mirror::String> ref = class_linker->ResolveString(idx, dex_cache); - if (ref.IsNull()) { - DCHECK(self->IsExceptionPending()); - return nullptr; - } - bootstrap_frame->SetVRegReference(vreg, ref.Ptr()); - vreg += 1; - break; - } - case EncodedArrayValueIterator::ValueType::kType: { - dex::TypeIndex idx(static_cast<uint32_t>(jvalue.i)); - ObjPtr<mirror::Class> ref = class_linker->ResolveType(idx, dex_cache, class_loader); - if (ref.IsNull()) { - DCHECK(self->IsExceptionPending()); - return nullptr; - } - bootstrap_frame->SetVRegReference(vreg, ref.Ptr()); - vreg += 1; - break; + setter.SetReference(lookup); + + // Pack the remaining arguments into the frame. + int number_of_arguments = call_site_type->GetNumberOfPTypes(); + int argument_index; + for (argument_index = 1; argument_index < number_of_arguments; ++argument_index) { + if (argument_index == number_of_arguments - 1 && + call_site_type->GetPTypes()->Get(argument_index)->IsArrayClass()) { + ObjPtr<mirror::Class> array_type = call_site_type->GetPTypes()->Get(argument_index); + if (!PackCollectorArrayForBootstrapMethod(self, + referrer, + array_type, + collector_arguments_length, + &it, + &setter)) { + DCHECK(self->IsExceptionPending()); + return nullptr; } - case EncodedArrayValueIterator::ValueType::kNull: - bootstrap_frame->SetVRegReference(vreg, nullptr); - vreg += 1; - break; - case EncodedArrayValueIterator::ValueType::kField: - case EncodedArrayValueIterator::ValueType::kMethod: - case EncodedArrayValueIterator::ValueType::kEnum: - case EncodedArrayValueIterator::ValueType::kArray: - case EncodedArrayValueIterator::ValueType::kAnnotation: - // Unreachable based on current EncodedArrayValueIterator::Next(). - UNREACHABLE(); + } else if (!PackArgumentForBootstrapMethod(self, referrer, &it, &setter)) { + DCHECK(self->IsExceptionPending()); + return nullptr; } - it.Next(); } + DCHECK(!it.HasNext()); + DCHECK(setter.Done()); // Invoke the bootstrap method handle. JValue result; - RangeInstructionOperands operands(0, vreg); - bool invoke_success = MethodHandleInvokeExact(self, - *bootstrap_frame, - bootstrap, - bootstrap_method_type, - &operands, - &result); + RangeInstructionOperands operands(0, bootstrap_frame->NumberOfVRegs()); + bool invoke_success = MethodHandleInvoke(self, + *bootstrap_frame, + bsm, + call_site_type, + &operands, + &result); if (!invoke_success) { DCHECK(self->IsExceptionPending()); return nullptr; @@ -1077,31 +1395,20 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self, return nullptr; } - // Check the result type is a subclass of CallSite. + // Check the result type is a subclass of j.l.i.CallSite. if (UNLIKELY(!object->InstanceOf(mirror::CallSite::StaticClass()))) { ThrowClassCastException(object->GetClass(), mirror::CallSite::StaticClass()); return nullptr; } + // Check the call site target is not null as we're going to invoke it. Handle<mirror::CallSite> call_site = hs.NewHandle(ObjPtr<mirror::CallSite>::DownCast(ObjPtr<mirror::Object>(result.GetL()))); - // Check the call site target is not null as we're going to invoke it. Handle<mirror::MethodHandle> target = hs.NewHandle(call_site->GetTarget()); if (UNLIKELY(target.IsNull())) { - ThrowClassCastException("Bootstrap method did not return a callsite"); - return nullptr; - } - - // 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()); + ThrowClassCastException("Bootstrap method returned a CallSite with a null target"); return nullptr; } - return call_site.Get(); } @@ -1129,8 +1436,11 @@ bool DoInvokeCustom(Thread* self, call_site.Assign(InvokeBootstrapMethod(self, shadow_frame, call_site_idx)); if (UNLIKELY(call_site.IsNull())) { CHECK(self->IsExceptionPending()); - ThrowWrappedBootstrapMethodError("Exception from call site #%u bootstrap method", - call_site_idx); + if (!self->GetException()->IsError()) { + // Use a BootstrapMethodError if the exception is not an instance of java.lang.Error. + ThrowWrappedBootstrapMethodError("Exception from call site #%u bootstrap method", + call_site_idx); + } result->SetJ(0); return false; } @@ -1139,9 +1449,6 @@ bool DoInvokeCustom(Thread* self, call_site.Assign(winning_call_site); } - // CallSite.java checks the re-assignment of the call site target - // when mutating call site targets. We only check the target is - // non-null and has the right type during bootstrap method execution. Handle<mirror::MethodHandle> target = hs.NewHandle(call_site->GetTarget()); Handle<mirror::MethodType> target_method_type = hs.NewHandle(target->GetMethodType()); DCHECK_EQ(static_cast<size_t>(inst->VRegA()), target_method_type->NumberOfVRegs()); |