xfer to odin
authorScott Wood <scott@buserror.net>
Tue, 12 Jun 2007 03:46:46 +0000 (22:46 -0500)
committerScott Wood <scott@buserror.net>
Tue, 12 Jun 2007 03:46:46 +0000 (22:46 -0500)
doc/abi/x86
doc/orb/marshalling
doc/orb/newobject [new file with mode: 0644]
doc/orb/parameter-info-block
idl/exceptions.idl
idlcomp/TODO
include/c++/orb.h
lib/c++/orb.cc

index c62911dd5b0213402c2cbafe94a45e74ada92e9a..805eb76a630f16fa019b67b3e493c509c7c9b799 100644 (file)
@@ -8,7 +8,7 @@ Out-of-Process Method Invocation:
       
       Upon return:
       ebx, esi, edi, ebp, esp: preserved
-      eax: pointer to exception, or NULL if none.
+      eax: pointer to exception, or NULL if none
            If there is an exception, the user part of the syscall
            function will search for an exception handling function
            that covers the calling address.  If none is found,
@@ -20,12 +20,32 @@ Out-of-Process Method Invocation:
    Callee:
       eax: pointer to PIB
       edx: pointer to caller information struct, or NULL if not
-           requested.
+           requested
       esp: NULL.
 
       Jump to the 32-bit address stored at 0x7fff0004 to return.
       
       Upon return:
-      eax: pointer to exception, or NULL if none.
+      eax: pointer to exception, or NULL if none
       edx: length of exception segment, if any
       ebx, esi, edi, ebp, esp: may be clobbered
+
+Object registration:
+       eax: number of objects to register with initial refcount 1
+       edx: pointer to list of NewObject structs
+       
+       Call the 32-bit address stored at 0x7fff0008.
+       
+       Upon return:
+       eax: pointer to exception, or NULL if none
+       edx: length of exception segment, if any
+
+GUID hash retrieval:
+       eax: object id
+       edx: 16-byte buffer
+       
+       Call the 32-bit address stored at 0x7fff000c.
+       
+       Upon return:
+       eax: pointer to exception, or NULL if none
+       edx: length of exception segment, if any
index a400d8860d0ef8f2aee4954a69788b766be6d51d..ab429bb8e853ee0e27a0e02154c8dbb6ff96f98b 100644 (file)
@@ -1,28 +1,41 @@
-segment 0, byte 0 is a request code.  Codes are:
+Segment 0, byte 0 is a request code.  Currently defined codes are:
  0: Invoke Method
  1: Get Interface List
  2: Return Interface List
 
 Bytes 1-3 (32-bit) and 1-7 (64-bit) are reserved, and must be zero.
 All offsets described in the rest of this file are relative to the
-first non-reserved byte (a.k.a. the message payload).  The reserved
-bytes do not need to be included in the message if the payload is
-empty.
+first non-reserved byte (a.k.a. the message payload); however,
+offsets encoded in the message are relative to the beginning of the
+segment, not the payload.  The reserved bytes do not need to be
+included in the message if the payload is empty.
 
 Op0: Invoke Method
 ------------------
 
-The segment 0 payload contains the method's arguments as if they were
-a struct, followed by a depth-first traversal of any referenced
-structs, excluding references which could potentially lead to loops
-(i.e. references to types that exist in a parent node in the
-traversal, or their supertypes) or aliases (i.e. references to types
-that exist elsewhere in the traversal, or their supertypes).  Where
-loops or aliases are possible, the reference is encoded as a
-segment/offset pair (a 32-bit word, segment is upper 6 bits), and the
-data may be placed wherever the sender wishes.  Non-inline arrays are
-also encoded with segment/offset pairs.  Object references are
-encoded as 16-bit offsets into the objlist array.
+The payload begins with the index of the interface being used,
+followed by the index of the method.  Both are 32-bit integers.
+
+After that, the payload contains the method's arguments as if they
+were a struct.
+
+Non-inline structs and arrays (hereafter referred to as data chunks)
+which contain object ids and/or references to other data chunks are
+stored at arbitrary locations in segment 0, and are referenced as an
+offset into the segment.
+
+Data chunks which do not contain object id or references to other
+data chunks (i.e. they are pure data, and do not need to be altered
+for marshalling) are stored at arbitrary locations in arbitrary
+segments.  References to these pure data chunks are encoded as a
+pointer-sized integer, with the upper N bits holding the segment and
+the remaining bits holding the offset into that segment.  The value
+of N is architecture-defined, but should generally be 6 (this may
+change once enough of the system is in place to do some benchmarks)
+for 32-bit architectures and 32 for 64-bit architectures.
+
+Object references are encoded as pointer-sized offsets into the
+objlist array.
 
 Op1: Get Interface List
 -----------------------
