org.vishia.java2C
Class Docu.D_SuperClassesAndInterfaces

java.lang.Object
  extended by org.vishia.java2C.Docu.D_SuperClassesAndInterfaces
Enclosing class:
Docu

public class Docu.D_SuperClassesAndInterfaces
extends java.lang.Object

Java knows simple inheritance but multiple usage of interfaces. Interfaces may contain static final variables, they are constants, and method declarations. All method declarations should be implemented in a non-abstract inheriting class. The super classes may contain also method declarations (using abstract keyword), which have to be implemented in an inheriting class.

Interface may contain complete classes as inner classes too.

All variables of super classes are available in the data of the inheriting class too, only a private modifier prevents an access. Interface hasn't any class variable


Constructor Summary
Docu.D_SuperClassesAndInterfaces()
           
 
Method Summary
 void D1_baseStructures()
          A super class in Java is mapped in C using a base struct as first element of the class representing struct.
 void D2_virtualMethodsAndInheritanceInfo()
          The concept of virtual methods is necessary for implementation of interfaces and for overridden methods in derived classes.
 void D3_detectOverriddenMethods()
          If a method of the current translated class is processed and adds to the class using ClassData.addMethod(String, String, int, FieldData, FieldData[]), it is searched in all super classes and interfaces calling ClassData.searchOverrideableMethod(String, FieldData[]).
 void D4_newOverrideAbleMethods()
          If a new method is created, and it is able to override, it is registered in ClassData.methodsOverrideableNew just now.
 void D5_cCodeForOverriddenMethods()
          The overridden methods have the type of ythis from the first declaring class, because they have to be the same signature (type of method definition) as the first declaring ones.
 void D6_callingOverrideableMethods()
          If a method is called in Java, which is override-able, the generated C-code depends on several conditions:

Stack-local reference:
If the reference is a stack-local reference in Java, it may be generated in C as a so named method-table-reference.
 void D7_preventCallingViaMethodTable()
          In Java the methods are override-able normally, because a final designation to prevent overriding is written only if the ability to override should prevent in inheriting classes.
 void D8_gen_MethodTable()
          The structure of a method table is generated into the header-file, but the definition of a method table is generated into the C-file.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

Docu.D_SuperClassesAndInterfaces

public Docu.D_SuperClassesAndInterfaces()
Method Detail

D1_baseStructures

public void D1_baseStructures()
A super class in Java is mapped in C using a base struct as first element of the class representing struct. The following commonly form is used:
 typedef struct TheClass_t
 { union { ObjectJc object; SuperClass_s super; Interface1_s Interface1; Ifc2_s Ifc2; } base;
   //rest of class data
 }
 
A union is built in C because the object, all interfaces and the data of the super class represents the same data: The super class starts with the object, all interfaces contains only the same object. The SuperClass determines the size of the union's data.



