blob: 3f4a28ce9d700bb3acb2fb82eaeaa2464b623b0d [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
Orion Hodsonfe92d122018-01-02 10:45:17 +000029struct VarHandleAccessorToAccessModeEntry {
30 const char* method_name;
31 VarHandle::AccessMode access_mode;
32
33 // Binary predicate function for finding access_mode by
34 // method_name. The access_mode field is ignored.
35 static bool CompareName(const VarHandleAccessorToAccessModeEntry& lhs,
36 const VarHandleAccessorToAccessModeEntry& rhs) {
37 return strcmp(lhs.method_name, rhs.method_name) < 0;
38 }
39};
40
41// Map of VarHandle accessor method names to access mode values. The list is alpha-sorted to support
42// binary search. For the usage scenario - lookups in the verifier - a linear scan would likely
43// suffice since we expect VarHandles to be a lesser encountered class. We could use a std::hashmap
44// here and this would be easier to maintain if new values are added here. However, this entails
45// CPU cycles initializing the structure on every execution and uses O(N) more memory for
46// intermediate nodes and makes that memory dirty. Compile-time magic using constexpr is possible
47// here, but that's a tax when this code is recompiled.
48const VarHandleAccessorToAccessModeEntry kAccessorToAccessMode[VarHandle::kNumberOfAccessModes] = {
49 { "compareAndExchange", VarHandle::AccessMode::kCompareAndExchange },
50 { "compareAndExchangeAcquire", VarHandle::AccessMode::kCompareAndExchangeAcquire },
51 { "compareAndExchangeRelease", VarHandle::AccessMode::kCompareAndExchangeRelease },
52 { "compareAndSet", VarHandle::AccessMode::kCompareAndSet },
53 { "get", VarHandle::AccessMode::kGet },
54 { "getAcquire", VarHandle::AccessMode::kGetAcquire },
55 { "getAndAdd", VarHandle::AccessMode::kGetAndAdd },
56 { "getAndAddAcquire", VarHandle::AccessMode::kGetAndAddAcquire },
57 { "getAndAddRelease", VarHandle::AccessMode::kGetAndAddRelease },
58 { "getAndBitwiseAnd", VarHandle::AccessMode::kGetAndBitwiseAnd },
59 { "getAndBitwiseAndAcquire", VarHandle::AccessMode::kGetAndBitwiseAndAcquire },
60 { "getAndBitwiseAndRelease", VarHandle::AccessMode::kGetAndBitwiseAndRelease },
61 { "getAndBitwiseOr", VarHandle::AccessMode::kGetAndBitwiseOr },
62 { "getAndBitwiseOrAcquire", VarHandle::AccessMode::kGetAndBitwiseOrAcquire },
63 { "getAndBitwiseOrRelease", VarHandle::AccessMode::kGetAndBitwiseOrRelease },
64 { "getAndBitwiseXor", VarHandle::AccessMode::kGetAndBitwiseXor },
65 { "getAndBitwiseXorAcquire", VarHandle::AccessMode::kGetAndBitwiseXorAcquire },
66 { "getAndBitwiseXorRelease", VarHandle::AccessMode::kGetAndBitwiseXorRelease },
67 { "getAndSet", VarHandle::AccessMode::kGetAndSet },
68 { "getAndSetAcquire", VarHandle::AccessMode::kGetAndSetAcquire },
69 { "getAndSetRelease", VarHandle::AccessMode::kGetAndSetRelease },
70 { "getOpaque", VarHandle::AccessMode::kGetOpaque },
71 { "getVolatile", VarHandle::AccessMode::kGetVolatile },
72 { "set", VarHandle::AccessMode::kSet },
73 { "setOpaque", VarHandle::AccessMode::kSetOpaque },
74 { "setRelease", VarHandle::AccessMode::kSetRelease },
75 { "setVolatile", VarHandle::AccessMode::kSetVolatile },
76 { "weakCompareAndSet", VarHandle::AccessMode::kWeakCompareAndSet },
77 { "weakCompareAndSetAcquire", VarHandle::AccessMode::kWeakCompareAndSetAcquire },
78 { "weakCompareAndSetPlain", VarHandle::AccessMode::kWeakCompareAndSetPlain },
79 { "weakCompareAndSetRelease", VarHandle::AccessMode::kWeakCompareAndSetRelease },
80};
81
Orion Hodson005ac512017-10-24 15:43:43 +010082// Enumeration for describing the parameter and return types of an AccessMode.
83enum class AccessModeTemplate : uint32_t {
84 kGet, // T Op(C0..CN)
85 kSet, // void Op(C0..CN, T)
86 kCompareAndSet, // boolean Op(C0..CN, T, T)
87 kCompareAndExchange, // T Op(C0..CN, T, T)
88 kGetAndUpdate, // T Op(C0..CN, T)
89};
90
91// Look up the AccessModeTemplate for a given VarHandle
92// AccessMode. This simplifies finding the correct signature for a
93// VarHandle accessor method.
94AccessModeTemplate GetAccessModeTemplate(VarHandle::AccessMode access_mode) {
95 switch (access_mode) {
96 case VarHandle::AccessMode::kGet:
97 return AccessModeTemplate::kGet;
98 case VarHandle::AccessMode::kSet:
99 return AccessModeTemplate::kSet;
100 case VarHandle::AccessMode::kGetVolatile:
101 return AccessModeTemplate::kGet;
102 case VarHandle::AccessMode::kSetVolatile:
103 return AccessModeTemplate::kSet;
104 case VarHandle::AccessMode::kGetAcquire:
105 return AccessModeTemplate::kGet;
106 case VarHandle::AccessMode::kSetRelease:
107 return AccessModeTemplate::kSet;
108 case VarHandle::AccessMode::kGetOpaque:
109 return AccessModeTemplate::kGet;
110 case VarHandle::AccessMode::kSetOpaque:
111 return AccessModeTemplate::kSet;
112 case VarHandle::AccessMode::kCompareAndSet:
113 return AccessModeTemplate::kCompareAndSet;
114 case VarHandle::AccessMode::kCompareAndExchange:
115 return AccessModeTemplate::kCompareAndExchange;
116 case VarHandle::AccessMode::kCompareAndExchangeAcquire:
117 return AccessModeTemplate::kCompareAndExchange;
118 case VarHandle::AccessMode::kCompareAndExchangeRelease:
119 return AccessModeTemplate::kCompareAndExchange;
120 case VarHandle::AccessMode::kWeakCompareAndSetPlain:
121 return AccessModeTemplate::kCompareAndSet;
122 case VarHandle::AccessMode::kWeakCompareAndSet:
123 return AccessModeTemplate::kCompareAndSet;
124 case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
125 return AccessModeTemplate::kCompareAndSet;
126 case VarHandle::AccessMode::kWeakCompareAndSetRelease:
127 return AccessModeTemplate::kCompareAndSet;
128 case VarHandle::AccessMode::kGetAndSet:
129 return AccessModeTemplate::kGetAndUpdate;
130 case VarHandle::AccessMode::kGetAndSetAcquire:
131 return AccessModeTemplate::kGetAndUpdate;
132 case VarHandle::AccessMode::kGetAndSetRelease:
133 return AccessModeTemplate::kGetAndUpdate;
134 case VarHandle::AccessMode::kGetAndAdd:
135 return AccessModeTemplate::kGetAndUpdate;
136 case VarHandle::AccessMode::kGetAndAddAcquire:
137 return AccessModeTemplate::kGetAndUpdate;
138 case VarHandle::AccessMode::kGetAndAddRelease:
139 return AccessModeTemplate::kGetAndUpdate;
140 case VarHandle::AccessMode::kGetAndBitwiseOr:
141 return AccessModeTemplate::kGetAndUpdate;
142 case VarHandle::AccessMode::kGetAndBitwiseOrRelease:
143 return AccessModeTemplate::kGetAndUpdate;
144 case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
145 return AccessModeTemplate::kGetAndUpdate;
146 case VarHandle::AccessMode::kGetAndBitwiseAnd:
147 return AccessModeTemplate::kGetAndUpdate;
148 case VarHandle::AccessMode::kGetAndBitwiseAndRelease:
149 return AccessModeTemplate::kGetAndUpdate;
150 case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
151 return AccessModeTemplate::kGetAndUpdate;
152 case VarHandle::AccessMode::kGetAndBitwiseXor:
153 return AccessModeTemplate::kGetAndUpdate;
154 case VarHandle::AccessMode::kGetAndBitwiseXorRelease:
155 return AccessModeTemplate::kGetAndUpdate;
156 case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
157 return AccessModeTemplate::kGetAndUpdate;
158 }
159}
160
161// Returns the number of parameters associated with an
162// AccessModeTemplate and the supplied coordinate types.
163int32_t GetParameterCount(AccessModeTemplate access_mode_template,
164 ObjPtr<Class> coordinateType0,
165 ObjPtr<Class> coordinateType1) {
166 int32_t index = 0;
167 if (!coordinateType0.IsNull()) {
168 index++;
169 if (!coordinateType1.IsNull()) {
170 index++;
171 }
172 }
173
174 switch (access_mode_template) {
175 case AccessModeTemplate::kGet:
176 return index;
177 case AccessModeTemplate::kSet:
178 case AccessModeTemplate::kGetAndUpdate:
179 return index + 1;
180 case AccessModeTemplate::kCompareAndSet:
181 case AccessModeTemplate::kCompareAndExchange:
182 return index + 2;
183 }
184 UNREACHABLE();
185}
186
187// Writes the parameter types associated with the AccessModeTemplate
188// into an array. The parameter types are derived from the specified
189// variable type and coordinate types. Returns the number of
190// parameters written.
191int32_t BuildParameterArray(ObjPtr<Class> (&parameters)[VarHandle::kMaxAccessorParameters],
192 AccessModeTemplate access_mode_template,
193 ObjPtr<Class> varType,
194 ObjPtr<Class> coordinateType0,
195 ObjPtr<Class> coordinateType1)
196 REQUIRES_SHARED(Locks::mutator_lock_) {
197 DCHECK(varType != nullptr);
198 int32_t index = 0;
199 if (!coordinateType0.IsNull()) {
200 parameters[index++] = coordinateType0;
201 if (!coordinateType1.IsNull()) {
202 parameters[index++] = coordinateType1;
203 }
204 } else {
205 DCHECK(coordinateType1.IsNull());
206 }
207
208 switch (access_mode_template) {
209 case AccessModeTemplate::kCompareAndExchange:
210 case AccessModeTemplate::kCompareAndSet:
211 parameters[index++] = varType;
212 parameters[index++] = varType;
213 return index;
214 case AccessModeTemplate::kGet:
215 return index;
216 case AccessModeTemplate::kGetAndUpdate:
217 case AccessModeTemplate::kSet:
218 parameters[index++] = varType;
219 return index;
220 }
221 return -1;
222}
223
224// Returns the return type associated with an AccessModeTemplate based
225// on the template and the variable type specified.
226Class* GetReturnType(AccessModeTemplate access_mode_template, ObjPtr<Class> varType)
227 REQUIRES_SHARED(Locks::mutator_lock_) {
228 DCHECK(varType != nullptr);
229 switch (access_mode_template) {
230 case AccessModeTemplate::kCompareAndSet:
231 return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('Z');
232 case AccessModeTemplate::kCompareAndExchange:
233 case AccessModeTemplate::kGet:
234 case AccessModeTemplate::kGetAndUpdate:
235 return varType.Ptr();
236 case AccessModeTemplate::kSet:
237 return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V');
238 }
239 return nullptr;
240}
241
242ObjectArray<Class>* NewArrayOfClasses(Thread* self, int count)
243 REQUIRES_SHARED(Locks::mutator_lock_) {
244 Runtime* const runtime = Runtime::Current();
245 ClassLinker* const class_linker = runtime->GetClassLinker();
246 ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
247 ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type);
248 return ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, count);
249}
250
251} // namespace
252
253Class* VarHandle::GetVarType() {
254 return GetFieldObject<Class>(VarTypeOffset());
255}
256
257Class* VarHandle::GetCoordinateType0() {
258 return GetFieldObject<Class>(CoordinateType0Offset());
259}
260
261Class* VarHandle::GetCoordinateType1() {
262 return GetFieldObject<Class>(CoordinateType1Offset());
263}
264
265int32_t VarHandle::GetAccessModesBitMask() {
266 return GetField32(AccessModesBitMaskOffset());
267}
268
269bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) {
270 ScopedAssertNoThreadSuspension ants(__FUNCTION__);
271
272 AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
273 // Check return types first.
274 ObjPtr<Class> var_type = GetVarType();
275 ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type);
276 ObjPtr<Class> void_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V');
277 ObjPtr<Class> mt_rtype = method_type->GetRType();
278
279 // If the mt_rtype is void, the result of the operation will be discarded (okay).
280 if (mt_rtype != void_type && mt_rtype != vh_rtype) {
281 return false;
282 }
283
284 // Check the number of parameters matches.
285 ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
286 const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
287 access_mode_template,
288 var_type,
289 GetCoordinateType0(),
290 GetCoordinateType1());
291 if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
292 return false;
293 }
294
295 // Check the parameter types match.
296 ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
297 for (int32_t i = 0; i < vh_ptypes_count; ++i) {
298 if (mt_ptypes->Get(i) != vh_ptypes[i].Ptr()) {
299 return false;
300 }
301 }
302 return true;
303}
304
305MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self,
306 ObjPtr<VarHandle> var_handle,
307 AccessMode access_mode) {
308 // This is a static as the var_handle might be moved by the GC during it's execution.
309 AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
310
311 StackHandleScope<3> hs(self);
312 Handle<VarHandle> vh = hs.NewHandle(var_handle);
313 Handle<Class> rtype = hs.NewHandle(GetReturnType(access_mode_template, vh->GetVarType()));
314 const int32_t ptypes_count =
315 GetParameterCount(access_mode_template, vh->GetCoordinateType0(), vh->GetCoordinateType1());
316 Handle<ObjectArray<Class>> ptypes = hs.NewHandle(NewArrayOfClasses(self, ptypes_count));
317 if (ptypes == nullptr) {
318 return nullptr;
319 }
320
321 ObjPtr<Class> ptypes_array[VarHandle::kMaxAccessorParameters];
322 BuildParameterArray(ptypes_array,
323 access_mode_template,
324 vh->GetVarType(),
325 vh->GetCoordinateType0(),
326 vh->GetCoordinateType1());
327 for (int32_t i = 0; i < ptypes_count; ++i) {
328 ptypes->Set(i, ptypes_array[i].Ptr());
329 }
330 return MethodType::Create(self, rtype, ptypes);
331}
332
333MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) {
334 return GetMethodTypeForAccessMode(self, this, access_mode);
335}
336
Orion Hodsonfe92d122018-01-02 10:45:17 +0000337const char* VarHandle::GetReturnTypeDescriptor(const char* accessor_name) {
338 AccessMode access_mode;
339 if (!GetAccessModeByMethodName(accessor_name, &access_mode)) {
340 return nullptr;
341 }
342 AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
343 switch (access_mode_template) {
344 case AccessModeTemplate::kGet:
345 case AccessModeTemplate::kCompareAndExchange:
346 case AccessModeTemplate::kGetAndUpdate:
347 return "Ljava/lang/Object;";
348 case AccessModeTemplate::kCompareAndSet:
349 return "Z";
350 case AccessModeTemplate::kSet:
351 return "V";
352 }
353}
354
355bool VarHandle::GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode) {
356 if (method_name == nullptr) {
357 return false;
358 }
359 VarHandleAccessorToAccessModeEntry target = { method_name, /*dummy*/VarHandle::AccessMode::kGet };
360 auto last = std::cend(kAccessorToAccessMode);
361 auto it = std::lower_bound(std::cbegin(kAccessorToAccessMode),
362 last,
363 target,
364 VarHandleAccessorToAccessModeEntry::CompareName);
365 if (it == last || strcmp(it->method_name, method_name) != 0) {
366 return false;
367 }
368 *access_mode = it->access_mode;
369 return true;
370}
371
Orion Hodson005ac512017-10-24 15:43:43 +0100372void VarHandle::SetClass(Class* klass) {
373 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
374 CHECK(klass != nullptr);
375 static_class_ = GcRoot<Class>(klass);
376}
377
378void VarHandle::ResetClass() {
379 CHECK(!static_class_.IsNull());
380 static_class_ = GcRoot<Class>(nullptr);
381}
382
383void VarHandle::VisitRoots(RootVisitor* visitor) {
384 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
385}
386
387GcRoot<Class> VarHandle::static_class_;
388
389ArtField* FieldVarHandle::GetField() {
390 uintptr_t opaque_field = static_cast<uintptr_t>(GetField64(ArtFieldOffset()));
391 return reinterpret_cast<ArtField*>(opaque_field);
392}
393
394Class* FieldVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
395 return static_class_.Read();
396}
397
398void FieldVarHandle::SetClass(Class* klass) {
399 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
400 CHECK(klass != nullptr);
401 static_class_ = GcRoot<Class>(klass);
402}
403
404void FieldVarHandle::ResetClass() {
405 CHECK(!static_class_.IsNull());
406 static_class_ = GcRoot<Class>(nullptr);
407}
408
409void FieldVarHandle::VisitRoots(RootVisitor* visitor) {
410 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
411}
412
413GcRoot<Class> FieldVarHandle::static_class_;
414
415Class* ArrayElementVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
416 return static_class_.Read();
417}
418
419void ArrayElementVarHandle::SetClass(Class* klass) {
420 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
421 CHECK(klass != nullptr);
422 static_class_ = GcRoot<Class>(klass);
423}
424
425void ArrayElementVarHandle::ResetClass() {
426 CHECK(!static_class_.IsNull());
427 static_class_ = GcRoot<Class>(nullptr);
428}
429
430void ArrayElementVarHandle::VisitRoots(RootVisitor* visitor) {
431 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
432}
433
434GcRoot<Class> ArrayElementVarHandle::static_class_;
435
436bool ByteArrayViewVarHandle::GetNativeByteOrder() {
437 return GetFieldBoolean(NativeByteOrderOffset());
438}
439
440Class* ByteArrayViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
441 return static_class_.Read();
442}
443
444void ByteArrayViewVarHandle::SetClass(Class* klass) {
445 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
446 CHECK(klass != nullptr);
447 static_class_ = GcRoot<Class>(klass);
448}
449
450void ByteArrayViewVarHandle::ResetClass() {
451 CHECK(!static_class_.IsNull());
452 static_class_ = GcRoot<Class>(nullptr);
453}
454
455void ByteArrayViewVarHandle::VisitRoots(RootVisitor* visitor) {
456 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
457}
458
459GcRoot<Class> ByteArrayViewVarHandle::static_class_;
460
461bool ByteBufferViewVarHandle::GetNativeByteOrder() {
462 return GetFieldBoolean(NativeByteOrderOffset());
463}
464
465Class* ByteBufferViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
466 return static_class_.Read();
467}
468
469void ByteBufferViewVarHandle::SetClass(Class* klass) {
470 CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
471 CHECK(klass != nullptr);
472 static_class_ = GcRoot<Class>(klass);
473}
474
475void ByteBufferViewVarHandle::ResetClass() {
476 CHECK(!static_class_.IsNull());
477 static_class_ = GcRoot<Class>(nullptr);
478}
479
480void ByteBufferViewVarHandle::VisitRoots(RootVisitor* visitor) {
481 static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
482}
483
484GcRoot<Class> ByteBufferViewVarHandle::static_class_;
485
486} // namespace mirror
487} // namespace art