dmose%mozilla.org 2ccab49e6d updating license boilerplate to xPL v1.1
git-svn-id: svn://10.0.0.236/trunk@52526 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-02 06:38:29 +00:00

753 lines
21 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (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.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "java_lang_Class.h"
#include "java_lang_reflect_Field.h"
#include "java_lang_reflect_Method.h"
#include "java_lang_reflect_Constructor.h"
#include "JavaVM.h"
#include "JavaString.h"
#include "prprf.h"
#include "SysCallsRuntime.h"
#include "StackWalker.h"
enum FieldOrMethodCategory {
fieldOrMethodCategoryPublic=0,
fieldOrMethodCategoryDeclared=1
};
static inline void throwClassVerifyException(VerifyError err)
{
// FIXME Need to be more specific in the exceptions we throw here
switch (err.cause) {
case VerifyError::noClassDefFound:
case VerifyError::badClassFormat:
default:
sysThrowNamedException("java/lang/ClassNotFoundException");
break;
case VerifyError::illegalAccess:
sysThrowNamedException("java/lang/IllegalAccessException");
break;
}
}
static inline void throwClassRuntimeException(RuntimeError err)
{
// FIXME Need to be more specific in the exceptions we throw here
switch (err.cause) {
case RuntimeError::illegalAccess:
sysThrowNamedException("java/lang/IllegalAccessException");
break;
case RuntimeError::nullPointer:
sysThrowNullPointerException();
break;
default:
sysThrowNamedException("java/lang/IllegalArgumentException");
break;
}
}
extern "C" {
/* Some interesting things to remember:
* (1) What is passed to all native methods of java/lang/Class is an instance
* of the VM class Class.
* (2) All native routines here do not check for security restrictions; it is
* assumed that security is dealt with at a higher level.
*/
static inline Type &toType(Java_java_lang_Class &inClass)
{
Type &type = *(Type *) (&inClass);
return type;
}
static inline JavaObject &toObject(Java_java_lang_Object &inObject)
{
return *(Class *)(&inObject);
}
/*
* Class : java/lang/Class
* Method : forName
* Signature : (Ljava/lang/String;)Ljava/lang/Class;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_Class *)
Netscape_Java_java_lang_Class_forName(Java_java_lang_String *nameString)
{
if (!nameString)
sysThrowNamedException("java/lang/ClassNotFoundException");
ClassCentral &central = VM::getCentral();
char *name = ((JavaString *) nameString)->convertUtf();
// Replace dots with slashes to obtain the fully qualified name of the class.
// central.addClass() expects a fully qualified class name.
for (char *p = name; *p; p++)
if (*p == '.') *p = '/';
Class *clz;
try {
clz = static_cast<Class *>(central.addClass(name).getThisClass());
} catch(VerifyError err) {
throwClassVerifyException(err);
} catch(RuntimeError err) {
throwClassRuntimeException(err);
}
/* Free the memory we just allocated */
JavaString::freeUtf(name);
return (Java_java_lang_Class *) clz;
}
/*
* Class : java/lang/Class
* Method : forName0
* Signature : (Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_Class *)
Netscape_Java_java_lang_Class_forName0(Java_java_lang_String *nameString,
uint32 /* bool */,
Java_java_lang_ClassLoader *)
{
// IMPLEMENT
return Netscape_Java_java_lang_Class_forName(nameString);
}
/*
* Class : java/lang/Class
* Method : newInstance0
* Signature : ()Ljava/lang/Object;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_Object *)
Netscape_Java_java_lang_Class_newInstance0(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
// We can't instantiate primitive types, arrays or interfaces
if (type.typeKind != tkObject)
sysThrowNamedException("java/lang/InstantiationException");
const Class &clazz = asClass(type);
// Check to see if the caller of the class has package access to this class
Frame thisFrame;
// Skip over our caller's frame, that of java.lang.Class.newInstance()
Method &callerMethod = thisFrame.getCallingJavaMethod(2);
ClassOrInterface *callingClass;
callingClass = callerMethod.getDeclaringClass();
bool hasPackageAccess = false;
if (callingClass->package.name == clazz.package.name)
hasPackageAccess = true;
// Check argument type. Make sure that the class that called this
// method is a class that can access the class clazz.
if (!(clazz.getModifiers() & CR_ACC_PUBLIC) && !hasPackageAccess)
sysThrowNamedException("java/lang/IllegalAccessException");
// Make sure that the class is instantiable. The class is
// instantiable if it is not abstract, and has at least one constructor
// that the calling class can access.
if ((clazz.getModifiers() & CR_ACC_ABSTRACT) || clazz.isInterface())
sysThrowNamedException("java/lang/InstantiationException");
Constructor *constructor = NULL;
const Constructor **declaredConstructors;
Int32 nDeclaredConstructors;
// Check that there is at least one constructor that the calling class can call
nDeclaredConstructors =
const_cast<Class *>(&clazz)->getDeclaredConstructors(declaredConstructors);
/* Now go through each of these declared constructors and see if we have
* package access to any of them
* FIXME This is horrendous, too much work. Think about not doing this much
* work everytime.
*/
for (int i = 0; i < nDeclaredConstructors; i++) {
constructor = const_cast<Constructor*>(declaredConstructors[i]);
// Find a constructor that takes no arguments other than 'this'
if (constructor->getSignature().nArguments > 1)
continue;
int32 modifiers = constructor->getModifiers();
if (modifiers & CR_METHOD_PUBLIC)
break;
// Can't invoke private constructors
if (modifiers & CR_METHOD_PRIVATE)
continue;
// See if we can invoke a constructor with package scope
if (hasPackageAccess)
break;
}
if (i == nDeclaredConstructors)
sysThrowNamedException("java/lang/IllegalAccessException");
try {
return (Java_java_lang_Object *)&constructor->newInstance(NULL, 0);
} catch (RuntimeError err) {
throwClassRuntimeException(err);
}
}
/*
* Class : java/lang/Class
* Method : isInstance
* Signature : (Ljava/lang/Object;)Z
*/
NS_EXPORT NS_NATIVECALL(uint32 /* bool */)
Netscape_Java_java_lang_Class_isInstance(Java_java_lang_Class *inClass,
Java_java_lang_Object *inObj)
{
Type &type = toType(*inClass);
if (type.isPrimitive())
return (Uint32)false;
if (!inObj)
return false;
const Class &clazz = asClass(type);
return (Uint32) clazz.isInstance(toObject(*inObj));
}
/*
* Class : java/lang/Class
* Method : isAssignableFrom
* Signature : (Ljava/lang/Class;)Z
*/
NS_EXPORT NS_NATIVECALL(uint32) /* bool */
Netscape_Java_java_lang_Class_isAssignableFrom(Java_java_lang_Class * inClass,
Java_java_lang_Class * inToClass)
{
if (!inToClass)
sysThrowNullPointerException();
return toType(*inClass).isAssignableFrom(toType(*inToClass));
}
/*
* Class : java/lang/Class
* Method : isInterface
* Signature : ()Z
*/
NS_EXPORT NS_NATIVECALL(uint32 /* bool */)
Netscape_Java_java_lang_Class_isInterface(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
return type.isInterface();
}
/*
* Class : java/lang/Class
* Method : isArray
* Signature : ()Z
*/
NS_EXPORT NS_NATIVECALL(uint32 /* bool */)
Netscape_Java_java_lang_Class_isArray(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
return type.isArray();
}
/*
* Class : java/lang/Class
* Method : isPrimitive
* Signature : ()Z
*/
NS_EXPORT NS_NATIVECALL(uint32 /* bool */)
Netscape_Java_java_lang_Class_isPrimitive(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
return type.isPrimitive();
}
/*
* Class : java/lang/Class
* Method : getName
* Signature : ()Ljava/lang/String;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_String *)
Netscape_Java_java_lang_Class_getName(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
const char *fullName = type.getName();
JavaString &fullNameStr = VM::intern(fullName);
return (Java_java_lang_String *) &fullNameStr;
}
/*
* Class : java/lang/Class
* Method : getClassLoader
* Signature : ()Ljava/lang/ClassLoader;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_ClassLoader *)
Netscape_Java_java_lang_Class_getClassLoader(Java_java_lang_Class *)
{
#ifdef DEBUG_LOG
PR_fprintf(PR_STDERR, "Netscape_Java_java_lang_Class_getClassLoader() not implemented");
#endif
return 0;
}
/*
* Class : java/lang/Class
* Method : getSuperclass
* Signature : ()Ljava/lang/Class;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_Class *)
Netscape_Java_java_lang_Class_getSuperclass(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
const Type *superClass = type.getSuperClass();
return (Java_java_lang_Class *) superClass;
}
/*
* Class : java/lang/Class
* Method : getInterfaces
* Signature : ()[Ljava/lang/Class;
*/
NS_EXPORT NS_NATIVECALL(ArrayOf_Java_java_lang_Class *)
Netscape_Java_java_lang_Class_getInterfaces(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
if (isPrimitiveKind(type.typeKind))
sysThrowNamedException("java/lang/IllegalAccessException");
ClassOrInterface &clazz = *static_cast<ClassOrInterface *>(&type);
Interface **interfaces;
Int32 numInterfaces = clazz.getInterfaces(interfaces);
JavaArray *arr = (JavaArray *) sysNewObjectArray(&VM::getStandardClass(cClass), numInterfaces);
ArrayOf_Java_java_lang_Class *clazzArray = (ArrayOf_Java_java_lang_Class *) arr;
for (Int32 i = 0; i < numInterfaces; i++)
clazzArray->elements[i] = (Java_java_lang_Class *) interfaces[i];
return clazzArray;
}
/*
* Class : java/lang/Class
* Method : getComponentType
* Signature : ()Ljava/lang/Class;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_Class *)
Netscape_Java_java_lang_Class_getComponentType(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
if (!type.isArray())
return NULL;
const Type &componentType = asArray(type).getComponentType();
return (Java_java_lang_Class *) &componentType;
}
/*
* Class : java/lang/Class
* Method : getModifiers
* Signature : ()I
*/
NS_EXPORT NS_NATIVECALL(int32)
Netscape_Java_java_lang_Class_getModifiers(Java_java_lang_Class *inClass)
{
Type &type = toType(*inClass);
return type.getModifiers();
}
/*
* Class : java/lang/Class
* Method : getSigners
* Signature : ()[Ljava/lang/Object;
*/
NS_EXPORT NS_NATIVECALL(ArrayOf_Java_java_lang_Object *)
Netscape_Java_java_lang_Class_getSigners(Java_java_lang_Class *)
{
printf("Netscape_Java_java_lang_Class_getSigners() not implemented");
return 0;
}
/*
* Class : java/lang/Class
* Method : setSigners
* Signature : ([Ljava/lang/Object;)V
*/
NS_EXPORT NS_NATIVECALL(void)
Netscape_Java_java_lang_Class_setSigners(Java_java_lang_Class *, ArrayOf_Java_java_lang_Object *)
{
printf("Netscape_Java_java_lang_Class_setSigners() not implemented");
}
/*
* Class : java/lang/Class
* Method : getPrimitiveClass
* Signature : (Ljava/lang/String;)Ljava/lang/Class;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_Class *)
Netscape_Java_java_lang_Class_getPrimitiveClass(Java_java_lang_String *nameString)
{
if (!nameString)
return NULL;
char *className = ((JavaString *) nameString)->convertUtf();
const PrimitiveType *clazz = PrimitiveType::getClass(className);
/* Free the memory we just allocated */
JavaString::freeUtf(className);
return (Java_java_lang_Class *)clazz;
}
/*
* Class : java/lang/Class
* Method : getFields0
* Signature : (I)[Ljava/lang/reflect/Field;
*
* fieldCategory tells us what class of fields to return.
* fieldCategory can have the values defined in enum FieldCategory,
* defined above.
*/
NS_EXPORT NS_NATIVECALL(ArrayOf_Java_java_lang_reflect_Field *)
Netscape_Java_java_lang_Class_getFields0(Java_java_lang_Class *inClass,
int32 category)
{
#if 0
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
const Field **fields;
Int32 numFields;
if (category == fieldOrMethodCategoryPublic)
numFields = clazz.getFields(fields);
else
numFields = clazz.getDeclaredFields(fields);
const Type *classField = &VM::getStandardClass(cField);
JavaArray *arr = (JavaArray *) sysNewObjectArray(classField, numFields);
ArrayOf_Java_java_lang_reflect_Field *fieldArray =
(ArrayOf_Java_java_lang_reflect_Field *) arr;
for (Int32 i = 0; i < numFields; i++)
fieldArray->elements[i] = (Java_java_lang_reflect_Field *) fields[i];
return fieldArray;
#else
bool publik = (category == fieldOrMethodCategoryPublic);
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
Int32 numFields = 0;
if (publik) {
Int32 i;
/* Walk all interfaces that we implement */
Int32 interfaceCount;
Interface **interfaces;
interfaceCount = clazz.getInterfaces(interfaces);
for (i = 0; i < interfaceCount; i++) {
const Field **dummy;
numFields += interfaces[i]->getFields(dummy);
}
/* Walk our instance fields from child to parent */
ClassOrInterface *tmp;
for (tmp = &clazz; tmp; tmp = (ClassOrInterface *) tmp->getSuperClass()) {
const Field **fieldsInThisClass;
Int32 numFieldsInThisClass = tmp->getDeclaredFields(fieldsInThisClass);
for (i = 0; i < numFieldsInThisClass; i++)
if (fieldsInThisClass[i]->getModifiers() & CR_FIELD_PUBLIC)
numFields++;
}
/* Allocate a JavaArray of the correct size */
const Type *classField = &VM::getStandardClass(cField);
JavaArray *arr = (JavaArray *) sysNewObjectArray(classField, numFields);
ArrayOf_Java_java_lang_reflect_Field *fieldArray =
(ArrayOf_Java_java_lang_reflect_Field *) arr;
Int32 index = 0;
/* Walk the fields again, this time copying them into our array */
for (i = 0; i < interfaceCount; i++) {
const Field **interfaceFields;
Int32 numInterfaceFields = interfaces[i]->getFields(interfaceFields);
for (Int32 j = 0; j < numInterfaceFields; j++)
fieldArray->elements[index++] = (Java_java_lang_reflect_Field *) interfaceFields[j];
}
/* Add instance fields, starting with the topmost superclass */
Vector<ClassOrInterface *> vec;
for (tmp = &clazz; tmp; tmp = (ClassOrInterface *)(tmp->getSuperClass()))
vec.append(tmp);
for (Int32 vectorIndex = vec.size(); vectorIndex > 0; vectorIndex--) {
tmp = vec[vectorIndex-1];
const Field **fieldsInThisClass;
Int32 numFieldsInThisClass = tmp->getDeclaredFields(fieldsInThisClass);
for (i = 0; i < numFieldsInThisClass; i++)
if (fieldsInThisClass[i]->getModifiers() & CR_FIELD_PUBLIC)
fieldArray->elements[index++] = (Java_java_lang_reflect_Field *) fieldsInThisClass[i];
}
assert(index == numFields);
return fieldArray;
} else {
const Field **fields;
numFields = clazz.getDeclaredFields(fields);
const Type *classField = &VM::getStandardClass(cField);
JavaArray *arr = (JavaArray *) sysNewObjectArray(classField, numFields);
ArrayOf_Java_java_lang_reflect_Field *fieldArray =
(ArrayOf_Java_java_lang_reflect_Field *) arr;
for (Int32 i = 0; i < numFields; i++)
fieldArray->elements[i] = (Java_java_lang_reflect_Field *) fields[i];
return fieldArray;
}
#endif
}
/*
* Class : java/lang/Class
* Method : getMethods0
* Signature : (I)[Ljava/lang/reflect/Method;
*/
NS_EXPORT NS_NATIVECALL(ArrayOf_Java_java_lang_reflect_Method *)
Netscape_Java_java_lang_Class_getMethods0(Java_java_lang_Class *inClass,
int32 category)
{
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
const Method **methods;
Int32 numMethods;
if (category == fieldOrMethodCategoryPublic)
numMethods = clazz.getMethods(methods);
else
numMethods = clazz.getDeclaredMethods(methods);
const Type *classMethod = &VM::getStandardClass(cMethod);
JavaArray *arr = (JavaArray *) sysNewObjectArray(classMethod, numMethods);
ArrayOf_Java_java_lang_reflect_Method *methodArray =
(ArrayOf_Java_java_lang_reflect_Method *) arr;
for (Int32 i = 0; i < numMethods; i++)
methodArray->elements[i] = (Java_java_lang_reflect_Method *) methods[i];
return methodArray;
}
/*
* Class : java/lang/Class
* Method : getConstructors0
* Signature : (I)[Ljava/lang/reflect/Constructor;
*/
NS_EXPORT NS_NATIVECALL(ArrayOf_Java_java_lang_reflect_Constructor *)
Netscape_Java_java_lang_Class_getConstructors0(Java_java_lang_Class *inClass,
int32 category)
{
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
const Constructor **constructors;
Int32 numConstructors;
if (category == fieldOrMethodCategoryPublic)
numConstructors = clazz.getConstructors(constructors);
else
numConstructors = clazz.getDeclaredConstructors(constructors);
const Type *classConstructor = &VM::getStandardClass(cConstructor);
JavaArray *arr = (JavaArray *) sysNewObjectArray(classConstructor, numConstructors);
ArrayOf_Java_java_lang_reflect_Constructor *constructorArray =
(ArrayOf_Java_java_lang_reflect_Constructor *) arr;
for (Int32 i = 0; i < numConstructors; i++)
constructorArray->elements[i] = (Java_java_lang_reflect_Constructor *) constructors[i];
return constructorArray;
}
/*
* Class : java/lang/Class
* Method : getField0
* Signature : (Ljava/lang/String;I)Ljava/lang/reflect/Field;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_reflect_Field *)
Netscape_Java_java_lang_Class_getField0(Java_java_lang_Class *inClass,
Java_java_lang_String *inName,
int32 category)
{
if (!inName || !inClass)
sysThrowNullPointerException();
char *name = ((JavaString *) inName)->convertUtf();
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
const Field *field;
try {
if (category == fieldOrMethodCategoryPublic)
field = &clazz.getField(name);
else
field = &clazz.getDeclaredField(name);
} catch (RuntimeError) {
sysThrowNamedException("java/lang/NoSuchFieldException");
}
JavaString::freeUtf(name);
return (Java_java_lang_reflect_Field *)field;
}
/*
* Class : java/lang/Class
* Method : getMethod0
* Signature : (Ljava/lang/String;[Ljava/lang/Class;I)Ljava/lang/reflect/Method;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_reflect_Method *)
Netscape_Java_java_lang_Class_getMethod0(Java_java_lang_Class *inClass,
Java_java_lang_String *inName,
ArrayOf_Java_java_lang_Class *paramTypes,
int32 category)
{
if (!inName)
sysThrowNullPointerException();
Int32 numParams;
const Type **params;
if (!paramTypes) {
Type *dummy[1];
params = (const Type **) dummy;
numParams = 0;
} else {
params = (const Type **) paramTypes->elements;
numParams = paramTypes->length;
}
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
char *name = ((JavaString *) inName)->convertUtf();
const Method *method;
try {
if (category == fieldOrMethodCategoryPublic)
method = &clazz.getMethod(name, params, numParams);
else
method = &clazz.getDeclaredMethod(name, params, numParams);
} catch (RuntimeError) {
sysThrowNamedException("java/lang/NoSuchMethodException");
}
JavaString::freeUtf(name);
return (Java_java_lang_reflect_Method *) method;
}
/*
* Class : java/lang/Class
* Method : getConstructor0
* Signature : ([Ljava/lang/Class;I)Ljava/lang/reflect/Constructor;
*/
NS_EXPORT NS_NATIVECALL(Java_java_lang_reflect_Constructor *)
Netscape_Java_java_lang_Class_getConstructor0(Java_java_lang_Class *inClass,
ArrayOf_Java_java_lang_Class *paramTypes,
int32 category)
{
ClassOrInterface &clazz = *(ClassOrInterface *) &toType(*inClass);
const Type **params;
Uint32 nParams;
if (paramTypes == 0) {
params = (const Type **) 0;
nParams = 0;
} else {
params = (const Type **) paramTypes->elements;
nParams = paramTypes->length;
}
Constructor *constructor;
try {
if (category == fieldOrMethodCategoryPublic)
constructor = &clazz.getConstructor(params, nParams);
else
constructor = &clazz.getDeclaredConstructor(params, nParams);
} catch (RuntimeError) {
sysThrowNamedException("java/lang/NoSuchMethodException");
}
return (Java_java_lang_reflect_Constructor *) constructor;
}
} /* extern "C" */