The Types of super, Interfaces etc. are the built C-Types. It may have pre- and suffixes (see Docu.ProcessOfTranslation#packageReplacement()) and it has the usual suffix _s to different it from a possible C++ type definition.


D2_virtualMethodsAndInheritanceInfo

public void D2_virtualMethodsAndInheritanceInfo()
The concept of virtual methods is necessary for implementation of interfaces and for overridden methods in derived classes.

The class ClassData contains a field ClassData.inheritanceInfo. The Type ClassData.InheritanceInfo contains the reference to the superclass's and interfaces InheritanceInfo. The referenced instances of the type ClassData.InheritanceInfo are not instances of the inherited class, they are independent instances and built a data-private own InheritanceInfo-tree. The reason for that plurality of InheritanceInfo is: They contain the override-able (virtual) method names: ClassData.InheritanceInfo.methodTable. The virtual methods are differently for a class as superclass of another class (contains the derived virtual method) and for the class able to instantiate in another context. The field ClassData.InheritanceInfo.methodTable contains the overriding names of all override-able methods of the current class. The override-able and overridden methods of interfaces and super classes are located in the ClassData.InheritanceInfo.methodTable of the super-classes and interface referenced with ClassData.InheritanceInfo.superInheritance and ClassData.InheritanceInfo.ifcInheritance.

The constructor ClassData.InheritanceInfo#InheritanceInfo(ClassData, ClassData, ClassData[]) uses the superclass and all interfaces to build its own tree of Inheritance objects. Thereby the names in ClassData.MethodOverrideable.sNameOverriding are copied from the original instance, the overridden method is the same:





D3_detectOverriddenMethods

public void D3_detectOverriddenMethods()
If a method of the current translated class is processed and adds to the class using ClassData.addMethod(String, String, int, FieldData, FieldData[]), it is searched in all super classes and interfaces calling ClassData.searchOverrideableMethod(String, FieldData[]). If it is found there, it is an overridden method. Therefore a new Instance of Method is created, but the information about the Method.declaringClass is taken from the found method. The name in the ClassData.InheritanceInfo.methodTable is replaced with the actual method.


D4_newOverrideAbleMethods

public void D4_newOverrideAbleMethods()
If a new method is created, and it is able to override, it is registered in ClassData.methodsOverrideableNew just now. On finishing of translation the class the method ClassData.completeInheritanceWithOwnMethods() is called. It creates the array in ClassData.InheritanceInfo.methodTable with the correct array size and adds the methods. Thereby the override-able methods of the current class, which are not defined in super classes or interfaces, where registered. A method is able to override if it is non-final.


D5_cCodeForOverriddenMethods

public void D5_cCodeForOverriddenMethods()
The overridden methods have the type of ythis from the first declaring class, because they have to be the same signature (type of method definition) as the first declaring ones. The type of ythis of interface-defined methods is ObjectJc* any time and not, like able to expect, the type of the interface. It is, because a method can be declared in more as one interface. If a class implements more as one interface with the same method declaration, it exists only one implementation. This implementation can't regard a type of one of the interfaces, it should be resolved both. The type ObjectJc* is the commonly of all.

The implementation of an override-able method is designated with the suffix _F (means Final). This method name is used as entry in the method table of the class. This name is used too if a method of a dedicated type is called (annotation @ java2c=instanceType:"Type".).

Additionally a method with the normal built name of non-override-able methods are generated, but that method contains (example):
 / * J2C: dynamic call variant of the override-able method: * /
 int32 processIfcMethod_i_ImplIfc_Test(ObjectJc* ithis, int32 input, ThCxt* _thCxt)
 { Mtbl_Ifc_Test const* mtbl = (Mtbl_Ifc_Test const*)getMtbl_ObjectJc(ithis, sign_Mtbl_Ifc_Test);
   return mtbl->processIfcMethod(ithis, input, _thCxt);
 }
 
It is the variant ready to call at C-level which gets the pointer to the method table internally. A simple call from outside C sources can use this variant of method. But it isn't optimal in calculation time, because the call of getMtbl_ObjectJc(...) needs additional time. See #callingOverrideableMethods() in its variants.

The implementation of a method in a derived class starts with a casting from the given data type, at example:
 int32 processIfcMethod_i_ImplIfc_Test_F(ObjectJc* ithis, int32 input, ThCxt* _thCxt)
 { ImplIfc_Test_s* ythis = (ImplIfc_Test_s*)ithis;
 
The pointer casting should be accept as safe, because this method is only called in an context, where the really instance is of the correct type or a derived type, which contains the correct type as first part of data. The name of method is only used in an programming context of the method table, and in an context where the user declares a reference pointer from base or interface type as a pointer of a given instance using @ java2c=instanceType:"Type". That positions of code should be checked carefully.

It is possible to check the instance additionally, but this check needs additional calculation time. If it may be needed, at Java-level an instanceof operation can be written either in the implementing method or, it may be better, at calling position of a method with designation @ java2c=instanceType:"Type". Than the declaration of a determined instance type will be checked at run time too. The assert(ref instanceof Type) produces a C-code like
 ASSERT(instanceof_ObjectJc(& ((* (ref)).base.object), &reflection_Type_s));
 


D6_callingOverrideableMethods

public void D6_callingOverrideableMethods()
If a method is called in Java, which is override-able, the generated C-code depends on several conditions:

Stack-local reference:
If the reference is a stack-local reference in Java, it may be generated in C as a so named method-table-reference. The conditions for that are: The method-table-reference is defined locally in the C-file in form (example)
   typedef struct Type_t { struct Mtbl_Type_t const* mtbl; struct Type_t* ref; } TypeMTB;
 
The named class in C is Type, The method-table-reference contains the reference (pointer) to the data and additionally the reference to the method table. The reference variable should be set before using of course, The setting is generated (example)
   SETMTBJc(ifc3, & ((ythis->implifc).base.Ifc_Test), Ifc_Test);
 
It is a macro, defined in ObjectJc.h. The first parameter is the reference to set, the second parameter is the source, in this case the class-locally reference implifc, correct casted to the interface type using the access to base classes. The third parameter is the type. The implementation of this macro is done with (objectJc.h)
   #define SETMTBJc(DST, REF, TYPE) 
   { (DST).ref = REF; 
     (DST).mtbl = (Mtbl_##TYPE const*)
                  getMtbl_ObjectJc(&(DST).ref->base.object, sign_Mtbl_##TYPE); 
   } 
 
The data-reference is set, the reference to the method table is got calling the showed method. Therefore the pointer to the method table is checked, it isn't only a lightweight pointer in data area, it is got with two significance checks, and therefore secure. Because the pointer is stored in the stack range, it should be secure in the current thread, no other thread can disturb it (importend for safety critical software).

The access to virtual methods is generated in form (example)
   ifc3.mtbl->processIfcMethod(&(( (ifc3.ref))->base.object), 5, _thCxt);
 
It is an immediate access to the method table reference (in stack, therefore safety) with selecting the correct method (a C-function-pointer in the method table). The first parameter is the reference to the data in form of the ObjectJc*-Type, the following parameters are normal.

If the method is called some times in the same context, or the method-table-reference is passed as parameter to called methods, the method table reference is used immediately, no additional calculation time is need to get the method-tables reference once more. This is the optimized version if dynamic linked calls are necessary, able to use in very hard realtime too.

ythis-reference, own methods:
If own methods are called in a subroutine, it can't be assumed that the methods are methods of the current type, it can be methods from a inheriting instance too. It is because the instance can be inherited, but the current method is a method implemented in base-class. Therefore a call via method table is generated. If any own method is called, at start of routine the reference to the method table of the instance mthis is built generating (example):
 Mtbl_TestAllConcepts_Test const* mtthis = 
     (Mtbl_TestAllConcepts_Test const*)
     getMtbl_ObjectJc(&ythis->base.object, sign_Mtbl_TestAllConcepts_Test);
 
This reference is used to call own override-able methods (example):
 mtthis->Ifc_Test.processIfcMethod(&
           ((& ((* (ythis)).base.super.base.Ifc_Test))->base.object)
           , 4, _thCxt);
 
In the example a method from a super class is called which is override-able in the current class too. It is an interface-defined method. Therefore the data pointer is the pointer to ObjectJc*, got with access to the &(...)->base.object. The building of interface reference starting with the reference to the base class in the example & ((* (ythis)).base.super.base.Ifc_Test is a unnecessary but automatic generated complexity, which are resolved from the C-compiler to a simple pointer, because all offsets are zero. It isn't disturb.

The built of the mthis locally in the subroutine isn't optimal if it is repeated in called subroutines. It should be optimized (later versions): If a method calls own override-able methods, it shouldn't get the ythis-pointer of the data, but instead a method-table-enhanced reference. The calling method, which has this enhanced reference already, can use it directly without additional effort. Only a method which calls such a routine firstly, should built the reference to the methodtable (calling getMtbl_ObjectJc(...). The reference to the method table can recognize as safety, because it is stored only in the stack area, not in thread-unbound data areas.

reference in data area (ythis->ref) A dynamic call with a reference in the data area is the most non-economic, because the pointer to the method table is built in specially for this call. It is translated from Java2C in form (example):
 ((Mtbl_Ifc_Test const*)getMtbl_ObjectJc
   (&(REFJc(ythis->ifc))->base.object, sign_Mtbl_Ifc_Test) )->processIfcMethod
   (&((REFJc(ythis->ifc))->base.object), 56, _thCxt);
 
The getting of the method table is generated inline before call the method (first+second line). The third line contains the normal parameter (in reality its one line).

Because this operation need the call of getMtbl_ObjectJc(...) only for this intention, it should only used for a simple single dynamic call. If the algorithm should be optimized in calculation time, the class-visible reference is transfered in a reference in stack (statement-block-local)- variable). Than the call of getMtbl_ObjectJc(...) is done only one time, maybe before start of an loop, and it is used many times. It is a mission for the Java programming. In pure-Java it is indifferent using a class visible or block visible reference. But if an optimized C-source is need, use the block-local variant.

prevent dynamic call, use static instead See #preventCallingViaMethodTable(), it is a signifying feature for optimal C code.


D7_preventCallingViaMethodTable

public void D7_preventCallingViaMethodTable()
In Java the methods are override-able normally, because a final designation to prevent overriding is written only if the ability to override should prevent in inheriting classes. Therefore the most of methods should be called in a override-able mode, using the method table-call. But that is not economically in calculation time, and in some cases it is unnecessary. It is against the C-style of programming and testing.

The difference provocation is: In a object oriented architecture interfaces should be used to divide software in independent parts. Interfaces are the main choice to do so, base classes are the other choice. So specific implementations can be implemented without cross effects. But therefore the overridden methods appear as the only one solution.

In opposite to Java the independence of modules are realizes in C using forward declarations of methods in header files and their implementation in separated C-files (compiling units). The linker have to link only with knowledge of the labels (method names) without knowledge of any implementation details. This form of independence can't realize the polymorphism in opposite to interfaces and super classes, only the aspect of independence is regarded. But this aspect is the prior aspect mostly.

The solution of this provocation is found in the following way: If it is known, that a reference references a determined instance in the C-implementation, it can be designated with a @ java2c=instanceType:"Type".-annotation in its comment block. Another way is using a final assignment final IfcType ref = new Type();, what generates an embedded instance. Than the Java2C-translator generates a non-overridden calling of the method of the designated instance type for using that reference. The annotation is the decision written in the source in knowledge of the implementation goals. In Java it isn't active. So in Java several implementations can be implemented, at example for testing.

If the user is deceived in the usage of the reference, it is not detected in Java neither by compiling nor by testing, because it isn't active there. But it should be attracted attention in testing at C-(implementation)-level. The Java2C-compiler may test the correctness of the designation @ java2c="instancetype"., because it translates the assignments too. But than all temporary used references should be designated too. That don't may be helpfully.

But the designated reference can be tested in Java in Runtime, whether at least the designated type is referenced, using a reference instanceof Type-Java-sourcecode. Than fatal errors are excluded, only if the instance is from a derived type, it isn't detected. The instanceof-check needs a small part of calculation time, if the instance is from the expected type. Such tests are slowly only if the instance is from a far derived type, than the implementation type should be searched in reflections. In the current case only 2 indirect accesses and a compare operation is necessary in the implementation of instanceof_ObjectJc(ref, reflection_Type).

A reference, which has a dedicated instance type, is determined in its FieldData.instanceClazz- element. This element is able to seen in the stc-File of the translated class with notation instance: as part of the fieldIdents {...}.

The method-call is translated to C using the Method.sImplementationName.


D8_gen_MethodTable

public void D8_gen_MethodTable()
The structure of a method table is generated into the header-file, but the definition of a method table is generated into the C-file.

Method type definition:
A method type definition is a type definition of a method. At example the definition of the basicly method Object.toString is contained in Object.h in the form
 typedef METHOD_C StringJc MT_toString_ObjectJc(ObjectJc* ythis);
 
The generated form is the same (example):
 typedef int32 MT_testOverrideAble_ImplIfc_Test(ImplIfc_Test_s* ythis, float value, ThCxt* _thCxt);
 
It looks like a simple forward declaration of a method, but it is the typedef of the so named C-function pointer. The typedef of an method of an interface is at example:
 typedef int32 MT_processIfcMethod_Ifc_Test(ObjectJc* ithis, int32 input, ThCxt* _thCxt);
 
The reference to the data for interface defined methods is the ObjectJc*-pointer in any time. The defined interface pointer, in this case struct Ifc_Test_t* isn't use, because if the same method is definded in more as one interface, it is implemented only one time. The data reference should be the same. Therefore the base of all data is used. On calling an interface method the correct type of reference is generated accessing the &ref->base.object-Part of a data structure. For methods not defined in interfaces the associated type is used.

Method table definition:
The form is (example):
 extern const char sign_Mtbl_ImplIfc_Test[]; //marker for methodTable check
 typedef struct Mtbl_ImplIfc_Test_t
 { MtblHeadJc head;
   MT_testOverrideAble_ImplIfc_Test* testOverrideAble;
   MT_returnThisA_ImplIfc_Test* returnThisA;
   Mtbl_SimpleClass_Test SimpleClass_Test;
   //Method table of interfaces:
   Mtbl_Ifc_Test Ifc_Test;
   Mtbl_Ifc2_Test Ifc2_Test;
 } Mtbl_ImplIfc_Test;
 
The example shows the generated method table of the class ImplIfc. This struct is used as part of a method table of a class, which extends this class, in the same kind like the method table Mtbl_SimpleClass_Test is used here. That used method table is generated from SimpleClass with C-code:
 extern const char sign_Mtbl_SimpleClass_Test[]; //marker for methodTable check
 typedef struct Mtbl_SimpleClass_Test_t
 { MtblHeadJc head;
   Mtbl_ObjectJc ObjectJc;
 } Mtbl_SimpleClass_Test;
 
The method table definitions have the following parts: Because the SimpleClass in simple only, it contains no override-able method and only the method table of its superclass Mtbl_ObjectJc. That is defined in ObjectJc and contains:
 typedef struct Mtbl_ObjectJc_t
 { MtblHeadJc head;
   MT_clone_ObjectJc*    clone;
   MT_equals_ObjectJc*   equals;
   MT_finalize_ObjectJc* finalize;
   MT_hashCode_ObjectJc* hashCode;
   MT_toString_ObjectJc* toString;
 } Mtbl_ObjectJc;
 
It contains the 5 methods, which are override-able for any class.

Definition of the instance of a method table for a Type/Class:
The instance is defined in the C-file in the following form (example):
At start of C-file the constant is declared because it may be used inside the C-file to detect sub method table parts. The used type of the method table contains its commonly type declared in headerfile plus the end-sign.
 typedef struct MtblDef_ImplIfc_Test_t { Mtbl_ImplIfc_Test mtbl; MtblHeadJc end; } MtblDef_ImplIfc_Test;
 extern MtblDef_ImplIfc_Test const mtblImplIfc_Test;
 
At end of C-file or methods are defined, than the content can be filled without additional prototype declarations of implementing methods:
 const MtblDef_ImplIfc_Test mtblImplIfc_Test = {
      { { sign_Mtbl_ImplIfc_Test//J2C: Head of methodtable.
        , (struct Size_Mtbl_t*)((3 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
        }
      , testOverrideAble_ImplIfc_Test_F //testOverrideAble
      , testOverridden_ImplIfc_Test_F //testOverridden
      , returnThisA_ImplIfc_Test_F //returnThisA
      , { { sign_Mtbl_SimpleClass_Test//J2C: Head of methodtable.
          , (struct Size_Mtbl_t*)((0 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
          }
        , { { sign_Mtbl_ObjectJc//J2C: Head of methodtable.
            , (struct Size_Mtbl_t*)((5 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
            }
          , clone_ObjectJc_F //clone
          , equals_ObjectJc_F //equals
          , finalize_ImplIfc_Test_F //finalize
          , hashCode_ObjectJc_F //hashCode
          , toString_ImplIfc_Test_F //toString
          }
        }
        / **J2C: Mtbl-interfaces of ImplIfc_Test: * /
      , { { sign_Mtbl_Ifc_Test//J2C: Head of methodtable.
          , (struct Size_Mtbl_t*)((3 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
          }
        , processIfcMethod_i_ImplIfc_Test_F //processIfcMethod
        , anotherIfcmethod_i_ImplIfc_Test //anotherIfcmethod_i
        , anotherIfcmethod_f_ImplIfc_Test_F //anotherIfcmethod_f
        , { { sign_Mtbl_ObjectJc//J2C: Head of methodtable.
            , (struct Size_Mtbl_t*)((5 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
            }
          , clone_ObjectJc_F //clone
          , equals_ObjectJc_F //equals
          , finalize_ImplIfc_Test_F //finalize
          , hashCode_ObjectJc_F //hashCode
          , toString_ImplIfc_Test_F //toString
          }
        }
      , { { sign_Mtbl_Ifc2_Test//J2C: Head of methodtable.
          , (struct Size_Mtbl_t*)((3 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
          }
        , processIfcMethod_f_ImplIfc_Test //processIfcMethod
        , testIfc2_f_ImplIfc_Test //testIfc2
        , anotherIfcmethod_f_ImplIfc_Test_F //anotherIfcmethod
        , { { sign_Mtbl_ObjectJc//J2C: Head of methodtable.
            , (struct Size_Mtbl_t*)((5 +2) * sizeof(void*)) //size. NOTE: all elements are standard-pointer-types.
            }
          , clone_ObjectJc_F //clone
          , equals_ObjectJc_F //equals
          , finalize_ImplIfc_Test_F //finalize
          , hashCode_ObjectJc_F //hashCode
          , toString_ImplIfc_Test_F //toString
          }
        }
      }, { signEnd_Mtbl_ObjectJc, null } }; //Mtbl

 
It is a long term, because all method table parts of super classes and interfaces are contained with the here implemented methods. The definition follows the type definition. Because the type definition contains nested data, the data are extensive here in comparison to the type definition.