summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--dex2oat/dex2oat.cc2
-rw-r--r--runtime/common_runtime_test.cc2
-rw-r--r--runtime/interpreter/interpreter.cc4
-rw-r--r--runtime/interpreter/interpreter_common.cc2
-rw-r--r--runtime/interpreter/unstarted_runtime.cc312
-rw-r--r--runtime/interpreter/unstarted_runtime.h69
-rw-r--r--runtime/interpreter/unstarted_runtime_list.h79
-rw-r--r--runtime/interpreter/unstarted_runtime_test.cc251
9 files changed, 506 insertions, 216 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 3c2408c..bfc8956 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -163,6 +163,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \
runtime/instrumentation_test.cc \
runtime/intern_table_test.cc \
runtime/interpreter/safe_math_test.cc \
+ runtime/interpreter/unstarted_runtime_test.cc \
runtime/java_vm_ext_test.cc \
runtime/jit/jit_code_cache_test.cc \
runtime/leb128_test.cc \
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3cf458a..43bec37 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1594,7 +1594,7 @@ class Dex2Oat FINAL {
// Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this
// set up.
- interpreter::UnstartedRuntimeInitialize();
+ interpreter::UnstartedRuntime::Initialize();
runtime->GetClassLinker()->RunRootClinits();
runtime_ = runtime;
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 7a711cc..de3a29b 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -327,7 +327,7 @@ void CommonRuntimeTest::SetUp() {
// Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this
// set up.
if (!unstarted_initialized_) {
- interpreter::UnstartedRuntimeInitialize();
+ interpreter::UnstartedRuntime::Initialize();
unstarted_initialized_ = true;
}
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index a37aee5..26860e7 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -386,7 +386,7 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive
// references pointers due to moving GC.
args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1);
if (!Runtime::Current()->IsStarted()) {
- UnstartedRuntimeJni(self, method, receiver, args, result);
+ UnstartedRuntime::Jni(self, method, receiver, args, result);
} else {
InterpreterJni(self, method, shorty, receiver, args, result);
}
@@ -474,7 +474,7 @@ extern "C" void artInterpreterToInterpreterBridge(Thread* self, const DexFile::C
CHECK(!Runtime::Current()->IsStarted());
Object* receiver = is_static ? nullptr : shadow_frame->GetVRegReference(0);
uint32_t* args = shadow_frame->GetVRegArgs(is_static ? 0 : 1);
- UnstartedRuntimeJni(self, shadow_frame->GetMethod(), receiver, args, result);
+ UnstartedRuntime::Jni(self, shadow_frame->GetMethod(), receiver, args, result);
}
self->PopShadowFrame();
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 59d3008..363c65a 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -659,7 +659,7 @@ bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
}
entry(self, code_item, new_shadow_frame, result);
} else {
- UnstartedRuntimeInvoke(self, code_item, new_shadow_frame, result, first_dest_reg);
+ UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result, first_dest_reg);
}
if (string_init && !self->IsExceptionPending()) {
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 317106b..738e52b 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -120,7 +120,7 @@ static mirror::String* GetClassName(Thread* self, ShadowFrame* shadow_frame, siz
return param->AsString();
}
-static void UnstartedClassForName(
+void UnstartedRuntime::UnstartedClassForName(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
@@ -134,7 +134,7 @@ static void UnstartedClassForName(
CheckExceptionGenerateClassNotFound(self);
}
-static void UnstartedClassForNameLong(
+void UnstartedRuntime::UnstartedClassForNameLong(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
@@ -152,7 +152,7 @@ static void UnstartedClassForNameLong(
CheckExceptionGenerateClassNotFound(self);
}
-static void UnstartedClassClassForName(
+void UnstartedRuntime::UnstartedClassClassForName(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
@@ -170,7 +170,7 @@ static void UnstartedClassClassForName(
CheckExceptionGenerateClassNotFound(self);
}
-static void UnstartedClassNewInstance(
+void UnstartedRuntime::UnstartedClassNewInstance(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
StackHandleScope<3> hs(self); // Class, constructor, object.
@@ -226,7 +226,7 @@ static void UnstartedClassNewInstance(
}
}
-static void UnstartedClassGetDeclaredField(
+void UnstartedRuntime::UnstartedClassGetDeclaredField(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
@@ -265,7 +265,7 @@ static void UnstartedClassGetDeclaredField(
}
}
-static void UnstartedVmClassLoaderFindLoadedClass(
+void UnstartedRuntime::UnstartedVmClassLoaderFindLoadedClass(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* class_name = shadow_frame->GetVRegReference(arg_offset + 1)->AsString();
@@ -286,7 +286,7 @@ static void UnstartedVmClassLoaderFindLoadedClass(
}
}
-static void UnstartedVoidLookupType(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedVoidLookupType(Thread* self ATTRIBUTE_UNUSED,
ShadowFrame* shadow_frame ATTRIBUTE_UNUSED,
JValue* result,
size_t arg_offset ATTRIBUTE_UNUSED)
@@ -323,7 +323,7 @@ static void PrimitiveArrayCopy(Thread* self,
}
}
-static void UnstartedSystemArraycopy(
+void UnstartedRuntime::UnstartedSystemArraycopy(
Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Special case array copying without initializing System.
@@ -409,7 +409,21 @@ static void UnstartedSystemArraycopy(
}
}
-static void UnstartedThreadLocalGet(
+void UnstartedRuntime::UnstartedSystemArraycopyChar(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Just forward.
+ UnstartedRuntime::UnstartedSystemArraycopy(self, shadow_frame, result, arg_offset);
+}
+
+void UnstartedRuntime::UnstartedSystemArraycopyInt(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Just forward.
+ UnstartedRuntime::UnstartedSystemArraycopy(self, shadow_frame, result, arg_offset);
+}
+
+void UnstartedRuntime::UnstartedThreadLocalGet(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset ATTRIBUTE_UNUSED)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string caller(PrettyMethod(shadow_frame->GetLink()->GetMethod()));
@@ -459,7 +473,7 @@ static void UnstartedThreadLocalGet(
}
}
-static void UnstartedMathCeil(
+void UnstartedRuntime::UnstartedMathCeil(
Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
double in = shadow_frame->GetVRegDouble(arg_offset);
double out;
@@ -474,21 +488,21 @@ static void UnstartedMathCeil(
result->SetD(out);
}
-static void UnstartedArtMethodGetMethodName(
+void UnstartedRuntime::UnstartedArtMethodGetMethodName(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtMethod* method = shadow_frame->GetVRegReference(arg_offset)->AsArtMethod();
result->SetL(method->GetNameAsString(self));
}
-static void UnstartedObjectHashCode(
+void UnstartedRuntime::UnstartedObjectHashCode(
Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset);
result->SetI(obj->IdentityHashCode());
}
-static void UnstartedDoubleDoubleToRawLongBits(
+void UnstartedRuntime::UnstartedDoubleDoubleToRawLongBits(
Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
double in = shadow_frame->GetVRegDouble(arg_offset);
result->SetJ(bit_cast<int64_t, double>(in));
@@ -522,7 +536,7 @@ static mirror::Object* GetDexFromDexCache(Thread* self, mirror::DexCache* dex_ca
return self->DecodeJObject(dex.get());
}
-static void UnstartedDexCacheGetDexNative(
+void UnstartedRuntime::UnstartedDexCacheGetDexNative(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// We will create the Dex object, but the image writer will release it before creating the
@@ -555,17 +569,20 @@ static void UnstartedMemoryPeek(
}
case Primitive::kPrimShort: {
- result->SetS(*reinterpret_cast<int16_t*>(static_cast<intptr_t>(address)));
+ typedef int16_t unaligned_short __attribute__ ((aligned (1)));
+ result->SetS(*reinterpret_cast<unaligned_short*>(static_cast<intptr_t>(address)));
return;
}
case Primitive::kPrimInt: {
- result->SetI(*reinterpret_cast<int32_t*>(static_cast<intptr_t>(address)));
+ typedef int32_t unaligned_int __attribute__ ((aligned (1)));
+ result->SetI(*reinterpret_cast<unaligned_int*>(static_cast<intptr_t>(address)));
return;
}
case Primitive::kPrimLong: {
- result->SetJ(*reinterpret_cast<int64_t*>(static_cast<intptr_t>(address)));
+ typedef int64_t unaligned_long __attribute__ ((aligned (1)));
+ result->SetJ(*reinterpret_cast<unaligned_long*>(static_cast<intptr_t>(address)));
return;
}
@@ -582,22 +599,28 @@ static void UnstartedMemoryPeek(
UNREACHABLE();
}
-static void UnstartedMemoryPeekEntry(
+void UnstartedRuntime::UnstartedMemoryPeekByte(
Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- std::string name(PrettyMethod(shadow_frame->GetMethod()));
- if (name == "byte libcore.io.Memory.peekByte(long)") {
- UnstartedMemoryPeek(Primitive::kPrimByte, shadow_frame, result, arg_offset);
- } else if (name == "short libcore.io.Memory.peekShortNative(long)") {
- UnstartedMemoryPeek(Primitive::kPrimShort, shadow_frame, result, arg_offset);
- } else if (name == "int libcore.io.Memory.peekIntNative(long)") {
- UnstartedMemoryPeek(Primitive::kPrimInt, shadow_frame, result, arg_offset);
- } else if (name == "long libcore.io.Memory.peekLongNative(long)") {
- UnstartedMemoryPeek(Primitive::kPrimLong, shadow_frame, result, arg_offset);
- } else {
- LOG(FATAL) << "Unsupported Memory.peek entry: " << name;
- UNREACHABLE();
- }
+ UnstartedMemoryPeek(Primitive::kPrimByte, shadow_frame, result, arg_offset);
+}
+
+void UnstartedRuntime::UnstartedMemoryPeekShort(
+ Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ UnstartedMemoryPeek(Primitive::kPrimShort, shadow_frame, result, arg_offset);
+}
+
+void UnstartedRuntime::UnstartedMemoryPeekInt(
+ Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ UnstartedMemoryPeek(Primitive::kPrimInt, shadow_frame, result, arg_offset);
+}
+
+void UnstartedRuntime::UnstartedMemoryPeekLong(
+ Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ UnstartedMemoryPeek(Primitive::kPrimLong, shadow_frame, result, arg_offset);
}
static void UnstartedMemoryPeekArray(
@@ -649,20 +672,14 @@ static void UnstartedMemoryPeekArray(
UNREACHABLE();
}
-static void UnstartedMemoryPeekArrayEntry(
+void UnstartedRuntime::UnstartedMemoryPeekByteArray(
Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- std::string name(PrettyMethod(shadow_frame->GetMethod()));
- if (name == "void libcore.io.Memory.peekByteArray(long, byte[], int, int)") {
- UnstartedMemoryPeekArray(Primitive::kPrimByte, self, shadow_frame, arg_offset);
- } else {
- LOG(FATAL) << "Unsupported Memory.peekArray entry: " << name;
- UNREACHABLE();
- }
+ UnstartedMemoryPeekArray(Primitive::kPrimByte, self, shadow_frame, arg_offset);
}
// This allows reading security.properties in an unstarted runtime and initialize Security.
-static void UnstartedSecurityGetSecurityPropertiesReader(
+void UnstartedRuntime::UnstartedSecurityGetSecurityPropertiesReader(
Thread* self,
ShadowFrame* shadow_frame ATTRIBUTE_UNUSED,
JValue* result,
@@ -756,7 +773,7 @@ static void UnstartedSecurityGetSecurityPropertiesReader(
}
// This allows reading the new style of String objects during compilation.
-static void UnstartedStringGetCharsNoCheck(
+void UnstartedRuntime::UnstartedStringGetCharsNoCheck(
Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jint start = shadow_frame->GetVReg(arg_offset + 1);
@@ -777,7 +794,7 @@ static void UnstartedStringGetCharsNoCheck(
}
// This allows reading chars from the new style of String objects during compilation.
-static void UnstartedStringCharAt(
+void UnstartedRuntime::UnstartedStringCharAt(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jint index = shadow_frame->GetVReg(arg_offset + 1);
@@ -790,7 +807,7 @@ static void UnstartedStringCharAt(
}
// This allows setting chars from the new style of String objects during compilation.
-static void UnstartedStringSetCharAt(
+void UnstartedRuntime::UnstartedStringSetCharAt(
Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jint index = shadow_frame->GetVReg(arg_offset + 1);
@@ -804,7 +821,7 @@ static void UnstartedStringSetCharAt(
}
// This allows creating the new style of String objects during compilation.
-static void UnstartedStringFactoryNewStringFromChars(
+void UnstartedRuntime::UnstartedStringFactoryNewStringFromChars(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jint offset = shadow_frame->GetVReg(arg_offset);
@@ -818,7 +835,7 @@ static void UnstartedStringFactoryNewStringFromChars(
}
// This allows creating the new style of String objects during compilation.
-static void UnstartedStringFactoryNewStringFromString(
+void UnstartedRuntime::UnstartedStringFactoryNewStringFromString(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* to_copy = shadow_frame->GetVRegReference(arg_offset)->AsString();
@@ -834,8 +851,7 @@ static void UnstartedStringFactoryNewStringFromString(
allocator));
}
-// This allows creating the new style of String objects during compilation.
-static void UnstartedStringFastSubstring(
+void UnstartedRuntime::UnstartedStringFastSubstring(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jint start = shadow_frame->GetVReg(arg_offset + 1);
@@ -852,7 +868,7 @@ static void UnstartedStringFastSubstring(
}
// This allows getting the char array for new style of String objects during compilation.
-static void UnstartedStringToCharArray(
+void UnstartedRuntime::UnstartedStringToCharArray(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString();
@@ -863,7 +879,7 @@ static void UnstartedStringToCharArray(
result->SetL(string->ToCharArray(self));
}
-static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self,
+void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -880,7 +896,7 @@ static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self,
array_class->GetComponentSizeShift(), allocator));
}
-static void UnstartedJNIVMStackGetCallingClassLoader(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIVMStackGetCallingClassLoader(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -888,7 +904,7 @@ static void UnstartedJNIVMStackGetCallingClassLoader(Thread* self ATTRIBUTE_UNUS
result->SetL(nullptr);
}
-static void UnstartedJNIVMStackGetStackClass2(Thread* self,
+void UnstartedRuntime::UnstartedJNIVMStackGetStackClass2(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -901,7 +917,7 @@ static void UnstartedJNIVMStackGetStackClass2(Thread* self,
}
}
-static void UnstartedJNIMathLog(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIMathLog(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -911,7 +927,7 @@ static void UnstartedJNIMathLog(Thread* self ATTRIBUTE_UNUSED,
result->SetD(log(value.GetD()));
}
-static void UnstartedJNIMathExp(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIMathExp(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -921,7 +937,7 @@ static void UnstartedJNIMathExp(Thread* self ATTRIBUTE_UNUSED,
result->SetD(exp(value.GetD()));
}
-static void UnstartedJNIClassGetNameNative(Thread* self,
+void UnstartedRuntime::UnstartedJNIClassGetNameNative(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -931,7 +947,7 @@ static void UnstartedJNIClassGetNameNative(Thread* self,
result->SetL(mirror::Class::ComputeName(hs.NewHandle(receiver->AsClass())));
}
-static void UnstartedJNIFloatFloatToRawIntBits(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIFloatFloatToRawIntBits(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -939,7 +955,7 @@ static void UnstartedJNIFloatFloatToRawIntBits(Thread* self ATTRIBUTE_UNUSED,
result->SetI(args[0]);
}
-static void UnstartedJNIFloatIntBitsToFloat(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIFloatIntBitsToFloat(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -947,7 +963,7 @@ static void UnstartedJNIFloatIntBitsToFloat(Thread* self ATTRIBUTE_UNUSED,
result->SetI(args[0]);
}
-static void UnstartedJNIObjectInternalClone(Thread* self,
+void UnstartedRuntime::UnstartedJNIObjectInternalClone(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -956,7 +972,7 @@ static void UnstartedJNIObjectInternalClone(Thread* self,
result->SetL(receiver->Clone(self));
}
-static void UnstartedJNIObjectNotifyAll(Thread* self,
+void UnstartedRuntime::UnstartedJNIObjectNotifyAll(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -965,7 +981,7 @@ static void UnstartedJNIObjectNotifyAll(Thread* self,
receiver->NotifyAll(self);
}
-static void UnstartedJNIStringCompareTo(Thread* self,
+void UnstartedRuntime::UnstartedJNIStringCompareTo(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver,
uint32_t* args,
@@ -978,7 +994,7 @@ static void UnstartedJNIStringCompareTo(Thread* self,
result->SetI(receiver->AsString()->CompareTo(rhs));
}
-static void UnstartedJNIStringIntern(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIStringIntern(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -987,7 +1003,7 @@ static void UnstartedJNIStringIntern(Thread* self ATTRIBUTE_UNUSED,
result->SetL(receiver->AsString()->Intern());
}
-static void UnstartedJNIStringFastIndexOf(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIStringFastIndexOf(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver,
uint32_t* args,
@@ -996,7 +1012,7 @@ static void UnstartedJNIStringFastIndexOf(Thread* self ATTRIBUTE_UNUSED,
result->SetI(receiver->AsString()->FastIndexOf(args[0], args[1]));
}
-static void UnstartedJNIArrayCreateMultiArray(Thread* self,
+void UnstartedRuntime::UnstartedJNIArrayCreateMultiArray(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -1008,7 +1024,7 @@ static void UnstartedJNIArrayCreateMultiArray(Thread* self,
result->SetL(mirror::Array::CreateMultiArray(self, h_class, h_dimensions));
}
-static void UnstartedJNIArrayCreateObjectArray(Thread* self,
+void UnstartedRuntime::UnstartedJNIArrayCreateObjectArray(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -1033,7 +1049,7 @@ static void UnstartedJNIArrayCreateObjectArray(Thread* self,
result->SetL(new_array);
}
-static void UnstartedJNIThrowableNativeFillInStackTrace(Thread* self,
+void UnstartedRuntime::UnstartedJNIThrowableNativeFillInStackTrace(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -1047,7 +1063,7 @@ static void UnstartedJNIThrowableNativeFillInStackTrace(Thread* self,
}
}
-static void UnstartedJNISystemIdentityHashCode(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNISystemIdentityHashCode(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -1057,7 +1073,7 @@ static void UnstartedJNISystemIdentityHashCode(Thread* self ATTRIBUTE_UNUSED,
result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0);
}
-static void UnstartedJNIByteOrderIsLittleEndian(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIByteOrderIsLittleEndian(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args ATTRIBUTE_UNUSED,
@@ -1065,7 +1081,7 @@ static void UnstartedJNIByteOrderIsLittleEndian(Thread* self ATTRIBUTE_UNUSED,
result->SetZ(JNI_TRUE);
}
-static void UnstartedJNIUnsafeCompareAndSwapInt(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIUnsafeCompareAndSwapInt(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -1086,7 +1102,7 @@ static void UnstartedJNIUnsafeCompareAndSwapInt(Thread* self ATTRIBUTE_UNUSED,
result->SetZ(success ? JNI_TRUE : JNI_FALSE);
}
-static void UnstartedJNIUnsafePutObject(Thread* self ATTRIBUTE_UNUSED,
+void UnstartedRuntime::UnstartedJNIUnsafePutObject(Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args,
@@ -1102,7 +1118,7 @@ static void UnstartedJNIUnsafePutObject(Thread* self ATTRIBUTE_UNUSED,
}
}
-static void UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType(
+void UnstartedRuntime::UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType(
Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
@@ -1114,7 +1130,7 @@ static void UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType(
result->SetI(mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value());
}
-static void UnstartedJNIUnsafeGetArrayIndexScaleForComponentType(
+void UnstartedRuntime::UnstartedJNIUnsafeGetArrayIndexScaleForComponentType(
Thread* self ATTRIBUTE_UNUSED,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
@@ -1136,147 +1152,37 @@ static bool tables_initialized_ = false;
static std::unordered_map<std::string, InvokeHandler> invoke_handlers_;
static std::unordered_map<std::string, JNIHandler> jni_handlers_;
-static void UnstartedRuntimeInitializeInvokeHandlers() {
- struct InvokeHandlerDef {
- std::string name;
- InvokeHandler function;
- };
-
- InvokeHandlerDef defs[] {
- { "java.lang.Class java.lang.Class.forName(java.lang.String)",
- &UnstartedClassForName },
- { "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)",
- &UnstartedClassForNameLong },
- { "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)",
- &UnstartedClassClassForName },
- { "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)",
- &UnstartedVmClassLoaderFindLoadedClass },
- { "java.lang.Class java.lang.Void.lookupType()",
- &UnstartedVoidLookupType },
- { "java.lang.Object java.lang.Class.newInstance()",
- &UnstartedClassNewInstance },
- { "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)",
- &UnstartedClassGetDeclaredField },
- { "int java.lang.Object.hashCode()",
- &UnstartedObjectHashCode },
- { "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)",
- &UnstartedArtMethodGetMethodName },
- { "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)",
- &UnstartedSystemArraycopy},
- { "void java.lang.System.arraycopy(char[], int, char[], int, int)",
- &UnstartedSystemArraycopy },
- { "void java.lang.System.arraycopy(int[], int, int[], int, int)",
- &UnstartedSystemArraycopy },
- { "long java.lang.Double.doubleToRawLongBits(double)",
- &UnstartedDoubleDoubleToRawLongBits },
- { "double java.lang.Math.ceil(double)",
- &UnstartedMathCeil },
- { "java.lang.Object java.lang.ThreadLocal.get()",
- &UnstartedThreadLocalGet },
- { "com.android.dex.Dex java.lang.DexCache.getDexNative()",
- &UnstartedDexCacheGetDexNative },
- { "byte libcore.io.Memory.peekByte(long)",
- &UnstartedMemoryPeekEntry },
- { "short libcore.io.Memory.peekShortNative(long)",
- &UnstartedMemoryPeekEntry },
- { "int libcore.io.Memory.peekIntNative(long)",
- &UnstartedMemoryPeekEntry },
- { "long libcore.io.Memory.peekLongNative(long)",
- &UnstartedMemoryPeekEntry },
- { "void libcore.io.Memory.peekByteArray(long, byte[], int, int)",
- &UnstartedMemoryPeekArrayEntry },
- { "java.io.Reader java.security.Security.getSecurityPropertiesReader()",
- &UnstartedSecurityGetSecurityPropertiesReader },
- { "void java.lang.String.getCharsNoCheck(int, int, char[], int)",
- &UnstartedStringGetCharsNoCheck },
- { "char java.lang.String.charAt(int)",
- &UnstartedStringCharAt },
- { "void java.lang.String.setCharAt(int, char)",
- &UnstartedStringSetCharAt },
- { "java.lang.String java.lang.StringFactory.newStringFromChars(int, int, char[])",
- &UnstartedStringFactoryNewStringFromChars },
- { "java.lang.String java.lang.StringFactory.newStringFromString(java.lang.String)",
- &UnstartedStringFactoryNewStringFromString },
- { "java.lang.String java.lang.String.fastSubstring(int, int)",
- &UnstartedStringFastSubstring },
- { "char[] java.lang.String.toCharArray()",
- &UnstartedStringToCharArray },
- };
-
- for (auto& def : defs) {
- invoke_handlers_.insert(std::make_pair(def.name, def.function));
- }
+void UnstartedRuntime::InitializeInvokeHandlers() {
+#define UNSTARTED_DIRECT(ShortName, Sig) \
+ invoke_handlers_.insert(std::make_pair(Sig, & UnstartedRuntime::Unstarted ## ShortName));
+#include "unstarted_runtime_list.h"
+ UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT)
+#undef UNSTARTED_RUNTIME_DIRECT_LIST
+#undef UNSTARTED_RUNTIME_JNI_LIST
+#undef UNSTARTED_DIRECT
}
-static void UnstartedRuntimeInitializeJNIHandlers() {
- struct JNIHandlerDef {
- std::string name;
- JNIHandler function;
- };
-
- JNIHandlerDef defs[] {
- { "java.lang.Object dalvik.system.VMRuntime.newUnpaddedArray(java.lang.Class, int)",
- &UnstartedJNIVMRuntimeNewUnpaddedArray },
- { "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()",
- &UnstartedJNIVMStackGetCallingClassLoader },
- { "java.lang.Class dalvik.system.VMStack.getStackClass2()",
- &UnstartedJNIVMStackGetStackClass2 },
- { "double java.lang.Math.log(double)",
- &UnstartedJNIMathLog },
- { "java.lang.String java.lang.Class.getNameNative()",
- &UnstartedJNIClassGetNameNative },
- { "int java.lang.Float.floatToRawIntBits(float)",
- &UnstartedJNIFloatFloatToRawIntBits },
- { "float java.lang.Float.intBitsToFloat(int)",
- &UnstartedJNIFloatIntBitsToFloat },
- { "double java.lang.Math.exp(double)",
- &UnstartedJNIMathExp },
- { "java.lang.Object java.lang.Object.internalClone()",
- &UnstartedJNIObjectInternalClone },
- { "void java.lang.Object.notifyAll()",
- &UnstartedJNIObjectNotifyAll},
- { "int java.lang.String.compareTo(java.lang.String)",
- &UnstartedJNIStringCompareTo },
- { "java.lang.String java.lang.String.intern()",
- &UnstartedJNIStringIntern },
- { "int java.lang.String.fastIndexOf(int, int)",
- &UnstartedJNIStringFastIndexOf },
- { "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])",
- &UnstartedJNIArrayCreateMultiArray },
- { "java.lang.Object java.lang.reflect.Array.createObjectArray(java.lang.Class, int)",
- &UnstartedJNIArrayCreateObjectArray },
- { "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()",
- &UnstartedJNIThrowableNativeFillInStackTrace },
- { "int java.lang.System.identityHashCode(java.lang.Object)",
- &UnstartedJNISystemIdentityHashCode },
- { "boolean java.nio.ByteOrder.isLittleEndian()",
- &UnstartedJNIByteOrderIsLittleEndian },
- { "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)",
- &UnstartedJNIUnsafeCompareAndSwapInt },
- { "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)",
- &UnstartedJNIUnsafePutObject },
- { "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)",
- &UnstartedJNIUnsafeGetArrayBaseOffsetForComponentType },
- { "int sun.misc.Unsafe.getArrayIndexScaleForComponentType(java.lang.Class)",
- &UnstartedJNIUnsafeGetArrayIndexScaleForComponentType },
- };
-
- for (auto& def : defs) {
- jni_handlers_.insert(std::make_pair(def.name, def.function));
- }
+void UnstartedRuntime::InitializeJNIHandlers() {
+#define UNSTARTED_JNI(ShortName, Sig) \
+ jni_handlers_.insert(std::make_pair(Sig, & UnstartedRuntime::UnstartedJNI ## ShortName));
+#include "unstarted_runtime_list.h"
+ UNSTARTED_RUNTIME_JNI_LIST(UNSTARTED_JNI)
+#undef UNSTARTED_RUNTIME_DIRECT_LIST
+#undef UNSTARTED_RUNTIME_JNI_LIST
+#undef UNSTARTED_JNI
}
-void UnstartedRuntimeInitialize() {
+void UnstartedRuntime::Initialize() {
CHECK(!tables_initialized_);
- UnstartedRuntimeInitializeInvokeHandlers();
- UnstartedRuntimeInitializeJNIHandlers();
+ InitializeInvokeHandlers();
+ InitializeJNIHandlers();
tables_initialized_ = true;
}
-void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
CHECK(tables_initialized_);
@@ -1294,8 +1200,8 @@ void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
}
// Hand select a number of methods to be run in a not yet started runtime without using JNI.
-void UnstartedRuntimeJni(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver,
- uint32_t* args, JValue* result) {
+void UnstartedRuntime::Jni(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver,
+ uint32_t* args, JValue* result) {
std::string name(PrettyMethod(method));
const auto& iter = jni_handlers_.find(name);
if (iter != jni_handlers_.end()) {
diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h
index 2d7d380..a361af0 100644
--- a/runtime/interpreter/unstarted_runtime.h
+++ b/runtime/interpreter/unstarted_runtime.h
@@ -36,16 +36,69 @@ class Object;
namespace interpreter {
-void UnstartedRuntimeInitialize();
+// Support for an unstarted runtime. These are special handwritten implementations for select
+// libcore native and non-native methods so we can compile-time initialize classes in the boot
+// image.
+//
+// While it would technically be OK to only expose the public functions, a class was chosen to
+// wrap this so the actual implementations are exposed for testing. This is also why the private
+// methods are not documented here - they are not intended to be used directly except in
+// testing.
-void UnstartedRuntimeInvoke(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame,
- JValue* result, size_t arg_offset)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+class UnstartedRuntime {
+ public:
+ static void Initialize();
-void UnstartedRuntimeJni(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver,
- uint32_t* args, JValue* result)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static void Invoke(Thread* self,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame* shadow_frame,
+ JValue* result,
+ size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void Jni(Thread* self,
+ mirror::ArtMethod* method,
+ mirror::Object* receiver,
+ uint32_t* args,
+ JValue* result)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ // Methods that intercept available libcore implementations.
+#define UNSTARTED_DIRECT(ShortName, SigIgnored) \
+ static void Unstarted ## ShortName(Thread* self, \
+ ShadowFrame* shadow_frame, \
+ JValue* result, \
+ size_t arg_offset) \
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+#include "unstarted_runtime_list.h"
+ UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT)
+#undef UNSTARTED_RUNTIME_DIRECT_LIST
+#undef UNSTARTED_RUNTIME_JNI_LIST
+#undef UNSTARTED_DIRECT
+
+ // Methods that are native.
+#define UNSTARTED_JNI(ShortName, SigIgnored) \
+ static void UnstartedJNI ## ShortName(Thread* self, \
+ mirror::ArtMethod* method, \
+ mirror::Object* receiver, \
+ uint32_t* args, \
+ JValue* result) \
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+#include "unstarted_runtime_list.h"
+ UNSTARTED_RUNTIME_JNI_LIST(UNSTARTED_JNI)
+#undef UNSTARTED_RUNTIME_DIRECT_LIST
+#undef UNSTARTED_RUNTIME_JNI_LIST
+#undef UNSTARTED_JNI
+
+ static void InitializeInvokeHandlers();
+ static void InitializeJNIHandlers();
+
+ friend class UnstartedRuntimeTest;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(UnstartedRuntime);
+};
} // namespace interpreter
} // namespace art
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
new file mode 100644
index 0000000..8f6014c
--- /dev/null
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_LIST_H_
+#define ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_LIST_H_
+
+// Methods that intercept available libcore implementations.
+#define UNSTARTED_RUNTIME_DIRECT_LIST(V) \
+ V(ClassForName, "java.lang.Class java.lang.Class.forName(java.lang.String)") \
+ V(ClassForNameLong, "java.lang.Class java.lang.Class.forName(java.lang.String, boolean, java.lang.ClassLoader)") \
+ V(ClassClassForName, "java.lang.Class java.lang.Class.classForName(java.lang.String, boolean, java.lang.ClassLoader)") \
+ V(ClassNewInstance, "java.lang.Object java.lang.Class.newInstance()") \
+ V(ClassGetDeclaredField, "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") \
+ V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \
+ V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \
+ V(SystemArraycopy, "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") \
+ V(SystemArraycopyChar, "void java.lang.System.arraycopy(char[], int, char[], int, int)") \
+ V(SystemArraycopyInt, "void java.lang.System.arraycopy(int[], int, int[], int, int)") \
+ V(ThreadLocalGet, "java.lang.Object java.lang.ThreadLocal.get()") \
+ V(MathCeil, "double java.lang.Math.ceil(double)") \
+ V(ArtMethodGetMethodName, "java.lang.String java.lang.reflect.ArtMethod.getMethodName(java.lang.reflect.ArtMethod)") \
+ V(ObjectHashCode, "int java.lang.Object.hashCode()") \
+ V(DoubleDoubleToRawLongBits, "long java.lang.Double.doubleToRawLongBits(double)") \
+ V(DexCacheGetDexNative, "com.android.dex.Dex java.lang.DexCache.getDexNative()") \
+ V(MemoryPeekByte, "byte libcore.io.Memory.peekByte(long)") \
+ V(MemoryPeekShort, "short libcore.io.Memory.peekShortNative(long)") \
+ V(MemoryPeekInt, "int libcore.io.Memory.peekIntNative(long)") \
+ V(MemoryPeekLong, "long libcore.io.Memory.peekLongNative(long)") \
+ V(MemoryPeekByteArray, "void libcore.io.Memory.peekByteArray(long, byte[], int, int)") \
+ V(SecurityGetSecurityPropertiesReader, "java.io.Reader java.security.Security.getSecurityPropertiesReader()") \
+ V(StringGetCharsNoCheck, "void java.lang.String.getCharsNoCheck(int, int, char[], int)") \
+ V(StringCharAt, "char java.lang.String.charAt(int)") \
+ V(StringSetCharAt, "void java.lang.String.setCharAt(int, char)") \
+ V(StringFactoryNewStringFromChars, "java.lang.String java.lang.StringFactory.newStringFromChars(int, int, char[])") \
+ V(StringFactoryNewStringFromString, "java.lang.String java.lang.StringFactory.newStringFromString(java.lang.String)") \
+ V(StringFastSubstring, "java.lang.String java.lang.String.fastSubstring(int, int)") \
+ V(StringToCharArray, "char[] java.lang.String.toCharArray()")
+
+// Methods that are native.
+#define UNSTARTED_RUNTIME_JNI_LIST(V) \
+ V(VMRuntimeNewUnpaddedArray, "java.lang.Object dalvik.system.VMRuntime.newUnpaddedArray(java.lang.Class, int)") \
+ V(VMStackGetCallingClassLoader, "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") \
+ V(VMStackGetStackClass2, "java.lang.Class dalvik.system.VMStack.getStackClass2()") \
+ V(MathLog, "double java.lang.Math.log(double)") \
+ V(MathExp, "double java.lang.Math.exp(double)") \
+ V(ClassGetNameNative, "java.lang.String java.lang.Class.getNameNative()") \
+ V(FloatFloatToRawIntBits, "int java.lang.Float.floatToRawIntBits(float)") \
+ V(FloatIntBitsToFloat, "float java.lang.Float.intBitsToFloat(int)") \
+ V(ObjectInternalClone, "java.lang.Object java.lang.Object.internalClone()") \
+ V(ObjectNotifyAll, "void java.lang.Object.notifyAll()") \
+ V(StringCompareTo, "int java.lang.String.compareTo(java.lang.String)") \
+ V(StringIntern, "java.lang.String java.lang.String.intern()") \
+ V(StringFastIndexOf, "int java.lang.String.fastIndexOf(int, int)") \
+ V(ArrayCreateMultiArray, "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])") \
+ V(ArrayCreateObjectArray, "java.lang.Object java.lang.reflect.Array.createObjectArray(java.lang.Class, int)") \
+ V(ThrowableNativeFillInStackTrace, "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") \
+ V(SystemIdentityHashCode, "int java.lang.System.identityHashCode(java.lang.Object)") \
+ V(ByteOrderIsLittleEndian, "boolean java.nio.ByteOrder.isLittleEndian()") \
+ V(UnsafeCompareAndSwapInt, "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") \
+ V(UnsafePutObject, "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") \
+ V(UnsafeGetArrayBaseOffsetForComponentType, "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") \
+ V(UnsafeGetArrayIndexScaleForComponentType, "int sun.misc.Unsafe.getArrayIndexScaleForComponentType(java.lang.Class)")
+
+#endif // ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_LIST_H_
+// the guard in this file is just for cpplint
+#undef ART_RUNTIME_INTERPRETER_UNSTARTED_RUNTIME_LIST_H_
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
new file mode 100644
index 0000000..34ab277
--- /dev/null
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include "unstarted_runtime.h"
+
+#include "class_linker.h"
+#include "common_runtime_test.h"
+#include "handle.h"
+#include "handle_scope-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/string-inl.h"
+#include "runtime.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+namespace interpreter {
+
+class UnstartedRuntimeTest : public CommonRuntimeTest {
+ protected:
+ // Re-expose all UnstartedRuntime implementations so we don't need to declare a million
+ // test friends.
+
+ // Methods that intercept available libcore implementations.
+#define UNSTARTED_DIRECT(Name, SigIgnored) \
+ static void Unstarted ## Name(Thread* self, \
+ ShadowFrame* shadow_frame, \
+ JValue* result, \
+ size_t arg_offset) \
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
+ interpreter::UnstartedRuntime::Unstarted ## Name(self, shadow_frame, result, arg_offset); \
+ }
+#include "unstarted_runtime_list.h"
+ UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT)
+#undef UNSTARTED_RUNTIME_DIRECT_LIST
+#undef UNSTARTED_RUNTIME_JNI_LIST
+#undef UNSTARTED_DIRECT
+
+ // Methods that are native.
+#define UNSTARTED_JNI(Name, SigIgnored) \
+ static void UnstartedJNI ## Name(Thread* self, \
+ mirror::ArtMethod* method, \
+ mirror::Object* receiver, \
+ uint32_t* args, \
+ JValue* result) \
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \
+ interpreter::UnstartedRuntime::UnstartedJNI ## Name(self, method, receiver, args, result); \
+ }
+#include "unstarted_runtime_list.h"
+ UNSTARTED_RUNTIME_JNI_LIST(UNSTARTED_JNI)
+#undef UNSTARTED_RUNTIME_DIRECT_LIST
+#undef UNSTARTED_RUNTIME_JNI_LIST
+#undef UNSTARTED_JNI
+};
+
+TEST_F(UnstartedRuntimeTest, MemoryPeekByte) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ constexpr const uint8_t base_array[] = "abcdefghijklmnop";
+ constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
+ const uint8_t* base_ptr = base_array;
+
+ JValue result;
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ for (int32_t i = 0; i < kBaseLen; ++i) {
+ tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
+
+ UnstartedMemoryPeekByte(self, tmp, &result, 0);
+
+ EXPECT_EQ(result.GetB(), static_cast<int8_t>(base_array[i]));
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+TEST_F(UnstartedRuntimeTest, MemoryPeekShort) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ constexpr const uint8_t base_array[] = "abcdefghijklmnop";
+ constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
+ const uint8_t* base_ptr = base_array;
+
+ JValue result;
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ int32_t adjusted_length = kBaseLen - sizeof(int16_t);
+ for (int32_t i = 0; i < adjusted_length; ++i) {
+ tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
+
+ UnstartedMemoryPeekShort(self, tmp, &result, 0);
+
+ typedef int16_t unaligned_short __attribute__ ((aligned (1)));
+ const unaligned_short* short_ptr = reinterpret_cast<const unaligned_short*>(base_ptr + i);
+ EXPECT_EQ(result.GetS(), *short_ptr);
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+TEST_F(UnstartedRuntimeTest, MemoryPeekInt) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ constexpr const uint8_t base_array[] = "abcdefghijklmnop";
+ constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
+ const uint8_t* base_ptr = base_array;
+
+ JValue result;
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ int32_t adjusted_length = kBaseLen - sizeof(int32_t);
+ for (int32_t i = 0; i < adjusted_length; ++i) {
+ tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
+
+ UnstartedMemoryPeekInt(self, tmp, &result, 0);
+
+ typedef int32_t unaligned_int __attribute__ ((aligned (1)));
+ const unaligned_int* int_ptr = reinterpret_cast<const unaligned_int*>(base_ptr + i);
+ EXPECT_EQ(result.GetI(), *int_ptr);
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+TEST_F(UnstartedRuntimeTest, MemoryPeekLong) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ constexpr const uint8_t base_array[] = "abcdefghijklmnop";
+ constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
+ const uint8_t* base_ptr = base_array;
+
+ JValue result;
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ int32_t adjusted_length = kBaseLen - sizeof(int64_t);
+ for (int32_t i = 0; i < adjusted_length; ++i) {
+ tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
+
+ UnstartedMemoryPeekLong(self, tmp, &result, 0);
+
+ typedef int64_t unaligned_long __attribute__ ((aligned (1)));
+ const unaligned_long* long_ptr = reinterpret_cast<const unaligned_long*>(base_ptr + i);
+ EXPECT_EQ(result.GetJ(), *long_ptr);
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+TEST_F(UnstartedRuntimeTest, StringGetCharsNoCheck) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ StackHandleScope<2> hs(self);
+ // TODO: Actual UTF.
+ constexpr const char base_string[] = "abcdefghijklmnop";
+ Handle<mirror::String> h_test_string(hs.NewHandle(
+ mirror::String::AllocFromModifiedUtf8(self, base_string)));
+ constexpr int32_t kBaseLen = sizeof(base_string) / sizeof(char) - 1;
+ Handle<mirror::CharArray> h_char_array(hs.NewHandle(
+ mirror::CharArray::Alloc(self, kBaseLen)));
+ // A buffer so we can make sure we only modify the elements targetted.
+ uint16_t buf[kBaseLen];
+
+ JValue result;
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ for (int32_t start_index = 0; start_index < kBaseLen; ++start_index) {
+ for (int32_t count = 0; count <= kBaseLen; ++count) {
+ for (int32_t trg_offset = 0; trg_offset < kBaseLen; ++trg_offset) {
+ // Only do it when in bounds.
+ if (start_index + count <= kBaseLen && trg_offset + count <= kBaseLen) {
+ tmp->SetVRegReference(0, h_test_string.Get());
+ tmp->SetVReg(1, start_index);
+ tmp->SetVReg(2, count);
+ tmp->SetVRegReference(3, h_char_array.Get());
+ tmp->SetVReg(3, trg_offset);
+
+ // Copy the char_array into buf.
+ memcpy(buf, h_char_array->GetData(), kBaseLen * sizeof(uint16_t));
+
+ UnstartedStringCharAt(self, tmp, &result, 0);
+
+ uint16_t* data = h_char_array->GetData();
+
+ bool success = true;
+
+ // First segment should be unchanged.
+ for (int32_t i = 0; i < trg_offset; ++i) {
+ success = success && (data[i] == buf[i]);
+ }
+ // Second segment should be a copy.
+ for (int32_t i = trg_offset; i < trg_offset + count; ++i) {
+ success = success && (data[i] == buf[i - trg_offset + start_index]);
+ }
+ // Third segment should be unchanged.
+ for (int32_t i = trg_offset + count; i < kBaseLen; ++i) {
+ success = success && (data[i] == buf[i]);
+ }
+
+ EXPECT_TRUE(success);
+ }
+ }
+ }
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+TEST_F(UnstartedRuntimeTest, StringCharAt) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ // TODO: Actual UTF.
+ constexpr const char* base_string = "abcdefghijklmnop";
+ int32_t base_len = static_cast<int32_t>(strlen(base_string));
+ mirror::String* test_string = mirror::String::AllocFromModifiedUtf8(self, base_string);
+
+ JValue result;
+ ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ for (int32_t i = 0; i < base_len; ++i) {
+ tmp->SetVRegReference(0, test_string);
+ tmp->SetVReg(1, i);
+
+ UnstartedStringCharAt(self, tmp, &result, 0);
+
+ EXPECT_EQ(result.GetI(), base_string[i]);
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(tmp);
+}
+
+} // namespace interpreter
+} // namespace art