class ArgArray { public:
ArgArray(constchar* shorty, uint32_t shorty_len)
: shorty_(shorty), shorty_len_(shorty_len), num_bytes_(0) {
size_t num_slots = shorty_len + 1; // +1 in case of receiver. if (LIKELY((num_slots * 2) < kSmallArgArraySize)) { // We can trivially use the small arg array.
arg_array_ = small_arg_array_;
} else { // Analyze shorty to see if we need the large arg array. for (size_t i = 1; i < shorty_len; ++i) { char c = shorty[i]; if (c == 'J' || c == 'D') {
num_slots++;
}
} if (num_slots <= kSmallArgArraySize) {
arg_array_ = small_arg_array_;
} else {
large_arg_array_.reset(new uint32_t[num_slots]);
arg_array_ = large_arg_array_.get();
}
}
}
void CheckMethodArguments(JavaVMExt* vm, ArtMethod* m, uint32_t* args)
REQUIRES_SHARED(Locks::mutator_lock_) { const dex::TypeList* params = m->GetParameterTypeList(); if (params == nullptr) { return; // No arguments so nothing to check.
}
uint32_t offset = 0;
uint32_t num_params = params->Size();
size_t error_count = 0; if (!m->IsStatic()) {
offset = 1;
} // TODO: If args contain object references, it may cause problems.
Thread* const self = Thread::Current(); for (uint32_t i = 0; i < num_params; i++) {
dex::TypeIndex type_idx = params->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> param_type(m->ResolveClassFromTypeIndex(type_idx)); if (param_type == nullptr) {
CHECK(self->IsExceptionPending());
LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
<< m->GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
<< self->GetException()->Dump();
self->ClearException();
++error_count;
} elseif (!param_type->IsPrimitive()) { // TODO: There is a compaction bug here since GetClassFromTypeIdx can cause thread suspension, // this is a hard to fix problem since the args can contain Object*, we need to save and // restore them by using a visitor similar to the ones used in the trampoline entrypoints.
ObjPtr<mirror::Object> argument =
(reinterpret_cast<StackReference<mirror::Object>*>(&args[i + offset]))->AsMirrorPtr(); if (argument != nullptr && !argument->InstanceOf(param_type)) {
LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
<< argument->PrettyTypeOf() << " as argument " << (i + 1)
<< " to " << m->PrettyMethod();
++error_count;
}
} elseif (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble()) {
offset++;
} else {
int32_t arg = static_cast<int32_t>(args[i + offset]); if (param_type->IsPrimitiveBoolean()) { if (arg != JNI_TRUE && arg != JNI_FALSE) {
LOG(ERROR) << "JNI ERROR (app bug): expected jboolean (0/1) but got value of "
<< arg << " as argument " << (i + 1) << " to " << m->PrettyMethod();
++error_count;
}
} elseif (param_type->IsPrimitiveByte()) { if (arg < -128 || arg > 127) {
LOG(ERROR) << "JNI ERROR (app bug): expected jbyte but got value of "
<< arg << " as argument " << (i + 1) << " to " << m->PrettyMethod();
++error_count;
}
} elseif (param_type->IsPrimitiveChar()) { if (args[i + offset] > 0xFFFF) {
LOG(ERROR) << "JNI ERROR (app bug): expected jchar but got value of "
<< arg << " as argument " << (i + 1) << " to " << m->PrettyMethod();
++error_count;
}
} elseif (param_type->IsPrimitiveShort()) { if (arg < -32768 || arg > 0x7FFF) {
LOG(ERROR) << "JNI ERROR (app bug): expected jshort but got value of "
<< arg << " as argument " << (i + 1) << " to " << m->PrettyMethod();
++error_count;
}
}
}
} if (UNLIKELY(error_count > 0)) { // TODO: pass the JNI function name (such as "CallVoidMethodV") through so we can call JniAbort // with an argument.
vm->JniAbortF(nullptr, "bad arguments passed to %s (see above for details)",
m->PrettyMethod().c_str());
}
}
InvokeWithArgArray(soa, m, &arg_array, result, *shorty);
// Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early. if (soa.Self()->IsExceptionPending()) { // To abort a transaction we use a fake exception that should never be caught by the bytecode // and therefore it makes no sense to wrap it. if (Runtime::Current()->IsActiveTransaction() &&
Runtime::Current()->GetClassLinker()->IsTransactionAborted()) {
DCHECK(soa.Self()->GetException()->GetClass()->DescriptorEquals( "Ldalvik/system/TransactionAbortError;"))
<< soa.Self()->GetException()->GetClass()->PrettyDescriptor();
} else { // If we get another exception when we are trying to wrap, then just use that instead.
StackHandleScope<2u> hs(soa.Self());
Handle<mirror::Throwable> cause = hs.NewHandle(soa.Self()->GetException());
soa.Self()->ClearException();
Handle<mirror::Object> exception_instance =
WellKnownClasses::java_lang_reflect_InvocationTargetException_init->NewObject<'L'>(
hs, soa.Self(), cause); if (exception_instance == nullptr) {
soa.Self()->AssertPendingException(); returnfalse;
}
soa.Self()->SetException(exception_instance->AsThrowable());
} returnfalse;
}
returntrue;
}
} // anonymous namespace
template <>
NO_STACK_PROTECTOR
JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
jobject obj,
ArtMethod* method,
va_list args) REQUIRES_SHARED(Locks::mutator_lock_) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd<kNativeStackType>())) {
ThrowStackOverflowError<kNativeStackType>(soa.Self()); return JValue();
} bool is_string_init = method->IsStringConstructor(); if (is_string_init) { // Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
}
ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
uint32_t shorty_len = 0; constchar* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
JValue result;
ArgArray arg_array(shorty, shorty_len);
arg_array.BuildArgArrayFromVarArgs(soa, receiver, args);
InvokeWithArgArray(soa, method, &arg_array, &result, shorty); if (is_string_init) { // For string init, remap original receiver to StringFactory result.
UpdateReference(soa.Self(), obj, result.GetL());
} return result;
}
template <>
JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
jobject obj,
ArtMethod* method, const jvalue* args) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd<kNativeStackType>())) {
ThrowStackOverflowError<kNativeStackType>(soa.Self()); return JValue();
} bool is_string_init = method->IsStringConstructor(); if (is_string_init) { // Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
}
ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
uint32_t shorty_len = 0; constchar* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
JValue result;
ArgArray arg_array(shorty, shorty_len);
arg_array.BuildArgArrayFromJValues(soa, receiver, args);
InvokeWithArgArray(soa, method, &arg_array, &result, shorty); if (is_string_init) { // For string init, remap original receiver to StringFactory result.
UpdateReference(soa.Self(), obj, result.GetL());
} return result;
}
template <>
JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
jobject obj,
ArtMethod* interface_method, const jvalue* args) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd<kNativeStackType>())) {
ThrowStackOverflowError<kNativeStackType>(soa.Self()); return JValue();
}
ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
ArtMethod* method = FindVirtualMethod(receiver, interface_method); bool is_string_init = method->IsStringConstructor(); if (is_string_init) { // Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
receiver = nullptr;
}
uint32_t shorty_len = 0; constchar* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
JValue result;
ArgArray arg_array(shorty, shorty_len);
arg_array.BuildArgArrayFromJValues(soa, receiver, args);
InvokeWithArgArray(soa, method, &arg_array, &result, shorty); if (is_string_init) { // For string init, remap original receiver to StringFactory result.
UpdateReference(soa.Self(), obj, result.GetL());
} return result;
}
template <>
JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
jobject obj,
ArtMethod* interface_method,
va_list args) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEnd<kNativeStackType>())) {
ThrowStackOverflowError<kNativeStackType>(soa.Self()); return JValue();
}
template <PointerSize kPointerSize>
jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod,
jobject javaReceiver, jobject javaArgs, size_t num_frames) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. if (UNLIKELY(__builtin_frame_address(0) <
soa.Self()->GetStackEndForInterpreter(true))) {
ThrowStackOverflowError<kNativeStackType>(soa.Self()); return nullptr;
}
ObjPtr<mirror::Object> receiver; if (!m->IsStatic()) { // Replace calls to String.<init> with equivalent StringFactory call. if (declaring_class->IsStringClass() && m->IsConstructor()) {
m = WellKnownClasses::StringInitToStringFactory(m);
CHECK(javaReceiver == nullptr);
} else { // Check that the receiver is non-null and an instance of the field's declaring class.
receiver = soa.Decode<mirror::Object>(javaReceiver); if (!VerifyObjectIsClass(receiver, declaring_class)) { return nullptr;
}
// Find the actual implementation of the virtual method.
m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m, kPointerSize);
}
}
// Get our arrays of arguments and their types, and check they're the same size.
ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs); auto* np_method = m->GetInterfaceMethodIfProxy(kPointerSize); if (!CheckArgsForInvokeMethod(np_method, objects)) { return nullptr;
}
// If method is not set to be accessible, verify it can be accessed by the caller.
ObjPtr<mirror::Class> calling_class; if (!accessible && !VerifyAccess(soa.Self(),
receiver,
declaring_class,
m->GetAccessFlags(),
&calling_class,
num_frames)) {
ThrowIllegalAccessException(
StringPrintf("Class %s cannot access %s method %s of class %s",
calling_class == nullptr ? "null" : calling_class->PrettyClass().c_str(),
PrettyJavaAccessFlags(m->GetAccessFlags()).c_str(),
m->PrettyMethod().c_str(),
m->GetDeclaringClass() == nullptr ? "null" :
m->GetDeclaringClass()->PrettyClass().c_str()).c_str()); return nullptr;
}
// Invoke the method.
JValue result; constchar* shorty; if (!InvokeMethodImpl(soa, m, np_method, receiver, objects, &shorty, &result)) { return nullptr;
} return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
}
void InvokeConstructor(const ScopedObjectAccessAlreadyRunnable& soa,
ArtMethod* constructor,
ObjPtr<mirror::Object> receiver,
jobject javaArgs) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEndForInterpreter(true))) {
ThrowStackOverflowError<kNativeStackType>(soa.Self()); return;
}
if (kIsDebugBuild) {
CHECK(constructor->IsConstructor());
// Calls to String.<init> should have been repplaced with with equivalent StringFactory calls.
CHECK(!declaring_class->IsStringClass());
// Check that the receiver is non-null and an instance of the field's declaring class.
CHECK(receiver != nullptr);
CHECK(VerifyObjectIsClass(receiver, declaring_class));
CHECK_EQ(constructor,
receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(constructor,
kRuntimePointerSize));
}
// Get our arrays of arguments and their types, and check they're the same size.
ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs);
ArtMethod* np_method = constructor->GetInterfaceMethodIfProxy(kRuntimePointerSize); if (!CheckArgsForInvokeMethod(np_method, objects)) { return;
}
ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) { if (src_class == Primitive::kPrimNot) { return value.GetL();
} if (src_class == Primitive::kPrimVoid) { // There's no such thing as a void field, and void methods invoked via reflection return null. return nullptr;
}
ArtMethod* m = nullptr; constchar* shorty; switch (src_class) { case Primitive::kPrimBoolean:
m = WellKnownClasses::java_lang_Boolean_valueOf;
shorty = "LZ"; break; case Primitive::kPrimByte:
m = WellKnownClasses::java_lang_Byte_valueOf;
shorty = "LB"; break; case Primitive::kPrimChar:
m = WellKnownClasses::java_lang_Character_valueOf;
shorty = "LC"; break; case Primitive::kPrimDouble:
m = WellKnownClasses::java_lang_Double_valueOf;
shorty = "LD"; break; case Primitive::kPrimFloat:
m = WellKnownClasses::java_lang_Float_valueOf;
shorty = "LF"; break; case Primitive::kPrimInt:
m = WellKnownClasses::java_lang_Integer_valueOf;
shorty = "LI"; break; case Primitive::kPrimLong:
m = WellKnownClasses::java_lang_Long_valueOf;
shorty = "LJ"; break; case Primitive::kPrimShort:
m = WellKnownClasses::java_lang_Short_valueOf;
shorty = "LS"; break; default:
LOG(FATAL) << static_cast<int>(src_class);
shorty = nullptr;
}
staticbool UnboxPrimitive(ObjPtr<mirror::Object> o,
ObjPtr<mirror::Class> dst_class,
ArtField* f,
JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_) { bool unbox_for_result = (f == nullptr); if (!dst_class->IsPrimitive()) { if (UNLIKELY(o != nullptr && !o->InstanceOf(dst_class))) { if (!unbox_for_result) {
ThrowIllegalArgumentException(
StringPrintf("%s has type %s, got %s",
UnboxingFailureKind(f).c_str(),
dst_class->PrettyDescriptor().c_str(),
o->PrettyTypeOf().c_str()).c_str());
} else {
ThrowClassCastException(
StringPrintf("Couldn't convert result of type %s to %s",
o->PrettyTypeOf().c_str(),
dst_class->PrettyDescriptor().c_str()).c_str());
} returnfalse;
}
unboxed_value->SetL(o); returntrue;
} if (UNLIKELY(dst_class->GetPrimitiveType() == Primitive::kPrimVoid)) {
ThrowIllegalArgumentException(StringPrintf("Can't unbox %s to void",
UnboxingFailureKind(f).c_str()).c_str()); returnfalse;
} if (UNLIKELY(o == nullptr)) { if (!unbox_for_result) {
ThrowIllegalArgumentException(
StringPrintf("%s has type %s, got null",
UnboxingFailureKind(f).c_str(),
dst_class->PrettyDescriptor().c_str()).c_str());
} else {
ThrowNullPointerException(
StringPrintf("Expected to unbox a '%s' primitive type but was returned null",
dst_class->PrettyDescriptor().c_str()).c_str());
} returnfalse;
}
void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
std::string expected_class_name(mirror::Class::PrettyDescriptor(c));
std::string actual_class_name(mirror::Object::PrettyTypeOf(o));
ThrowIllegalArgumentException(StringPrintf("Expected receiver of type %s, but got %s",
expected_class_name.c_str(),
actual_class_name.c_str()).c_str());
}
// This only works if there's one reference which points to the object in obj. // Will need to be fixed if there's cases where it's not. void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result) {
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = IndirectReferenceTable::GetIndirectRefKind(ref); if (kind == kLocal) {
self->GetJniEnv()->UpdateLocal(obj, result);
} elseif (kind == kJniTransition) {
LOG(FATAL) << "Unsupported UpdateReference for kind kJniTransition";
} elseif (kind == kGlobal) {
self->GetJniEnv()->GetVm()->UpdateGlobal(self, ref, result);
} else {
DCHECK_EQ(kind, kWeakGlobal);
self->GetJniEnv()->GetVm()->UpdateWeakGlobal(self, ref, result);
}
}
} // namespace art
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.4 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.