/* src/vm/method.c - method functions
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
- C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
- E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
- J. Wenninger, Institut f. Computersprachen - TU Wien
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Reinhard Grafl
-
- Changes: Andreas Krall
- Roman Obermaiser
- Mark Probst
- Edwin Steiner
- Christian Thalinger
-
- $Id: method.c 5258 2006-08-22 09:02:25Z tbfg $
-
*/
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include <stdio.h>
#include "vm/types.h"
#include "mm/memory.h"
-#include "vm/class.h"
+
+#include "native/llni.h"
+
+#include "threads/mutex.hpp"
+
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/exceptions.hpp"
#include "vm/global.h"
+#include "vm/globals.hpp"
#include "vm/linker.h"
-#include "vm/loader.h"
+#include "vm/loader.hpp"
#include "vm/method.h"
#include "vm/options.h"
+#include "vm/resolve.hpp"
+#include "vm/suck.hpp"
+#include "vm/utf8.h"
+#include "vm/vm.hpp"
+
+#include "vm/jit/code.hpp"
#include "vm/jit/methodheader.h"
+#include "vm/jit/stubs.hpp"
+
+
+#if !defined(NDEBUG) && defined(ENABLE_INLINING)
+#define INLINELOG(code) do { if (opt_TraceInlining) { code } } while (0)
+#else
+#define INLINELOG(code)
+#endif
+
+
+/* global variables ***********************************************************/
+
+methodinfo *method_java_lang_reflect_Method_invoke;
+
+
+/* method_init *****************************************************************
+
+ Initialize method subsystem.
+
+*******************************************************************************/
+
+void method_init(void)
+{
+#if defined(ENABLE_JAVASE)
+ /* Sanity check. */
+
+ if (class_java_lang_reflect_Method == NULL)
+ vm_abort("method_init: class_java_lang_reflect_Method is NULL");
+
+ /* Cache java.lang.reflect.Method.invoke() */
+
+ method_java_lang_reflect_Method_invoke =
+ class_findmethod(class_java_lang_reflect_Method, utf_invoke, NULL);
+
+ if (method_java_lang_reflect_Method_invoke == NULL)
+ vm_abort("method_init: Could not resolve method java.lang.reflect.Method.invoke().");
+#endif
+}
+
+
+/* method_load *****************************************************************
+
+ Loads a method from the class file and fills an existing methodinfo
+ structure.
+
+ method_info {
+ u2 access_flags;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ attribute_info attributes[attribute_count];
+ }
+
+ attribute_info {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u1 info[attribute_length];
+ }
+
+ LineNumberTable_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u2 line_number_table_length;
+ {
+ u2 start_pc;
+ u2 line_number;
+ } line_number_table[line_number_table_length];
+ }
+
+*******************************************************************************/
+
+bool method_load(classbuffer *cb, methodinfo *m, descriptor_pool *descpool)
+{
+ classinfo *c;
+ int argcount;
+ s4 i, j, k, l;
+ utf *u;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ u2 attribute_name_index;
+ utf *attribute_name;
+ u2 code_attributes_count;
+ u2 code_attribute_name_index;
+ utf *code_attribute_name;
+
+ /* get classinfo */
+
+ c = cb->clazz;
+
+ m->mutex = Mutex_new();
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ count_all_methods++;
+#endif
+
+ /* all fields of m have been zeroed in load_class_from_classbuffer */
+
+ m->clazz = c;
+
+ if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
+ return false;
+
+ /* access flags */
+
+ m->flags = suck_u2(cb);
+
+ /* name */
+
+ name_index = suck_u2(cb);
+
+ if (!(u = class_getconstant(c, name_index, CONSTANT_Utf8)))
+ return false;
+
+ m->name = u;
+
+ /* descriptor */
+
+ descriptor_index = suck_u2(cb);
+
+ if (!(u = class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
+ return false;
+
+ m->descriptor = u;
+
+ if (!descriptor_pool_add(descpool, u, &argcount))
+ return false;
+
+#ifdef ENABLE_VERIFIER
+ if (opt_verify) {
+ if (!is_valid_name_utf(m->name)) {
+ exceptions_throw_classformaterror(c, "Method with invalid name");
+ return false;
+ }
+
+ if (m->name->text[0] == '<' &&
+ m->name != utf_init && m->name != utf_clinit) {
+ exceptions_throw_classformaterror(c, "Method with invalid special name");
+ return false;
+ }
+ }
+#endif /* ENABLE_VERIFIER */
+
+ if (!(m->flags & ACC_STATIC))
+ argcount++; /* count the 'this' argument */
+
+#ifdef ENABLE_VERIFIER
+ if (opt_verify) {
+ if (argcount > 255) {
+ exceptions_throw_classformaterror(c, "Too many arguments in signature");
+ return false;
+ }
+
+ /* check flag consistency */
+ if (m->name != utf_clinit) {
+ i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
+
+ if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
+ exceptions_throw_classformaterror(c,
+ "Illegal method modifiers: 0x%X",
+ m->flags);
+ return false;
+ }
+
+ if (m->flags & ACC_ABSTRACT) {
+ if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
+ ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
+ exceptions_throw_classformaterror(c,
+ "Illegal method modifiers: 0x%X",
+ m->flags);
+ return false;
+ }
+ }
+
+ if (c->flags & ACC_INTERFACE) {
+ if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
+ exceptions_throw_classformaterror(c,
+ "Illegal method modifiers: 0x%X",
+ m->flags);
+ return false;
+ }
+ }
+
+ if (m->name == utf_init) {
+ if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_NATIVE | ACC_ABSTRACT)) {
+ exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
+ return false;
+ }
+ }
+ }
+ }
+#endif /* ENABLE_VERIFIER */
+
+ /* mark the method as monomorphic until further notice */
+
+ m->flags |= ACC_METHOD_MONOMORPHIC;
+
+ /* non-abstract methods have an implementation in this class */
+
+ if (!(m->flags & ACC_ABSTRACT))
+ m->flags |= ACC_METHOD_IMPLEMENTED;
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* attributes count */
+
+ attributes_count = suck_u2(cb);
+
+ for (i = 0; i < attributes_count; i++) {
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* attribute name index */
+
+ attribute_name_index = suck_u2(cb);
+
+ attribute_name =
+ class_getconstant(c, attribute_name_index, CONSTANT_Utf8);
+
+ if (attribute_name == NULL)
+ return false;
+
+ if (attribute_name == utf_Code) {
+ /* Code */
+
+ if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
+ exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
+ return false;
+ }
+
+ if (m->jcode) {
+ exceptions_throw_classformaterror(c, "Multiple Code attributes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
+ return false;
+
+ suck_u4(cb);
+ m->maxstack = suck_u2(cb);
+ m->maxlocals = suck_u2(cb);
+
+ if (m->maxlocals < argcount) {
+ exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4))
+ return false;
+
+ m->jcodelength = suck_u4(cb);
+
+ if (m->jcodelength == 0) {
+ exceptions_throw_classformaterror(c, "Code of a method has length 0");
+ return false;
+ }
+
+ if (m->jcodelength > 65535) {
+ exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, m->jcodelength))
+ return false;
+
+ m->jcode = MNEW(u1, m->jcodelength);
+ suck_nbytes(m->jcode, cb, m->jcodelength);
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ m->rawexceptiontablelength = suck_u2(cb);
+ if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
+ return false;
+
+ m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat) {
+ count_vmcode_len += m->jcodelength + 18;
+ count_extable_len +=
+ m->rawexceptiontablelength * sizeof(raw_exception_entry);
+ }
+#endif
+
+ for (j = 0; j < m->rawexceptiontablelength; j++) {
+ u4 idx;
+ m->rawexceptiontable[j].startpc = suck_u2(cb);
+ m->rawexceptiontable[j].endpc = suck_u2(cb);
+ m->rawexceptiontable[j].handlerpc = suck_u2(cb);
+
+ idx = suck_u2(cb);
+
+ if (!idx) {
+ m->rawexceptiontable[j].catchtype.any = NULL;
+ }
+ else {
+ /* the classref is created later */
+ if (!(m->rawexceptiontable[j].catchtype.any =
+ (utf *) class_getconstant(c, idx, CONSTANT_Class)))
+ return false;
+ }
+ }
+
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* code attributes count */
+
+ code_attributes_count = suck_u2(cb);
+
+ for (k = 0; k < code_attributes_count; k++) {
+ if (!suck_check_classbuffer_size(cb, 2))
+ return false;
+
+ /* code attribute name index */
+
+ code_attribute_name_index = suck_u2(cb);
+
+ code_attribute_name =
+ class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8);
+
+ if (code_attribute_name == NULL)
+ return false;
+
+ /* check which code attribute */
+
+ if (code_attribute_name == utf_LineNumberTable) {
+ /* LineNumberTable */
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ /* attribute length */
+
+ (void) suck_u4(cb);
+
+ /* line number table length */
+
+ m->linenumbercount = suck_u2(cb);
+
+ if (!suck_check_classbuffer_size(cb,
+ (2 + 2) * m->linenumbercount))
+ return false;
+
+ m->linenumbers = MNEW(lineinfo, m->linenumbercount);
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
+#endif
+
+ for (l = 0; l < m->linenumbercount; l++) {
+ m->linenumbers[l].start_pc = suck_u2(cb);
+ m->linenumbers[l].line_number = suck_u2(cb);
+ }
+ }
+#if defined(ENABLE_JAVASE)
+ else if (code_attribute_name == utf_StackMapTable) {
+ /* StackTableMap */
+
+ if (!stackmap_load_attribute_stackmaptable(cb, m))
+ return false;
+ }
+#endif
+ else {
+ /* unknown code attribute */
+
+ if (!loader_skip_attribute_body(cb))
+ return false;
+ }
+ }
+ }
+ else if (attribute_name == utf_Exceptions) {
+ /* Exceptions */
+
+ if (m->thrownexceptions != NULL) {
+ exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
+ return false;
+ }
+
+ if (!suck_check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ /* attribute length */
+
+ (void) suck_u4(cb);
+
+ m->thrownexceptionscount = suck_u2(cb);
+
+ if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
+ return false;
+
+ m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
+
+ for (j = 0; j < m->thrownexceptionscount; j++) {
+ /* the classref is created later */
+ if (!((m->thrownexceptions)[j].any =
+ (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
+ return false;
+ }
+ }
+#if defined(ENABLE_JAVASE)
+ else if (attribute_name == utf_Signature) {
+ /* Signature */
+
+ if (!loader_load_attribute_signature(cb, &(m->signature)))
+ return false;
+ }
+
+#if defined(ENABLE_ANNOTATIONS)
+ else if (attribute_name == utf_RuntimeVisibleAnnotations) {
+ /* RuntimeVisibleAnnotations */
+ if (!annotation_load_method_attribute_runtimevisibleannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeInvisibleAnnotations) {
+ /* RuntimeInvisibleAnnotations */
+ if (!annotation_load_method_attribute_runtimeinvisibleannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeVisibleParameterAnnotations) {
+ /* RuntimeVisibleParameterAnnotations */
+ if (!annotation_load_method_attribute_runtimevisibleparameterannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_RuntimeInvisibleParameterAnnotations) {
+ /* RuntimeInvisibleParameterAnnotations */
+ if (!annotation_load_method_attribute_runtimeinvisibleparameterannotations(cb, m))
+ return false;
+ }
+ else if (attribute_name == utf_AnnotationDefault) {
+ /* AnnotationDefault */
+ if (!annotation_load_method_attribute_annotationdefault(cb, m))
+ return false;
+ }
+#endif
+#endif
+ else {
+ /* unknown attribute */
+
+ if (!loader_skip_attribute_body(cb))
+ return false;
+ }
+ }
+
+ if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
+ exceptions_throw_classformaterror(c, "Missing Code attribute");
+ return false;
+ }
+
+#if defined(ENABLE_REPLACEMENT)
+ /* initialize the hit countdown field */
+
+ m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
+#endif
+
+ /* everything was ok */
+
+ return true;
+}
/* method_free *****************************************************************
void method_free(methodinfo *m)
{
+ if (m->mutex)
+ Mutex_delete(m->mutex);
+
if (m->jcode)
MFREE(m->jcode, u1, m->jcodelength);
- if (m->exceptiontable)
- MFREE(m->exceptiontable, exceptiontable, m->exceptiontablelength);
+ if (m->rawexceptiontable)
+ MFREE(m->rawexceptiontable, raw_exception_entry, m->rawexceptiontablelength);
code_free_code_of_method(m);
if (m->stubroutine) {
if (m->flags & ACC_NATIVE) {
- removenativestub(m->stubroutine);
-
- } else {
- removecompilerstub(m->stubroutine);
+ NativeStub_remove(m->stubroutine);
+ }
+ else {
+ CompilerStub_remove(m->stubroutine);
}
}
}
}
+/* method_new_builtin **********************************************************
+
+ Creates a minimal methodinfo structure for builtins. This comes handy
+ when dealing with builtin stubs or stacktraces.
+
+*******************************************************************************/
+
+methodinfo *method_new_builtin(builtintable_entry *bte)
+{
+ methodinfo *m;
+
+ /* allocate the methodinfo structure */
+
+ m = NEW(methodinfo);
+
+ /* initialize methodinfo structure */
+
+ MZERO(m, methodinfo, 1);
+
+ m->mutex = Mutex_new();
+ m->flags = ACC_METHOD_BUILTIN;
+ m->parseddesc = bte->md;
+ m->name = bte->name;
+ m->descriptor = bte->descriptor;
+
+ /* return the newly created methodinfo */
+
+ return m;
+}
+
+
/* method_vftbl_lookup *********************************************************
Does a method lookup in the passed virtual function table. This
methodptr mptr;
methodptr *pmptr;
methodinfo *resm; /* pointer to new resolved method */
- codeinfo *code;
/* If the method is not an instance method, just return it. */
/* Get the method from the virtual function table. Is this an
interface method? */
- if (m->class->flags & ACC_INTERFACE) {
- pmptr = vftbl->interfacetable[-(m->class->index)];
- mptr = pmptr[(m - m->class->methods)];
+ if (m->clazz->flags & ACC_INTERFACE) {
+ pmptr = vftbl->interfacetable[-(m->clazz->index)];
+ mptr = pmptr[(m - m->clazz->methods)];
}
else {
mptr = vftbl->table[m->vftblindex];
/* and now get the codeinfo pointer from the first data segment slot */
- code = *((codeinfo **) (mptr + CodeinfoPointer));
-
- resm = code->m;
+ resm = code_get_methodinfo_for_pv(mptr);
return resm;
}
+/* method_get_parametercount **************************************************
+
+ Use the descriptor of a method to determine the number of parameters
+ of the method. The this pointer of non-static methods is not counted.
+
+ IN:
+ m........the method of which the parameters should be counted
+
+ RETURN VALUE:
+ The parameter count or -1 on error.
+
+*******************************************************************************/
+
+int32_t method_get_parametercount(methodinfo *m)
+{
+ methoddesc *md; /* method descriptor of m */
+ int32_t paramcount = 0; /* the parameter count of m */
+
+ md = m->parseddesc;
+
+ /* is the descriptor fully parsed? */
+
+ if (md->params == NULL) {
+ if (!descriptor_params_from_paramtypes(md, m->flags)) {
+ return -1;
+ }
+ }
+
+ paramcount = md->paramcount;
+
+ /* skip `this' pointer */
+
+ if (!(m->flags & ACC_STATIC)) {
+ --paramcount;
+ }
+
+ return paramcount;
+}
+
+
+/* method_get_parametertypearray ***********************************************
+
+ Use the descriptor of a method to generate a java.lang.Class array
+ which contains the classes of the parametertypes of the method.
+
+ This function is called by java.lang.reflect.{Constructor,Method}.
+
+*******************************************************************************/
+
+java_handle_objectarray_t *method_get_parametertypearray(methodinfo *m)
+{
+ methoddesc *md;
+ typedesc *paramtypes;
+ int32_t paramcount;
+ java_handle_objectarray_t *oa;
+ int32_t i;
+ classinfo *c;
+
+ md = m->parseddesc;
+
+ /* is the descriptor fully parsed? */
+
+ if (m->parseddesc->params == NULL)
+ if (!descriptor_params_from_paramtypes(md, m->flags))
+ return NULL;
+
+ paramtypes = md->paramtypes;
+ paramcount = md->paramcount;
+
+ /* skip `this' pointer */
+
+ if (!(m->flags & ACC_STATIC)) {
+ paramtypes++;
+ paramcount--;
+ }
+
+ /* create class-array */
+
+ oa = builtin_anewarray(paramcount, class_java_lang_Class);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* get classes */
+
+ for (i = 0; i < paramcount; i++) {
+ if (!resolve_class_from_typedesc(¶mtypes[i], true, false, &c))
+ return NULL;
+
+ LLNI_array_direct(oa, i) = (java_object_t *) c;
+ }
+
+ return oa;
+}
+
+
+/* method_get_exceptionarray ***************************************************
+
+ Get the exceptions which can be thrown by a method.
+
+*******************************************************************************/
+
+java_handle_objectarray_t *method_get_exceptionarray(methodinfo *m)
+{
+ java_handle_objectarray_t *oa;
+ classinfo *c;
+ s4 i;
+
+ /* create class-array */
+
+ oa = builtin_anewarray(m->thrownexceptionscount, class_java_lang_Class);
+
+ if (oa == NULL)
+ return NULL;
+
+ /* iterate over all exceptions and store the class in the array */
+
+ for (i = 0; i < m->thrownexceptionscount; i++) {
+ c = resolve_classref_or_classinfo_eager(m->thrownexceptions[i], true);
+
+ if (c == NULL)
+ return NULL;
+
+ LLNI_array_direct(oa, i) = (java_object_t *) c;
+ }
+
+ return oa;
+}
+
+
+/* method_returntype_get *******************************************************
+
+ Get the return type of the method.
+
+*******************************************************************************/
+
+classinfo *method_returntype_get(methodinfo *m)
+{
+ typedesc *td;
+ classinfo *c;
+
+ td = &(m->parseddesc->returntype);
+
+ if (!resolve_class_from_typedesc(td, true, false, &c))
+ return NULL;
+
+ return c;
+}
+
+
+/* method_count_implementations ************************************************
+
+ Count the implementations of a method in a class cone (a class and all its
+ subclasses.)
+
+ IN:
+ m................the method to count
+ c................class at which to start the counting (this class and
+ all its subclasses will be searched)
+
+ OUT:
+ *found...........if found != NULL, *found receives the method
+ implementation that was found. This value is only
+ meaningful if the return value is 1.
+
+ RETURN VALUE:
+ the number of implementations found
+
+*******************************************************************************/
+
+s4 method_count_implementations(methodinfo *m, classinfo *c, methodinfo **found)
+{
+ s4 count;
+ methodinfo *mp;
+ methodinfo *mend;
+ classinfo *child;
+
+ count = 0;
+
+ mp = c->methods;
+ mend = mp + c->methodscount;
+
+ for (; mp < mend; ++mp) {
+ if (method_canoverwrite(mp, m)) {
+ if (found)
+ *found = mp;
+ count++;
+ break;
+ }
+ }
+
+ for (child = c->sub; child != NULL; child = child->nextsub) {
+ count += method_count_implementations(m, child, found);
+ }
+
+ return count;
+}
+
+
+/* method_get_annotations ******************************************************
+
+ Get a methods' unparsed annotations in a byte array.
+
+ IN:
+ m........the method of which the annotations should be returned
+
+ RETURN VALUE:
+ The unparsed annotations in a byte array (or NULL if there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_annotations(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+ classinfo *c; /* methods' declaring class */
+ int slot; /* methods' slot */
+ java_handle_t *annotations; /* methods' unparsed annotations */
+ java_handle_t *method_annotations; /* all methods' unparsed annotations */
+ /* of the declaring class */
+
+ c = m->clazz;
+ slot = m - c->methods;
+ annotations = NULL;
+
+ LLNI_classinfo_field_get(c, method_annotations, method_annotations);
+
+ /* the method_annotations array might be shorter then the method
+ * count if the methods above a certain index have no annotations.
+ */
+ if (method_annotations != NULL &&
+ array_length_get(method_annotations) > slot) {
+ annotations = array_objectarray_element_get(
+ (java_handle_objectarray_t*)method_annotations, slot);
+ }
+
+ return (java_handle_bytearray_t*)annotations;
+#else
+ return NULL;
+#endif
+}
+
+
+/* method_get_parameterannotations ********************************************
+
+ Get a methods' unparsed parameter annotations in an array of byte
+ arrays.
+
+ IN:
+ m........the method of which the parameter annotations should be
+ returned
+
+ RETURN VALUE:
+ The unparsed parameter annotations in a byte array (or NULL if
+ there aren't any).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_parameterannotations(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+ classinfo *c; /* methods' declaring class */
+ int slot; /* methods' slot */
+ java_handle_t *parameterAnnotations; /* methods' unparsed */
+ /* parameter annotations */
+ java_handle_t *method_parameterannotations; /* all methods' unparsed */
+ /* parameter annotations of */
+ /* the declaring class */
+
+ c = m->clazz;
+ slot = m - c->methods;
+ parameterAnnotations = NULL;
+
+ LLNI_classinfo_field_get(
+ c, method_parameterannotations, method_parameterannotations);
+
+ /* the method_annotations array might be shorter then the method
+ * count if the methods above a certain index have no annotations.
+ */
+ if (method_parameterannotations != NULL &&
+ array_length_get(method_parameterannotations) > slot) {
+ parameterAnnotations = array_objectarray_element_get(
+ (java_handle_objectarray_t*)method_parameterannotations,
+ slot);
+ }
+
+ return (java_handle_bytearray_t*)parameterAnnotations;
+#else
+ return NULL;
+#endif
+}
+
+
+/* method_get_annotationdefault ***********************************************
+
+ Get a methods' unparsed annotation default value in a byte array.
+
+ IN:
+ m........the method of which the annotation default value should be
+ returned
+
+ RETURN VALUE:
+ The unparsed annotation default value in a byte array (or NULL if
+ there isn't one).
+
+*******************************************************************************/
+
+java_handle_bytearray_t *method_get_annotationdefault(methodinfo *m)
+{
+#if defined(ENABLE_ANNOTATIONS)
+ classinfo *c; /* methods' declaring class */
+ int slot; /* methods' slot */
+ java_handle_t *annotationDefault; /* methods' unparsed */
+ /* annotation default value */
+ java_handle_t *method_annotationdefaults; /* all methods' unparsed */
+ /* annotation default values of */
+ /* the declaring class */
+
+ c = m->clazz;
+ slot = m - c->methods;
+ annotationDefault = NULL;
+
+ LLNI_classinfo_field_get(
+ c, method_annotationdefaults, method_annotationdefaults);
+
+ /* the method_annotations array might be shorter then the method
+ * count if the methods above a certain index have no annotations.
+ */
+ if (method_annotationdefaults != NULL &&
+ array_length_get(method_annotationdefaults) > slot) {
+ annotationDefault = array_objectarray_element_get(
+ (java_handle_objectarray_t*)method_annotationdefaults, slot);
+ }
+
+ return (java_handle_bytearray_t*)annotationDefault;
+#else
+ return NULL;
+#endif
+}
+
+
+/* method_add_to_worklist ******************************************************
+
+ Add the method to the given worklist. If the method already occurs in
+ the worklist, the worklist remains unchanged.
+
+*******************************************************************************/
+
+static void method_add_to_worklist(methodinfo *m, method_worklist **wl)
+{
+ method_worklist *wi;
+
+ for (wi = *wl; wi != NULL; wi = wi->next)
+ if (wi->m == m)
+ return;
+
+ wi = NEW(method_worklist);
+ wi->next = *wl;
+ wi->m = m;
+
+ *wl = wi;
+}
+
+
+/* method_add_assumption_monomorphic *******************************************
+
+ Record the assumption that the method is monomorphic.
+
+ IN:
+ m.................the method
+ caller............the caller making the assumption
+
+*******************************************************************************/
+
+void method_add_assumption_monomorphic(methodinfo *m, methodinfo *caller)
+{
+ method_assumption *as;
+
+ /* XXX LOCKING FOR THIS FUNCTION? */
+
+ /* check if we already have registered this assumption */
+
+ for (as = m->assumptions; as != NULL; as = as->next) {
+ if (as->context == caller)
+ return;
+ }
+
+ /* register the assumption */
+
+ as = NEW(method_assumption);
+ as->next = m->assumptions;
+ as->context = caller;
+
+ m->assumptions = as;
+}
+
+/* method_break_assumption_monomorphic *****************************************
+
+ Break the assumption that this method is monomorphic. All callers that
+ have registered this assumption are added to the worklist.
+
+ IN:
+ m.................the method
+ wl................worklist where to add invalidated callers
+
+*******************************************************************************/
+
+void method_break_assumption_monomorphic(methodinfo *m, method_worklist **wl)
+{
+ method_assumption *as;
+
+ /* XXX LOCKING FOR THIS FUNCTION? */
+
+ for (as = m->assumptions; as != NULL; as = as->next) {
+ INLINELOG(
+ printf("ASSUMPTION BROKEN (monomorphism): ");
+ method_print(m);
+ printf(" in ");
+ method_println(as->context);
+ );
+
+ method_add_to_worklist(as->context, wl);
+
+#if defined(ENABLE_TLH) && 0
+ /* XXX hack */
+ method_assumption *as2;
+ as2 = m->assumptions;
+ m->assumptions = NULL;
+ method_break_assumption_monomorphic(as->context, wl);
+ /*
+ assert(m->assumptions == NULL);
+ m->assumptions = as2;*/
+#endif
+
+ }
+}
+
/* method_printflags ***********************************************************
Prints the flags of a method to stdout like.
return;
}
- if (m->flags & ACC_PUBLIC) printf(" PUBLIC");
- if (m->flags & ACC_PRIVATE) printf(" PRIVATE");
- if (m->flags & ACC_PROTECTED) printf(" PROTECTED");
- if (m->flags & ACC_STATIC) printf(" STATIC");
- if (m->flags & ACC_FINAL) printf(" FINAL");
- if (m->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
- if (m->flags & ACC_VOLATILE) printf(" VOLATILE");
- if (m->flags & ACC_TRANSIENT) printf(" TRANSIENT");
- if (m->flags & ACC_NATIVE) printf(" NATIVE");
- if (m->flags & ACC_INTERFACE) printf(" INTERFACE");
- if (m->flags & ACC_ABSTRACT) printf(" ABSTRACT");
+ if (m->flags & ACC_PUBLIC) printf(" PUBLIC");
+ if (m->flags & ACC_PRIVATE) printf(" PRIVATE");
+ if (m->flags & ACC_PROTECTED) printf(" PROTECTED");
+ if (m->flags & ACC_STATIC) printf(" STATIC");
+ if (m->flags & ACC_FINAL) printf(" FINAL");
+ if (m->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
+ if (m->flags & ACC_VOLATILE) printf(" VOLATILE");
+ if (m->flags & ACC_TRANSIENT) printf(" TRANSIENT");
+ if (m->flags & ACC_NATIVE) printf(" NATIVE");
+ if (m->flags & ACC_INTERFACE) printf(" INTERFACE");
+ if (m->flags & ACC_ABSTRACT) printf(" ABSTRACT");
+ if (m->flags & ACC_METHOD_BUILTIN) printf(" (builtin)");
+ if (m->flags & ACC_METHOD_MONOMORPHIC) printf(" (mono)");
+ if (m->flags & ACC_METHOD_IMPLEMENTED) printf(" (impl)");
}
#endif /* !defined(NDEBUG) */
return;
}
- utf_display_printable_ascii_classname(m->class->name);
+ if (m->clazz != NULL)
+ utf_display_printable_ascii_classname(m->clazz->name);
+ else
+ printf("NULL");
printf(".");
utf_display_printable_ascii(m->name);
utf_display_printable_ascii(m->descriptor);