Objects in E1 interact via method calls. This type of communication is synchronous. Each call is accompanied by a set of input and output parameters, specified by the object developer by means of Interface Definition language (IDL).
In E1 all method calls are executed by the local replica of the invoked object. In order to guarantee that such a replica will exist and will not be destroyed by the garbage collection system, one must create a reference on an object before using any of its methods >>.
Object methods are invoked through a pointer to one of its interfaces. Since all objects in E1 are located in a single address space, this pointer is valid in any system node and in any protection domain.
Within the domain boundaries, method calls work very similar to C++ language: arguments are placed in stack and registers, and the control is transferred to the address specified in the method table of an invoked object.
Implementation of crossdomain calls is more complicated, although for the interacting objects the difference is transparent. An attempt to access an object outside the local domain triggers a page fault exception, handled by Crossdomain Adapter (CA), located in the same domain as the object where the exception occurs. The CA's task is to prepare the stack, containing the invocation arguments, which will be mapped into the target domain and on which the method will be executed. All arguments (both passed by value and by reference) are copied directly to the new stack. Although crossdomain call mechanism does not explicitly support passing large data arrays without copying, a similar functionality can be achieved by passing pointers to objects, representing shared memory regions.
Each node contains exactly one instance of CA, mapped to all domains. Thus, CA operates as a universal proxy object, handling all crossdomain calls in a system. To prepare the call stack, the CA needs to know the called method's parameter types, which can be obtained from its class object through a special reflective interface.
To avoid the creation of a separate stack segment for each crossdomain call, CA uses the stack that the calling thread was running on before the call. The top of this stack is aligned to page boundary and the resulting address is interpreted as the bottom of a new stack (see figure), which is then mapped to a target domain, so that the content of the calling object's stack is not accessible to the called object.
Stack management during crossdomain call.
Having created the call stack, the CA transfers control to the microkernel to complete the call. The kernel then refers to the Object Registry for the validation of the caller's capabilities to invoke the given operation, and finally maps the call stack to the target domain and transfers control to the called object. Return from crossdomain call occurs in a similar way, through the target domain CA.