/* -*- 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 "ClassWorld.h" #include #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(central.addClass(className).getThisClass()); } inline const Interface *toInterface(ClassCentral ¢ral, const char *className) { return static_cast(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(&sub)->implements(*static_cast(&super)); case tkInterface: return static_cast(&sub)->implements(*static_cast(&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(&sub)->elementType, static_cast(&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(&sub)->implements(*static_cast(&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(_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; }