1998-12-04 00:10:47 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
1999-11-02 09:38:29 +03:00
|
|
|
* 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/
|
1998-12-04 00:10:47 +03:00
|
|
|
*
|
1999-11-02 09:38:29 +03:00
|
|
|
* 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.
|
1998-12-04 00:10:47 +03:00
|
|
|
*
|
1999-11-02 09:38:29 +03:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1998-12-04 00:10:47 +03:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-02 09:38:29 +03:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
1998-12-04 00:10:47 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ClassWorld.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#if 0
|
|
|
|
#include "ClassCentral.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Size of each TypeKind
|
|
|
|
const int8 typeKindSizes[nTypeKinds] =
|
|
|
|
{
|
|
|
|
0, // tkVoid
|
|
|
|
1, // tkBoolean
|
|
|
|
1, // tkUByte
|
|
|
|
1, // tkByte
|
|
|
|
2, // tkChar
|
|
|
|
2, // tkShort
|
|
|
|
4, // tkInt
|
|
|
|
8, // tkLong
|
|
|
|
4, // tkFloat
|
|
|
|
8, // tkDouble
|
|
|
|
4, // tkObject
|
|
|
|
4, // tkSpecial
|
|
|
|
4, // tkArray
|
|
|
|
4 // tkInterface
|
|
|
|
};
|
|
|
|
|
|
|
|
// lg2 of the size of each TypeKind
|
|
|
|
const int8 lgTypeKindSizes[nTypeKinds] =
|
|
|
|
{
|
|
|
|
-1, // tkVoid
|
|
|
|
0, // tkBoolean
|
|
|
|
0, // tkUByte
|
|
|
|
0, // tkByte
|
|
|
|
1, // tkChar
|
|
|
|
1, // tkShort
|
|
|
|
2, // tkInt
|
|
|
|
3, // tkLong
|
|
|
|
2, // tkFloat
|
|
|
|
3, // tkDouble
|
|
|
|
2, // tkObject
|
|
|
|
2, // tkSpecial
|
|
|
|
2, // tkArray
|
|
|
|
2 // tkInterface
|
|
|
|
};
|
|
|
|
|
|
|
|
// Number of environment slots taken by each TypeKind
|
|
|
|
const int8 typeKindNSlots[nTypeKinds] =
|
|
|
|
{
|
|
|
|
0, // tkVoid
|
|
|
|
1, // tkBoolean
|
|
|
|
1, // tkUByte
|
|
|
|
1, // tkByte
|
|
|
|
1, // tkChar
|
|
|
|
1, // tkShort
|
|
|
|
1, // tkInt
|
|
|
|
2, // tkLong
|
|
|
|
1, // tkFloat
|
|
|
|
2, // tkDouble
|
|
|
|
1, // tkObject
|
|
|
|
1, // tkSpecial
|
|
|
|
1, // tkArray
|
|
|
|
1 // tkInterface
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
// Distinguished classes
|
|
|
|
const Class *cObject;
|
|
|
|
const Class *cThrowable;
|
|
|
|
const Class *cException;
|
|
|
|
const Class *cRuntimeException;
|
|
|
|
const Class *cArithmeticException;
|
|
|
|
const Class *cArrayStoreException;
|
|
|
|
const Class *cClassCastException;
|
|
|
|
const Class *cArrayIndexOutOfBoundsException;
|
|
|
|
const Class *cNegativeArraySizeException;
|
|
|
|
const Class *cNullPointerException;
|
|
|
|
|
|
|
|
// Internal classes
|
|
|
|
const Class *cPrimitiveType;
|
|
|
|
const Class *cPrimitiveArray;
|
|
|
|
const Class *cObjectArray;
|
|
|
|
const Class *cClass;
|
|
|
|
const Class *cInterface;
|
|
|
|
|
|
|
|
// Distinguished interfaces
|
|
|
|
const Interface *iCloneable;
|
|
|
|
|
|
|
|
// Distinguished objects
|
|
|
|
const JavaObject *oArithmeticException;
|
|
|
|
const JavaObject *oArrayStoreException;
|
|
|
|
const JavaObject *oClassCastException;
|
|
|
|
const JavaObject *oArrayIndexOutOfBoundsException;
|
|
|
|
const JavaObject *oNegativeArraySizeException;
|
|
|
|
const JavaObject *oNullPointerException;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the distinguished classes and objects.
|
|
|
|
// This routine must be called before any of these are referenced.
|
|
|
|
// Soon to be obsolete.
|
|
|
|
//
|
|
|
|
void initDistinguishedObjects()
|
|
|
|
{
|
|
|
|
cPrimitiveType = &Class::make(pkgInternal, "PrimitiveType", 0, 0, 0, 0, 0, 0, 0, true, sizeof(PrimitiveType), 0);
|
|
|
|
cPrimitiveArray = &Class::make(pkgInternal, "PrimitiveArray", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Array), 0);
|
|
|
|
cObjectArray = &Class::make(pkgInternal, "ObjectArray", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Array), 0);
|
|
|
|
cClass = &Class::make(pkgInternal, "Class", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Class), 0);
|
|
|
|
cInterface = &Class::make(pkgInternal, "Interface", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Interface), 0);
|
|
|
|
|
|
|
|
PrimitiveType::staticInit();
|
|
|
|
Array::staticInit();
|
|
|
|
|
|
|
|
cObject = &Class::make(pkgJavaLang, "Object", 0, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cThrowable = &Class::make(pkgJavaLang, "Throwable", cObject, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cException = &Class::make(pkgJavaLang, "Exception", cThrowable, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cRuntimeException = &Class::make(pkgJavaLang, "RuntimeException", cException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cArithmeticException = &Class::make(pkgJavaLang, "ArithmeticException", cRuntimeException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cArrayStoreException = &Class::make(pkgJavaLang, "ArrayStoreException", cRuntimeException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cClassCastException = &Class::make(pkgJavaLang, "ClassCastException", cRuntimeException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cIndexOutOfBoundsException = &Class::make(pkgJavaLang, "IndexOutOfBoundsException", cRuntimeException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cArrayIndexOutOfBoundsException = &Class::make(pkgJavaLang, "ArrayIndexOutOfBoundsException", cIndexOutOfBoundsException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cNegativeArraySizeException = &Class::make(pkgJavaLang, "NegativeArraySizeException", cRuntimeException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
cNullPointerException = &Class::make(pkgJavaLang, "NullPointerException", cRuntimeException, 0, 0, 0, 0, 0, 0, false, sizeof(JavaObject), 0);
|
|
|
|
|
|
|
|
iCloneable = new Interface(pkgJavaLang, "Cloneable", 0, 0, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
oArithmeticException = new JavaObject(*cArithmeticException);
|
|
|
|
oArrayStoreException = new JavaObject(*cArrayStoreException);
|
|
|
|
oClassCastException = new JavaObject(*cClassCastException);
|
|
|
|
oArrayIndexOutOfBoundsException = new JavaObject(*cArrayIndexOutOfBoundsException);
|
|
|
|
oNegativeArraySizeException = new JavaObject(*cNegativeArraySizeException);
|
|
|
|
oNullPointerException = new JavaObject(*cNullPointerException);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
inline const Class *toClass(ClassCentral ¢ral, const char *className)
|
|
|
|
{
|
|
|
|
return static_cast<Class *>(central.addClass(className).getThisClass());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const Interface *toInterface(ClassCentral ¢ral,
|
|
|
|
const char *className)
|
|
|
|
{
|
|
|
|
return static_cast<Interface *>(central.addClass(className).getThisClass());
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the distinguished classes and objects.
|
|
|
|
// This routine must be called before any of these are referenced.
|
|
|
|
//
|
|
|
|
void initDistinguishedObjects(ClassCentral &c)
|
|
|
|
{
|
|
|
|
cPrimitiveType = &Class::make(pkgInternal, "PrimitiveType", 0, 0, 0, 0, 0, 0, 0, true, sizeof(PrimitiveType), 0);
|
|
|
|
cPrimitiveArray = &Class::make(pkgInternal, "PrimitiveArray", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Array), 0);
|
|
|
|
cObjectArray = &Class::make(pkgInternal, "ObjectArray", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Array), 0);
|
|
|
|
cClass = &Class::make(pkgInternal, "Class", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Class), 0);
|
|
|
|
cInterface = &Class::make(pkgInternal, "Interface", 0, 0, 0, 0, 0, 0, 0, true, sizeof(Interface), 0);
|
|
|
|
|
|
|
|
PrimitiveType::staticInit();
|
|
|
|
Array::staticInit();
|
|
|
|
|
|
|
|
cObject = toClass(c, "java/lang/Object");
|
|
|
|
cThrowable = toClass(c, "java/lang/Throwable");
|
|
|
|
cException = toClass(c, "java/lang/Exception");
|
|
|
|
cRuntimeException = toClass(c, "java/lang/RuntimeException");
|
|
|
|
cArithmeticException = toClass(c, "java/lang/ArithmeticException");
|
|
|
|
cArrayStoreException = toClass(c, "java/lang/ArrayStoreException");
|
|
|
|
cClassCastException = toClass(c, "java/lang/ClassCastException");
|
|
|
|
cIndexOutOfBoundsException = toClass(c, "java/lang/IndexOutOfBoundsException");
|
|
|
|
cArrayIndexOutOfBoundsException = toClass(c, "java/lang/ArrayIndexOutOfBoundsException");
|
|
|
|
cNegativeArraySizeException = toClass(c, "java/lang/NegativeArraySizeException");
|
|
|
|
cNullPointerException = toClass(c, "java/lang/NullPointerException");
|
|
|
|
|
|
|
|
iCloneable = toInterface(c, "java/lang/Cloneable");
|
|
|
|
|
|
|
|
oArithmeticException = new JavaObject(*cArithmeticException);
|
|
|
|
oArrayStoreException = new JavaObject(*cArrayStoreException);
|
|
|
|
oClassCastException = new JavaObject(*cClassCastException);
|
|
|
|
oArrayIndexOutOfBoundsException = new JavaObject(*cIndexOutOfBoundsException);
|
|
|
|
oNegativeArraySizeException = new JavaObject(*cNegativeArraySizeException);
|
|
|
|
oNullPointerException = new JavaObject(*cNullPointerException);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Type
|
|
|
|
|
|
|
|
//
|
|
|
|
// Return true if sub is a subtype of super. In other words, return true if
|
|
|
|
// an instance or variable of type sub can be assigned to a variable of type super.
|
|
|
|
//
|
|
|
|
bool implements(const Type &sub, const Type &super)
|
|
|
|
{
|
|
|
|
// Every type is a subtype of itself.
|
|
|
|
if (&super == &sub)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
TypeKind superKind = super.typeKind;
|
|
|
|
TypeKind subKind = sub.typeKind;
|
|
|
|
|
|
|
|
switch (subKind) {
|
|
|
|
case tkObject:
|
|
|
|
switch (superKind) {
|
|
|
|
// A class's supertypes can only be its superclasses or superinterfaces --
|
|
|
|
// never primitive objects, arrays, or special objects.
|
|
|
|
case tkObject:
|
|
|
|
return static_cast<const Class *>(&sub)->implements(*static_cast<const Class *>(&super));
|
|
|
|
case tkInterface:
|
|
|
|
return static_cast<const Class *>(&sub)->implements(*static_cast<const Interface *>(&super));
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tkArray:
|
|
|
|
switch (superKind) {
|
|
|
|
// An array's supertypes can only be:
|
|
|
|
// the class Object,
|
|
|
|
// the interface Cloneable, or
|
|
|
|
// arrays whose element type is a supertype of this array's element type.
|
|
|
|
case tkObject:
|
|
|
|
return &super == cObject;
|
|
|
|
case tkArray:
|
|
|
|
return implements(static_cast<const Array *>(&sub)->elementType,
|
|
|
|
static_cast<const Array *>(&super)->elementType);
|
|
|
|
case tkInterface:
|
|
|
|
return &super == iCloneable;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tkInterface:
|
|
|
|
switch (superKind) {
|
|
|
|
// An interface's supertypes can only be:
|
|
|
|
// the class Object, or
|
|
|
|
// the interface's superinterfaces.
|
|
|
|
case tkObject:
|
|
|
|
return &super == cObject;
|
|
|
|
case tkInterface:
|
|
|
|
return static_cast<const Interface *>(&sub)->implements(*static_cast<const Interface *>(&super));
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
|
|
|
|
// There are no other nontrivial subtyping relationships.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// PrimitiveType
|
|
|
|
|
|
|
|
const PrimitiveType *PrimitiveType::primitiveTypes[nPrimitiveTypeKinds];
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the table used by the obtain method.
|
|
|
|
// cPrimitiveType must have already been initialized.
|
|
|
|
//
|
|
|
|
void PrimitiveType::staticInit()
|
|
|
|
{
|
|
|
|
assert(cPrimitiveType);
|
|
|
|
for (TypeKind tk = tkVoid; tk < nPrimitiveTypeKinds; tk = (TypeKind)(tk+1))
|
|
|
|
primitiveTypes[tk] = new PrimitiveType(*cPrimitiveType, tk);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Array
|
|
|
|
|
|
|
|
const Array *Array::primitiveArrays[nPrimitiveTypeKinds];
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize a type for arrays.
|
|
|
|
// Do not call this constructor directly; use obtain or Type::getArrayType instead.
|
|
|
|
//
|
|
|
|
Array::Array(const Type &elementType):
|
|
|
|
Type(isPrimitiveKind(elementType.typeKind) ? *cPrimitiveArray : *cObjectArray, tkArray, elementType.final, 0),
|
|
|
|
elementType(elementType)
|
|
|
|
{
|
|
|
|
assert(elementType.typeKind != tkVoid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the table used by the obtain method.
|
|
|
|
// PrimitiveType::obtain must have already been initialized.
|
|
|
|
//
|
|
|
|
void Array::staticInit()
|
|
|
|
{
|
|
|
|
primitiveArrays[tkVoid] = 0; // Can't have an array of type Void.
|
|
|
|
for (TypeKind tk = tkBoolean; tk < nPrimitiveTypeKinds; tk = (TypeKind)(tk+1))
|
|
|
|
primitiveArrays[tk] = &PrimitiveType::obtain(tk).getArrayType();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ClassOrInterface
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
//
|
|
|
|
// Print a reference to this class or interface for debugging purposes.
|
|
|
|
// Return the number of characters printed.
|
|
|
|
//
|
|
|
|
int ClassOrInterface::printRef(FILE *f) const
|
|
|
|
{
|
|
|
|
int o = package.printRef(f);
|
|
|
|
return o + fprintf(f, ".%s", name);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Class
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the fields of a Class object. This constructor may only be called
|
|
|
|
// from within Class::make because the Class object must be specially allocated to
|
|
|
|
// allow room for its vtable.
|
|
|
|
//
|
|
|
|
inline Class::Class(Package &package, const char *name, const Class *_parent,
|
|
|
|
uint32 nInterfaces,
|
|
|
|
Interface **interfaces,
|
|
|
|
uint32 nFields,
|
|
|
|
Field **fields,
|
|
|
|
uint32 nMethods,
|
|
|
|
Method **methods,
|
|
|
|
bool final, uint32 instanceSize, uint32 nVTableSlots):
|
|
|
|
ClassOrInterface(*cClass, tkObject, final, nVTableSlots, package, name,
|
|
|
|
nInterfaces, interfaces,
|
|
|
|
nFields, fields,
|
|
|
|
nMethods, methods),
|
|
|
|
instanceSize(instanceSize)
|
|
|
|
{
|
|
|
|
parent = const_cast<Class *>(_parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize a new Class object that describes essential information such as layout
|
|
|
|
// and inheritance relationships of objects of a single Java class.
|
|
|
|
//
|
|
|
|
// package is the package that defined this class.
|
|
|
|
// name is the unqualified name of this class.
|
|
|
|
// parent is the parent class or nil if this is the Class for the Object class.
|
|
|
|
// interfaces is an array of nInterfaces elements that lists all interfaces from which
|
|
|
|
// this class derives except that the interfaces array does not include interfaces
|
|
|
|
// from which the parent class derives.
|
|
|
|
// extraSize is the number of additional bytes taken by fields of this class and should
|
|
|
|
// be a multiple of 4.
|
|
|
|
// nExtraVTableSlots is the number of additional virtual methods that this class declares;
|
|
|
|
// it does not include the one vtable slot used for class membership testing.
|
|
|
|
//
|
|
|
|
Class &Class::make(Package &package, const char *name, const Class *parent, uint32 nInterfaces, Interface **interfaces,
|
|
|
|
uint32 nFields, Field **fields,
|
|
|
|
uint32 nMethods, Method **methods,
|
|
|
|
bool final, uint32 extraSize, uint32 nExtraVTableSlots)
|
|
|
|
{
|
|
|
|
uint32 nVTableSlots = nExtraVTableSlots + 1;
|
|
|
|
if (parent) {
|
|
|
|
assert(!parent->final);
|
|
|
|
nVTableSlots += parent->nVTableSlots;
|
|
|
|
extraSize += parent->instanceSize;
|
|
|
|
}
|
|
|
|
void *mem = malloc(sizeof(Class) + nVTableSlots*sizeof(VTableEntry));
|
|
|
|
return *new(mem) Class(package, name, parent, nInterfaces, interfaces,
|
|
|
|
nFields, fields, nMethods, methods,
|
|
|
|
final, extraSize, nVTableSlots);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Return true if this class implements class c.
|
|
|
|
//
|
|
|
|
bool Class::implements(const Class &c) const
|
|
|
|
{
|
|
|
|
const Class *a = this;
|
|
|
|
do {
|
|
|
|
if (a == &c)
|
|
|
|
return true;
|
|
|
|
a = a->parent;
|
|
|
|
} while (a);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Return true if this class implements interface i.
|
|
|
|
//
|
|
|
|
bool Class::implements(const Interface &i) const
|
|
|
|
{
|
|
|
|
const Class *a = this;
|
|
|
|
do {
|
|
|
|
uint32 n = a->nInterfaces;
|
|
|
|
Interface *const*intfs = a->interfaces;
|
|
|
|
while (n--) {
|
|
|
|
if (*intfs == &i)
|
|
|
|
return true;
|
|
|
|
intfs++;
|
|
|
|
}
|
|
|
|
a = a->parent;
|
|
|
|
} while (a);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Interface
|
|
|
|
|
|
|
|
//
|
|
|
|
// Return true if this interface implements interface i.
|
|
|
|
//
|
|
|
|
bool Interface::implements(const Interface &i) const
|
|
|
|
{
|
|
|
|
uint32 n = nInterfaces;
|
|
|
|
Interface *const*intfs = interfaces;
|
|
|
|
while (n--) {
|
|
|
|
if (*intfs == &i)
|
|
|
|
return true;
|
|
|
|
intfs++;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|