diff options
| author | 2015-03-12 23:17:12 +0000 | |
|---|---|---|
| committer | 2015-03-12 23:19:15 +0000 | |
| commit | c685bce4e6cfec075cb5b468d06b2fcdeeda2005 (patch) | |
| tree | df0066973ff62cd8c034d7bedea167ba9c2253b5 | |
| parent | 003e7aad9a6e57032dfc7b4677dc815c6aa462ea (diff) | |
| parent | dd9d055ddfe4bd66fcf58fde4e8066670acce011 (diff) | |
Merge "ART: More cutouts for unstarted runtime"
| -rw-r--r-- | compiler/image_writer.cc | 24 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime.cc | 229 | ||||
| -rw-r--r-- | runtime/mirror/dex_cache.h | 4 |
3 files changed, 230 insertions, 27 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index b4732c87c8..c7f81eab2f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -71,6 +71,17 @@ namespace art { // Separate objects into multiple bins to optimize dirty memory use. static constexpr bool kBinObjects = true; +static void CheckNoDexObjectsCallback(Object* obj, void* arg ATTRIBUTE_UNUSED) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Class* klass = obj->GetClass(); + CHECK_NE(PrettyClass(klass), "com.android.dex.Dex"); +} + +static void CheckNoDexObjects() { + ScopedObjectAccess soa(Thread::Current()); + Runtime::Current()->GetHeap()->VisitObjects(CheckNoDexObjectsCallback, nullptr); +} + bool ImageWriter::PrepareImageAddressSpace() { target_ptr_size_ = InstructionSetPointerSize(compiler_driver_.GetInstructionSet()); { @@ -83,6 +94,16 @@ bool ImageWriter::PrepareImageAddressSpace() { gc::Heap* heap = Runtime::Current()->GetHeap(); heap->CollectGarbage(false); // Remove garbage. + // Dex caches must not have their dex fields set in the image. These are memory buffers of mapped + // dex files. + // + // We may open them in the unstarted-runtime code for class metadata. Their fields should all be + // reset in PruneNonImageClasses and the objects reclaimed in the GC. Make sure that's actually + // true. + if (kIsDebugBuild) { + CheckNoDexObjects(); + } + if (!AllocMemory()) { return false; } @@ -644,6 +665,9 @@ void ImageWriter::PruneNonImageClasses() { dex_cache->SetResolvedField(i, NULL); } } + // Clean the dex field. It might have been populated during the initialization phase, but + // contains data only valid during a real run. + dex_cache->SetFieldObject<false>(mirror::DexCache::DexOffset(), nullptr); } } diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 95f3357f7c..356a438085 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -97,8 +97,8 @@ static void CheckExceptionGenerateClassNotFound(Thread* self) } } -static void UnstartedClassForName(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset) +static void UnstartedClassForName( + 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)->AsString(); StackHandleScope<1> hs(self); @@ -108,8 +108,8 @@ static void UnstartedClassForName(Thread* self, ShadowFrame* shadow_frame, JValu CheckExceptionGenerateClassNotFound(self); } -static void UnstartedClassForNameLong(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset) +static void UnstartedClassForNameLong( + 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)->AsString(); bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0; @@ -123,8 +123,8 @@ static void UnstartedClassForNameLong(Thread* self, ShadowFrame* shadow_frame, J CheckExceptionGenerateClassNotFound(self); } -static void UnstartedClassClassForName(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset) +static void UnstartedClassClassForName( + 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)->AsString(); bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0; @@ -138,8 +138,8 @@ static void UnstartedClassClassForName(Thread* self, ShadowFrame* shadow_frame, CheckExceptionGenerateClassNotFound(self); } -static void UnstartedClassNewInstance(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset) +static void 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. mirror::Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); @@ -189,8 +189,8 @@ static void UnstartedClassNewInstance(Thread* self, ShadowFrame* shadow_frame, J } } -static void UnstartedClassGetDeclaredField(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset) +static void 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 // going the reflective Dex way. @@ -234,8 +234,8 @@ static void UnstartedClassGetDeclaredField(Thread* self, ShadowFrame* shadow_fra result->SetL(field.Get()); } -static void UnstartedVmClassLoaderFindLoadedClass(Thread* self, ShadowFrame* shadow_frame, - JValue* result, size_t arg_offset) +static void 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(); mirror::ClassLoader* class_loader = @@ -263,8 +263,8 @@ static void UnstartedVoidLookupType(Thread* self ATTRIBUTE_UNUSED, result->SetL(Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V')); } -static void UnstartedSystemArraycopy(Thread* self, ShadowFrame* shadow_frame, - JValue* result ATTRIBUTE_UNUSED, size_t arg_offset) +static void 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. mirror::Class* ctype = shadow_frame->GetVRegReference(arg_offset)->GetClass()->GetComponentType(); @@ -297,8 +297,8 @@ static void UnstartedSystemArraycopy(Thread* self, ShadowFrame* shadow_frame, } } -static void UnstartedThreadLocalGet(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset ATTRIBUTE_UNUSED) +static void 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())); bool ok = false; @@ -347,8 +347,8 @@ static void UnstartedThreadLocalGet(Thread* self, ShadowFrame* shadow_frame, JVa } } -static void UnstartedMathCeil(Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, - JValue* result, size_t arg_offset) { +static void UnstartedMathCeil( + Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { double in = shadow_frame->GetVRegDouble(arg_offset); double out; // Special cases: @@ -362,27 +362,190 @@ static void UnstartedMathCeil(Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow result->SetD(out); } -static void UnstartedArtMethodGetMethodName(Thread* self, ShadowFrame* shadow_frame, - JValue* result, size_t arg_offset) +static void 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(Thread* self ATTRIBUTE_UNUSED, ShadowFrame* shadow_frame, - JValue* result, size_t arg_offset) +static void 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(Thread* self ATTRIBUTE_UNUSED, - ShadowFrame* shadow_frame, JValue* result, - size_t arg_offset) { +static void 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>(in)); } +static mirror::Object* GetDexFromDexCache(Thread* self, mirror::DexCache* dex_cache) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile* dex_file = dex_cache->GetDexFile(); + if (dex_file == nullptr) { + return nullptr; + } + + // Create the direct byte buffer. + JNIEnv* env = self->GetJniEnv(); + DCHECK(env != nullptr); + void* address = const_cast<void*>(reinterpret_cast<const void*>(dex_file->Begin())); + jobject byte_buffer = env->NewDirectByteBuffer(address, dex_file->Size()); + if (byte_buffer == nullptr) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } + + jvalue args[1]; + args[0].l = byte_buffer; + return self->DecodeJObject( + env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, + WellKnownClasses::com_android_dex_Dex_create, + args)); +} + +static void 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 + // art file. + mirror::Object* src = shadow_frame->GetVRegReference(arg_offset); + bool have_dex = false; + if (src != nullptr) { + mirror::Object* dex = GetDexFromDexCache(self, reinterpret_cast<mirror::DexCache*>(src)); + if (dex != nullptr) { + have_dex = true; + result->SetL(dex); + } + } + if (!have_dex) { + self->ClearException(); + Runtime::Current()->AbortTransactionAndThrowInternalError(self, "Could not create Dex object"); + } +} + +static void UnstartedMemoryPeek( + Primitive::Type type, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + int64_t address = shadow_frame->GetVRegLong(arg_offset); + // TODO: Check that this is in the heap somewhere. Otherwise we will segfault instead of + // aborting the transaction. + + switch (type) { + case Primitive::kPrimByte: { + result->SetB(*reinterpret_cast<int8_t*>(static_cast<intptr_t>(address))); + return; + } + + case Primitive::kPrimShort: { + result->SetS(*reinterpret_cast<int16_t*>(static_cast<intptr_t>(address))); + return; + } + + case Primitive::kPrimInt: { + result->SetI(*reinterpret_cast<int32_t*>(static_cast<intptr_t>(address))); + return; + } + + case Primitive::kPrimLong: { + result->SetJ(*reinterpret_cast<int64_t*>(static_cast<intptr_t>(address))); + return; + } + + case Primitive::kPrimBoolean: + case Primitive::kPrimChar: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + case Primitive::kPrimVoid: + case Primitive::kPrimNot: + LOG(FATAL) << "Not in the Memory API: " << type; + UNREACHABLE(); + } + LOG(FATAL) << "Should not reach here"; + UNREACHABLE(); +} + +static void UnstartedMemoryPeekEntry( + 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(); + } +} + +static void UnstartedMemoryPeekArray( + Primitive::Type type, Thread* self, ShadowFrame* shadow_frame, size_t arg_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + int64_t address_long = shadow_frame->GetVRegLong(arg_offset); + mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset + 2); + if (obj == nullptr) { + Runtime::Current()->AbortTransactionAndThrowInternalError(self, "Null pointer in peekArray"); + return; + } + mirror::Array* array = obj->AsArray(); + + int offset = shadow_frame->GetVReg(arg_offset + 3); + int count = shadow_frame->GetVReg(arg_offset + 4); + if (offset < 0 || offset + count > array->GetLength()) { + std::string error_msg(StringPrintf("Array out of bounds in peekArray: %d/%d vs %d", + offset, count, array->GetLength())); + Runtime::Current()->AbortTransactionAndThrowInternalError(self, error_msg.c_str()); + return; + } + + switch (type) { + case Primitive::kPrimByte: { + int8_t* address = reinterpret_cast<int8_t*>(static_cast<intptr_t>(address_long)); + mirror::ByteArray* byte_array = array->AsByteArray(); + for (int32_t i = 0; i < count; ++i, ++address) { + byte_array->SetWithoutChecks<true>(i + offset, *address); + } + return; + } + + case Primitive::kPrimShort: + case Primitive::kPrimInt: + case Primitive::kPrimLong: + LOG(FATAL) << "Type unimplemented for Memory Array API, should not reach here: " << type; + UNREACHABLE(); + + case Primitive::kPrimBoolean: + case Primitive::kPrimChar: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + case Primitive::kPrimVoid: + case Primitive::kPrimNot: + LOG(FATAL) << "Not in the Memory API: " << type; + UNREACHABLE(); + } + LOG(FATAL) << "Should not reach here"; + UNREACHABLE(); +} + +static void UnstartedMemoryPeekArrayEntry( + 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(); + } +} + static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self, mirror::ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED, @@ -621,10 +784,10 @@ static void UnstartedJNIUnsafeGetArrayIndexScaleForComponentType( result->SetI(Primitive::ComponentSize(primitive_type)); } -typedef void(*InvokeHandler)(Thread* self, ShadowFrame* shadow_frame, JValue* result, +typedef void (*InvokeHandler)(Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_size); -typedef void(*JNIHandler)(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver, +typedef void (*JNIHandler)(Thread* self, mirror::ArtMethod* method, mirror::Object* receiver, uint32_t* args, JValue* result); static bool tables_initialized_ = false; @@ -668,6 +831,18 @@ static void UnstartedRuntimeInitializeInvokeHandlers() { &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 }, }; for (auto& def : defs) { diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 3c947ab37b..c548c03e63 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -59,6 +59,10 @@ class MANAGED DexCache FINAL : public Object { return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_)); } + static MemberOffset DexOffset() { + return OFFSET_OF_OBJECT_MEMBER(DexCache, dex_); + } + static MemberOffset StringsOffset() { return OFFSET_OF_OBJECT_MEMBER(DexCache, strings_); } |