@@ -37,5 +50,5 @@ Op2: Return Interface List
 For async requests, objlist[1] is the object whose interfaces were
 requested.
 
-The payload consists of a list of GUIDs of interfaces that the object
+Segment 1 consists of a list of GUIDs of interfaces that the object
 supports.
diff --git a/doc/orb/newobject b/doc/orb/newobject
new file mode 100644 (file)
index 0000000..7b1c4c5
--- /dev/null
@@ -0,0 +1,5 @@
+struct NewObject {
+       u32 guid_hash[4]; // Interface GUID checksum
+       u32 id; // Filled in by ORB
+       u32 reserved[3]; // must be zero
+};
index 0c5281dcac963342d83ca1f947431266275ad683..a39372b637408ba9ad4f2bc7fe6f1514160284bd 100644 (file)
@@ -1,6 +1,6 @@
-Parameter Info Block (PIB), all offsets in pointer-length words
-   Name            Offset  Meaning
-   buffer_size     0       Size of the destination buffer, excluding
+Parameter Info Block (PIB)
+   Name            Size    Meaning
+   buffer_size     32-bit  Size of the destination buffer, excluding
                            Copy segments.
    
       The total number of bytes in all of the segments that require a
@@ -19,12 +19,12 @@ Parameter Info Block (PIB), all offsets in pointer-length words
       for the duration of the call.  Copy segments are handled
       separately.
    
-   copy_size       1       Size of all Copy segments.
+   copy_size       32-bit  Size of all Copy segments.
    
       This is like buffer_size, but for Copy segments.
 
-   objlist_ptr     2       Pointer to the object list
-   objlist_len     3       Length of the object list, in IDs
+   objlist_ptr     pointer Pointer to the object list
+   objlist_len     32-bit  Length of the object list, in IDs
 
       The object list is a special segment that contains object IDs
       rather than arbitrary data.  Each object ID will be translated
@@ -33,12 +33,14 @@ Parameter Info Block (PIB), all offsets in pointer-length words
       regardless of the pointer size.  The first object in the list
       is the object to receive the message.
 
-   num_segments    4       Number of data segments
-   segment.ptr     5+n*4   Pointer to data segment
-   segment.len     6+n*4   Length of data segment in bytes
-   segment.flags   7+n*4   Attributes of data segment
-   reserved        8+n*4   Reserved for future use, and for
-                           power-of-two indexing
+   num_segments    32-bit  Number of data segments
+
+   segment.ptr     pointer Pointer to data segment
+   segment.len     32-bit  Length of data segment in bytes
+   segment.flags   32-bit  Attributes of data segment
+   reserved                Reserved for future use, and for
+                           power-of-two indexing -- pad to
+                           32 bytes.
    
       Each segment describes data being transmitted to and/or from the
       callee.  For out segments, the caller may designate a buffer to hold
index f32e597d4c7fee4302e040888ab9b6f62af7148e..d0f2a2e9ec74885cbe95591f19de42455838680a 100644 (file)
@@ -235,6 +235,12 @@ struct InvalidArgument : SystemException {
        char[] exp immutable;
 };
 
+struct InternalFailure : SystemException {
+       guid: "52819E26-1791-11DC-931E-00112431A05E";
+       
+       char[] exp immutable;
+};
+
 // GeneralFailure, as the name implies, is a general purpose exception
 // to indicate failure conditions not covered by existing exceptions.
 // It is generally preferable to define a specific exception for
@@ -297,3 +303,23 @@ struct RefCountException : SystemException {
        
        int refs, released;
 };
+
+// Thrown when an ORB message is malformed.
+// FIXME: Move into orb namespace
+
+struct BadMessage : SystemException {
+       guid: "5347B217-1790-11DC-A89E-00112431A05E";
+};
+
+struct ShortMessage : BadMessage {
+       guid: "5DA142FA-1791-11DC-A3BE-00112431A05E";
+
+       int segment; // Short segment, or -1 for objlist
+       int len, expected;
+};
+
+struct InvalidOpcode : BadMessage {
+       guid: "5708BF7E-1791-11DC-B1D3-00112431A05E";
+
+       int opcode;
+};
index a8206fa15cba823c040600488cd22abfea5277d5..36123ad90309a669229a2bc299274dd31dffe1cf 100644 (file)
@@ -51,3 +51,5 @@ Possibly implement out parameters on remote-only async methods that
 can only be used when invoked as a sync in-process method; the method
 implementation can check to see how it was invoked, and use the out
 parameters to avoid having to make a completion callback.
