public class Docu.D_SuperClassesAndInterfaces extends java.lang.Object
Constructor and Description |
---|
Docu.D_SuperClassesAndInterfaces() |
Modifier and Type | Method and Description |
---|---|
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.
|
public Docu.D_SuperClassesAndInterfaces()
public void D1_baseStructures()
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.
&ref->base.object
.
&ref->base.super
. If a super-super-class should accessed,
in Java written using super.super
, the C-equivalent form is &ref->base.super.base.super
.
&ref->base.Interface1
, where the identified element is the name of the interface
like in the Java code.
Docu.ProcessOfTranslation#packageReplacement()
) and it has the usual suffix _s
to different it
from a possible C++ type definition.public void D2_virtualMethodsAndInheritanceInfo()
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
.
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:
public void D3_detectOverriddenMethods()
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.public void D4_newOverrideAbleMethods()
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.public void D5_cCodeForOverriddenMethods()
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.
_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".
).
/ * 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.
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.
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));
public void D6_callingOverrideableMethods()
@ java2c=dynamic-call.
,
at example
/**Use local variable to enforce only one preparation of the method table for dynamic call:
@ java2c=dynamic-call.
* /
final TestWaitNotify.WaitNotifyData theNotifyingDataMtbl = theNotifyingData;
The translated C-code is than
TestWaitNotify_Test__WaitNotifyDataMTB theNotifyingDataMtbl; ... SETMTBJc(theNotifyingDataMtbl, REFJc(ythis->theNotifyingData), TestWaitNotify_Test__WaitNotifyData);
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).
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.
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.
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.
((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).
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.
#preventCallingViaMethodTable()
, it is a signifying feature for optimal C code.public void D7_preventCallingViaMethodTable()
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.
@ 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.
@ java2c="instancetype".
,
because it translates the assignments too. But than all temporary used references should be designated
too. That don't may be helpfully.
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).
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 {...}
.
Method.sImplementationName
.public void D8_gen_MethodTable()
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.
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:
sign_Mtbl_Type
: It is a zero-terminated string.
But only the address is used to identify the method tables.
MtblHeadJc
is defined in ObjectJc.h
and contains 2 elements:
char const* sign
: The value of sign hava to be identically
with the address of the sign_Mtbl_TYPE. It is checked for safe access respectively used
to find out the method table part of a base class.
int sizeTable
, it is the number of byte (size) of the appropriate table.
MT_
(Method Type) anyway.
MtblHeadJc head
and than the own methods, its immediate superclass and so on.
In this kind the method tables of derived classes are nested.
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.
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 } }; //MtblThis method table is generated in the method
SecondPass.write_Reflections()
which calls
ClassData.genMethodTableContent(org.vishia.java2C.ClassData.InheritanceInfo, String, int)
.