summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/intrinsics_mips.cc194
-rw-r--r--runtime/openjdkjvmti/ti_method.cc15
-rw-r--r--test/904-object-allocation/expected.txt10
-rw-r--r--test/904-object-allocation/src/art/Test904.java10
-rw-r--r--test/904-object-allocation/tracking.cc27
-rw-r--r--test/910-methods/expected.txt14
-rw-r--r--test/910-methods/src/art/Test910.java69
7 files changed, 306 insertions, 33 deletions
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 429797976c..41df56b514 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2940,6 +2940,199 @@ void IntrinsicCodeGeneratorMIPS::VisitMathTanh(HInvoke* invoke) {
GenFPToFPCall(invoke, codegen_, kQuickTanh);
}
+// static void java.lang.System.arraycopy(Object src, int srcPos,
+// Object dest, int destPos,
+// int length)
+void IntrinsicLocationsBuilderMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
+ HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
+ HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
+ HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
+
+ // As long as we are checking, we might as well check to see if the src and dest
+ // positions are >= 0.
+ if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
+ (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
+ // We will have to fail anyways.
+ return;
+ }
+
+ // And since we are already checking, check the length too.
+ if (length != nullptr) {
+ int32_t len = length->GetValue();
+ if (len < 0) {
+ // Just call as normal.
+ return;
+ }
+ }
+
+ // Okay, it is safe to generate inline code.
+ LocationSummary* locations =
+ new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
+ // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
+ locations->SetInAt(2, Location::RequiresRegister());
+ locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
+ locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
+
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+}
+
+// Utility routine to verify that "length(input) - pos >= length"
+static void EnoughItems(MipsAssembler* assembler,
+ Register length_input_minus_pos,
+ Location length,
+ SlowPathCodeMIPS* slow_path) {
+ if (length.IsConstant()) {
+ int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
+
+ if (IsInt<16>(length_constant)) {
+ __ Slti(TMP, length_input_minus_pos, length_constant);
+ __ Bnez(TMP, slow_path->GetEntryLabel());
+ } else {
+ __ LoadConst32(TMP, length_constant);
+ __ Blt(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
+ }
+ } else {
+ __ Blt(length_input_minus_pos, length.AsRegister<Register>(), slow_path->GetEntryLabel());
+ }
+}
+
+static void CheckPosition(MipsAssembler* assembler,
+ Location pos,
+ Register input,
+ Location length,
+ SlowPathCodeMIPS* slow_path,
+ bool length_is_input_length = false) {
+ // Where is the length in the Array?
+ const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+
+ // Calculate length(input) - pos.
+ if (pos.IsConstant()) {
+ int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
+ if (pos_const == 0) {
+ if (!length_is_input_length) {
+ // Check that length(input) >= length.
+ __ LoadFromOffset(kLoadWord, AT, input, length_offset);
+ EnoughItems(assembler, AT, length, slow_path);
+ }
+ } else {
+ // Check that (length(input) - pos) >= zero.
+ __ LoadFromOffset(kLoadWord, AT, input, length_offset);
+ DCHECK_GT(pos_const, 0);
+ __ Addiu32(AT, AT, -pos_const, TMP);
+ __ Bltz(AT, slow_path->GetEntryLabel());
+
+ // Verify that (length(input) - pos) >= length.
+ EnoughItems(assembler, AT, length, slow_path);
+ }
+ } else if (length_is_input_length) {
+ // The only way the copy can succeed is if pos is zero.
+ Register pos_reg = pos.AsRegister<Register>();
+ __ Bnez(pos_reg, slow_path->GetEntryLabel());
+ } else {
+ // Verify that pos >= 0.
+ Register pos_reg = pos.AsRegister<Register>();
+ __ Bltz(pos_reg, slow_path->GetEntryLabel());
+
+ // Check that (length(input) - pos) >= zero.
+ __ LoadFromOffset(kLoadWord, AT, input, length_offset);
+ __ Subu(AT, AT, pos_reg);
+ __ Bltz(AT, slow_path->GetEntryLabel());
+
+ // Verify that (length(input) - pos) >= length.
+ EnoughItems(assembler, AT, length, slow_path);
+ }
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
+ MipsAssembler* assembler = GetAssembler();
+ LocationSummary* locations = invoke->GetLocations();
+
+ Register src = locations->InAt(0).AsRegister<Register>();
+ Location src_pos = locations->InAt(1);
+ Register dest = locations->InAt(2).AsRegister<Register>();
+ Location dest_pos = locations->InAt(3);
+ Location length = locations->InAt(4);
+
+ MipsLabel loop;
+
+ Register dest_base = locations->GetTemp(0).AsRegister<Register>();
+ Register src_base = locations->GetTemp(1).AsRegister<Register>();
+ Register count = locations->GetTemp(2).AsRegister<Register>();
+
+ SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
+ codegen_->AddSlowPath(slow_path);
+
+ // Bail out if the source and destination are the same (to handle overlap).
+ __ Beq(src, dest, slow_path->GetEntryLabel());
+
+ // Bail out if the source is null.
+ __ Beqz(src, slow_path->GetEntryLabel());
+
+ // Bail out if the destination is null.
+ __ Beqz(dest, slow_path->GetEntryLabel());
+
+ // Load length into register for count.
+ if (length.IsConstant()) {
+ __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
+ } else {
+ // If the length is negative, bail out.
+ // We have already checked in the LocationsBuilder for the constant case.
+ __ Bltz(length.AsRegister<Register>(), slow_path->GetEntryLabel());
+
+ __ Move(count, length.AsRegister<Register>());
+ }
+
+ // Validity checks: source.
+ CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
+
+ // Validity checks: dest.
+ CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
+
+ // If count is zero, we're done.
+ __ Beqz(count, slow_path->GetExitLabel());
+
+ // Okay, everything checks out. Finally time to do the copy.
+ // Check assumption that sizeof(Char) is 2 (used in scaling below).
+ const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+ DCHECK_EQ(char_size, 2u);
+
+ const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
+
+ const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
+
+ // Calculate source and destination addresses.
+ if (src_pos.IsConstant()) {
+ int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
+
+ __ Addiu32(src_base, src, data_offset + char_size * src_pos_const, TMP);
+ } else {
+ __ Addiu32(src_base, src, data_offset, TMP);
+ __ ShiftAndAdd(src_base, src_pos.AsRegister<Register>(), src_base, char_shift);
+ }
+ if (dest_pos.IsConstant()) {
+ int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
+
+ __ Addiu32(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
+ } else {
+ __ Addiu32(dest_base, dest, data_offset, TMP);
+ __ ShiftAndAdd(dest_base, dest_pos.AsRegister<Register>(), dest_base, char_shift);
+ }
+
+ __ Bind(&loop);
+ __ Lh(TMP, src_base, 0);
+ __ Addiu(src_base, src_base, char_size);
+ __ Addiu(count, count, -1);
+ __ Sh(TMP, dest_base, 0);
+ __ Addiu(dest_base, dest_base, char_size);
+ __ Bnez(count, &loop);
+
+ __ Bind(slow_path->GetExitLabel());
+}
+
// Unimplemented intrinsics.
UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
@@ -2951,7 +3144,6 @@ UNIMPLEMENTED_INTRINSIC(MIPS, UnsafePutLongVolatile);
UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
-UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index bc73029f41..01bf21d53e 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -61,8 +61,13 @@ jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
art::ScopedObjectAccess soa(art::Thread::Current());
if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
- // This isn't specified as an error case, so return 0.
- *size_ptr = 0;
+ // Use the shorty.
+ art::ArtMethod* base_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
+ size_t arg_count = art::ArtMethod::NumArgRegisters(base_method->GetShorty());
+ if (!base_method->IsStatic()) {
+ arg_count++;
+ }
+ *size_ptr = static_cast<jint>(arg_count);
return ERR(NONE);
}
@@ -203,9 +208,9 @@ jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED,
art::ScopedObjectAccess soa(art::Thread::Current());
if (art_method->IsProxyMethod() || art_method->IsAbstract()) {
- // This isn't specified as an error case, so return 0/0.
- *start_location_ptr = 0;
- *end_location_ptr = 0;
+ // This isn't specified as an error case, so return -1/-1 as the RI does.
+ *start_location_ptr = -1;
+ *end_location_ptr = -1;
return ERR(NONE);
}
diff --git a/test/904-object-allocation/expected.txt b/test/904-object-allocation/expected.txt
index 371d2b7593..fdec470529 100644
--- a/test/904-object-allocation/expected.txt
+++ b/test/904-object-allocation/expected.txt
@@ -1,8 +1,8 @@
-ObjectAllocated type java.lang.Object/java.lang.Object size 8
-ObjectAllocated type java.lang.Integer/java.lang.Integer size 16
-ObjectAllocated type java.lang.Short/java.lang.Short size 16
+[]
+[ObjectAllocated type java.lang.Object/java.lang.Object size 8, ObjectAllocated type java.lang.Integer/java.lang.Integer size 16, ObjectAllocated type java.lang.Short/java.lang.Short size 16]
Tracking on same thread
-ObjectAllocated type java.lang.Double/java.lang.Double size 16
+[ObjectAllocated type java.lang.Double/java.lang.Double size 16]
Tracking on same thread, not disabling tracking
-ObjectAllocated type java.lang.Double/java.lang.Double size 16
+[ObjectAllocated type java.lang.Double/java.lang.Double size 16]
Tracking on different thread
+[]
diff --git a/test/904-object-allocation/src/art/Test904.java b/test/904-object-allocation/src/art/Test904.java
index 31e0c8c1ae..70a4b9847f 100644
--- a/test/904-object-allocation/src/art/Test904.java
+++ b/test/904-object-allocation/src/art/Test904.java
@@ -17,6 +17,7 @@
package art;
import java.util.ArrayList;
+import java.util.Arrays;
public class Test904 {
public static void run() throws Exception {
@@ -48,6 +49,8 @@ public class Test904 {
// Enable actual logging callback.
setupObjectAllocCallback(true);
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
+
enableAllocationTracking(null, true);
l.add(new Object());
@@ -65,16 +68,19 @@ public class Test904 {
l.add(new Byte((byte)0));
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
System.out.println("Tracking on same thread");
testThread(l, true, true);
l.add(new Byte((byte)0));
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
System.out.println("Tracking on same thread, not disabling tracking");
testThread(l, true, false);
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
System.out.println("Tracking on different thread");
testThread(l, false, true);
@@ -84,6 +90,9 @@ public class Test904 {
// Disable actual logging callback and re-enable tracking, so we can keep the event enabled and
// check that shutdown works correctly.
setupObjectAllocCallback(false);
+
+ System.out.println(Arrays.toString(getTrackingEventMessages()));
+
enableAllocationTracking(null, true);
}
@@ -142,4 +151,5 @@ public class Test904 {
private static native void setupObjectAllocCallback(boolean enable);
private static native void enableAllocationTracking(Thread thread, boolean enable);
+ private static native String[] getTrackingEventMessages();
}
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index 8de350b06c..20b53281a2 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -15,11 +15,13 @@
*/
#include <iostream>
+#include <mutex>
#include <pthread.h>
#include <stdio.h>
#include <vector>
#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
#include "jni.h"
#include "jvmti.h"
#include "scoped_local_ref.h"
@@ -41,6 +43,9 @@ static std::string GetClassName(JNIEnv* jni_env, jclass cls) {
return utf_chars.c_str();
}
+static std::mutex gEventsMutex;
+static std::vector<std::string> gEvents;
+
static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED,
JNIEnv* jni_env,
jthread thread ATTRIBUTE_UNUSED,
@@ -51,10 +56,11 @@ static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED,
ScopedLocalRef<jclass> object_klass2(jni_env, jni_env->GetObjectClass(object));
std::string object_klass_descriptor2 = GetClassName(jni_env, object_klass2.get());
- printf("ObjectAllocated type %s/%s size %zu\n",
- object_klass_descriptor.c_str(),
- object_klass_descriptor2.c_str(),
- static_cast<size_t>(size));
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ gEvents.push_back(android::base::StringPrintf("ObjectAllocated type %s/%s size %zu",
+ object_klass_descriptor.c_str(),
+ object_klass_descriptor2.c_str(),
+ static_cast<size_t>(size)));
}
extern "C" JNIEXPORT void JNICALL Java_art_Test904_setupObjectAllocCallback(
@@ -76,5 +82,18 @@ extern "C" JNIEXPORT void JNICALL Java_art_Test904_enableAllocationTracking(
JvmtiErrorToException(env, jvmti_env, ret);
}
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test904_getTrackingEventMessages(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ jobjectArray ret = CreateObjectArray(env,
+ static_cast<jint>(gEvents.size()),
+ "java/lang/String",
+ [&](jint i) {
+ return env->NewStringUTF(gEvents[i].c_str());
+ });
+ gEvents.clear();
+ return ret;
+}
+
} // namespace Test904ObjectAllocation
} // namespace art
diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt
index 8e6b6e76d9..c14c6c49e1 100644
--- a/test/910-methods/expected.txt
+++ b/test/910-methods/expected.txt
@@ -32,19 +32,19 @@ Is synthetic: false
interface java.util.List
1025
Max locals: 0
-Argument size: 0
-Location start: 0
-Location end: 0
+Argument size: 2
+Location start: -1
+Location end: -1
Is native: false
Is obsolete: false
Is synthetic: false
[run, ()V, null]
-class $Proxy0
+class $Proxy20
17
Max locals: 0
-Argument size: 0
-Location start: 0
-Location end: 0
+Argument size: 1
+Location start: -1
+Location end: -1
Is native: false
Is obsolete: false
Is synthetic: false
diff --git a/test/910-methods/src/art/Test910.java b/test/910-methods/src/art/Test910.java
index b3490e9518..aa6d13af9a 100644
--- a/test/910-methods/src/art/Test910.java
+++ b/test/910-methods/src/art/Test910.java
@@ -39,17 +39,6 @@ public class Test910 {
testMethod(findSyntheticMethod(), NestedSynthetic.class, false);
}
- private static Class<?> proxyClass = null;
-
- private static Class<?> getProxyClass() throws Exception {
- if (proxyClass != null) {
- return proxyClass;
- }
-
- proxyClass = Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Runnable.class });
- return proxyClass;
- }
-
private static void testMethod(String className, String methodName, Class<?>... types)
throws Exception {
Class<?> base = Class.forName(className);
@@ -145,4 +134,62 @@ public class Test910 {
private static native boolean isMethodNative(Method m);
private static native boolean isMethodObsolete(Method m);
private static native boolean isMethodSynthetic(Method m);
+
+ // We need this machinery for a consistent proxy name. Names of proxy classes include a
+ // unique number (derived by counting). This means that a simple call to getProxyClass
+ // depends on the test environment.
+ //
+ // To work around this, we assume that at most twenty proxies have been created before
+ // the test is run, and canonicalize on "$Proxy20". We add infrastructure to create
+ // as many proxy classes but cycling through subsets of the test-provided interfaces
+ // I0...I4.
+ //
+ //
+ // (This is made under the judgment that we do not want to have proxy-specific behavior
+ // for testMethod.)
+
+ private static Class<?> proxyClass = null;
+
+ private static Class<?> getProxyClass() throws Exception {
+ if (proxyClass != null) {
+ return proxyClass;
+ }
+
+ for (int i = 1; i <= 21; i++) {
+ proxyClass = createProxyClass(i);
+ String name = proxyClass.getName();
+ if (name.equals("$Proxy20")) {
+ return proxyClass;
+ }
+ }
+ return proxyClass;
+ }
+
+ private static Class<?> createProxyClass(int i) throws Exception {
+ int count = Integer.bitCount(i);
+ Class<?>[] input = new Class<?>[count + 1];
+ input[0] = Runnable.class;
+ int inputIndex = 1;
+ int bitIndex = 0;
+ while (i != 0) {
+ if ((i & 1) != 0) {
+ input[inputIndex++] = Class.forName("art.Test910$I" + bitIndex);
+ }
+ i >>>= 1;
+ bitIndex++;
+ }
+ return Proxy.getProxyClass(Test910.class.getClassLoader(), input);
+ }
+
+ // Need this for the proxy naming.
+ public static interface I0 {
+ }
+ public static interface I1 {
+ }
+ public static interface I2 {
+ }
+ public static interface I3 {
+ }
+ public static interface I4 {
+ }
}