Portable refactorings.
Separate quick from portable entrypoints.
Move architectural dependencies into arch.
Change-Id: I9adbc0a9782e2959fdc3308215f01e3107632b7c
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
new file mode 100644
index 0000000..c297841
--- /dev/null
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+
+#include "class_linker-inl.h"
+#include "dex_file-inl.h"
+#include "gc/accounting/card_table-inl.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/field-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/proxy.h"
+#include "reflection.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedLocalRef.h"
+#include "well_known_classes.h"
+
+namespace art {
+
+// Helper function to allocate array for FILLED_NEW_ARRAY.
+mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::AbstractMethod* referrer,
+ int32_t component_count, Thread* self,
+ bool access_check) {
+ if (UNLIKELY(component_count < 0)) {
+ ThrowNegativeArraySizeException(component_count);
+ return NULL; // Failure
+ }
+ mirror::Class* klass = referrer->GetDexCacheResolvedTypes()->Get(type_idx);
+ if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
+ klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, referrer);
+ if (klass == NULL) { // Error
+ DCHECK(self->IsExceptionPending());
+ return NULL; // Failure
+ }
+ }
+ if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
+ if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
+ ThrowRuntimeException("Bad filled array request for type %s",
+ PrettyDescriptor(klass).c_str());
+ } else {
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ DCHECK(throw_location.GetMethod() == referrer);
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
+ "Found type %s; filled-new-array not implemented for anything but \'int\'",
+ PrettyDescriptor(klass).c_str());
+ }
+ return NULL; // Failure
+ } else {
+ if (access_check) {
+ mirror::Class* referrer_klass = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referrer_klass->CanAccess(klass))) {
+ ThrowIllegalAccessErrorClass(referrer_klass, klass);
+ return NULL; // Failure
+ }
+ }
+ DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
+ return mirror::Array::Alloc(self, klass, component_count);
+ }
+}
+
+mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
+ Thread* self, FindFieldType type, size_t expected_size,
+ bool access_check) {
+ bool is_primitive;
+ bool is_set;
+ bool is_static;
+ switch (type) {
+ case InstanceObjectRead: is_primitive = false; is_set = false; is_static = false; break;
+ case InstanceObjectWrite: is_primitive = false; is_set = true; is_static = false; break;
+ case InstancePrimitiveRead: is_primitive = true; is_set = false; is_static = false; break;
+ case InstancePrimitiveWrite: is_primitive = true; is_set = true; is_static = false; break;
+ case StaticObjectRead: is_primitive = false; is_set = false; is_static = true; break;
+ case StaticObjectWrite: is_primitive = false; is_set = true; is_static = true; break;
+ case StaticPrimitiveRead: is_primitive = true; is_set = false; is_static = true; break;
+ case StaticPrimitiveWrite: // Keep GCC happy by having a default handler, fall-through.
+ default: is_primitive = true; is_set = true; is_static = true; break;
+ }
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
+ if (UNLIKELY(resolved_field == NULL)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
+ return NULL; // Failure.
+ }
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ if (access_check) {
+ if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+ ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
+ return NULL;
+ }
+ mirror::Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
+ !referring_class->CanAccessMember(fields_class,
+ resolved_field->GetAccessFlags()))) {
+ // The referring class can't access the resolved field, this may occur as a result of a
+ // protected field being made public by a sub-class. Resort to the dex file to determine
+ // the correct class for the access check.
+ const DexFile& dex_file = *referring_class->GetDexCache()->GetDexFile();
+ fields_class = class_linker->ResolveType(dex_file,
+ dex_file.GetFieldId(field_idx).class_idx_,
+ referring_class);
+ if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
+ ThrowIllegalAccessErrorClass(referring_class, fields_class);
+ return NULL; // failure
+ } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
+ resolved_field->GetAccessFlags()))) {
+ ThrowIllegalAccessErrorField(referring_class, resolved_field);
+ return NULL; // failure
+ }
+ }
+ if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
+ ThrowIllegalAccessErrorFinalField(referrer, resolved_field);
+ return NULL; // failure
+ } else {
+ FieldHelper fh(resolved_field);
+ if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+ fh.FieldSize() != expected_size)) {
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ DCHECK(throw_location.GetMethod() == referrer);
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
+ "Attempted read of %zd-bit %s on field '%s'",
+ expected_size * (32 / sizeof(int32_t)),
+ is_primitive ? "primitive" : "non-primitive",
+ PrettyField(resolved_field, true).c_str());
+ return NULL; // failure
+ }
+ }
+ }
+ if (!is_static) {
+ // instance fields must be being accessed on an initialized class
+ return resolved_field;
+ } else {
+ // If the class is initialized we're done.
+ if (fields_class->IsInitialized()) {
+ return resolved_field;
+ } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
+ // Otherwise let's ensure the class is initialized before resolving the field.
+ return resolved_field;
+ } else {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ }
+ }
+}
+
+// Slow path method resolution
+mirror::AbstractMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* self, bool access_check, InvokeType type) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ bool is_direct = type == kStatic || type == kDirect;
+ mirror::AbstractMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
+ if (UNLIKELY(resolved_method == NULL)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
+ return NULL; // Failure.
+ } else if (UNLIKELY(this_object == NULL && type != kStatic)) {
+ // Maintain interpreter-like semantics where NullPointerException is thrown
+ // after potential NoSuchMethodError from class linker.
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ DCHECK(referrer == throw_location.GetMethod());
+ ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type);
+ return NULL; // Failure.
+ } else {
+ if (!access_check) {
+ if (is_direct) {
+ return resolved_method;
+ } else if (type == kInterface) {
+ mirror::AbstractMethod* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == NULL)) {
+ ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object,
+ referrer);
+ return NULL; // Failure.
+ } else {
+ return interface_method;
+ }
+ } else {
+ mirror::ObjectArray<mirror::AbstractMethod>* vtable;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (type == kSuper) {
+ vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
+ } else {
+ vtable = this_object->GetClass()->GetVTable();
+ }
+ // TODO: eliminate bounds check?
+ return vtable->Get(vtable_index);
+ }
+ } else {
+ // Incompatible class change should have been handled in resolve method.
+ if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
+ ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
+ referrer);
+ return NULL; // Failure.
+ }
+ mirror::Class* methods_class = resolved_method->GetDeclaringClass();
+ mirror::Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
+ !referring_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags()))) {
+ // The referring class can't access the resolved method, this may occur as a result of a
+ // protected method being made public by implementing an interface that re-declares the
+ // method public. Resort to the dex file to determine the correct class for the access check
+ const DexFile& dex_file = *referring_class->GetDexCache()->GetDexFile();
+ methods_class = class_linker->ResolveType(dex_file,
+ dex_file.GetMethodId(method_idx).class_idx_,
+ referring_class);
+ if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
+ ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class,
+ referrer, resolved_method, type);
+ return NULL; // Failure.
+ } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags()))) {
+ ThrowIllegalAccessErrorMethod(referring_class, resolved_method);
+ return NULL; // Failure.
+ }
+ }
+ if (is_direct) {
+ return resolved_method;
+ } else if (type == kInterface) {
+ mirror::AbstractMethod* interface_method =
+ this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ if (UNLIKELY(interface_method == NULL)) {
+ ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object,
+ referrer);
+ return NULL; // Failure.
+ } else {
+ return interface_method;
+ }
+ } else {
+ mirror::ObjectArray<mirror::AbstractMethod>* vtable;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (type == kSuper) {
+ mirror::Class* super_class = referring_class->GetSuperClass();
+ if (LIKELY(super_class != NULL)) {
+ vtable = referring_class->GetSuperClass()->GetVTable();
+ } else {
+ vtable = NULL;
+ }
+ } else {
+ vtable = this_object->GetClass()->GetVTable();
+ }
+ if (LIKELY(vtable != NULL &&
+ vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
+ return vtable->GetWithoutChecks(vtable_index);
+ } else {
+ // Behavior to agree with that of the verifier.
+ MethodHelper mh(resolved_method);
+ ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), mh.GetName(),
+ mh.GetSignature());
+ return NULL; // Failure.
+ }
+ }
+ }
+ }
+}
+
+void ThrowStackOverflowError(Thread* self) {
+ CHECK(!self->IsHandlingStackOverflow()) << "Recursive stack overflow.";
+
+ if (Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()) {
+ // Remove extra entry pushed onto second stack during method tracing.
+ Runtime::Current()->GetInstrumentation()->PopMethodForUnwind(self, false);
+ }
+
+ self->SetStackEndForStackOverflow(); // Allow space on the stack for constructor to execute.
+ JNIEnvExt* env = self->GetJniEnv();
+ std::string msg("stack size ");
+ msg += PrettySize(self->GetStackSize());
+ // Use low-level JNI routine and pre-baked error class to avoid class linking operations that
+ // would consume more stack.
+ int rc = ::art::ThrowNewException(env, WellKnownClasses::java_lang_StackOverflowError,
+ msg.c_str(), NULL);
+ if (rc != JNI_OK) {
+ // TODO: ThrowNewException failed presumably because of an OOME, we continue to throw the OOME
+ // or die in the CHECK below. We may want to throw a pre-baked StackOverflowError
+ // instead.
+ LOG(ERROR) << "Couldn't throw new StackOverflowError because JNI ThrowNew failed.";
+ CHECK(self->IsExceptionPending());
+ }
+ self->ResetDefaultStackEnd(); // Return to default stack size.
+}
+
+JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
+ jobject rcvr_jobj, jobject interface_method_jobj,
+ std::vector<jvalue>& args) {
+ DCHECK(soa.Env()->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
+
+ // Build argument array possibly triggering GC.
+ soa.Self()->AssertThreadSuspensionIsAllowable();
+ jobjectArray args_jobj = NULL;
+ const JValue zero;
+ if (args.size() > 0) {
+ args_jobj = soa.Env()->NewObjectArray(args.size(), WellKnownClasses::java_lang_Object, NULL);
+ if (args_jobj == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ return zero;
+ }
+ for (size_t i = 0; i < args.size(); ++i) {
+ if (shorty[i + 1] == 'L') {
+ jobject val = args.at(i).l;
+ soa.Env()->SetObjectArrayElement(args_jobj, i, val);
+ } else {
+ JValue jv;
+ jv.SetJ(args.at(i).j);
+ mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
+ if (val == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ return zero;
+ }
+ soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set(i, val);
+ }
+ }
+ }
+
+ // Call InvocationHandler.invoke(Object proxy, Method method, Object[] args).
+ jobject inv_hand = soa.Env()->GetObjectField(rcvr_jobj,
+ WellKnownClasses::java_lang_reflect_Proxy_h);
+ jvalue invocation_args[3];
+ invocation_args[0].l = rcvr_jobj;
+ invocation_args[1].l = interface_method_jobj;
+ invocation_args[2].l = args_jobj;
+ jobject result =
+ soa.Env()->CallObjectMethodA(inv_hand,
+ WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
+ invocation_args);
+
+ // Unbox result and handle error conditions.
+ if (LIKELY(!soa.Self()->IsExceptionPending())) {
+ if (shorty[0] == 'V' || (shorty[0] == 'L' && result == NULL)) {
+ // Do nothing.
+ return zero;
+ } else {
+ mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
+ mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
+ mirror::AbstractMethod* interface_method =
+ soa.Decode<mirror::AbstractMethod*>(interface_method_jobj);
+ mirror::Class* result_type = MethodHelper(interface_method).GetReturnType();
+ mirror::AbstractMethod* proxy_method;
+ if (interface_method->GetDeclaringClass()->IsInterface()) {
+ proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(interface_method);
+ } else {
+ // Proxy dispatch to a method defined in Object.
+ DCHECK(interface_method->GetDeclaringClass()->IsObjectClass());
+ proxy_method = interface_method;
+ }
+ ThrowLocation throw_location(rcvr, proxy_method, -1);
+ JValue result_unboxed;
+ if (!UnboxPrimitiveForResult(throw_location, result_ref, result_type, result_unboxed)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return zero;
+ }
+ return result_unboxed;
+ }
+ } else {
+ // In the case of checked exceptions that aren't declared, the exception must be wrapped by
+ // a UndeclaredThrowableException.
+ mirror::Throwable* exception = soa.Self()->GetException(NULL);
+ if (exception->IsCheckedException()) {
+ mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
+ mirror::SynthesizedProxyClass* proxy_class =
+ down_cast<mirror::SynthesizedProxyClass*>(rcvr->GetClass());
+ mirror::AbstractMethod* interface_method =
+ soa.Decode<mirror::AbstractMethod*>(interface_method_jobj);
+ mirror::AbstractMethod* proxy_method =
+ rcvr->GetClass()->FindVirtualMethodForInterface(interface_method);
+ int throws_index = -1;
+ size_t num_virt_methods = proxy_class->NumVirtualMethods();
+ for (size_t i = 0; i < num_virt_methods; i++) {
+ if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+ throws_index = i;
+ break;
+ }
+ }
+ CHECK_NE(throws_index, -1);
+ mirror::ObjectArray<mirror::Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+ mirror::Class* exception_class = exception->GetClass();
+ bool declares_exception = false;
+ for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
+ mirror::Class* declared_exception = declared_exceptions->Get(i);
+ declares_exception = declared_exception->IsAssignableFrom(exception_class);
+ }
+ if (!declares_exception) {
+ ThrowLocation throw_location(rcvr, proxy_method, -1);
+ soa.Self()->ThrowNewWrappedException(throw_location,
+ "Ljava/lang/reflect/UndeclaredThrowableException;",
+ NULL);
+ }
+ }
+ return zero;
+ }
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
new file mode 100644
index 0000000..3f28b5e
--- /dev/null
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2012 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_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
+#define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
+
+#include "class_linker.h"
+#include "common_throws.h"
+#include "dex_file.h"
+#include "indirect_reference_table.h"
+#include "invoke_type.h"
+#include "jni_internal.h"
+#include "mirror/abstract_method.h"
+#include "mirror/array.h"
+#include "mirror/class-inl.h"
+#include "mirror/throwable.h"
+#include "object_utils.h"
+#include "thread.h"
+
+extern "C" void art_interpreter_invoke_handler();
+extern "C" void art_jni_dlsym_lookup_stub();
+extern "C" void art_portable_abstract_method_error_stub();
+extern "C" void art_portable_proxy_invoke_handler();
+extern "C" void art_quick_abstract_method_error_stub();
+extern "C" void art_quick_deoptimize();
+extern "C" void art_quick_instrumentation_entry_from_code(void*);
+extern "C" void art_quick_instrumentation_exit_from_code();
+extern "C" void art_quick_interpreter_entry(void*);
+extern "C" void art_quick_proxy_invoke_handler();
+extern "C" void art_work_around_app_jni_bugs();
+
+namespace art {
+namespace mirror {
+class Class;
+class Field;
+class Object;
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
+// cannot be resolved, throw an error. If it can, use it to create an instance.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx, mirror::AbstractMethod* method,
+ Thread* self,
+ bool access_check)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+ Runtime* runtime = Runtime::Current();
+ if (UNLIKELY(klass == NULL)) {
+ klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
+ if (klass == NULL) {
+ DCHECK(self->IsExceptionPending());
+ return NULL; // Failure
+ }
+ }
+ if (access_check) {
+ if (UNLIKELY(!klass->IsInstantiable())) {
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;",
+ PrettyDescriptor(klass).c_str());
+ return NULL; // Failure
+ }
+ mirror::Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ ThrowIllegalAccessErrorClass(referrer, klass);
+ return NULL; // Failure
+ }
+ }
+ if (!klass->IsInitialized() &&
+ !runtime->GetClassLinker()->EnsureInitialized(klass, true, true)) {
+ DCHECK(self->IsExceptionPending());
+ return NULL; // Failure
+ }
+ return klass->AllocObject(self);
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
+// it cannot be resolved, throw an error. If it can, use it to create an array.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx, mirror::AbstractMethod* method,
+ int32_t component_count,
+ Thread* self, bool access_check)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (UNLIKELY(component_count < 0)) {
+ ThrowNegativeArraySizeException(component_count);
+ return NULL; // Failure
+ }
+ mirror::Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+ if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
+ klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+ if (klass == NULL) { // Error
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return NULL; // Failure
+ }
+ CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+ }
+ if (access_check) {
+ mirror::Class* referrer = method->GetDeclaringClass();
+ if (UNLIKELY(!referrer->CanAccess(klass))) {
+ ThrowIllegalAccessErrorClass(referrer, klass);
+ return NULL; // Failure
+ }
+ }
+ return mirror::Array::Alloc(self, klass, component_count);
+}
+
+extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, mirror::AbstractMethod* method,
+ int32_t component_count,
+ Thread* self, bool access_check)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+// Type of find field operation for fast and slow case.
+enum FindFieldType {
+ InstanceObjectRead,
+ InstanceObjectWrite,
+ InstancePrimitiveRead,
+ InstancePrimitiveWrite,
+ StaticObjectRead,
+ StaticObjectWrite,
+ StaticPrimitiveRead,
+ StaticPrimitiveWrite,
+};
+
+// Slow field find that can initialize classes and may throw exceptions.
+extern mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
+ Thread* self, FindFieldType type, size_t expected_size,
+ bool access_check)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+// Fast path field resolution that can't initialize classes or throw exceptions.
+static inline mirror::Field* FindFieldFast(uint32_t field_idx,
+ const mirror::AbstractMethod* referrer,
+ FindFieldType type, size_t expected_size)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* resolved_field =
+ referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
+ if (UNLIKELY(resolved_field == NULL)) {
+ return NULL;
+ }
+ mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+ // Check class is initiliazed or initializing.
+ if (UNLIKELY(!fields_class->IsInitializing())) {
+ return NULL;
+ }
+ // Check for incompatible class change.
+ bool is_primitive;
+ bool is_set;
+ bool is_static;
+ switch (type) {
+ case InstanceObjectRead: is_primitive = false; is_set = false; is_static = false; break;
+ case InstanceObjectWrite: is_primitive = false; is_set = true; is_static = false; break;
+ case InstancePrimitiveRead: is_primitive = true; is_set = false; is_static = false; break;
+ case InstancePrimitiveWrite: is_primitive = true; is_set = true; is_static = false; break;
+ case StaticObjectRead: is_primitive = false; is_set = false; is_static = true; break;
+ case StaticObjectWrite: is_primitive = false; is_set = true; is_static = true; break;
+ case StaticPrimitiveRead: is_primitive = true; is_set = false; is_static = true; break;
+ case StaticPrimitiveWrite: is_primitive = true; is_set = true; is_static = true; break;
+ default:
+ LOG(FATAL) << "UNREACHABLE"; // Assignment below to avoid GCC warnings.
+ is_primitive = true;
+ is_set = true;
+ is_static = true;
+ break;
+ }
+ if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+ // Incompatible class change.
+ return NULL;
+ }
+ mirror::Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
+ !referring_class->CanAccessMember(fields_class,
+ resolved_field->GetAccessFlags()) ||
+ (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
+ // Illegal access.
+ return NULL;
+ }
+ FieldHelper fh(resolved_field);
+ if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+ fh.FieldSize() != expected_size)) {
+ return NULL;
+ }
+ return resolved_field;
+}
+
+// Fast path method resolution that can't throw exceptions.
+static inline mirror::AbstractMethod* FindMethodFast(uint32_t method_idx,
+ mirror::Object* this_object,
+ const mirror::AbstractMethod* referrer,
+ bool access_check, InvokeType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ bool is_direct = type == kStatic || type == kDirect;
+ if (UNLIKELY(this_object == NULL && !is_direct)) {
+ return NULL;
+ }
+ mirror::AbstractMethod* resolved_method =
+ referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
+ if (UNLIKELY(resolved_method == NULL)) {
+ return NULL;
+ }
+ if (access_check) {
+ // Check for incompatible class change errors and access.
+ bool icce = resolved_method->CheckIncompatibleClassChange(type);
+ if (UNLIKELY(icce)) {
+ return NULL;
+ }
+ mirror::Class* methods_class = resolved_method->GetDeclaringClass();
+ mirror::Class* referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
+ !referring_class->CanAccessMember(methods_class,
+ resolved_method->GetAccessFlags()))) {
+ // Potential illegal access, may need to refine the method's class.
+ return NULL;
+ }
+ }
+ if (type == kInterface) { // Most common form of slow path dispatch.
+ return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ } else if (is_direct) {
+ return resolved_method;
+ } else if (type == kSuper) {
+ return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
+ Get(resolved_method->GetMethodIndex());
+ } else {
+ DCHECK(type == kVirtual);
+ return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
+ }
+}
+
+extern mirror::AbstractMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* self, bool access_check, InvokeType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+ const mirror::AbstractMethod* referrer,
+ Thread* self, bool can_run_clinit,
+ bool verify_access)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
+ if (UNLIKELY(klass == NULL)) {
+ CHECK(self->IsExceptionPending());
+ return NULL; // Failure - Indicate to caller to deliver exception
+ }
+ // Perform access check if necessary.
+ mirror::Class* referring_class = referrer->GetDeclaringClass();
+ if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
+ ThrowIllegalAccessErrorClass(referring_class, klass);
+ return NULL; // Failure - Indicate to caller to deliver exception
+ }
+ // If we're just implementing const-class, we shouldn't call <clinit>.
+ if (!can_run_clinit) {
+ return klass;
+ }
+ // If we are the <clinit> of this class, just return our storage.
+ //
+ // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
+ // running.
+ if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
+ return klass;
+ }
+ if (!class_linker->EnsureInitialized(klass, true, true)) {
+ CHECK(self->IsExceptionPending());
+ return NULL; // Failure - Indicate to caller to deliver exception
+ }
+ referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
+ return klass;
+}
+
+extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline mirror::String* ResolveStringFromCode(const mirror::AbstractMethod* referrer,
+ uint32_t string_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->ResolveString(string_idx, referrer);
+}
+
+static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ UNLOCK_FUNCTION(monitor_lock_) {
+ // Save any pending exception over monitor exit call.
+ mirror::Throwable* saved_exception = NULL;
+ ThrowLocation saved_throw_location;
+ if (UNLIKELY(self->IsExceptionPending())) {
+ saved_exception = self->GetException(&saved_throw_location);
+ self->ClearException();
+ }
+ // Decode locked object and unlock, before popping local references.
+ self->DecodeJObject(locked)->MonitorExit(self);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
+ << saved_exception->Dump()
+ << "\nEncountered second exception during implicit MonitorExit:\n"
+ << self->GetException(NULL)->Dump();
+ }
+ // Restore pending exception.
+ if (saved_exception != NULL) {
+ self->SetException(saved_throw_location, saved_exception);
+ }
+}
+
+static inline void CheckReferenceResult(mirror::Object* o, Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (o == NULL) {
+ return;
+ }
+ mirror::AbstractMethod* m = self->GetCurrentMethod(NULL);
+ if (o == kInvalidIndirectRefObject) {
+ JniAbortF(NULL, "invalid reference returned from %s", PrettyMethod(m).c_str());
+ }
+ // Make sure that the result is an instance of the type this method was expected to return.
+ mirror::Class* return_type = MethodHelper(m).GetReturnType();
+
+ if (!o->InstanceOf(return_type)) {
+ JniAbortF(NULL, "attempt to return an instance of %s from %s",
+ PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
+ }
+}
+
+static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ for (;;) {
+ if (thread->ReadFlag(kCheckpointRequest)) {
+ thread->RunCheckpointFunction();
+ thread->AtomicClearFlag(kCheckpointRequest);
+ } else if (thread->ReadFlag(kSuspendRequest)) {
+ thread->FullSuspendCheck();
+ } else {
+ break;
+ }
+ }
+}
+
+JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty,
+ jobject rcvr_jobj, jobject interface_method_jobj,
+ std::vector<jvalue>& args)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+// Entry point for deoptimization.
+static inline uintptr_t GetDeoptimizationEntryPoint() {
+ return reinterpret_cast<uintptr_t>(art_quick_deoptimize);
+}
+
+// Return address of instrumentation stub.
+static inline void* GetInstrumentationEntryPoint() {
+ return reinterpret_cast<void*>(art_quick_instrumentation_entry_from_code);
+}
+
+// The return_pc of instrumentation exit stub.
+static inline uintptr_t GetInstrumentationExitPc() {
+ return reinterpret_cast<uintptr_t>(art_quick_instrumentation_exit_from_code);
+}
+
+// Return address of interpreter stub.
+static inline void* GetInterpreterEntryPoint() {
+ return reinterpret_cast<void*>(art_quick_interpreter_entry);
+}
+
+static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) {
+ return class_linker->GetPortableResolutionTrampoline();
+}
+
+static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) {
+ return class_linker->GetQuickResolutionTrampoline();
+}
+
+// Return address of resolution trampoline stub for defined compiler.
+static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+ return GetPortableResolutionTrampoline(class_linker);
+#else
+ return GetQuickResolutionTrampoline(class_linker);
+#endif
+}
+
+static inline void* GetPortableAbstractMethodErrorStub() {
+ return reinterpret_cast<void*>(art_portable_abstract_method_error_stub);
+}
+
+static inline void* GetQuickAbstractMethodErrorStub() {
+ return reinterpret_cast<void*>(art_quick_abstract_method_error_stub);
+}
+
+// Return address of abstract method error stub for defined compiler.
+static inline void* GetAbstractMethodErrorStub() {
+#if defined(ART_USE_PORTABLE_COMPILER)
+ return GetPortableAbstractMethodErrorStub();
+#else
+ return GetQuickAbstractMethodErrorStub();
+#endif
+}
+
+static inline void* GetJniDlsymLookupStub() {
+ return reinterpret_cast<void*>(art_jni_dlsym_lookup_stub);
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_H_
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
new file mode 100644
index 0000000..98f7b12
--- /dev/null
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 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 "base/logging.h"
+#include "mirror/abstract_method.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+
+// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
+extern "C" void* artFindNativeMethod(Thread* self) {
+ Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native.
+ DCHECK(Thread::Current() == self);
+ ScopedObjectAccess soa(self);
+
+ mirror::AbstractMethod* method = self->GetCurrentMethod(NULL);
+ DCHECK(method != NULL);
+
+ // Lookup symbol address for method, on failure we'll return NULL with an
+ // exception set, otherwise we return the address of the method we found.
+ void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
+ if (native_code == NULL) {
+ DCHECK(self->IsExceptionPending());
+ return NULL;
+ } else {
+ // Register so that future calls don't come here
+ method->RegisterNative(self, native_code);
+ return native_code;
+ }
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/math_entrypoints.cc b/runtime/entrypoints/math_entrypoints.cc
new file mode 100644
index 0000000..31d13c8
--- /dev/null
+++ b/runtime/entrypoints/math_entrypoints.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 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 "math_entrypoints.h"
+
+namespace art {
+
+extern "C" double art_l2d(int64_t l) {
+ return static_cast<double>(l);
+}
+
+extern "C" float art_l2f(int64_t l) {
+ return static_cast<float>(l);
+}
+
+/*
+ * Float/double conversion requires clamping to min and max of integer form. If
+ * target doesn't support this normally, use these.
+ */
+extern "C" int64_t art_d2l(double d) {
+ static const double kMaxLong = static_cast<double>(static_cast<int64_t>(0x7fffffffffffffffULL));
+ static const double kMinLong = static_cast<double>(static_cast<int64_t>(0x8000000000000000ULL));
+ if (d >= kMaxLong) {
+ return static_cast<int64_t>(0x7fffffffffffffffULL);
+ } else if (d <= kMinLong) {
+ return static_cast<int64_t>(0x8000000000000000ULL);
+ } else if (d != d) { // NaN case
+ return 0;
+ } else {
+ return static_cast<int64_t>(d);
+ }
+}
+
+extern "C" int64_t art_f2l(float f) {
+ static const float kMaxLong = static_cast<float>(static_cast<int64_t>(0x7fffffffffffffffULL));
+ static const float kMinLong = static_cast<float>(static_cast<int64_t>(0x8000000000000000ULL));
+ if (f >= kMaxLong) {
+ return static_cast<int64_t>(0x7fffffffffffffffULL);
+ } else if (f <= kMinLong) {
+ return static_cast<int64_t>(0x8000000000000000ULL);
+ } else if (f != f) { // NaN case
+ return 0;
+ } else {
+ return static_cast<int64_t>(f);
+ }
+}
+
+extern "C" int32_t art_d2i(double d) {
+ static const double kMaxInt = static_cast<double>(static_cast<int32_t>(0x7fffffffUL));
+ static const double kMinInt = static_cast<double>(static_cast<int32_t>(0x80000000UL));
+ if (d >= kMaxInt) {
+ return static_cast<int32_t>(0x7fffffffUL);
+ } else if (d <= kMinInt) {
+ return static_cast<int32_t>(0x80000000UL);
+ } else if (d != d) { // NaN case
+ return 0;
+ } else {
+ return static_cast<int32_t>(d);
+ }
+}
+
+extern "C" int32_t art_f2i(float f) {
+ static const float kMaxInt = static_cast<float>(static_cast<int32_t>(0x7fffffffUL));
+ static const float kMinInt = static_cast<float>(static_cast<int32_t>(0x80000000UL));
+ if (f >= kMaxInt) {
+ return static_cast<int32_t>(0x7fffffffUL);
+ } else if (f <= kMinInt) {
+ return static_cast<int32_t>(0x80000000UL);
+ } else if (f != f) { // NaN case
+ return 0;
+ } else {
+ return static_cast<int32_t>(f);
+ }
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/math_entrypoints.h b/runtime/entrypoints/math_entrypoints.h
new file mode 100644
index 0000000..717c734
--- /dev/null
+++ b/runtime/entrypoints/math_entrypoints.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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_ENTRYPOINTS_MATH_ENTRYPOINTS_H_
+#define ART_RUNTIME_ENTRYPOINTS_MATH_ENTRYPOINTS_H_
+
+#include <stdint.h>
+
+extern "C" double art_l2d(int64_t l);
+extern "C" float art_l2f(int64_t l);
+extern "C" int64_t art_d2l(double d);
+extern "C" int32_t art_d2i(double d);
+extern "C" int64_t art_f2l(float f);
+extern "C" int32_t art_f2i(float f);
+
+#endif // ART_RUNTIME_ENTRYPOINTS_MATH_ENTRYPOINTS_H_
diff --git a/runtime/entrypoints/math_entrypoints_test.cc b/runtime/entrypoints/math_entrypoints_test.cc
new file mode 100644
index 0000000..ca8b931
--- /dev/null
+++ b/runtime/entrypoints/math_entrypoints_test.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 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 "math_entrypoints.h"
+
+#include "common_test.h"
+#include <limits>
+
+namespace art {
+
+class MathEntrypointsTest : public CommonTest {};
+
+TEST_F(MathEntrypointsTest, DoubleToLong) {
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), art_d2l(1.85e19));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), art_d2l(-1.85e19));
+ EXPECT_EQ(0LL, art_d2l(0));
+ EXPECT_EQ(1LL, art_d2l(1.0));
+ EXPECT_EQ(10LL, art_d2l(10.0));
+ EXPECT_EQ(100LL, art_d2l(100.0));
+ EXPECT_EQ(-1LL, art_d2l(-1.0));
+ EXPECT_EQ(-10LL, art_d2l(-10.0));
+ EXPECT_EQ(-100LL, art_d2l(-100.0));
+}
+
+TEST_F(MathEntrypointsTest, FloatToLong) {
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), art_f2l(1.85e19));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), art_f2l(-1.85e19));
+ EXPECT_EQ(0LL, art_f2l(0));
+ EXPECT_EQ(1LL, art_f2l(1.0));
+ EXPECT_EQ(10LL, art_f2l(10.0));
+ EXPECT_EQ(100LL, art_f2l(100.0));
+ EXPECT_EQ(-1LL, art_f2l(-1.0));
+ EXPECT_EQ(-10LL, art_f2l(-10.0));
+ EXPECT_EQ(-100LL, art_f2l(-100.0));
+}
+
+TEST_F(MathEntrypointsTest, DoubleToInt) {
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), art_d2i(4.3e9));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), art_d2i(-4.3e9));
+ EXPECT_EQ(0L, art_d2i(0));
+ EXPECT_EQ(1L, art_d2i(1.0));
+ EXPECT_EQ(10L, art_d2i(10.0));
+ EXPECT_EQ(100L, art_d2i(100.0));
+ EXPECT_EQ(-1L, art_d2i(-1.0));
+ EXPECT_EQ(-10L, art_d2i(-10.0));
+ EXPECT_EQ(-100L, art_d2i(-100.0));
+}
+
+TEST_F(MathEntrypointsTest, FloatToInt) {
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), art_f2i(4.3e9));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), art_f2i(-4.3e9));
+ EXPECT_EQ(0L, art_f2i(0));
+ EXPECT_EQ(1L, art_f2i(1.0));
+ EXPECT_EQ(10L, art_f2i(10.0));
+ EXPECT_EQ(100L, art_f2i(100.0));
+ EXPECT_EQ(-1L, art_f2i(-1.0));
+ EXPECT_EQ(-10L, art_f2i(-10.0));
+ EXPECT_EQ(-100L, art_f2i(-100.0));
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_alloc_entrypoints.cc b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
new file mode 100644
index 0000000..2869269
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_alloc_entrypoints.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" mirror::Object* art_portable_alloc_object_from_code(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return AllocObjectFromCode(type_idx, referrer, thread, false);
+}
+
+extern "C" mirror::Object* art_portable_alloc_object_from_code_with_access_check(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return AllocObjectFromCode(type_idx, referrer, thread, true);
+}
+
+extern "C" mirror::Object* art_portable_alloc_array_from_code(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ uint32_t length,
+ Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return AllocArrayFromCode(type_idx, referrer, length, self, false);
+}
+
+extern "C" mirror::Object* art_portable_alloc_array_from_code_with_access_check(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ uint32_t length,
+ Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return AllocArrayFromCode(type_idx, referrer, length, self, true);
+}
+
+extern "C" mirror::Object* art_portable_check_and_alloc_array_from_code(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ uint32_t length,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, false);
+}
+
+extern "C" mirror::Object* art_portable_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ uint32_t length,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, true);
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_argument_visitor.h b/runtime/entrypoints/portable/portable_argument_visitor.h
new file mode 100644
index 0000000..f268baf
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_argument_visitor.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 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_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
+#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
+
+#include "object_utils.h"
+
+namespace art {
+
+// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
+class PortableArgumentVisitor {
+ public:
+// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
+// Size of Runtime::kRefAndArgs callee save frame.
+// Size of Method* and register parameters in out stack arguments.
+#if defined(__arm__)
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
+#define PORTABLE_STACK_ARG_SKIP 0
+#elif defined(__mips__)
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
+#define PORTABLE_STACK_ARG_SKIP 16
+#elif defined(__i386__)
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
+#define PORTABLE_STACK_ARG_SKIP 4
+#else
+#error "Unsupported architecture"
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
+#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
+#define PORTABLE_STACK_ARG_SKIP 0
+#endif
+
+ PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
+ caller_mh_(caller_mh),
+ args_in_regs_(ComputeArgsInRegs(caller_mh)),
+ num_params_(caller_mh.NumArgs()),
+ reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
+ stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
+ + PORTABLE_STACK_ARG_SKIP),
+ cur_args_(reg_args_),
+ cur_arg_index_(0),
+ param_index_(0) {
+ }
+
+ virtual ~PortableArgumentVisitor() {}
+
+ virtual void Visit() = 0;
+
+ bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return caller_mh_.IsParamAReference(param_index_);
+ }
+
+ bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return caller_mh_.IsParamALongOrDouble(param_index_);
+ }
+
+ Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return caller_mh_.GetParamPrimitiveType(param_index_);
+ }
+
+ byte* GetParamAddress() const {
+ return cur_args_ + (cur_arg_index_ * kPointerSize);
+ }
+
+ void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
+#if (defined(__arm__) || defined(__mips__))
+ if (IsParamALongOrDouble() && cur_arg_index_ == 2) {
+ break;
+ }
+#endif
+ Visit();
+ cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
+ param_index_++;
+ }
+ cur_args_ = stack_args_;
+ cur_arg_index_ = 0;
+ while (param_index_ < num_params_) {
+#if (defined(__arm__) || defined(__mips__))
+ if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) {
+ cur_arg_index_++;
+ }
+#endif
+ Visit();
+ cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
+ param_index_++;
+ }
+ }
+
+ private:
+ static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+#if (defined(__i386__))
+ return 0;
+#else
+ size_t args_in_regs = 0;
+ size_t num_params = mh.NumArgs();
+ for (size_t i = 0; i < num_params; i++) {
+ args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
+ if (args_in_regs > 3) {
+ args_in_regs = 3;
+ break;
+ }
+ }
+ return args_in_regs;
+#endif
+ }
+ MethodHelper& caller_mh_;
+ const size_t args_in_regs_;
+ const size_t num_params_;
+ byte* const reg_args_;
+ byte* const stack_args_;
+ byte* cur_args_;
+ size_t cur_arg_index_;
+ size_t param_index_;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ARGUMENT_VISITOR_H_
diff --git a/runtime/entrypoints/portable/portable_cast_entrypoints.cc b/runtime/entrypoints/portable/portable_cast_entrypoints.cc
new file mode 100644
index 0000000..d343c5d
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_cast_entrypoints.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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 "common_throws.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" int32_t art_portable_is_assignable_from_code(const mirror::Class* dest_type,
+ const mirror::Class* src_type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(dest_type != NULL);
+ DCHECK(src_type != NULL);
+ return dest_type->IsAssignableFrom(src_type) ? 1 : 0;
+}
+
+extern "C" void art_portable_check_cast_from_code(const mirror::Class* dest_type,
+ const mirror::Class* src_type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
+ DCHECK(src_type->IsClass()) << PrettyClass(src_type);
+ if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) {
+ ThrowClassCastException(dest_type, src_type);
+ }
+}
+
+extern "C" void art_portable_check_put_array_element_from_code(const mirror::Object* element,
+ const mirror::Object* array)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (element == NULL) {
+ return;
+ }
+ DCHECK(array != NULL);
+ mirror::Class* array_class = array->GetClass();
+ DCHECK(array_class != NULL);
+ mirror::Class* component_type = array_class->GetComponentType();
+ mirror::Class* element_class = element->GetClass();
+ if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
+ ThrowArrayStoreException(element_class, array_class);
+ }
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
new file mode 100644
index 0000000..bdab587
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_dexcache_entrypoints.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "gc/accounting/card_table-inl.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" mirror::Object* art_portable_initialize_static_storage_from_code(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return ResolveVerifyAndClinit(type_idx, referrer, thread, true, false);
+}
+
+extern "C" mirror::Object* art_portable_initialize_type_from_code(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return ResolveVerifyAndClinit(type_idx, referrer, thread, false, false);
+}
+
+extern "C" mirror::Object* art_portable_initialize_type_and_verify_access_from_code(uint32_t type_idx,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Called when caller isn't guaranteed to have access to a type and the dex cache may be
+ // unpopulated
+ return ResolveVerifyAndClinit(type_idx, referrer, thread, false, true);
+}
+
+extern "C" mirror::Object* art_portable_resolve_string_from_code(mirror::AbstractMethod* referrer,
+ uint32_t string_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return ResolveStringFromCode(referrer, string_idx);
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h
new file mode 100644
index 0000000..a229c76
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_entrypoints.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 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_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_
+#define ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_
+
+#include "dex_file-inl.h"
+#include "runtime.h"
+
+namespace art {
+namespace mirror {
+ class AbstractMethod;
+ class Object;
+} // namespace mirror
+class Thread;
+
+#define PORTABLE_ENTRYPOINT_OFFSET(x) \
+ (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, portable_entrypoints_)) + \
+ static_cast<uintptr_t>(OFFSETOF_MEMBER(PortableEntryPoints, x)))
+
+// Pointers to functions that are called by code generated by compiler's adhering to the portable
+// compiler ABI.
+struct PACKED(4) PortableEntryPoints {
+ // Invocation
+ const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+ mirror::AbstractMethod**, Thread*);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ENTRYPOINTS_PORTABLE_PORTABLE_ENTRYPOINTS_H_
diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc
new file mode 100644
index 0000000..aa0f03c
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_field_entrypoints.cc
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/field-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" int32_t art_portable_set32_static_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ int32_t new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx,
+ referrer,
+ StaticPrimitiveWrite,
+ sizeof(uint32_t));
+ if (LIKELY(field != NULL)) {
+ field->Set32(field->GetDeclaringClass(), new_value);
+ return 0;
+ }
+ field = FindFieldFromCode(field_idx,
+ referrer,
+ Thread::Current(),
+ StaticPrimitiveWrite,
+ sizeof(uint32_t),
+ true);
+ if (LIKELY(field != NULL)) {
+ field->Set32(field->GetDeclaringClass(), new_value);
+ return 0;
+ }
+ return -1;
+}
+
+extern "C" int32_t art_portable_set64_static_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ int64_t new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t));
+ if (LIKELY(field != NULL)) {
+ field->Set64(field->GetDeclaringClass(), new_value);
+ return 0;
+ }
+ field = FindFieldFromCode(field_idx,
+ referrer,
+ Thread::Current(),
+ StaticPrimitiveWrite,
+ sizeof(uint64_t),
+ true);
+ if (LIKELY(field != NULL)) {
+ field->Set64(field->GetDeclaringClass(), new_value);
+ return 0;
+ }
+ return -1;
+}
+
+extern "C" int32_t art_portable_set_obj_static_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite,
+ sizeof(mirror::Object*));
+ if (LIKELY(field != NULL)) {
+ field->SetObj(field->GetDeclaringClass(), new_value);
+ return 0;
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ StaticObjectWrite, sizeof(mirror::Object*), true);
+ if (LIKELY(field != NULL)) {
+ field->SetObj(field->GetDeclaringClass(), new_value);
+ return 0;
+ }
+ return -1;
+}
+
+extern "C" int32_t art_portable_get32_static_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get32(field->GetDeclaringClass());
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ StaticPrimitiveRead, sizeof(uint32_t), true);
+ if (LIKELY(field != NULL)) {
+ return field->Get32(field->GetDeclaringClass());
+ }
+ return 0;
+}
+
+extern "C" int64_t art_portable_get64_static_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get64(field->GetDeclaringClass());
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ StaticPrimitiveRead, sizeof(uint64_t), true);
+ if (LIKELY(field != NULL)) {
+ return field->Get64(field->GetDeclaringClass());
+ }
+ return 0;
+}
+
+extern "C" mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead,
+ sizeof(mirror::Object*));
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(field->GetDeclaringClass());
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ StaticObjectRead, sizeof(mirror::Object*), true);
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(field->GetDeclaringClass());
+ }
+ return 0;
+}
+
+extern "C" int32_t art_portable_set32_instance_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* obj, uint32_t new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t));
+ if (LIKELY(field != NULL)) {
+ field->Set32(obj, new_value);
+ return 0;
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ InstancePrimitiveWrite, sizeof(uint32_t), true);
+ if (LIKELY(field != NULL)) {
+ field->Set32(obj, new_value);
+ return 0;
+ }
+ return -1;
+}
+
+extern "C" int32_t art_portable_set64_instance_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* obj, int64_t new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t));
+ if (LIKELY(field != NULL)) {
+ field->Set64(obj, new_value);
+ return 0;
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ InstancePrimitiveWrite, sizeof(uint64_t), true);
+ if (LIKELY(field != NULL)) {
+ field->Set64(obj, new_value);
+ return 0;
+ }
+ return -1;
+}
+
+extern "C" int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* obj,
+ mirror::Object* new_value)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
+ sizeof(mirror::Object*));
+ if (LIKELY(field != NULL)) {
+ field->SetObj(obj, new_value);
+ return 0;
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ InstanceObjectWrite, sizeof(mirror::Object*), true);
+ if (LIKELY(field != NULL)) {
+ field->SetObj(obj, new_value);
+ return 0;
+ }
+ return -1;
+}
+
+extern "C" int32_t art_portable_get32_instance_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* obj)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint32_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get32(obj);
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ InstancePrimitiveRead, sizeof(uint32_t), true);
+ if (LIKELY(field != NULL)) {
+ return field->Get32(obj);
+ }
+ return 0;
+}
+
+extern "C" int64_t art_portable_get64_instance_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* obj)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint64_t));
+ if (LIKELY(field != NULL)) {
+ return field->Get64(obj);
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ InstancePrimitiveRead, sizeof(uint64_t), true);
+ if (LIKELY(field != NULL)) {
+ return field->Get64(obj);
+ }
+ return 0;
+}
+
+extern "C" mirror::Object* art_portable_get_obj_instance_from_code(uint32_t field_idx,
+ mirror::AbstractMethod* referrer,
+ mirror::Object* obj)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Field* field = FindFieldFast(field_idx, referrer, InstanceObjectRead,
+ sizeof(mirror::Object*));
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(obj);
+ }
+ field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+ InstanceObjectRead, sizeof(mirror::Object*), true);
+ if (LIKELY(field != NULL)) {
+ return field->GetObj(obj);
+ }
+ return 0;
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
new file mode 100644
index 0000000..771608b
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_fillarray_entrypoints.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 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 "dex_instruction.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" void art_portable_fill_array_data_from_code(mirror::AbstractMethod* method,
+ uint32_t dex_pc,
+ mirror::Array* array,
+ uint32_t payload_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
+ const Instruction::ArrayDataPayload* payload =
+ reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item->insns_ + payload_offset);
+ DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
+ if (UNLIKELY(array == NULL)) {
+ ThrowNullPointerException(NULL, "null array in FILL_ARRAY_DATA");
+ return; // Error
+ }
+ DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
+ if (UNLIKELY(static_cast<int32_t>(payload->element_count) > array->GetLength())) {
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "failed FILL_ARRAY_DATA; length=%d, index=%d",
+ array->GetLength(), payload->element_count - 1);
+ return; // Error
+ }
+ uint32_t size_in_bytes = payload->element_count * payload->element_width;
+ memcpy(array->GetRawData(payload->element_width), payload->data, size_in_bytes);
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
new file mode 100644
index 0000000..5911ba3
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/dex_cache-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+static mirror::AbstractMethod* FindMethodHelper(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* caller_method,
+ bool access_check,
+ InvokeType type,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::AbstractMethod* method = FindMethodFast(method_idx,
+ this_object,
+ caller_method,
+ access_check,
+ type);
+ if (UNLIKELY(method == NULL)) {
+ method = FindMethodFromCode(method_idx, this_object, caller_method,
+ thread, access_check, type);
+ if (UNLIKELY(method == NULL)) {
+ CHECK(thread->IsExceptionPending());
+ return 0; // failure
+ }
+ }
+ DCHECK(!thread->IsExceptionPending());
+ const void* code = method->GetEntryPointFromCompiledCode();
+
+ // When we return, the caller will branch to this address, so it had better not be 0!
+ if (UNLIKELY(code == NULL)) {
+ MethodHelper mh(method);
+ LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method)
+ << " location: " << mh.GetDexFile().GetLocation();
+ }
+ return method;
+}
+
+extern "C" mirror::Object* art_portable_find_static_method_from_code_with_access_check(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kStatic, thread);
+}
+
+extern "C" mirror::Object* art_portable_find_direct_method_from_code_with_access_check(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kDirect, thread);
+}
+
+extern "C" mirror::Object* art_portable_find_virtual_method_from_code_with_access_check(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kVirtual, thread);
+}
+
+extern "C" mirror::Object* art_portable_find_super_method_from_code_with_access_check(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kSuper, thread);
+}
+
+extern "C" mirror::Object* art_portable_find_interface_method_from_code_with_access_check(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FindMethodHelper(method_idx, this_object, referrer, true, kInterface, thread);
+}
+
+extern "C" mirror::Object* art_portable_find_interface_method_from_code(uint32_t method_idx,
+ mirror::Object* this_object,
+ mirror::AbstractMethod* referrer,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FindMethodHelper(method_idx, this_object, referrer, false, kInterface, thread);
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_jni_entrypoints.cc b/runtime/entrypoints/portable/portable_jni_entrypoints.cc
new file mode 100644
index 0000000..8df16ae
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_jni_entrypoints.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "thread-inl.h"
+
+namespace art {
+
+// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
+extern "C" uint32_t art_portable_jni_method_start(Thread* self)
+ UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) {
+ JNIEnvExt* env = self->GetJniEnv();
+ uint32_t saved_local_ref_cookie = env->local_ref_cookie;
+ env->local_ref_cookie = env->locals.GetSegmentState();
+ self->TransitionFromRunnableToSuspended(kNative);
+ return saved_local_ref_cookie;
+}
+
+extern "C" uint32_t art_portable_jni_method_start_synchronized(jobject to_lock, Thread* self)
+ UNLOCK_FUNCTION(Locks::mutator_lock_) {
+ self->DecodeJObject(to_lock)->MonitorEnter(self);
+ return art_portable_jni_method_start(self);
+}
+
+static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
+ JNIEnvExt* env = self->GetJniEnv();
+ env->locals.SetSegmentState(env->local_ref_cookie);
+ env->local_ref_cookie = saved_local_ref_cookie;
+}
+
+extern "C" void art_portable_jni_method_end(uint32_t saved_local_ref_cookie, Thread* self)
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
+ self->TransitionFromSuspendedToRunnable();
+ PopLocalReferences(saved_local_ref_cookie, self);
+}
+
+
+extern "C" void art_portable_jni_method_end_synchronized(uint32_t saved_local_ref_cookie,
+ jobject locked,
+ Thread* self)
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
+ self->TransitionFromSuspendedToRunnable();
+ UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
+ PopLocalReferences(saved_local_ref_cookie, self);
+}
+
+extern "C" mirror::Object* art_portable_jni_method_end_with_reference(jobject result,
+ uint32_t saved_local_ref_cookie,
+ Thread* self)
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
+ self->TransitionFromSuspendedToRunnable();
+ mirror::Object* o = self->DecodeJObject(result); // Must decode before pop.
+ PopLocalReferences(saved_local_ref_cookie, self);
+ // Process result.
+ if (UNLIKELY(self->GetJniEnv()->check_jni)) {
+ if (self->IsExceptionPending()) {
+ return NULL;
+ }
+ CheckReferenceResult(o, self);
+ }
+ return o;
+}
+
+extern "C" mirror::Object* art_portable_jni_method_end_with_reference_synchronized(jobject result,
+ uint32_t saved_local_ref_cookie,
+ jobject locked,
+ Thread* self)
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
+ self->TransitionFromSuspendedToRunnable();
+ UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
+ mirror::Object* o = self->DecodeJObject(result);
+ PopLocalReferences(saved_local_ref_cookie, self);
+ // Process result.
+ if (UNLIKELY(self->GetJniEnv()->check_jni)) {
+ if (self->IsExceptionPending()) {
+ return NULL;
+ }
+ CheckReferenceResult(o, self);
+ }
+ return o;
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_lock_entrypoints.cc b/runtime/entrypoints/portable/portable_lock_entrypoints.cc
new file mode 100644
index 0000000..44d3da9
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_lock_entrypoints.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" void art_portable_lock_object_from_code(mirror::Object* obj, Thread* thread)
+ EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) {
+ DCHECK(obj != NULL); // Assumed to have been checked before entry.
+ obj->MonitorEnter(thread); // May block.
+ DCHECK(thread->HoldsLock(obj));
+ // Only possible exception is NPE and is handled before entry.
+ DCHECK(!thread->IsExceptionPending());
+}
+
+extern "C" void art_portable_unlock_object_from_code(mirror::Object* obj, Thread* thread)
+ UNLOCK_FUNCTION(monitor_lock_) {
+ DCHECK(obj != NULL); // Assumed to have been checked before entry.
+ // MonitorExit may throw exception.
+ obj->MonitorExit(thread);
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_proxy_entrypoints.cc b/runtime/entrypoints/portable/portable_proxy_entrypoints.cc
new file mode 100644
index 0000000..3db39cd
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_proxy_entrypoints.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "portable_argument_visitor.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
+// to jobjects.
+class BuildPortableArgumentVisitor : public PortableArgumentVisitor {
+ public:
+ BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp,
+ ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
+ PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
+
+ virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ jvalue val;
+ Primitive::Type type = GetParamPrimitiveType();
+ switch (type) {
+ case Primitive::kPrimNot: {
+ mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress());
+ val.l = soa_.AddLocalReference<jobject>(obj);
+ break;
+ }
+ case Primitive::kPrimLong: // Fall-through.
+ case Primitive::kPrimDouble:
+ val.j = *reinterpret_cast<jlong*>(GetParamAddress());
+ break;
+ case Primitive::kPrimBoolean: // Fall-through.
+ case Primitive::kPrimByte: // Fall-through.
+ case Primitive::kPrimChar: // Fall-through.
+ case Primitive::kPrimShort: // Fall-through.
+ case Primitive::kPrimInt: // Fall-through.
+ case Primitive::kPrimFloat:
+ val.i = *reinterpret_cast<jint*>(GetParamAddress());
+ break;
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "UNREACHABLE";
+ val.j = 0;
+ break;
+ }
+ args_.push_back(val);
+ }
+
+ private:
+ ScopedObjectAccessUnchecked& soa_;
+ std::vector<jvalue>& args_;
+
+ DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor);
+};
+
+// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
+// which is responsible for recording callee save registers. We explicitly place into jobjects the
+// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
+// field within the proxy object, which will box the primitive arguments and deal with error cases.
+extern "C" uint64_t artPortableProxyInvokeHandler(mirror::AbstractMethod* proxy_method,
+ mirror::Object* receiver,
+ Thread* self, mirror::AbstractMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
+ const char* old_cause =
+ self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
+ self->VerifyStack();
+ // Start new JNI local reference state.
+ JNIEnvExt* env = self->GetJniEnv();
+ ScopedObjectAccessUnchecked soa(env);
+ ScopedJniEnvLocalRefState env_state(env);
+ // Create local ref. copies of proxy method and the receiver.
+ jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
+
+ // Placing arguments into args vector and remove the receiver.
+ MethodHelper proxy_mh(proxy_method);
+ std::vector<jvalue> args;
+ BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
+ local_ref_visitor.VisitArguments();
+ args.erase(args.begin());
+
+ // Convert proxy method into expected interface method.
+ mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
+ DCHECK(interface_method != NULL);
+ DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
+ jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
+
+ // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
+ // that performs allocations.
+ self->EndAssertNoThreadSuspension(old_cause);
+ JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
+ rcvr_jobj, interface_method_jobj, args);
+ return result.GetJ();
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_stub_entrypoints.cc b/runtime/entrypoints/portable/portable_stub_entrypoints.cc
new file mode 100644
index 0000000..c510c65
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_stub_entrypoints.cc
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012 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 "dex_instruction-inl.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+// Lazily resolve a method for portable. Called by stub code.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+ mirror::Object* receiver,
+ mirror::AbstractMethod** called_addr,
+ Thread* thread)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint32_t dex_pc;
+ mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc);
+
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ InvokeType invoke_type;
+ bool is_range;
+ if (called->IsRuntimeMethod()) {
+ const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
+ CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+ const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+ Instruction::Code instr_code = instr->Opcode();
+ switch (instr_code) {
+ case Instruction::INVOKE_DIRECT:
+ invoke_type = kDirect;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_DIRECT_RANGE:
+ invoke_type = kDirect;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_STATIC:
+ invoke_type = kStatic;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_STATIC_RANGE:
+ invoke_type = kStatic;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_SUPER:
+ invoke_type = kSuper;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_SUPER_RANGE:
+ invoke_type = kSuper;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_VIRTUAL:
+ invoke_type = kVirtual;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_VIRTUAL_RANGE:
+ invoke_type = kVirtual;
+ is_range = true;
+ break;
+ case Instruction::INVOKE_INTERFACE:
+ invoke_type = kInterface;
+ is_range = false;
+ break;
+ case Instruction::INVOKE_INTERFACE_RANGE:
+ invoke_type = kInterface;
+ is_range = true;
+ break;
+ default:
+ LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
+ // Avoid used uninitialized warnings.
+ invoke_type = kDirect;
+ is_range = true;
+ }
+ uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
+ called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
+ // Refine called method based on receiver.
+ if (invoke_type == kVirtual) {
+ called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+ } else if (invoke_type == kInterface) {
+ called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+ }
+ } else {
+ CHECK(called->IsStatic()) << PrettyMethod(called);
+ invoke_type = kStatic;
+ }
+ const void* code = NULL;
+ if (LIKELY(!thread->IsExceptionPending())) {
+ // Incompatible class change should have been handled in resolve method.
+ CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+ // Ensure that the called method's class is initialized.
+ mirror::Class* called_class = called->GetDeclaringClass();
+ linker->EnsureInitialized(called_class, true, true);
+ if (LIKELY(called_class->IsInitialized())) {
+ code = called->GetEntryPointFromCompiledCode();
+ // TODO: remove this after we solve the link issue.
+ { // for lazy link.
+ if (code == NULL) {
+ code = linker->GetOatCodeFor(called);
+ }
+ }
+ } else if (called_class->IsInitializing()) {
+ if (invoke_type == kStatic) {
+ // Class is still initializing, go to oat and grab code (trampoline must be left in place
+ // until class is initialized to stop races between threads).
+ code = linker->GetOatCodeFor(called);
+ } else {
+ // No trampoline for non-static methods.
+ code = called->GetEntryPointFromCompiledCode();
+ // TODO: remove this after we solve the link issue.
+ { // for lazy link.
+ if (code == NULL) {
+ code = linker->GetOatCodeFor(called);
+ }
+ }
+ }
+ } else {
+ DCHECK(called_class->IsErroneous());
+ }
+ }
+ if (LIKELY(code != NULL)) {
+ // Expect class to at least be initializing.
+ DCHECK(called->GetDeclaringClass()->IsInitializing());
+ // Don't want infinite recursion.
+ DCHECK(code != GetResolutionTrampoline(linker));
+ // Set up entry into main method
+ *called_addr = called;
+ }
+ return code;
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
new file mode 100644
index 0000000..dac7388
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method.h"
+#include "mirror/object-inl.h"
+#include "verifier/dex_gc_map.h"
+#include "stack.h"
+
+namespace art {
+
+class ShadowFrameCopyVisitor : public StackVisitor {
+ public:
+ explicit ShadowFrameCopyVisitor(Thread* self) : StackVisitor(self, NULL), prev_frame_(NULL),
+ top_frame_(NULL) {}
+
+ bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (IsShadowFrame()) {
+ ShadowFrame* cur_frame = GetCurrentShadowFrame();
+ size_t num_regs = cur_frame->NumberOfVRegs();
+ mirror::AbstractMethod* method = cur_frame->GetMethod();
+ uint32_t dex_pc = cur_frame->GetDexPC();
+ ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
+
+ const uint8_t* gc_map = method->GetNativeGcMap();
+ uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
+ (gc_map[1] << 16) |
+ (gc_map[2] << 8) |
+ (gc_map[3] << 0));
+ verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
+ const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
+ for (size_t reg = 0; reg < num_regs; ++reg) {
+ if (TestBitmap(reg, reg_bitmap)) {
+ new_frame->SetVRegReference(reg, cur_frame->GetVRegReference(reg));
+ } else {
+ new_frame->SetVReg(reg, cur_frame->GetVReg(reg));
+ }
+ }
+
+ if (prev_frame_ != NULL) {
+ prev_frame_->SetLink(new_frame);
+ } else {
+ top_frame_ = new_frame;
+ }
+ prev_frame_ = new_frame;
+ }
+ return true;
+ }
+
+ ShadowFrame* GetShadowFrameCopy() {
+ return top_frame_;
+ }
+
+ private:
+ static bool TestBitmap(int reg, const uint8_t* reg_vector) {
+ return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
+ }
+
+ ShadowFrame* prev_frame_;
+ ShadowFrame* top_frame_;
+};
+
+extern "C" void art_portable_test_suspend_from_code(Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ CheckSuspend(self);
+ if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) {
+ // Save out the shadow frame to the heap
+ ShadowFrameCopyVisitor visitor(self);
+ visitor.WalkStack(true);
+ self->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy());
+ self->SetDeoptimizationReturnValue(JValue());
+ self->SetException(ThrowLocation(), reinterpret_cast<mirror::Throwable*>(-1));
+ }
+}
+
+extern "C" ShadowFrame* art_portable_push_shadow_frame_from_code(Thread* thread,
+ ShadowFrame* new_shadow_frame,
+ mirror::AbstractMethod* method,
+ uint32_t num_vregs) {
+ ShadowFrame* old_frame = thread->PushShadowFrame(new_shadow_frame);
+ new_shadow_frame->SetMethod(method);
+ new_shadow_frame->SetNumberOfVRegs(num_vregs);
+ return old_frame;
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/portable/portable_throw_entrypoints.cc b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
new file mode 100644
index 0000000..4b2b46b
--- /dev/null
+++ b/runtime/entrypoints/portable/portable_throw_entrypoints.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+
+namespace art {
+
+extern "C" void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ThrowArithmeticExceptionDivideByZero();
+}
+
+extern "C" void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ThrowArrayIndexOutOfBoundsException(index, length);
+}
+
+extern "C" void art_portable_throw_no_such_method_from_code(int32_t method_idx)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ThrowNoSuchMethodError(method_idx);
+}
+
+extern "C" void art_portable_throw_null_pointer_exception_from_code(uint32_t dex_pc)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // TODO: remove dex_pc argument from caller.
+ UNUSED(dex_pc);
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ ThrowNullPointerExceptionFromDexPC(throw_location);
+}
+
+extern "C" void art_portable_throw_stack_overflow_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ThrowStackOverflowError(Thread::Current());
+}
+
+extern "C" void art_portable_throw_exception_from_code(mirror::Throwable* exception)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ if (exception == NULL) {
+ ThrowNullPointerException(NULL, "throw with null exception");
+ } else {
+ self->SetException(throw_location, exception);
+ }
+}
+
+extern "C" void* art_portable_get_and_clear_exception(Thread* self)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(self->IsExceptionPending());
+ // TODO: make this inline.
+ mirror::Throwable* exception = self->GetException(NULL);
+ self->ClearException();
+ return exception;
+}
+
+extern "C" int32_t art_portable_find_catch_block_from_code(mirror::AbstractMethod* current_method,
+ uint32_t ti_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current(); // TODO: make an argument.
+ ThrowLocation throw_location;
+ mirror::Throwable* exception = self->GetException(&throw_location);
+ // Check for special deoptimization exception.
+ if (UNLIKELY(reinterpret_cast<int32_t>(exception) == -1)) {
+ return -1;
+ }
+ mirror::Class* exception_type = exception->GetClass();
+ MethodHelper mh(current_method);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ DCHECK_LT(ti_offset, code_item->tries_size_);
+ const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
+
+ int iter_index = 0;
+ int result = -1;
+ uint32_t catch_dex_pc = -1;
+ // Iterate over the catch handlers associated with dex_pc
+ for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) {
+ uint16_t iter_type_idx = it.GetHandlerTypeIndex();
+ // Catch all case
+ if (iter_type_idx == DexFile::kDexNoIndex16) {
+ catch_dex_pc = it.GetHandlerAddress();
+ result = iter_index;
+ break;
+ }
+ // Does this catch exception type apply?
+ mirror::Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
+ if (UNLIKELY(iter_exception_type == NULL)) {
+ // TODO: check, the verifier (class linker?) should take care of resolving all exception
+ // classes early.
+ LOG(WARNING) << "Unresolved exception class when finding catch block: "
+ << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
+ } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
+ catch_dex_pc = it.GetHandlerAddress();
+ result = iter_index;
+ break;
+ }
+ ++iter_index;
+ }
+ if (result != -1) {
+ // Handler found.
+ Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(self,
+ throw_location,
+ current_method,
+ catch_dex_pc,
+ exception);
+ }
+ return result;
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index f66fc84..9ed802a 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -15,11 +15,11 @@
*/
#include "callee_save_frame.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/class-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
-#include "runtime_support.h"
namespace art {
diff --git a/runtime/entrypoints/quick/quick_argument_visitor.h b/runtime/entrypoints/quick/quick_argument_visitor.h
index 4f81151..35fa972 100644
--- a/runtime/entrypoints/quick/quick_argument_visitor.h
+++ b/runtime/entrypoints/quick/quick_argument_visitor.h
@@ -22,116 +22,6 @@
namespace art {
// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
-class PortableArgumentVisitor {
- public:
-// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
-// Size of Runtime::kRefAndArgs callee save frame.
-// Size of Method* and register parameters in out stack arguments.
-#if defined(__arm__)
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
-#define PORTABLE_STACK_ARG_SKIP 0
-#elif defined(__mips__)
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
-#define PORTABLE_STACK_ARG_SKIP 16
-#elif defined(__i386__)
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
-#define PORTABLE_STACK_ARG_SKIP 4
-#else
-#error "Unsupported architecture"
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
-#define PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
-#define PORTABLE_STACK_ARG_SKIP 0
-#endif
-
- PortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
- caller_mh_(caller_mh),
- args_in_regs_(ComputeArgsInRegs(caller_mh)),
- num_params_(caller_mh.NumArgs()),
- reg_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
- stack_args_(reinterpret_cast<byte*>(sp) + PORTABLE_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
- + PORTABLE_STACK_ARG_SKIP),
- cur_args_(reg_args_),
- cur_arg_index_(0),
- param_index_(0) {
- }
-
- virtual ~PortableArgumentVisitor() {}
-
- virtual void Visit() = 0;
-
- bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return caller_mh_.IsParamAReference(param_index_);
- }
-
- bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return caller_mh_.IsParamALongOrDouble(param_index_);
- }
-
- Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return caller_mh_.GetParamPrimitiveType(param_index_);
- }
-
- byte* GetParamAddress() const {
- return cur_args_ + (cur_arg_index_ * kPointerSize);
- }
-
- void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- for (cur_arg_index_ = 0; cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
-#if (defined(__arm__) || defined(__mips__))
- if (IsParamALongOrDouble() && cur_arg_index_ == 2) {
- break;
- }
-#endif
- Visit();
- cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
- param_index_++;
- }
- cur_args_ = stack_args_;
- cur_arg_index_ = 0;
- while (param_index_ < num_params_) {
-#if (defined(__arm__) || defined(__mips__))
- if (IsParamALongOrDouble() && cur_arg_index_ % 2 != 0) {
- cur_arg_index_++;
- }
-#endif
- Visit();
- cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
- param_index_++;
- }
- }
-
- private:
- static size_t ComputeArgsInRegs(MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if (defined(__i386__))
- return 0;
-#else
- size_t args_in_regs = 0;
- size_t num_params = mh.NumArgs();
- for (size_t i = 0; i < num_params; i++) {
- args_in_regs = args_in_regs + (mh.IsParamALongOrDouble(i) ? 2 : 1);
- if (args_in_regs > 3) {
- args_in_regs = 3;
- break;
- }
- }
- return args_in_regs;
-#endif
- }
- MethodHelper& caller_mh_;
- const size_t args_in_regs_;
- const size_t num_params_;
- byte* const reg_args_;
- byte* const stack_args_;
- byte* cur_args_;
- size_t cur_arg_index_;
- size_t param_index_;
-};
-
-// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
class QuickArgumentVisitor {
public:
// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
diff --git a/runtime/entrypoints/quick/quick_cast_entrypoints.cc b/runtime/entrypoints/quick/quick_cast_entrypoints.cc
index fe91e61..b810bb7 100644
--- a/runtime/entrypoints/quick/quick_cast_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_cast_entrypoints.cc
@@ -15,10 +15,10 @@
*/
#include "callee_save_frame.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "runtime_support.h"
namespace art {
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 0af7a62..6400161b 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -15,13 +15,13 @@
*/
#include "callee_save_frame.h"
-#include "gc/accounting/card_table-inl.h"
+#include "entrypoints/entrypoint_utils.h"
#include "class_linker-inl.h"
#include "dex_file-inl.h"
+#include "gc/accounting/card_table-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
-#include "runtime_support.h"
namespace art {
diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index 8692e92..74b8cfd 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -20,15 +20,15 @@
#include "dex_file-inl.h"
#include "runtime.h"
-#define ENTRYPOINT_OFFSET(x) \
- (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, entrypoints_)) + \
+#define QUICK_ENTRYPOINT_OFFSET(x) \
+ (static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, quick_entrypoints_)) + \
static_cast<uintptr_t>(OFFSETOF_MEMBER(QuickEntryPoints, x)))
namespace art {
namespace mirror {
-class AbstractMethod;
-class Class;
-class Object;
+ class AbstractMethod;
+ class Class;
+ class Object;
} // namespace mirror
class DvmDex;
class MethodHelper;
@@ -123,8 +123,6 @@
void* (*pMemcpy)(void*, const void*, size_t);
// Invocation
- const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
- mirror::AbstractMethod**, Thread*);
const void* (*pQuickResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
mirror::AbstractMethod**, Thread*);
void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
@@ -167,9 +165,6 @@
jobject locked, Thread* self)
SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
-// Initialize an entry point data structure, architecture specific.
-void InitEntryPoints(QuickEntryPoints* points);
-
} // namespace art
#endif // ART_RUNTIME_ENTRYPOINTS_QUICK_QUICK_ENTRYPOINTS_H_
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index c20326c..a4e9dc9 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -16,10 +16,10 @@
#include "callee_save_frame.h"
#include "dex_file-inl.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/field-inl.h"
-#include "runtime_support.h"
#include <stdint.h>
diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
index a0b06fb..b81ad12 100644
--- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
@@ -52,7 +52,7 @@
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
"failed FILL_ARRAY_DATA; length=%d, index=%d",
- array->GetLength(), payload->element_count);
+ array->GetLength(), payload->element_count - 1);
return -1; // Error
}
uint32_t size_in_bytes = payload->element_count * payload->element_width;
diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
index 6a95f3c..53b3628 100644
--- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
@@ -16,12 +16,12 @@
#include "callee_save_frame.h"
#include "dex_instruction-inl.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "runtime_support.h"
namespace art {
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 2d31160..23a28f9 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -15,13 +15,13 @@
*/
#include "dex_file-inl.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/class-inl.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "object_utils.h"
-#include "runtime_support.h"
#include "scoped_thread_state_change.h"
#include "thread.h"
diff --git a/runtime/entrypoints/quick/quick_proxy_entrypoints.cc b/runtime/entrypoints/quick/quick_proxy_entrypoints.cc
index e4ef45f..4e3d749 100644
--- a/runtime/entrypoints/quick/quick_proxy_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_proxy_entrypoints.cc
@@ -16,12 +16,12 @@
#include "quick_argument_visitor.h"
#include "dex_file-inl.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/abstract_method-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "reflection.h"
-#include "runtime_support.h"
#include "scoped_thread_state_change.h"
#include "thread.h"
#include "well_known_classes.h"
@@ -32,50 +32,6 @@
// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
// to jobjects.
-class BuildPortableArgumentVisitor : public PortableArgumentVisitor {
- public:
- BuildPortableArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp,
- ScopedObjectAccessUnchecked& soa, std::vector<jvalue>& args) :
- PortableArgumentVisitor(caller_mh, sp), soa_(soa), args_(args) {}
-
- virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- jvalue val;
- Primitive::Type type = GetParamPrimitiveType();
- switch (type) {
- case Primitive::kPrimNot: {
- mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress());
- val.l = soa_.AddLocalReference<jobject>(obj);
- break;
- }
- case Primitive::kPrimLong: // Fall-through.
- case Primitive::kPrimDouble:
- val.j = *reinterpret_cast<jlong*>(GetParamAddress());
- break;
- case Primitive::kPrimBoolean: // Fall-through.
- case Primitive::kPrimByte: // Fall-through.
- case Primitive::kPrimChar: // Fall-through.
- case Primitive::kPrimShort: // Fall-through.
- case Primitive::kPrimInt: // Fall-through.
- case Primitive::kPrimFloat:
- val.i = *reinterpret_cast<jint*>(GetParamAddress());
- break;
- case Primitive::kPrimVoid:
- LOG(FATAL) << "UNREACHABLE";
- val.j = 0;
- break;
- }
- args_.push_back(val);
- }
-
- private:
- ScopedObjectAccessUnchecked& soa_;
- std::vector<jvalue>& args_;
-
- DISALLOW_COPY_AND_ASSIGN(BuildPortableArgumentVisitor);
-};
-
-// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
-// to jobjects.
class BuildQuickArgumentVisitor : public QuickArgumentVisitor {
public:
BuildQuickArgumentVisitor(MethodHelper& caller_mh, mirror::AbstractMethod** sp,
@@ -126,46 +82,6 @@
// which is responsible for recording callee save registers. We explicitly place into jobjects the
// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
// field within the proxy object, which will box the primitive arguments and deal with error cases.
-extern "C" uint64_t artPortableProxyInvokeHandler(mirror::AbstractMethod* proxy_method,
- mirror::Object* receiver,
- Thread* self, mirror::AbstractMethod** sp)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
- const char* old_cause =
- self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
- self->VerifyStack();
- // Start new JNI local reference state.
- JNIEnvExt* env = self->GetJniEnv();
- ScopedObjectAccessUnchecked soa(env);
- ScopedJniEnvLocalRefState env_state(env);
- // Create local ref. copies of proxy method and the receiver.
- jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
-
- // Placing arguments into args vector and remove the receiver.
- MethodHelper proxy_mh(proxy_method);
- std::vector<jvalue> args;
- BuildPortableArgumentVisitor local_ref_visitor(proxy_mh, sp, soa, args);
- local_ref_visitor.VisitArguments();
- args.erase(args.begin());
-
- // Convert proxy method into expected interface method.
- mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
- DCHECK(interface_method != NULL);
- DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
- jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
-
- // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
- // that performs allocations.
- self->EndAssertNoThreadSuspension(old_cause);
- JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
- rcvr_jobj, interface_method_jobj, args);
- return result.GetJ();
-}
-
-// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
-// which is responsible for recording callee save registers. We explicitly place into jobjects the
-// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
-// field within the proxy object, which will box the primitive arguments and deal with error cases.
extern "C" uint64_t artQuickProxyInvokeHandler(mirror::AbstractMethod* proxy_method,
mirror::Object* receiver,
Thread* self, mirror::AbstractMethod** sp)
diff --git a/runtime/entrypoints/quick/quick_stub_entrypoints.cc b/runtime/entrypoints/quick/quick_stub_entrypoints.cc
index f2af6d2..d78bbf3 100644
--- a/runtime/entrypoints/quick/quick_stub_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_stub_entrypoints.cc
@@ -30,127 +30,6 @@
namespace art {
-// Lazily resolve a method for portable. Called by stub code.
-extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
- mirror::Object* receiver,
- mirror::AbstractMethod** called_addr,
- Thread* thread)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- uint32_t dex_pc;
- mirror::AbstractMethod* caller = thread->GetCurrentMethod(&dex_pc);
-
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- InvokeType invoke_type;
- bool is_range;
- if (called->IsRuntimeMethod()) {
- const DexFile::CodeItem* code = MethodHelper(caller).GetCodeItem();
- CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
- Instruction::Code instr_code = instr->Opcode();
- switch (instr_code) {
- case Instruction::INVOKE_DIRECT:
- invoke_type = kDirect;
- is_range = false;
- break;
- case Instruction::INVOKE_DIRECT_RANGE:
- invoke_type = kDirect;
- is_range = true;
- break;
- case Instruction::INVOKE_STATIC:
- invoke_type = kStatic;
- is_range = false;
- break;
- case Instruction::INVOKE_STATIC_RANGE:
- invoke_type = kStatic;
- is_range = true;
- break;
- case Instruction::INVOKE_SUPER:
- invoke_type = kSuper;
- is_range = false;
- break;
- case Instruction::INVOKE_SUPER_RANGE:
- invoke_type = kSuper;
- is_range = true;
- break;
- case Instruction::INVOKE_VIRTUAL:
- invoke_type = kVirtual;
- is_range = false;
- break;
- case Instruction::INVOKE_VIRTUAL_RANGE:
- invoke_type = kVirtual;
- is_range = true;
- break;
- case Instruction::INVOKE_INTERFACE:
- invoke_type = kInterface;
- is_range = false;
- break;
- case Instruction::INVOKE_INTERFACE_RANGE:
- invoke_type = kInterface;
- is_range = true;
- break;
- default:
- LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
- // Avoid used uninitialized warnings.
- invoke_type = kDirect;
- is_range = true;
- }
- uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
- called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
- // Refine called method based on receiver.
- if (invoke_type == kVirtual) {
- called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
- } else if (invoke_type == kInterface) {
- called = receiver->GetClass()->FindVirtualMethodForInterface(called);
- }
- } else {
- CHECK(called->IsStatic()) << PrettyMethod(called);
- invoke_type = kStatic;
- }
- const void* code = NULL;
- if (LIKELY(!thread->IsExceptionPending())) {
- // Incompatible class change should have been handled in resolve method.
- CHECK(!called->CheckIncompatibleClassChange(invoke_type));
- // Ensure that the called method's class is initialized.
- mirror::Class* called_class = called->GetDeclaringClass();
- linker->EnsureInitialized(called_class, true, true);
- if (LIKELY(called_class->IsInitialized())) {
- code = called->GetEntryPointFromCompiledCode();
- // TODO: remove this after we solve the link issue.
- { // for lazy link.
- if (code == NULL) {
- code = linker->GetOatCodeFor(called);
- }
- }
- } else if (called_class->IsInitializing()) {
- if (invoke_type == kStatic) {
- // Class is still initializing, go to oat and grab code (trampoline must be left in place
- // until class is initialized to stop races between threads).
- code = linker->GetOatCodeFor(called);
- } else {
- // No trampoline for non-static methods.
- code = called->GetEntryPointFromCompiledCode();
- // TODO: remove this after we solve the link issue.
- { // for lazy link.
- if (code == NULL) {
- code = linker->GetOatCodeFor(called);
- }
- }
- }
- } else {
- DCHECK(called_class->IsErroneous());
- }
- }
- if (LIKELY(code != NULL)) {
- // Expect class to at least be initializing.
- DCHECK(called->GetDeclaringClass()->IsInitializing());
- // Don't want infinite recursion.
- DCHECK(code != GetResolutionTrampoline(linker));
- // Set up entry into main method
- *called_addr = called;
- }
- return code;
-}
-
// Lazily resolve a method for quick. Called by stub code.
extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
mirror::Object* receiver,
@@ -413,26 +292,4 @@
self->QuickDeliverException();
}
-// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
-extern "C" void* artFindNativeMethod(Thread* self) {
- Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native.
- DCHECK(Thread::Current() == self);
- ScopedObjectAccess soa(self);
-
- mirror::AbstractMethod* method = self->GetCurrentMethod(NULL);
- DCHECK(method != NULL);
-
- // Lookup symbol address for method, on failure we'll return NULL with an
- // exception set, otherwise we return the address of the method we found.
- void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
- if (native_code == NULL) {
- DCHECK(self->IsExceptionPending());
- return NULL;
- } else {
- // Register so that future calls don't come here
- method->RegisterNative(self, native_code);
- return native_code;
- }
-}
-
} // namespace art
diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
index e711714..b4d6c0b 100644
--- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
@@ -15,7 +15,7 @@
*/
#include "callee_save_frame.h"
-#include "runtime_support.h"
+#include "entrypoints/entrypoint_utils.h"
#include "thread.h"
#include "thread_list.h"
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index 9588698..3bfa2f2 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -15,9 +15,9 @@
*/
#include "callee_save_frame.h"
+#include "entrypoints/entrypoint_utils.h"
#include "mirror/object.h"
#include "object_utils.h"
-#include "runtime_support.h"
#include "thread.h"
#include "well_known_classes.h"