blob: e7eac1a5ab0a03d66d5026c8b03084559184d4e4 [file] [log] [blame]
Orion Hodson005ac512017-10-24 15:43:43 +01001/*
2 * Copyright (C) 2017 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 "var_handle.h"
18
19#include "class-inl.h"
20#include "class_linker.h"
21#include "gc_root-inl.h"
22#include "method_type.h"
23
24namespace art {
25namespace mirror {
26
27namespace {
28
29// Enumeration for describing the parameter and return types of an AccessMode.
30enum class AccessModeTemplate : uint32_t {
31 kGet, // T Op(C0..CN)
32 kSet, // void Op(C0..CN, T)
33 kCompareAndSet, // boolean Op(C0..CN, T, T)
34 kCompareAndExchange, // T Op(C0..CN, T, T)
35 kGetAndUpdate, // T Op(C0..CN, T)
36};
37
38// Look up the AccessModeTemplate for a given VarHandle
39// AccessMode. This simplifies finding the correct signature for a
40// VarHandle accessor method.
41AccessModeTemplate GetAccessModeTemplate(VarHandle::AccessMode access_mode) {
42 switch (access_mode) {
43 case VarHandle::AccessMode::kGet:
44 return AccessModeTemplate::kGet;
45 case VarHandle::AccessMode::kSet:
46 return AccessModeTemplate::kSet;
47 case VarHandle::AccessMode::kGetVolatile:
48 return AccessModeTemplate::kGet;
49 case VarHandle::AccessMode::kSetVolatile:
50 return AccessModeTemplate::kSet;
51 case VarHandle::AccessMode::kGetAcquire:
52 return AccessModeTemplate::kGet;
53 case VarHandle::AccessMode::kSetRelease:
54 return AccessModeTemplate::kSet;
55 case VarHandle::AccessMode::kGetOpaque:
56 return AccessModeTemplate::kGet;
57 case VarHandle::AccessMode::kSetOpaque:
58 return AccessModeTemplate::kSet;
59 case VarHandle::AccessMode::kCompareAndSet:
60 return AccessModeTemplate::kCompareAndSet;
61 case VarHandle::AccessMode::kCompareAndExchange:
62 return AccessModeTemplate::kCompareAndExchange;
63 case VarHandle::AccessMode::kCompareAndExchangeAcquire:
64 return AccessModeTemplate::kCompareAndExchange;
65 case VarHandle::AccessMode::kCompareAndExchangeRelease:
66 return AccessModeTemplate::kCompareAndExchange;
67 case VarHandle::AccessMode::kWeakCompareAndSetPlain:
68 return AccessModeTemplate::kCompareAndSet;
69 case VarHandle::AccessMode::kWeakCompareAndSet:
70 return AccessModeTemplate::kCompareAndSet;
71 case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
72 return AccessModeTemplate::kCompareAndSet;
73 case VarHandle::AccessMode::kWeakCompareAndSetRelease:
74 return AccessModeTemplate::kCompareAndSet;
75 case VarHandle::AccessMode::kGetAndSet:
76 return AccessModeTemplate::kGetAndUpdate;
77 case VarHandle::AccessMode::kGetAndSetAcquire:
78 return AccessModeTemplate::kGetAndUpdate;
79 case VarHandle::AccessMode::kGetAndSetRelease:
80 return AccessModeTemplate::kGetAndUpdate;
81 case VarHandle::AccessMode::kGetAndAdd:
82 return AccessModeTemplate::kGetAndUpdate;
83 case VarHandle::AccessMode::kGetAndAddAcquire:
84 return AccessModeTemplate::kGetAndUpdate;
85 case VarHandle::AccessMode::kGetAndAddRelease:
86 return AccessModeTemplate::kGetAndUpdate;
87 case VarHandle::AccessMode::kGetAndBitwiseOr:
88 return AccessModeTemplate::kGetAndUpdate;
89 case VarHandle::AccessMode::kGetAndBitwiseOrRelease:
90 return AccessModeTemplate::kGetAndUpdate;
91 case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
92 return AccessModeTemplate::kGetAndUpdate;
93 case VarHandle::AccessMode::kGetAndBitwiseAnd:
94 return AccessModeTemplate::kGetAndUpdate;
95 case VarHandle::AccessMode::kGetAndBitwiseAndRelease:
96 return AccessModeTemplate::kGetAndUpdate;
97 case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
98 return AccessModeTemplate::kGetAndUpdate;
99 case VarHandle::AccessMode::kGetAndBitwiseXor:
100 return AccessModeTemplate::kGetAndUpdate;
101 case VarHandle::AccessMode::kGetAndBitwiseXorRelease:
102 return AccessModeTemplate::kGetAndUpdate;
103 case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
104 return AccessModeTemplate::kGetAndUpdate;
105 }
106}
107
108// Returns the number of parameters associated with an
109// AccessModeTemplate and the supplied coordinate types.
110int32_t GetParameterCount(AccessModeTemplate access_mode_template,
111 ObjPtr<Class> coordinateType0,
112 ObjPtr<Class> coordinateType1) {
113 int32_t index = 0;
114 if (!coordinateType0.IsNull()) {
115 index++;
116 if (!coordinateType1.IsNull()) {
117 index++;
118 }
119 }
120
121 switch (access_mode_template) {
122 case AccessModeTemplate::kGet:
123 return index;
124 case AccessModeTemplate::kSet:
125 case AccessModeTemplate::kGetAndUpdate:
126 return index + 1;
127 case AccessModeTemplate::kCompareAndSet:
128 case AccessModeTemplate::kCompareAndExchange:
129 return index + 2;
130 }
131 UNREACHABLE();
132}
133
134// Writes the parameter types associated with the AccessModeTemplate
135// into an array. The parameter types are derived from the specified
136// variable type and coordinate types. Returns the number of
137// parameters written.
138int32_t BuildParameterArray(ObjPtr<Class> (&parameters)[VarHandle::kMaxAccessorParameters],
139 AccessModeTemplate access_mode_template,
140 ObjPtr<Class> varType,
141 ObjPtr<Class> coordinateType0,
142 ObjPtr<Class> coordinateType1)
143 REQUIRES_SHARED(Locks::mutator_lock_) {
144 DCHECK(varType != nullptr);
145 int32_t index = 0;
146 if (!coordinateType0.IsNull()) {
147 parameters[index++] = coordinateType0;
148 if (!coordinateType1.IsNull()) {
149 parameters[index++] = coordinateType1;
150 }
151 } else {
152 DCHECK(coordinateType1.IsNull());
153 }
154
155 switch (access_mode_template) {
156 case AccessModeTemplate::kCompareAndExchange:
157 case AccessModeTemplate::kCompareAndSet:
158 parameters[index++] = varType;
159 parameters[index++] = varType;
160 return index;
161 case AccessModeTemplate::kGet:
162 return index;
163 case AccessModeTemplate::kGetAndUpdate:
164 case AccessModeTemplate::kSet:
165 parameters[index++] = varType;
166 return index;
167 }
168 return -1;
169}
170
171// Returns the return type associated with an AccessModeTemplate based
172// on the template and the variable type specified.
173Class* GetReturnType(AccessModeTemplate access_mode_template, ObjPtr<Class> varType)
174 REQUIRES_SHARED(Locks::mutator_lock_) {
175 DCHECK(varType != nullptr);
176 switch (access_mode_template) {
177 case AccessModeTemplate::kCompareAndSet:
178 return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('Z');
179 case AccessModeTemplate::kCompareAndExchange:
180 case AccessModeTemplate::kGet:
181 case AccessModeTemplate::kGetAndUpdate:
182 return varType.Ptr();
183 case AccessModeTemplate::kSet:
184 return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V');
185 }
186 return nullptr;
187}
188
189ObjectArray<Class>* NewArrayOfClasses(Thread* self, int count)
190 REQUIRES_SHARED(Locks::mutator_lock_) {
191 Runtime* const runtime = Runtime::Current();
192 ClassLinker* const class_linker = runtime->GetClassLinker();
193 ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
194 ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type);
195 return ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, count);
196}
197
198} // namespace
199
200Class* VarHandle::GetVarType() {
201 return GetFieldObject<Class>(VarTypeOffset());
202}
203
204Class* VarHandle::GetCoordinateType0() {
205 return GetFieldObject<Class>(CoordinateType0Offset());
206}
207
208Class* VarHandle::GetCoordinateType1() {
209 return GetFieldObject<Class>(CoordinateType1Offset());
210}
211
212int32_t VarHandle::GetAccessModesBitMask() {
213 return GetField32(AccessModesBitMaskOffset());
214}
215
216bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) {
217 ScopedAssertNoThreadSuspension ants(__FUNCTION__);
218
219 AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
220 // Check return types first.
221 ObjPtr<Class> var_type = GetVarType();
222 ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type);
223 ObjPtr<Class> void_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V');
224 ObjPtr<Class> mt_rtype = method_type->GetRType();
225
226 // If the mt_rtype is void, the result of the operation will be discarded (okay).
227 if (mt_rtype != void_type && mt_rtype != vh_rtype) {
228 return false;
229 }
230
231 // Check the number of parameters matches.
232 ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
233 const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
234 access_mode_template,
235 var_type,
236 GetCoordinateType0(),
237 GetCoordinateType1());
238 if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
239 return false;
240 }
241
242 // Check the parameter types match.
243 ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
244 for (int32_t i = 0; i < vh_ptypes_count; ++i) {
245 if (mt_ptypes->Get(i) != vh_ptypes[i].Ptr()) {
246 return false;
247 }
248 }
249 return true;
250}
251
252MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self,
253 ObjPtr<VarHandle> var_handle,
254 AccessMode access_mode) {
255 // This is a static as the var_handle might be moved by the GC during it's execution.
256 AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
257
258 StackHandleScope<3> hs(self);
259 Handle<VarHandle> vh = hs.NewHandle(var_handle);
260 Handle<Class> rtype = hs.NewHandle(GetReturnType(access_mode_template, vh->GetVarType()));
261 const int32_t ptypes_count =
262 GetParameterCount(access_mode_template, vh->GetCoordinateType0(), vh->GetCoordinateType1());
263 Handle<ObjectArray<Class>> ptypes = hs.NewHandle(NewArrayOfClasses(self, ptypes_count));
264 if (ptypes == nullptr) {
265 return nullptr;
266 }
267
268 ObjPtr<Class> ptypes_array[VarHandle::kMaxAccessorParameters];
269 BuildParameterArray(ptypes_array,
270 access_mode_template,
271 vh->GetVarType(),
272 vh->GetCoordinateType0(),
273 vh->GetCoordinateType1());
274 for (int32_t i = 0; i < ptypes_count; ++i) {
275 ptypes->Set(i, ptypes_array[i].Ptr());
276 }
277 return MethodType::Create(self, rtype, ptypes);
278}
279
280MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) {
281 return GetMethodTypeForAccessMode(self, this, access_mode);
282}
283
284void VarHandle::SetClass(Class* klass) {
285 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
286 CHECK(klass != nullptr);
287 static_class_ = GcRoot<Class>(klass);
288}
289
290void VarHandle::ResetClass() {
291 CHECK(!static_class_.IsNull());
292 static_class_ = GcRoot<Class>(nullptr);
293}
294
295void VarHandle::VisitRoots(RootVisitor* visitor) {
296 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
297}
298
299GcRoot<Class> VarHandle::static_class_;
300
301ArtField* FieldVarHandle::GetField() {
302 uintptr_t opaque_field = static_cast<uintptr_t>(GetField64(ArtFieldOffset()));
303 return reinterpret_cast<ArtField*>(opaque_field);
304}
305
306Class* FieldVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
307 return static_class_.Read();
308}
309
310void FieldVarHandle::SetClass(Class* klass) {
311 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
312 CHECK(klass != nullptr);
313 static_class_ = GcRoot<Class>(klass);
314}
315
316void FieldVarHandle::ResetClass() {
317 CHECK(!static_class_.IsNull());
318 static_class_ = GcRoot<Class>(nullptr);
319}
320
321void FieldVarHandle::VisitRoots(RootVisitor* visitor) {
322 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
323}
324
325GcRoot<Class> FieldVarHandle::static_class_;
326
327Class* ArrayElementVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
328 return static_class_.Read();
329}
330
331void ArrayElementVarHandle::SetClass(Class* klass) {
332 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
333 CHECK(klass != nullptr);
334 static_class_ = GcRoot<Class>(klass);
335}
336
337void ArrayElementVarHandle::ResetClass() {
338 CHECK(!static_class_.IsNull());
339 static_class_ = GcRoot<Class>(nullptr);
340}
341
342void ArrayElementVarHandle::VisitRoots(RootVisitor* visitor) {
343 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
344}
345
346GcRoot<Class> ArrayElementVarHandle::static_class_;
347
348bool ByteArrayViewVarHandle::GetNativeByteOrder() {
349 return GetFieldBoolean(NativeByteOrderOffset());
350}
351
352Class* ByteArrayViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
353 return static_class_.Read();
354}
355
356void ByteArrayViewVarHandle::SetClass(Class* klass) {
357 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
358 CHECK(klass != nullptr);
359 static_class_ = GcRoot<Class>(klass);
360}
361
362void ByteArrayViewVarHandle::ResetClass() {
363 CHECK(!static_class_.IsNull());
364 static_class_ = GcRoot<Class>(nullptr);
365}
366
367void ByteArrayViewVarHandle::VisitRoots(RootVisitor* visitor) {
368 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
369}
370
371GcRoot<Class> ByteArrayViewVarHandle::static_class_;
372
373bool ByteBufferViewVarHandle::GetNativeByteOrder() {
374 return GetFieldBoolean(NativeByteOrderOffset());
375}
376
377Class* ByteBufferViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
378 return static_class_.Read();
379}
380
381void ByteBufferViewVarHandle::SetClass(Class* klass) {
382 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
383 CHECK(klass != nullptr);
384 static_class_ = GcRoot<Class>(klass);
385}
386
387void ByteBufferViewVarHandle::ResetClass() {
388 CHECK(!static_class_.IsNull());
389 static_class_ = GcRoot<Class>(nullptr);
390}
391
392void ByteBufferViewVarHandle::VisitRoots(RootVisitor* visitor) {
393 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
394}
395
396GcRoot<Class> ByteBufferViewVarHandle::static_class_;
397
398} // namespace mirror
399} // namespace art