+
+Vstructs need a length field.
index 1078555f625a9d33727365f138a8ac3db636cf9f..076f1ddea6e22aa4462ac40054ed6171bb08a7cb 100644 (file)
@@ -254,11 +254,18 @@ namespace System {
                        // Length of inheritance chain; 1 for System.VStruct
                        
                        const int chainlen;
+                       
+                       // Size of concrete vstruct
+                       
+                       const int structlen;
                };
                
                uintptr_t downcast(::System::_i_Object *obj,
                                   const unsigned long *new_guid);
 
+               typedef u64 GUID[2];
+
+               // FIXME: use above typedef
                static inline bool guids_equal(const unsigned long *guid1,
                                               const unsigned long *guid2)
                {
@@ -269,22 +276,16 @@ namespace System {
                                  guid1[3] == guid2[3])));
                }
                
-               // Return the caller's PC.  It'd be nice if GCC had a builtin for
-               // the current PC, so that a simple relocation could be used rather
-               // than a function call.  OPT: put this in lowlevel-lib, so that
-               // architectures can provide a faster version.
-               
-               unsigned long get_pc();
-               
+               typedef uint32_t ID;
                struct ParamInfoBlock {
-                       uintptr_t buffer_size;
-                       uintptr_t copy_size;
-                       uintptr_t *objlist;
-                       uintptr_t objlist_len;
-                       uintptr_t num_segments;
+                       uint32_t buffer_size;
+                       uint32_t copy_size;
+                       ID *objlist;
+                       uint32_t objlist_len;
+                       uint32_t num_segments;
 
                        struct Segment {
-                               unsigned char *ptr;
+                               uint8_t *ptr;
                                uintptr_t len;
                                uintptr_t flags;
                                uintptr_t reserved;
@@ -297,16 +298,60 @@ namespace System {
                                };
                        } segments[0];
                };
-       }
+               
+               struct Segment0 {
+                       enum {
+                               InvokeMethod = 0,
+                               GetIFaces = 1,
+                               ReturnIFaces = 2,
+                       };
+               
+                       union {
+                               struct {
+                                       uint8_t opcode;
+                               };
+                               
+                               unsigned long pad;
+                       };
+               };
+                       
+               struct InvokeMethod {
+                       Segment0 seg0;
+                       uint32_t iface;
+                       uint32_t method;
+                       uint8_t args[0];
+               };
+               
+               union Message {
+                       Segment0 seg0;
+                       InvokeMethod invoke;
+               };
        
-       namespace Priv {
-               static inline bool in_kernel()
-               {
+               namespace Priv {
+                       // Return the caller's PC.  It'd be nice if GCC had a builtin for
+                       // the current PC, so that a simple relocation could be used rather
+                       // than a function call.  OPT: put this in lowlevel-lib, so that
+                       // architectures can provide a faster version.
+                       
+                       unsigned long get_pc();
+
+                       static inline bool in_kernel()
+                       {
 #ifdef _KERNEL
-                       return true;
+                               return true;
 #else
-                       return false;
+                               return false;
 #endif
+                       }
+
+                       typedef void (*MethodEntry)(ParamInfoBlock *pib);
+
+                       struct Object {
+                               MethodEntry entry;
+                               void *ptr; // pointer to the class interface
+                       };
+
+                       typedef Util::RadixTree<Object, ID, 6> ObjTable;
                }
        };
 }
@@ -349,7 +394,7 @@ inline void operator delete[](void *ptr, ::System::RunTime::ORBMM *orbmm,
                new(::System::RunTime::orbmm) \
                   ::System::Exceptions::NativeCodeExceptionOriginInfo \
                   (::System::RunTime::get_pc()), \
-               ::System::Priv::in_kernel(), ##args); \
+               ::System::RunTime::Priv::in_kernel(), ##args); \
 } while (0)
 
 #define rethrow_idl(oldex, T, args...) do { \
@@ -357,7 +402,7 @@ inline void operator delete[](void *ptr, ::System::RunTime::ORBMM *orbmm,
                new(::System::RunTime::orbmm) \
                   ::System::Exceptions::NativeCodeExceptionOriginInfo \
                   (::System::RunTime::get_pc()), \
-               ::System::Priv::in_kernel(), ##args); \
+               ::System::RunTime::Priv::in_kernel(), ##args); \
 } while (0)
 #endif
 
