1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "method_type.h"
18
19#include "class-inl.h"
20#include "gc_root-inl.h"
21#include "method_handles.h"
22
23namespace art {
24namespace mirror {
25
26GcRoot<Class> MethodType::static_class_;
27
28MethodType* MethodType::Create(Thread* const self,
29                               Handle<Class> return_type,
30                               Handle<ObjectArray<Class>> parameter_types) {
31  StackHandleScope<1> hs(self);
32  Handle<MethodType> mt(
33      hs.NewHandle(ObjPtr<MethodType>::DownCast(StaticClass()->AllocObject(self))));
34
35  // TODO: Do we ever create a MethodType during a transaction ? There doesn't
36  // seem like a good reason to do a polymorphic invoke that results in the
37  // resolution of a method type in an unstarted runtime.
38  mt->SetFieldObject<false>(FormOffset(), nullptr);
39  mt->SetFieldObject<false>(MethodDescriptorOffset(), nullptr);
40  mt->SetFieldObject<false>(RTypeOffset(), return_type.Get());
41  mt->SetFieldObject<false>(PTypesOffset(), parameter_types.Get());
42  mt->SetFieldObject<false>(WrapAltOffset(), nullptr);
43
44  return mt.Get();
45}
46
47MethodType* MethodType::CloneWithoutLeadingParameter(Thread* const self,
48                                                     ObjPtr<MethodType> method_type) {
49  StackHandleScope<3> hs(self);
50  Handle<Class> rtype = hs.NewHandle(method_type->GetRType());
51  Handle<ObjectArray<Class>> src_ptypes = hs.NewHandle(method_type->GetPTypes());
52  ObjPtr<Class> class_type = Class::GetJavaLangClass();
53  ObjPtr<Class> class_array_type =
54      Runtime::Current()->GetClassLinker()->FindArrayClass(self, &class_type);
55  const int32_t dst_ptypes_count = src_ptypes->GetLength() - 1;
56  Handle<ObjectArray<Class>> dst_ptypes = hs.NewHandle(
57      ObjectArray<Class>::Alloc(self, class_array_type, dst_ptypes_count));
58  for (int32_t i = 0; i < dst_ptypes_count; ++i) {
59    dst_ptypes->Set(i, src_ptypes->Get(i + 1));
60  }
61  return Create(self, rtype, dst_ptypes);
62}
63
64size_t MethodType::NumberOfVRegs() REQUIRES_SHARED(Locks::mutator_lock_) {
65  ObjectArray<Class>* const p_types = GetPTypes();
66  const int32_t p_types_length = p_types->GetLength();
67
68  // Initialize |num_vregs| with number of parameters and only increment it for
69  // types requiring a second vreg.
70  size_t num_vregs = static_cast<size_t>(p_types_length);
71  for (int32_t i = 0; i < p_types_length; ++i) {
72    Class* klass = p_types->GetWithoutChecks(i);
73    if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
74      ++num_vregs;
75    }
76  }
77  return num_vregs;
78}
79
80bool MethodType::IsExactMatch(MethodType* target) REQUIRES_SHARED(Locks::mutator_lock_) {
81  ObjectArray<Class>* const p_types = GetPTypes();
82  const int32_t params_length = p_types->GetLength();
83
84  ObjectArray<Class>* const target_p_types = target->GetPTypes();
85  if (params_length != target_p_types->GetLength()) {
86    return false;
87  }
88  for (int32_t i = 0; i < params_length; ++i) {
89    if (p_types->GetWithoutChecks(i) != target_p_types->GetWithoutChecks(i)) {
90      return false;
91    }
92  }
93  return GetRType() == target->GetRType();
94}
95
96bool MethodType::IsConvertible(MethodType* target) REQUIRES_SHARED(Locks::mutator_lock_) {
97  ObjectArray<Class>* const p_types = GetPTypes();
98  const int32_t params_length = p_types->GetLength();
99
100  ObjectArray<Class>* const target_p_types = target->GetPTypes();
101  if (params_length != target_p_types->GetLength()) {
102    return false;
103  }
104
105  // Perform return check before invoking method handle otherwise side
106  // effects from the invocation may be observable before
107  // WrongMethodTypeException is raised.
108  if (!IsReturnTypeConvertible(target->GetRType(), GetRType())) {
109    return false;
110  }
111
112  for (int32_t i = 0; i < params_length; ++i) {
113    if (!IsParameterTypeConvertible(p_types->GetWithoutChecks(i),
114                                    target_p_types->GetWithoutChecks(i))) {
115      return false;
116    }
117  }
118  return true;
119}
120
121std::string MethodType::PrettyDescriptor() REQUIRES_SHARED(Locks::mutator_lock_) {
122  std::ostringstream ss;
123  ss << "(";
124
125  ObjectArray<Class>* const p_types = GetPTypes();
126  const int32_t params_length = p_types->GetLength();
127  for (int32_t i = 0; i < params_length; ++i) {
128    ss << p_types->GetWithoutChecks(i)->PrettyDescriptor();
129    if (i != (params_length - 1)) {
130      ss << ", ";
131    }
132  }
133
134  ss << ")";
135  ss << GetRType()->PrettyDescriptor();
136
137  return ss.str();
138}
139
140void MethodType::SetClass(Class* klass) {
141  CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
142  CHECK(klass != nullptr);
143  static_class_ = GcRoot<Class>(klass);
144}
145
146void MethodType::ResetClass() {
147  CHECK(!static_class_.IsNull());
148  static_class_ = GcRoot<Class>(nullptr);
149}
150
151void MethodType::VisitRoots(RootVisitor* visitor) {
152  static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
153}
154
155}  // namespace mirror
156}  // namespace art
157