From c3824c6844ad57c38f778177aa64a264c55898c7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 17 Jul 2011 19:54:55 -0600 Subject: [PATCH] fix crash when encountering invokespecial call to abstract method We must throw an AbstractMethodError when such a call is executed (not when the call is compiled), so we compile this case as a call to a thunk which throws such an error. --- classpath/java/lang/AbstractMethodError.java | 21 ++++++ src/compile.cpp | 69 +++++++++++++++++++- src/thunks.cpp | 1 + src/types.def | 2 + vm.pro | 1 + 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 classpath/java/lang/AbstractMethodError.java diff --git a/classpath/java/lang/AbstractMethodError.java b/classpath/java/lang/AbstractMethodError.java new file mode 100644 index 0000000000..bc8d05570a --- /dev/null +++ b/classpath/java/lang/AbstractMethodError.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class AbstractMethodError extends IncompatibleClassChangeError { + public AbstractMethodError() { + super(); + } + + public AbstractMethodError(String message) { + super(message); + } +} diff --git a/src/compile.cpp b/src/compile.cpp index 6fce5523bf..7531609b0b 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2344,6 +2344,26 @@ findVirtualMethodFromReference(MyThread* t, object pair, object instance) return prepareMethodForCall(t, target); } +bool +methodAbstract(Thread* t, object method) +{ + return methodCode(t, method) == 0 + and (methodFlags(t, method) & ACC_NATIVE) == 0; +} + +int64_t +getMethodAddress(MyThread* t, object target) +{ + if (methodAbstract(t, target)) { + throwNew(t, Machine::AbstractMethodErrorType, "%s.%s%s", + &byteArrayBody(t, className(t, methodClass(t, target)), 0), + &byteArrayBody(t, methodName(t, target), 0), + &byteArrayBody(t, methodSpec(t, target), 0)); + } else { + return prepareMethodForCall(t, target); + } +} + int64_t getJClassFromReference(MyThread* t, object pair) { @@ -3440,6 +3460,48 @@ compileDirectReferenceInvoke(MyThread* t, Frame* frame, Thunk thunk, reference, isStatic, tailCall); } +void +compileAbstractInvoke(MyThread* t, Frame* frame, Compiler::Operand* method, + object target, bool tailCall) +{ + unsigned parameterFootprint = methodParameterFootprint(t, target); + + int returnCode = methodReturnCode(t, target); + + unsigned rSize = resultSize(t, returnCode); + + Compiler::Operand* result = frame->c->stackCall + (method, + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, returnCode), + parameterFootprint); + + frame->pop(parameterFootprint); + + if (rSize) { + pushReturnValue(t, frame, returnCode, result); + } +} + +void +compileDirectAbstractInvoke(MyThread* t, Frame* frame, Thunk thunk, + object target, bool tailCall) +{ + Compiler* c = frame->c; + + compileAbstractInvoke + (t, frame, c->call + (c->constant(getThunk(t, thunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::AddressType, + 2, c->register_(t->arch->thread()), frame->append(target)), + target, tailCall); +} + void handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) { @@ -4844,7 +4906,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, bool tailCall = isTailCall(t, code, ip, context->method, target); - compileDirectInvoke(t, frame, target, tailCall); + if (UNLIKELY(methodAbstract(t, target))) { + compileDirectAbstractInvoke + (t, frame, getMethodAddressThunk, target, tailCall); + } else { + compileDirectInvoke(t, frame, target, tailCall); + } } else { compileDirectReferenceInvoke (t, frame, findSpecialMethodFromReferenceThunk, reference, false, diff --git a/src/thunks.cpp b/src/thunks.cpp index 9279cbb811..328e62c8f3 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -4,6 +4,7 @@ THUNK(findInterfaceMethodFromInstanceAndReference) THUNK(findSpecialMethodFromReference) THUNK(findStaticMethodFromReference) THUNK(findVirtualMethodFromReference) +THUNK(getMethodAddress) THUNK(compareDoublesG) THUNK(compareDoublesL) THUNK(compareFloatsG) diff --git a/src/types.def b/src/types.def index 1ac0d915ea..2178c3a7fa 100644 --- a/src/types.def +++ b/src/types.def @@ -249,6 +249,8 @@ (type incompatibleClassChangeError java/lang/IncompatibleClassChangeError) +(type abstractMethodError java/lang/AbstractMethodError) + (type noSuchFieldError java/lang/NoSuchFieldError) (type noSuchMethodError java/lang/NoSuchMethodError) diff --git a/vm.pro b/vm.pro index 2cdd1baef5..495bc4c3ab 100644 --- a/vm.pro +++ b/vm.pro @@ -62,6 +62,7 @@ -keep public class java.lang.StackOverflowError -keep public class java.lang.NoSuchFieldError -keep public class java.lang.NoSuchMethodError +-keep public class java.lang.AbstractMethodError -keep public class java.lang.UnsatisfiedLinkError -keep public class java.lang.ExceptionInInitializerError -keep public class java.lang.OutOfMemoryError