index a1f10a51da2add8555e39fc1f002ad5b691c2d86..26f3fc2731b4a74039a3fe84e1726b49b7925136 100644 (file)
 #include <System.h>
 
 namespace System {
-       namespace RunTime {
-               // This function could be made to do a binary search if we can
-               // manage to somehow sort the IFaceTables...
+namespace RunTime {
+       using ::System::Exceptions::Std;
 
-               uintptr_t downcast(::System::_i_Object *obj,
-                                  const unsigned long *new_guid)
-               {
-                       if (!obj)
-                               return 0;
+       // This function could be made to do a binary search if we can
+       // manage to somehow sort the IFaceTables...
 
-                       void unsupported_long_size();
-
-                       if (sizeof(long) != 4 && sizeof(long) != 8)
-                               unsupported_long_size();
-
-                       IFaceTable *tbl = obj->info->concrete_IFaceTable;
-                       unsigned long new_guid_first = *new_guid;
-                       
-                       // This doesn't use guids_equal(), as that would eliminate the
-                       // ability to cache the first word of new_guid.  The compiler
-                       // *might* do it anyway, but this code was written before
-                       // guids_equal existed, and I don't want to risk removing an
-                       // optimization by changing it now without testing how GCC
-                       // behaves.
-                       
-                       while (true) {
-                               if (tbl->guid[0] == new_guid_first &&
-                                   tbl->guid[1] == new_guid[1] &&
-                                   (sizeof(long) == 8 ||
-                                    (tbl->guid[2] == new_guid[2] &&
-                                     tbl->guid[3] == new_guid[3])))
-                                       break;                          
-
-                               tbl++;
-                               if (__builtin_expect(!tbl->guid, 0))
-                                       return 0;
-                       }
+       uintptr_t downcast(::System::_i_Object *obj,
+                          const unsigned long *new_guid)
+       {
+               if (!obj)
+                       return 0;
+
+               void unsupported_long_size();
+
+               if (sizeof(long) != 4 && sizeof(long) != 8)
+                       unsupported_long_size();
+
+               IFaceTable *tbl = obj->info->concrete_IFaceTable;
+               unsigned long new_guid_first = *new_guid;
                
-                       uintptr_t ptr = reinterpret_cast<uintptr_t>(obj);
-                       
-                       ptr += obj->info->concrete;
-                       ptr += tbl->offset;
-                       
-                       return ptr;
-               };
+               // This doesn't use guids_equal(), as that would eliminate the
+               // ability to cache the first word of new_guid.  The compiler
+               // *might* do it anyway, but this code was written before
+               // guids_equal existed, and I don't want to risk removing an
+               // optimization by changing it now without testing how GCC
+               // behaves.
                
+               while (true) {
+                       if (tbl->guid[0] == new_guid_first &&
+                           tbl->guid[1] == new_guid[1] &&
+                           (sizeof(long) == 8 ||
+                            (tbl->guid[2] == new_guid[2] &&
+                             tbl->guid[3] == new_guid[3])))
+                               break;                          
+
+                       tbl++;
+                       if (__builtin_expect(!tbl->guid, 0))
+                               return 0;
+               }
+       
+               uintptr_t ptr = reinterpret_cast<uintptr_t>(obj);
+               
+               ptr += obj->info->concrete;
+               ptr += tbl->offset;
+               
+               return ptr;
+       };
+       
+
+       namespace Priv {
+               ObjTable objtable;
+
                unsigned long get_pc()
                {
                        return reinterpret_cast<unsigned long>(__builtin_return_address(0));
                }
+
+               void exception_to_array(::System::VStruct *ex, Array<uint8_t> *ar)
+               {
+                       ar->ptr = reinterpret_cast<uint8_t *>(ex);
+                       ar->count = ex->_infoptr->structlen;
+               }
+               
+               void handle_message(ParameterInfoBlock *pib)
+               {
+                       Message *msg = reinterpret_cast<Message *>(pib->segments[0].ptr);
+               
+                       switch (seg0->opcode) {
+                               case Segment0::InvokeMethod: {
+                                       if (pib->segments[0].len < sizeof(InvokeMessage))
+                                               throw_idl(ShortMessage, 0, pib->segments[0].len,
+                                                         sizeof(InvokeMessage));
+       
+                                       ID obj = pib->objlist[0];
+                                       
+                                       
+                                       break;
+                               }
+                               
+                               default:
+                                       throw_idl(InvalidOpcode, seg0->opcode);
+                       }
+               }
+       }
+}}
+
+extern "C" handle_message(ParameterInfoaBlock *pib, Array<uint8_t> *ex_arr)
+{
+       try {
+               ::System::RunTime::handle_message(pib);
+       }
+       
+       catch (::System::Exception *ex) {
+               exception_to_array(ex, ex_arr);
+       }
+       
+       catch (...) {
+               assertl(0, Assert::Always);
        }
 }