diff options
-rw-r--r-- | build/Android.gtest.mk | 1 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 2 | ||||
-rw-r--r-- | runtime/common_runtime_test.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.cc | 4 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime.cc | 312 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime.h | 69 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime_list.h | 79 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime_test.cc | 251 |
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 |