Getter/Setter support for invoke-polymorphic of invokeExact().
Test: make test-art-host
Bug: 30550796
Change-Id: I427a6e0afba88b223655ad1ba30843aaf255182b
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 1ed3d55..73fc410 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -42,6 +42,59 @@
ThrowNullPointerExceptionFromDexPC();
}
+template<Primitive::Type field_type>
+static ALWAYS_INLINE void DoFieldGetCommon(Thread* self,
+ const ShadowFrame& shadow_frame,
+ ObjPtr<mirror::Object>& obj,
+ ArtField* field,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ field->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
+
+ // Report this field access to instrumentation if needed.
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+ if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
+ StackHandleScope<1> hs(self);
+ // Wrap in handle wrapper in case the listener does thread suspension.
+ HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj));
+ ObjPtr<mirror::Object> this_object;
+ if (!field->IsStatic()) {
+ this_object = obj;
+ }
+ instrumentation->FieldReadEvent(self,
+ this_object.Ptr(),
+ shadow_frame.GetMethod(),
+ shadow_frame.GetDexPC(),
+ field);
+ }
+
+ switch (field_type) {
+ case Primitive::kPrimBoolean:
+ result->SetZ(field->GetBoolean(obj));
+ break;
+ case Primitive::kPrimByte:
+ result->SetB(field->GetByte(obj));
+ break;
+ case Primitive::kPrimChar:
+ result->SetC(field->GetChar(obj));
+ break;
+ case Primitive::kPrimShort:
+ result->SetS(field->GetShort(obj));
+ break;
+ case Primitive::kPrimInt:
+ result->SetI(field->GetInt(obj));
+ break;
+ case Primitive::kPrimLong:
+ result->SetJ(field->GetLong(obj));
+ break;
+ case Primitive::kPrimNot:
+ result->SetL(field->GetObject(obj));
+ break;
+ default:
+ LOG(FATAL) << "Unreachable: " << field_type;
+ UNREACHABLE();
+ }
+}
+
template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
uint16_t inst_data) {
@@ -64,45 +117,31 @@
return false;
}
}
- f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
- // Report this field access to instrumentation if needed.
- instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
- if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
- StackHandleScope<1> hs(self);
- // Wrap in handle wrapper in case the listener does thread suspension.
- HandleWrapperObjPtr<mirror::Object> h(hs.NewHandleWrapper(&obj));
- ObjPtr<mirror::Object> this_object;
- if (!f->IsStatic()) {
- this_object = obj;
- }
- instrumentation->FieldReadEvent(self,
- this_object.Ptr(),
- shadow_frame.GetMethod(),
- shadow_frame.GetDexPC(),
- f);
- }
+
+ JValue result;
+ DoFieldGetCommon<field_type>(self, shadow_frame, obj, f, &result);
uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
switch (field_type) {
case Primitive::kPrimBoolean:
- shadow_frame.SetVReg(vregA, f->GetBoolean(obj));
+ shadow_frame.SetVReg(vregA, result.GetZ());
break;
case Primitive::kPrimByte:
- shadow_frame.SetVReg(vregA, f->GetByte(obj));
+ shadow_frame.SetVReg(vregA, result.GetB());
break;
case Primitive::kPrimChar:
- shadow_frame.SetVReg(vregA, f->GetChar(obj));
+ shadow_frame.SetVReg(vregA, result.GetC());
break;
case Primitive::kPrimShort:
- shadow_frame.SetVReg(vregA, f->GetShort(obj));
+ shadow_frame.SetVReg(vregA, result.GetS());
break;
case Primitive::kPrimInt:
- shadow_frame.SetVReg(vregA, f->GetInt(obj));
+ shadow_frame.SetVReg(vregA, result.GetI());
break;
case Primitive::kPrimLong:
- shadow_frame.SetVRegLong(vregA, f->GetLong(obj));
+ shadow_frame.SetVRegLong(vregA, result.GetJ());
break;
case Primitive::kPrimNot:
- shadow_frame.SetVRegReference(vregA, f->GetObject(obj).Ptr());
+ shadow_frame.SetVRegReference(vregA, result.GetL());
break;
default:
LOG(FATAL) << "Unreachable: " << field_type;
@@ -143,6 +182,48 @@
#undef EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL
#undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
+// Helper for getters in invoke-polymorphic.
+inline static void DoFieldGetForInvokePolymorphic(Thread* self,
+ const ShadowFrame& shadow_frame,
+ ObjPtr<mirror::Object>& obj,
+ ArtField* field,
+ Primitive::Type field_type,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ switch (field_type) {
+ case Primitive::kPrimBoolean:
+ DoFieldGetCommon<Primitive::kPrimBoolean>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimByte:
+ DoFieldGetCommon<Primitive::kPrimByte>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimChar:
+ DoFieldGetCommon<Primitive::kPrimChar>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimShort:
+ DoFieldGetCommon<Primitive::kPrimShort>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimInt:
+ DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimLong:
+ DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimFloat:
+ DoFieldGetCommon<Primitive::kPrimInt>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimDouble:
+ DoFieldGetCommon<Primitive::kPrimLong>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimNot:
+ DoFieldGetCommon<Primitive::kPrimNot>(self, shadow_frame, obj, field, result);
+ break;
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable: " << field_type;
+ UNREACHABLE();
+ }
+}
+
// Handles iget-quick, iget-wide-quick and iget-object-quick instructions.
// Returns true on success, otherwise throws an exception and returns false.
template<Primitive::Type field_type>
@@ -250,32 +331,14 @@
return field_value;
}
-template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
- bool transaction_active>
-bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst,
- uint16_t inst_data) {
- bool do_assignability_check = do_access_check;
- bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
- uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
- ArtField* f =
- FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self,
- Primitive::ComponentSize(field_type));
- if (UNLIKELY(f == nullptr)) {
- CHECK(self->IsExceptionPending());
- return false;
- }
- ObjPtr<mirror::Object> obj;
- if (is_static) {
- obj = f->GetDeclaringClass();
- } else {
- obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionForFieldAccess(f, false);
- return false;
- }
- }
+template<Primitive::Type field_type, bool do_assignability_check, bool transaction_active>
+static inline bool DoFieldPutCommon(Thread* self,
+ const ShadowFrame& shadow_frame,
+ ObjPtr<mirror::Object>& obj,
+ ArtField* f,
+ size_t vregA) REQUIRES_SHARED(Locks::mutator_lock_) {
f->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
- uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+
// Report this field access to instrumentation if needed. Since we only have the offset of
// the field from the base of the object, we need to look for it first.
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
@@ -291,6 +354,7 @@
f,
field_value);
}
+
switch (field_type) {
case Primitive::kPrimBoolean:
f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA));
@@ -343,6 +407,39 @@
return true;
}
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
+ bool transaction_active>
+bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction* inst,
+ uint16_t inst_data) {
+ const bool do_assignability_check = do_access_check;
+ bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
+ uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
+ ArtField* f =
+ FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self,
+ Primitive::ComponentSize(field_type));
+ if (UNLIKELY(f == nullptr)) {
+ CHECK(self->IsExceptionPending());
+ return false;
+ }
+ ObjPtr<mirror::Object> obj;
+ if (is_static) {
+ obj = f->GetDeclaringClass();
+ } else {
+ obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
+ if (UNLIKELY(obj == nullptr)) {
+ ThrowNullPointerExceptionForFieldAccess(f, false);
+ return false;
+ }
+ }
+
+ uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+ return DoFieldPutCommon<field_type, do_assignability_check, transaction_active>(self,
+ shadow_frame,
+ obj,
+ f,
+ vregA);
+}
+
// Explicitly instantiate all DoFieldPut functions.
#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active) \
template bool DoFieldPut<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, \
@@ -375,6 +472,49 @@
#undef EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL
#undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL
+// Helper for setters in invoke-polymorphic.
+bool DoFieldPutForInvokePolymorphic(Thread* self,
+ ShadowFrame& shadow_frame,
+ ObjPtr<mirror::Object>& obj,
+ ArtField* field,
+ Primitive::Type field_type,
+ size_t vregA) REQUIRES_SHARED(Locks::mutator_lock_) {
+ static const bool kDoCheckAssignability = false;
+ static const bool kTransaction = false;
+ switch (field_type) {
+ case Primitive::kPrimBoolean:
+ return DoFieldPutCommon<Primitive::kPrimBoolean, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimByte:
+ return DoFieldPutCommon<Primitive::kPrimByte, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimChar:
+ return DoFieldPutCommon<Primitive::kPrimChar, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimShort:
+ return DoFieldPutCommon<Primitive::kPrimShort, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimInt:
+ return DoFieldPutCommon<Primitive::kPrimInt, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimLong:
+ return DoFieldPutCommon<Primitive::kPrimLong, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimFloat:
+ return DoFieldPutCommon<Primitive::kPrimInt, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimDouble:
+ return DoFieldPutCommon<Primitive::kPrimLong, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimNot:
+ return DoFieldPutCommon<Primitive::kPrimNot, kDoCheckAssignability, kTransaction>(
+ self, shadow_frame, obj, field, vregA);
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "Unreachable: " << field_type;
+ UNREACHABLE();
+ }
+}
+
template<Primitive::Type field_type, bool transaction_active>
bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
@@ -620,6 +760,17 @@
}
}
+inline static bool IsInvokeExact(const DexFile& dex_file, int invoke_method_idx) {
+ // This check uses string comparison as it needs less code and data
+ // to do than fetching the associated ArtMethod from the DexCache
+ // and checking against ArtMethods in the well known classes. The
+ // verifier needs to perform a more rigorous check.
+ const char* method_name = dex_file.GetMethodName(dex_file.GetMethodId(invoke_method_idx));
+ bool is_invoke_exact = (0 == strcmp(method_name, "invokeExact"));
+ DCHECK(is_invoke_exact || (0 == strcmp(method_name, "invoke")));
+ return is_invoke_exact;
+}
+
template<bool is_range, bool do_access_check>
inline bool DoInvokePolymorphic(Thread* self,
ShadowFrame& shadow_frame,
@@ -628,8 +779,14 @@
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Invoke-polymorphic instructions always take a receiver. i.e, they are never static.
const uint32_t vRegC = (is_range) ? inst->VRegC_4rcc() : inst->VRegC_45cc();
+ const int invoke_method_idx = (is_range) ? inst->VRegB_4rcc() : inst->VRegB_45cc();
- // The method_idx here is the name of the signature polymorphic method that
+ // Determine if this invocation is MethodHandle.invoke() or
+ // MethodHandle.invokeExact().
+ bool is_invoke_exact = IsInvokeExact(shadow_frame.GetMethod()->GetDeclaringClass()->GetDexFile(),
+ invoke_method_idx);
+
+ // The invoke_method_idx here is the name of the signature polymorphic method that
// was symbolically invoked in bytecode (say MethodHandle.invoke or MethodHandle.invokeExact)
// and not the method that we'll dispatch to in the end.
//
@@ -642,11 +799,9 @@
ObjPtr<mirror::MethodHandleImpl>::DownCast(
MakeObjPtr(shadow_frame.GetVRegReference(vRegC)))));
if (UNLIKELY(method_handle.Get() == nullptr)) {
- const int method_idx = (is_range) ? inst->VRegB_4rcc() : inst->VRegB_45cc();
// Note that the invoke type is kVirtual here because a call to a signature
// polymorphic method is shaped like a virtual call at the bytecode level.
- ThrowNullPointerExceptionForMethodAccess(method_idx, InvokeType::kVirtual);
-
+ ThrowNullPointerExceptionForMethodAccess(invoke_method_idx, InvokeType::kVirtual);
result->SetJ(0);
return false;
}
@@ -672,15 +827,13 @@
return false;
}
- // Get the method we're actually invoking along with the kind of
- // invoke that is desired. We don't need to perform access checks at this
- // point because they would have been performed on our behalf at the point
- // of creation of the method handle.
- ArtMethod* called_method = method_handle->GetTargetMethod();
const MethodHandleKind handle_kind = method_handle->GetHandleKind();
Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
- CHECK(called_method != nullptr);
CHECK(handle_type.Get() != nullptr);
+ if (UNLIKELY(is_invoke_exact && !callsite_type->IsExactMatch(handle_type.Get()))) {
+ ThrowWrongMethodTypeException(callsite_type.Get(), handle_type.Get());
+ return false;
+ }
uint32_t arg[Instruction::kMaxVarArgRegs] = {};
uint32_t receiver_vregC = 0;
@@ -697,6 +850,13 @@
}
if (IsInvoke(handle_kind)) {
+ // Get the method we're actually invoking along with the kind of
+ // invoke that is desired. We don't need to perform access checks at this
+ // point because they would have been performed on our behalf at the point
+ // of creation of the method handle.
+ ArtMethod* called_method = method_handle->GetTargetMethod();
+ CHECK(called_method != nullptr);
+
if (handle_kind == kInvokeVirtual || handle_kind == kInvokeInterface) {
ObjPtr<mirror::Object> receiver = shadow_frame.GetVRegReference(receiver_vregC);
ObjPtr<mirror::Class> declaring_class = called_method->GetDeclaringClass();
@@ -761,9 +921,38 @@
receiver_vregC);
}
} else {
- // TODO(narayan): Implement field getters and setters.
- UNIMPLEMENTED(FATAL) << "Field references in method handles are not implemented yet.";
- return false;
+ DCHECK(!is_range);
+ ArtField* field = method_handle->GetTargetField();
+ Primitive::Type field_type = field->GetTypeAsPrimitiveType();;
+
+ if (!is_invoke_exact) {
+ // TODO(oth): conversion plumbing for invoke().
+ UNIMPLEMENTED(FATAL);
+ }
+
+ switch (handle_kind) {
+ case kInstanceGet: {
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(receiver_vregC);
+ DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
+ return true;
+ }
+ case kInstancePut: {
+ ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(receiver_vregC);
+ return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, arg[1]);
+ }
+ case kStaticGet: {
+ ObjPtr<mirror::Object> obj = field->GetDeclaringClass();
+ DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
+ return true;
+ }
+ case kStaticPut: {
+ ObjPtr<mirror::Object> obj = field->GetDeclaringClass();
+ return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, arg[0]);
+ }
+ default:
+ LOG(FATAL) << "Unreachable: " << handle_kind;
+ UNREACHABLE();
+ }
}
}
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 243ed57..435ac62 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -1571,7 +1571,6 @@
self, shadow_frame, inst, inst_data, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_4xx);
break;
- break;
}
case Instruction::NEG_INT:
PREAMBLE();
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index 40716ad..7bf9c5b 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -36,6 +36,11 @@
return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_));
}
+ ArtField* GetTargetField() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return reinterpret_cast<ArtField*>(
+ GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
+ }
+
ArtMethod* GetTargetMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
return reinterpret_cast<ArtMethod*>(
GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 329aae9..6206948 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -446,6 +446,12 @@
return soa.AddLocalReference<jobject>(annotations::GetAnnotationForField(field, klass));
}
+static jlong Field_getArtField(JNIEnv* env, jobject javaField) {
+ ScopedFastNativeObjectAccess soa(env);
+ ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
+ return reinterpret_cast<jlong>(field);
+}
+
static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
ScopedFastNativeObjectAccess soa(env);
ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
@@ -489,6 +495,7 @@
NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;)C"),
NATIVE_METHOD(Field, getAnnotationNative,
"!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
+ NATIVE_METHOD(Field, getArtField, "!()J"),
NATIVE_METHOD(Field, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"),
NATIVE_METHOD(Field, getSignatureAnnotation, "!()[Ljava/lang/String;"),
NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;)D"),
diff --git a/test/979-invoke-polymorphic-accessors/build b/test/979-invoke-polymorphic-accessors/build
new file mode 100644
index 0000000..a423ca6
--- /dev/null
+++ b/test/979-invoke-polymorphic-accessors/build
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+# make us exit on a failure
+set -e
+
+if [[ $@ != *"--jvm"* ]]; then
+ # Don't do anything with jvm.
+ export USE_JACK=true
+fi
+
+./default-build "$@" --experimental method-handles
diff --git a/test/979-invoke-polymorphic-accessors/expected.txt b/test/979-invoke-polymorphic-accessors/expected.txt
new file mode 100644
index 0000000..2987b6c
--- /dev/null
+++ b/test/979-invoke-polymorphic-accessors/expected.txt
@@ -0,0 +1 @@
+Passed InvokeExact tests for accessors.
diff --git a/test/979-invoke-polymorphic-accessors/info.txt b/test/979-invoke-polymorphic-accessors/info.txt
new file mode 100644
index 0000000..b2f55f0
--- /dev/null
+++ b/test/979-invoke-polymorphic-accessors/info.txt
@@ -0,0 +1 @@
+This test requires Jack with invoke-polymorphic support.
diff --git a/test/979-invoke-polymorphic-accessors/run b/test/979-invoke-polymorphic-accessors/run
new file mode 100644
index 0000000..a9f1822
--- /dev/null
+++ b/test/979-invoke-polymorphic-accessors/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+# make us exit on a failure
+set -e
+
+./default-run "$@" --experimental method-handles
diff --git a/test/979-invoke-polymorphic-accessors/src/Main.java b/test/979-invoke-polymorphic-accessors/src/Main.java
new file mode 100644
index 0000000..6cdcd10
--- /dev/null
+++ b/test/979-invoke-polymorphic-accessors/src/Main.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.WrongMethodTypeException;
+
+public class Main {
+
+ public static class ValueHolder {
+ public boolean m_z = false;
+ public byte m_b = 0;
+ public char m_c = 'a';
+ public short m_s = 0;
+ public int m_i = 0;
+ public float m_f = 0.0f;
+ public double m_d = 0.0;
+ public long m_j = 0;
+ public String m_l = "a";
+
+ public static boolean s_z;
+ public static byte s_b;
+ public static char s_c;
+ public static short s_s;
+ public static int s_i;
+ public static float s_f;
+ public static double s_d;
+ public static long s_j;
+ public static String s_l;
+
+ public final int m_fi = 0xa5a5a5a5;
+ public static final int s_fi = 0x5a5a5a5a;
+ }
+
+ public static class InvokeExactTester {
+ private enum PrimitiveType {
+ Boolean,
+ Byte,
+ Char,
+ Short,
+ Int,
+ Long,
+ Float,
+ Double,
+ String,
+ }
+
+ private enum AccessorType {
+ IPUT,
+ SPUT,
+ IGET,
+ SGET,
+ }
+
+ private static void assertActualAndExpectedMatch(boolean actual, boolean expected)
+ throws AssertionError {
+ if (actual != expected) {
+ throw new AssertionError("Actual != Expected (" + actual + " != " + expected + ")");
+ }
+ }
+
+ private static void assertTrue(boolean value) throws AssertionError {
+ if (!value) {
+ throw new AssertionError("Value is not true");
+ }
+ }
+
+ static void setByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
+ setByte(m, null, value, expectFailure);
+ }
+
+ static void getByte(MethodHandle m, ValueHolder v, byte value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final byte got;
+ if (v == null) {
+ got = (byte)m.invokeExact();
+ } else {
+ got = (byte)m.invokeExact(v);
+ }
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getByte(MethodHandle m, byte value, boolean expectFailure) throws Throwable {
+ getByte(m, null, value, expectFailure);
+ }
+
+ static void setChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
+ setChar(m, null, value, expectFailure);
+ }
+
+ static void getChar(MethodHandle m, ValueHolder v, char value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final char got;
+ if (v == null) {
+ got = (char)m.invokeExact();
+ } else {
+ got = (char)m.invokeExact(v);
+ }
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getChar(MethodHandle m, char value, boolean expectFailure) throws Throwable {
+ getChar(m, null, value, expectFailure);
+ }
+
+ static void setShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
+ setShort(m, null, value, expectFailure);
+ }
+
+ static void getShort(MethodHandle m, ValueHolder v, short value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final short got = (v == null) ? (short)m.invokeExact() : (short)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getShort(MethodHandle m, short value, boolean expectFailure) throws Throwable {
+ getShort(m, null, value, expectFailure);
+ }
+
+ static void setInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
+ setInt(m, null, value, expectFailure);
+ }
+
+ static void getInt(MethodHandle m, ValueHolder v, int value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final int got = (v == null) ? (int)m.invokeExact() : (int)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getInt(MethodHandle m, int value, boolean expectFailure) throws Throwable {
+ getInt(m, null, value, expectFailure);
+ }
+
+ static void setLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
+ setLong(m, null, value, expectFailure);
+ }
+
+ static void getLong(MethodHandle m, ValueHolder v, long value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final long got = (v == null) ? (long)m.invokeExact() : (long)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getLong(MethodHandle m, long value, boolean expectFailure) throws Throwable {
+ getLong(m, null, value, expectFailure);
+ }
+
+ static void setFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
+ setFloat(m, null, value, expectFailure);
+ }
+
+ static void getFloat(MethodHandle m, ValueHolder v, float value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final float got = (v == null) ? (float)m.invokeExact() : (float)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getFloat(MethodHandle m, float value, boolean expectFailure) throws Throwable {
+ getFloat(m, null, value, expectFailure);
+ }
+
+ static void setDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setDouble(MethodHandle m, double value, boolean expectFailure)
+ throws Throwable {
+ setDouble(m, null, value, expectFailure);
+ }
+
+ static void getDouble(MethodHandle m, ValueHolder v, double value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final double got = (v == null) ? (double)m.invokeExact() : (double)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getDouble(MethodHandle m, double value, boolean expectFailure)
+ throws Throwable {
+ getDouble(m, null, value, expectFailure);
+ }
+
+ static void setString(MethodHandle m, ValueHolder v, String value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setString(MethodHandle m, String value, boolean expectFailure)
+ throws Throwable {
+ setString(m, null, value, expectFailure);
+ }
+
+ static void getString(MethodHandle m, ValueHolder v, String value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final String got = (v == null) ? (String)m.invokeExact() : (String)m.invokeExact(v);
+ assertTrue(got.equals(value));
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getString(MethodHandle m, String value, boolean expectFailure)
+ throws Throwable {
+ getString(m, null, value, expectFailure);
+ }
+
+ static void setBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ if (v == null) {
+ m.invokeExact(value);
+ }
+ else {
+ m.invokeExact(v, value);
+ }
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void setBoolean(MethodHandle m, boolean value, boolean expectFailure)
+ throws Throwable {
+ setBoolean(m, null, value, expectFailure);
+ }
+
+ static void getBoolean(MethodHandle m, ValueHolder v, boolean value, boolean expectFailure)
+ throws Throwable {
+ boolean exceptionThrown = false;
+ try {
+ final boolean got =
+ (v == null) ? (boolean)m.invokeExact() : (boolean)m.invokeExact(v);
+ assertTrue(got == value);
+ }
+ catch (WrongMethodTypeException e) {
+ exceptionThrown = true;
+ }
+ assertActualAndExpectedMatch(exceptionThrown, expectFailure);
+ }
+
+ static void getBoolean(MethodHandle m, boolean value, boolean expectFailure)
+ throws Throwable {
+ getBoolean(m, null, value, expectFailure);
+ }
+
+ static boolean resultFor(PrimitiveType actualType, PrimitiveType expectedType,
+ AccessorType actualAccessor,
+ AccessorType expectedAccessor) {
+ return (actualType != expectedType) || (actualAccessor != expectedAccessor);
+ }
+
+ static void tryAccessor(MethodHandle methodHandle,
+ ValueHolder valueHolder,
+ PrimitiveType primitive,
+ Object value,
+ AccessorType accessor) throws Throwable {
+ boolean booleanValue =
+ value instanceof Boolean ? ((Boolean)value).booleanValue() : false;
+ setBoolean(methodHandle, valueHolder, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IPUT));
+ setBoolean(methodHandle, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SPUT));
+ getBoolean(methodHandle, valueHolder, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.IGET));
+ getBoolean(methodHandle, booleanValue,
+ resultFor(primitive, PrimitiveType.Boolean, accessor, AccessorType.SGET));
+
+ byte byteValue = value instanceof Byte ? ((Byte)value).byteValue() : (byte)0;
+ setByte(methodHandle, valueHolder, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IPUT));
+ setByte(methodHandle, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SPUT));
+ getByte(methodHandle, valueHolder, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.IGET));
+ getByte(methodHandle, byteValue,
+ resultFor(primitive, PrimitiveType.Byte, accessor, AccessorType.SGET));
+
+ char charValue = value instanceof Character ? ((Character)value).charValue() : 'z';
+ setChar(methodHandle, valueHolder, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IPUT));
+ setChar(methodHandle, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SPUT));
+ getChar(methodHandle, valueHolder, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.IGET));
+ getChar(methodHandle, charValue,
+ resultFor(primitive, PrimitiveType.Char, accessor, AccessorType.SGET));
+
+ short shortValue = value instanceof Short ? ((Short)value).shortValue() : (short)0;
+ setShort(methodHandle, valueHolder, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IPUT));
+ setShort(methodHandle, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SPUT));
+ getShort(methodHandle, valueHolder, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.IGET));
+ getShort(methodHandle, shortValue,
+ resultFor(primitive, PrimitiveType.Short, accessor, AccessorType.SGET));
+
+ int intValue = value instanceof Integer ? ((Integer)value).intValue() : -1;
+ setInt(methodHandle, valueHolder, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IPUT));
+ setInt(methodHandle, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SPUT));
+ getInt(methodHandle, valueHolder, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.IGET));
+ getInt(methodHandle, intValue,
+ resultFor(primitive, PrimitiveType.Int, accessor, AccessorType.SGET));
+
+ long longValue = value instanceof Long ? ((Long)value).longValue() : (long)-1;
+ setLong(methodHandle, valueHolder, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IPUT));
+ setLong(methodHandle, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SPUT));
+ getLong(methodHandle, valueHolder, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.IGET));
+ getLong(methodHandle, longValue,
+ resultFor(primitive, PrimitiveType.Long, accessor, AccessorType.SGET));
+
+ float floatValue = value instanceof Float ? ((Float)value).floatValue() : -1.0f;
+ setFloat(methodHandle, valueHolder, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IPUT));
+ setFloat(methodHandle, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SPUT));
+ getFloat(methodHandle, valueHolder, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.IGET));
+ getFloat(methodHandle, floatValue,
+ resultFor(primitive, PrimitiveType.Float, accessor, AccessorType.SGET));
+
+ double doubleValue = value instanceof Double ? ((Double)value).doubleValue() : -1.0;
+ setDouble(methodHandle, valueHolder, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IPUT));
+ setDouble(methodHandle, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SPUT));
+ getDouble(methodHandle, valueHolder, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.IGET));
+ getDouble(methodHandle, doubleValue,
+ resultFor(primitive, PrimitiveType.Double, accessor, AccessorType.SGET));
+
+ String stringValue = value instanceof String ? ((String) value) : "No Spock, no";
+ setString(methodHandle, valueHolder, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IPUT));
+ setString(methodHandle, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SPUT));
+ getString(methodHandle, valueHolder, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.IGET));
+ getString(methodHandle, stringValue,
+ resultFor(primitive, PrimitiveType.String, accessor, AccessorType.SGET));
+ }
+
+ public static void main() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ boolean [] booleans = { false, true, false };
+ for (boolean b : booleans) {
+ Boolean boxed = new Boolean(b);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_z == b);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_z", boolean.class),
+ valueHolder, PrimitiveType.Boolean, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_z == b);
+ }
+
+ byte [] bytes = { (byte)0x73, (byte)0xfe };
+ for (byte b : bytes) {
+ Byte boxed = new Byte(b);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_b == b);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_b", byte.class),
+ valueHolder, PrimitiveType.Byte, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_b == b);
+ }
+
+ char [] chars = { 'a', 'b', 'c' };
+ for (char c : chars) {
+ Character boxed = new Character(c);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_c == c);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_c", char.class),
+ valueHolder, PrimitiveType.Char, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_c == c);
+ }
+
+ short [] shorts = { (short)0x1234, (short)0x4321 };
+ for (short s : shorts) {
+ Short boxed = new Short(s);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_s == s);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_s", short.class),
+ valueHolder, PrimitiveType.Short, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_s == s);
+ }
+
+ int [] ints = { -100000000, 10000000 };
+ for (int i : ints) {
+ Integer boxed = new Integer(i);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_i == i);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_i", int.class),
+ valueHolder, PrimitiveType.Int, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_i == i);
+ }
+
+ float [] floats = { 0.99f, -1.23e-17f };
+ for (float f : floats) {
+ Float boxed = new Float(f);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_f == f);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_f", float.class),
+ valueHolder, PrimitiveType.Float, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_f == f);
+ }
+
+ double [] doubles = { 0.44444444444e37, -0.555555555e-37 };
+ for (double d : doubles) {
+ Double boxed = new Double(d);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_d == d);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_d", double.class),
+ valueHolder, PrimitiveType.Double, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_d == d);
+ }
+
+ long [] longs = { 0x0123456789abcdefl, 0xfedcba9876543210l };
+ for (long j : longs) {
+ Long boxed = new Long(j);
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.IGET);
+ assertTrue(valueHolder.m_j == j);
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_j", long.class),
+ valueHolder, PrimitiveType.Long, boxed, AccessorType.SGET);
+ assertTrue(ValueHolder.s_j == j);
+ }
+
+ String [] strings = { "octopus", "crab" };
+ for (String s : strings) {
+ tryAccessor(lookup.findSetter(ValueHolder.class, "m_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.IPUT);
+ tryAccessor(lookup.findGetter(ValueHolder.class, "m_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.IGET);
+ assertTrue(s.equals(valueHolder.m_l));
+ tryAccessor(lookup.findStaticSetter(ValueHolder.class, "s_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.SPUT);
+ tryAccessor(lookup.findStaticGetter(ValueHolder.class, "s_l", String.class),
+ valueHolder, PrimitiveType.String, s, AccessorType.SGET);
+ assertTrue(s.equals(ValueHolder.s_l));
+ }
+
+ System.out.println("Passed InvokeExact tests for accessors.");
+ }
+ }
+
+ public static class FindAccessorTester {
+ public static void main() throws Throwable {
+ ValueHolder valueHolder = new ValueHolder();
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ lookup.findStaticGetter(ValueHolder.class, "s_fi", int.class);
+ try {
+ lookup.findStaticGetter(ValueHolder.class, "s_fi", byte.class);
+ unreachable();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findGetter(ValueHolder.class, "s_fi", byte.class);
+ unreachable();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findStaticSetter(ValueHolder.class, "s_fi", int.class);
+ unreachable();
+ } catch (IllegalAccessException e) {}
+
+ lookup.findGetter(ValueHolder.class, "m_fi", int.class);
+ try {
+ lookup.findGetter(ValueHolder.class, "m_fi", byte.class);
+ unreachable();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findStaticGetter(ValueHolder.class, "m_fi", byte.class);
+ unreachable();
+ } catch (NoSuchFieldException e) {}
+ try {
+ lookup.findSetter(ValueHolder.class, "m_fi", int.class);
+ unreachable();
+ } catch (IllegalAccessException e) {}
+ }
+
+ public static void unreachable() throws Throwable{
+ throw new Error("unreachable");
+ }
+ }
+
+ public static void main(String[] args) throws Throwable {
+ FindAccessorTester.main();
+ InvokeExactTester.main();
+ }
+}