summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2013-01-04 10:50:28 +0100
committerBenoit Foucher <benoit@zeroc.com>2013-01-04 10:50:28 +0100
commit8b4674dbca704b9ffb48cd9a4fee43211e774cce (patch)
treeac55936ef4ba7b52ed8835c011b7c59cf2d1d3ee /cpp/src
parentFixed(ICE-5147) - Fix python scripts to not raise strings anymore (diff)
downloadice-8b4674dbca704b9ffb48cd9a4fee43211e774cce.tar.bz2
ice-8b4674dbca704b9ffb48cd9a4fee43211e774cce.tar.xz
ice-8b4674dbca704b9ffb48cd9a4fee43211e774cce.zip
ICE-4938: Super compact enoding
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/Ice/BasicStream.cpp1907
-rw-r--r--cpp/src/Ice/Object.cpp2
-rw-r--r--cpp/src/Ice/StreamI.cpp2
-rw-r--r--cpp/src/Slice/CsUtil.cpp4
-rw-r--r--cpp/src/Slice/JavaUtil.cpp4
-rw-r--r--cpp/src/Slice/Parser.cpp2
-rw-r--r--cpp/src/slice2cpp/Gen.cpp4
7 files changed, 1073 insertions, 852 deletions
diff --git a/cpp/src/Ice/BasicStream.cpp b/cpp/src/Ice/BasicStream.cpp
index 02b8f3046e0..d64d99f59a1 100644
--- a/cpp/src/Ice/BasicStream.cpp
+++ b/cpp/src/Ice/BasicStream.cpp
@@ -76,15 +76,18 @@ private:
BasicStream& _stream;
};
+const Byte OPTIONAL_END_MARKER = 0xFF;
+
+const Byte FLAG_HAS_TYPE_ID_STRING = (1<<0);
+const Byte FLAG_HAS_TYPE_ID_INDEX = (1<<1);
+const Byte FLAG_HAS_TYPE_ID_COMPACT = (1<<0) | (1<<1);
+const Byte FLAG_HAS_OPTIONAL_MEMBERS = (1<<2);
+const Byte FLAG_HAS_INDIRECTION_TABLE = (1<<3);
+const Byte FLAG_HAS_SLICE_SIZE = (1<<4);
+const Byte FLAG_IS_LAST_SLICE = (1<<5);
+
}
-const Byte BasicStream::FLAG_HAS_TYPE_ID_STRING = (1<<0);
-const Byte BasicStream::FLAG_HAS_TYPE_ID_INDEX = (1<<1);
-const Byte BasicStream::FLAG_HAS_TYPE_ID_COMPACT = (1<<0) | (1<<1);
-const Byte BasicStream::FLAG_HAS_OPTIONAL_MEMBERS = (1<<2);
-const Byte BasicStream::FLAG_HAS_INDIRECTION_TABLE = (1<<3);
-const Byte BasicStream::FLAG_HAS_SLICE_SIZE = (1<<4);
-const Byte BasicStream::FLAG_IS_LAST_SLICE = (1<<5);
IceInternal::BasicStream::BasicStream(Instance* instance, const EncodingVersion& encoding, bool unlimited) :
IceInternal::Buffer(instance->messageSizeMax()),
@@ -127,9 +130,7 @@ IceInternal::BasicStream::clear()
}
_startSeq = -1;
-
_sizePos = -1;
-
_sliceObjects = true;
}
@@ -263,8 +264,6 @@ IceInternal::BasicStream::readPendingObjects()
if(_currentReadEncaps && _currentReadEncaps->decoder)
{
_currentReadEncaps->decoder->readPendingObjects();
- delete _currentReadEncaps->decoder;
- _currentReadEncaps->decoder = 0;
}
else if(getReadEncoding() == Ice::Encoding_1_0)
{
@@ -287,8 +286,6 @@ IceInternal::BasicStream::writePendingObjects()
if(_currentWriteEncaps && _currentWriteEncaps->encoder)
{
_currentWriteEncaps->encoder->writePendingObjects();
- delete _currentWriteEncaps->encoder;
- _currentWriteEncaps->encoder = 0;
}
else if(getWriteEncoding() == Ice::Encoding_1_0)
{
@@ -305,7 +302,6 @@ IceInternal::BasicStream::writePendingObjects()
}
}
-
Int
IceInternal::BasicStream::readAndCheckSeqSize(int minSize)
{
@@ -1619,33 +1615,13 @@ IceInternal::BasicStream::writeException(const Ice::UserException& e)
{
initWriteEncaps();
_currentWriteEncaps->encoder->write(e);
-
- //
- // Reset the encoder, the writing of the exception wrote
- // pending objects if any.
- //
- delete _currentWriteEncaps->encoder;
- _currentWriteEncaps->encoder = 0;
}
void
IceInternal::BasicStream::throwException(const UserExceptionFactoryPtr& factory)
{
initReadEncaps();
- try
- {
- _currentReadEncaps->decoder->throwException(factory);
- }
- catch(const Ice::UserException&)
- {
- //
- // Reset the decoder, the reading of the exception wrote
- // pending objects if any.
- //
- delete _currentReadEncaps->decoder;
- _currentReadEncaps->decoder = 0;
- throw;
- }
+ _currentReadEncaps->decoder->throwException(factory);
}
void
@@ -1662,9 +1638,7 @@ IceInternal::BasicStream::readOptImpl(Int readTag, OptionalFormat expectedFormat
return false; // Optional members aren't supported with the 1.0 encoding.
}
- Int tag = 0;
- OptionalFormat format;
- do
+ while(true)
{
if(i >= b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz)
{
@@ -1673,38 +1647,40 @@ IceInternal::BasicStream::readOptImpl(Int readTag, OptionalFormat expectedFormat
Byte v;
read(v);
- format = static_cast<OptionalFormat>(v & 0x07); // First 3 bits.
- tag = static_cast<Int>(v >> 3);
- if(tag == 31)
+ if(v == OPTIONAL_END_MARKER)
+ {
+ --i; // Rewind
+ return false;
+ }
+
+ OptionalFormat format = static_cast<OptionalFormat>(v & 0x07); // First 3 bits.
+ Int tag = static_cast<Int>(v >> 3);
+ if(tag == 30)
{
tag = readSize();
}
- }
- while(format != OptionalFormatEndMarker && tag < readTag && skipOpt(format)); // Skip optional data members
-
- if(format == OptionalFormatEndMarker || tag > readTag)
- {
- //
- // Rewind the stream to correctly read the next optional data
- // member tag & format next time.
- //
- i -= tag < 31 ? 1 : (tag < 255 ? 2 : 6);
- return false; // No optional data members with the requested tag.
- }
-
- assert(readTag == tag);
- if(format != expectedFormat)
- {
- ostringstream os;
- os << "invalid optional data member `" << tag << "': unexpected format";
- throw MarshalException(__FILE__, __LINE__, os.str());
- }
- //
- // We have an optional data member with the requested tag and
- // format.
- //
- return true;
+ if(tag > readTag)
+ {
+ i -= tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind
+ return false; // No optional data members with the requested tag.
+ }
+ else if(tag < readTag)
+ {
+ skipOpt(format); // Skip optional data members
+ }
+ else
+ {
+ if(format != expectedFormat)
+ {
+ ostringstream os;
+ os << "invalid optional data member `" << tag << "': unexpected format";
+ throw MarshalException(__FILE__, __LINE__, os.str());
+ }
+ return true;
+ }
+ }
+ return true; // Keep the compiler happy.
}
bool
@@ -1716,95 +1692,97 @@ IceInternal::BasicStream::writeOptImpl(Int tag, OptionalFormat type)
}
Byte v = static_cast<Byte>(type);
- if(tag < 31)
+ if(tag < 30)
{
- v |= tag << 3;
+ v |= static_cast<Byte>(tag << 3);
write(v);
}
else
{
- v |= 0x0F8; // tag = 31
+ v |= 0xF0; // tag = 30
write(v);
writeSize(tag);
}
return true;
}
-bool
+void
IceInternal::BasicStream::skipOpt(OptionalFormat type)
{
- int sz;
switch(type)
{
case Ice::OptionalFormatF1:
{
- sz = 1;
+ skip(1);
break;
}
case Ice::OptionalFormatF2:
{
- sz = 2;
+ skip(2);
break;
}
case Ice::OptionalFormatF4:
{
- sz = 4;
+ skip(4);
break;
}
case Ice::OptionalFormatF8:
{
- sz = 8;
+ skip(8);
break;
}
case Ice::OptionalFormatSize:
{
skipSize();
- return true;
+ break;
}
case Ice::OptionalFormatVSize:
{
- sz = readSize();
+ skip(readSize());
break;
}
case Ice::OptionalFormatFSize:
{
+ Int sz;
read(sz);
+ skip(sz);
break;
}
- default:
+ case Ice::OptionalFormatClass:
{
- return false;
+ read(0, 0);
+ break;
}
}
- skip(sz);
- return true;
}
-bool
+void
BasicStream::skipOpts()
{
//
// Skip remaining un-read optional members.
//
- OptionalFormat format;
- do
+ while(true)
{
if(i >= b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz)
{
- return false; // End of encapsulation also indicates end of optionals.
+ return; // End of encapsulation also indicates end of optionals.
}
Byte v;
read(v);
- format = static_cast<OptionalFormat>(v & 0x07); // Read first 3 bits.
- if(static_cast<Int>(v >> 3) == 31)
+ if(v == OPTIONAL_END_MARKER)
+ {
+ return;
+ }
+
+ OptionalFormat format = static_cast<OptionalFormat>(v & 0x07); // Read first 3 bits.
+ if(static_cast<Int>(v >> 3) == 30)
{
skipSize();
}
+ skipOpt(format);
}
- while(skipOpt(format));
- assert(format == OptionalFormatEndMarker);
- return true;
}
void
@@ -1830,7 +1808,15 @@ IceInternal::BasicStream::initReadEncaps()
if(!_currentReadEncaps->decoder) // Lazy initialization.
{
- _currentReadEncaps->decoder = new EncapsDecoder(this, _currentReadEncaps, _sliceObjects);
+ ObjectFactoryManagerPtr factoryManager = _instance->servantFactoryManager();
+ if(_currentReadEncaps->encoding == Encoding_1_0)
+ {
+ _currentReadEncaps->decoder = new EncapsDecoder10(this, _currentReadEncaps, _sliceObjects, factoryManager);
+ }
+ else
+ {
+ _currentReadEncaps->decoder = new EncapsDecoder11(this, _currentReadEncaps, _sliceObjects, factoryManager);
+ }
}
}
@@ -1850,529 +1836,563 @@ IceInternal::BasicStream::initWriteEncaps()
if(!_currentWriteEncaps->encoder) // Lazy initialization.
{
- _currentWriteEncaps->encoder = new EncapsEncoder(this, _currentWriteEncaps);
+ if(_currentWriteEncaps->encoding == Encoding_1_0)
+ {
+ _currentWriteEncaps->encoder = new EncapsEncoder10(this, _currentWriteEncaps);
+ }
+ else
+ {
+ _currentWriteEncaps->encoder = new EncapsEncoder11(this, _currentWriteEncaps);
+ }
}
}
-void
-IceInternal::BasicStream::EncapsEncoder::write(const ObjectPtr& v)
+string
+IceInternal::BasicStream::EncapsDecoder::readTypeId(bool isIndex)
{
- if(v)
+ if(isIndex)
{
- //
- // Register the object.
- //
- Int index = registerObject(v);
-
- if(_encaps->encoding == Encoding_1_0)
- {
- //
- // Object references are encoded as a negative integer in 1.0.
- //
- _stream->write(-index);
- }
- else if(_sliceType != NoSlice && _encaps->format == SlicedFormat)
- {
- //
- // An object reference that appears inside a slice of an
- // object or exception encoded as a positive non-zero
- // index into a per-slice indirection table.
- //
- // We use _indirectionMap to keep track of the object
- // references in the current slice; it maps the object
- // reference to the position in the indirection list. Note
- // that the position is offset by one (e.g., the first
- // position = 1).
- //
- IndirectionMap::iterator p = _indirectionMap.find(index);
- if(p == _indirectionMap.end())
- {
- _indirectionTable.push_back(index);
- const Int sz = static_cast<Int>(_indirectionTable.size()); // Position + 1
- _indirectionMap.insert(make_pair(index, sz));
- _stream->writeSize(sz);
- }
- else
- {
- _stream->writeSize(p->second);
- }
- }
- else
+ Int index = _stream->readSize();
+ TypeIdReadMap::const_iterator k = _typeIdMap.find(index);
+ if(k == _typeIdMap.end())
{
- _stream->writeSize(index);
+ throw UnmarshalOutOfBoundsException(__FILE__, __LINE__);
}
+ return k->second;
}
else
{
- //
- // Write nil reference.
- //
- if(_encaps->encoding == Encoding_1_0)
- {
- _stream->write(0);
- }
- else
- {
- _stream->writeSize(0);
- }
+ string typeId;
+ _stream->read(typeId, false);
+ _typeIdMap.insert(make_pair(++_typeIdIndex, typeId));
+ return typeId;
}
}
-void
-IceInternal::BasicStream::EncapsEncoder::write(const UserException& v)
+Ice::ObjectPtr
+IceInternal::BasicStream::EncapsDecoder::newInstance(const string& typeId)
{
+ Ice::ObjectPtr v;
+
//
- // User exception with the 1.0 encoding start with a boolean
- // flag that indicates whether or not the exception uses
- // classes.
- //
- // This allows reading the pending objects even if some part of
- // the exception was sliced. With encoding > 1.0, we don't need
- // this, each slice indirect patch table indicates the presence of
- // objects.
+ // Try to find a factory registered for the specific type.
//
- bool usesClasses;
- if(_encaps->encoding == Encoding_1_0)
+ ObjectFactoryPtr userFactory = _servantFactoryManager->find(typeId);
+ if(userFactory)
{
- usesClasses = v.__usesClasses();
- _stream->write(usesClasses);
+ v = userFactory->create(typeId);
}
- else
+
+ //
+ // If that fails, invoke the default factory if one has been
+ // registered.
+ //
+ if(!v)
{
- usesClasses = true; // Always call writePendingObjects
+ userFactory = _servantFactoryManager->find("");
+ if(userFactory)
+ {
+ v = userFactory->create(typeId);
+ }
}
- v.__write(_stream);
- if(usesClasses)
+
+ //
+ // Last chance: check the table of static factories (i.e.,
+ // automatically generated factories for concrete classes).
+ //
+ if(!v)
{
- writePendingObjects();
+ ObjectFactoryPtr of = IceInternal::factoryTable->getObjectFactory(typeId);
+ if(of)
+ {
+ v = of->create(typeId);
+ assert(v);
+ }
}
+
+ return v;
}
void
-IceInternal::BasicStream::EncapsEncoder::startObject(const SlicedDataPtr& data)
+IceInternal::BasicStream::EncapsDecoder::addPatchEntry(Int index, PatchFunc patchFunc, void* patchAddr)
{
- _sliceType = ObjectSlice;
- _firstSlice = true;
- if(data)
+ assert(index > 0);
+
+ //
+ // Check if already un-marshalled the object. If that's the case,
+ // just patch the object smart pointer and we're done.
+ //
+ IndexToPtrMap::iterator p = _unmarshaledMap.find(index);
+ if(p != _unmarshaledMap.end())
{
- writeSlicedData(data);
+ (*patchFunc)(patchAddr, p->second);
+ return;
}
-}
-void
-IceInternal::BasicStream::EncapsEncoder::endObject()
-{
- if(_encaps->encoding == Encoding_1_0)
+ //
+ // Add patch entry if the object isn't un-marshalled yet, the
+ // smart pointer will be patched when the instance is
+ // un-marshalled.
+ //
+
+ PatchMap::iterator q = _patchMap.find(index);
+ if(q == _patchMap.end())
{
//
- // Write the Object slice.
+ // We have no outstanding instances to be patched for this
+ // index, so make a new entry in the patch map.
//
- startSlice(Object::ice_staticId(), -1, true);
- _stream->writeSize(0); // For compatibility with the old AFM.
- endSlice();
- }
- _sliceType = NoSlice;
-}
-
-void
-IceInternal::BasicStream::EncapsEncoder::startException(const SlicedDataPtr& data)
-{
- _sliceType = ExceptionSlice;
- _firstSlice = true;
- if(data)
- {
- writeSlicedData(data);
+ q = _patchMap.insert(make_pair(index, PatchList())).first;
}
-}
-void
-IceInternal::BasicStream::EncapsEncoder::endException()
-{
- _sliceType = NoSlice;
+ //
+ // Append a patch entry for this instance.
+ //
+ PatchEntry e;
+ e.patchFunc = patchFunc;
+ e.patchAddr = patchAddr;
+ q->second.push_back(e);
}
void
-IceInternal::BasicStream::EncapsEncoder::startSlice(const string& typeId, int compactId, bool last)
+IceInternal::BasicStream::EncapsDecoder::unmarshal(Int index, const Ice::ObjectPtr& v)
{
- assert(_indirectionTable.empty() && _indirectionMap.empty());
- _sliceFlags = 0;
- _sliceFlagsPos = _stream->b.size();
+ //
+ // Add the object to the map of un-marshalled objects, this must
+ // be done before reading the objects (for circular references).
+ //
+ _unmarshaledMap.insert(make_pair(index, v));
//
- // Encode the slice size for the old encoding and if using the
- // sliced format.
+ // Read the object.
//
- if(_encaps->encoding == Encoding_1_0 || _encaps->format == SlicedFormat)
- {
- _sliceFlags |= FLAG_HAS_SLICE_SIZE;
- }
+ v->__read(_stream);
//
- // This is the last slice.
+ // Patch all instances now that the object is un-marshalled.
//
- if(last)
+ PatchMap::iterator patchPos = _patchMap.find(index);
+ if(patchPos != _patchMap.end())
{
- _sliceFlags |= FLAG_IS_LAST_SLICE;
+ assert(patchPos->second.size() > 0);
+
+ //
+ // Patch all pointers that refer to the instance.
+ //
+ for(PatchList::iterator k = patchPos->second.begin(); k != patchPos->second.end(); ++k)
+ {
+ (*k->patchFunc)(k->patchAddr, v);
+ }
+
+ //
+ // Clear out the patch map for that index -- there is nothing left
+ // to patch for that index for the time being.
+ //
+ _patchMap.erase(patchPos);
}
- //
- // For object slices, encode the flag and the type ID either as a
- // string or index. For exception slices, don't encode slice flags
- // for the old encoding and always encode the type ID a string.
- //
- if(_sliceType == ObjectSlice)
+ if(_objectList.empty() && _patchMap.empty())
{
- _stream->write(Byte(0)); // Placeholder for the slice flags
+ try
+ {
+ v->ice_postUnmarshal();
+ }
+ catch(const std::exception& ex)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "std::exception raised by ice_postUnmarshal:\n" << ex;
+ }
+ catch(...)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "unknown exception raised by ice_postUnmarshal";
+ }
+ }
+ else
+ {
+ _objectList.push_back(v);
- //
- // Encode the type ID (only in the first slice for the compact
- // encoding).
- //
- if(_encaps->format == SlicedFormat || _encaps->encoding == Encoding_1_0 || _firstSlice)
+ if(_patchMap.empty())
{
- if(_encaps->encoding != Encoding_1_0 && compactId >= 0)
- {
- _sliceFlags |= FLAG_HAS_TYPE_ID_COMPACT;
- _stream->writeSize(compactId);
- }
- else
+ //
+ // Iterate over the object list and invoke ice_postUnmarshal on
+ // each object. We must do this after all objects have been
+ // unmarshaled in order to ensure that any object data members
+ // have been properly patched.
+ //
+ for(ObjectList::iterator p = _objectList.begin(); p != _objectList.end(); ++p)
{
- //
- // If the type ID has already been seen, write the index
- // of the type ID, otherwise allocate a new type ID and
- // write the string.
- //
- TypeIdWriteMap::const_iterator p = _typeIdMap.find(typeId);
- if(p != _typeIdMap.end())
+ try
{
- _sliceFlags |= FLAG_HAS_TYPE_ID_INDEX;
- _stream->writeSize(p->second);
+ (*p)->ice_postUnmarshal();
}
- else
+ catch(const std::exception& ex)
{
- _sliceFlags |= FLAG_HAS_TYPE_ID_STRING;
- _typeIdMap.insert(make_pair(typeId, ++_typeIdIndex));
- _stream->write(typeId, false);
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "std::exception raised by ice_postUnmarshal:\n" << ex;
+ }
+ catch(...)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "unknown exception raised by ice_postUnmarshal";
}
}
+ _objectList.clear();
}
}
- else
- {
- if(_encaps->encoding != Encoding_1_0)
- {
- _stream->write(Byte(0)); // Placeholder for the slice flags
- }
- _stream->write(typeId, false);
- }
-
- if(_sliceFlags & FLAG_HAS_SLICE_SIZE)
- {
- _stream->write(Int(0)); // Placeholder for the slice length.
- }
-
- _writeSlice = _stream->b.size();
- _firstSlice = false;
}
void
-IceInternal::BasicStream::EncapsEncoder::endSlice()
+IceInternal::BasicStream::EncapsDecoder10::read(PatchFunc patchFunc, void* patchAddr)
{
- //
- // Write the optional member end marker if some optional members
- // were encoded. Note that the optional members are encoded before
- // the indirection table and are included in the slice size.
- //
- if(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)
- {
- assert(_encaps->encoding != Encoding_1_0);
- _stream->write(static_cast<Byte>(OptionalFormatEndMarker));
- }
+ assert(patchFunc && patchAddr);
//
- // Write the slice length if necessary.
+ // Object references are encoded as a negative integer in 1.0.
//
- if(_sliceFlags & FLAG_HAS_SLICE_SIZE)
+ Int index;
+ _stream->read(index);
+ if(index > 0)
{
- Int sz = static_cast<Int>(_stream->b.size() - _writeSlice + sizeof(Int));
- Byte* dest = &(*(_stream->b.begin() + _writeSlice - sizeof(Int)));
- _stream->write(sz, dest);
+ throw MarshalException(__FILE__, __LINE__, "invalid object id");
}
+ index = -index;
- //
- // Only write the indirection table if it contains entries.
- //
- if(!_indirectionTable.empty())
+ if(index == 0)
{
- assert(_encaps->encoding != Encoding_1_0);
- assert(_encaps->format == SlicedFormat);
- _sliceFlags |= FLAG_HAS_INDIRECTION_TABLE;
-
//
- // Write the indirection table as a sequence<size> to conserve space.
+ // Calling the patch function for null instances is necessary for correct functioning of Ice for
+ // Python and Ruby.
//
- _stream->writeSizeSeq(_indirectionTable);
-
- _indirectionTable.clear();
- _indirectionMap.clear();
- }
-
- //
- // Finally, update the slice flags (or the object slice has index
- // type ID boolean for the 1.0 encoding)
- //
- if(_encaps->encoding == Encoding_1_0)
- {
- if(_sliceType == ObjectSlice) // No flags for 1.0 exception slices.
- {
- Byte* dest = &(*(_stream->b.begin() + _sliceFlagsPos));
- *dest = static_cast<Byte>(_sliceFlags & FLAG_HAS_TYPE_ID_INDEX ? true : false);
- }
+ ObjectPtr nil;
+ patchFunc(patchAddr, nil);
}
else
{
- Byte* dest = &(*(_stream->b.begin() + _sliceFlagsPos));
- *dest = _sliceFlags;
+ addPatchEntry(index, patchFunc, patchAddr);
}
}
void
-IceInternal::BasicStream::EncapsEncoder::writePendingObjects()
+IceInternal::BasicStream::EncapsDecoder10::throwException(const UserExceptionFactoryPtr& factory)
{
+ assert(_sliceType == NoSlice);
+
+ //
+ // User exception with the 1.0 encoding start with a boolean flag
+ // that indicates whether or not the exception has classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
//
- // With the 1.0 encoding, write pending objects if the marshalled
- // data uses classes. Otherwise with encoding > 1.0, only write
- // pending objects if some non-nil references were written.
+ bool usesClasses;
+ _stream->read(usesClasses);
+
+ _sliceType = ExceptionSlice;
+ _skipFirstSlice = false;
+
//
- if(_encaps->encoding != Encoding_1_0)
+ // Read the first slice header.
+ //
+ startSlice();
+ const string mostDerivedId = _typeId;
+ UserExceptionFactoryPtr exceptionFactory = factory;
+ while(true)
{
- if(_toBeMarshaledMap.empty())
- {
- return;
- }
- else
+ //
+ // Look for a statically-generated factory for this ID.
+ //
+ if(!exceptionFactory)
{
- //
- // Write end marker for encapsulation optionals before encoding
- // the pending objects.
- //
- _stream->write(static_cast<Byte>(OptionalFormatEndMarker));
+ exceptionFactory = factoryTable->getExceptionFactory(_typeId);
}
- }
- while(!_toBeMarshaledMap.empty())
- {
//
- // Consider the to be marshalled objects as marshalled now,
- // this is necessary to avoid adding again the "to be
- // marshalled objects" into _toBeMarshaledMap while writing
- // objects.
+ // We found a factory, we get out of this loop.
//
- _marshaledMap.insert(_toBeMarshaledMap.begin(), _toBeMarshaledMap.end());
-
- PtrToIndexMap savedMap;
- savedMap.swap(_toBeMarshaledMap);
- _stream->writeSize(static_cast<Int>(savedMap.size()));
- for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p)
+ if(exceptionFactory)
{
//
- // Ask the instance to marshal itself. Any new class
- // instances that are triggered by the classes marshaled
- // are added to toBeMarshaledMap.
+ // Got factory -- ask the factory to instantiate the
+ // exception, initialize the exception members, and throw
+ // the exception.
//
- if(_encaps->encoding == Encoding_1_0)
- {
- _stream->write(p->second);
- }
- else
- {
- _stream->writeSize(p->second);
- }
-
try
{
- p->first->ice_preMarshal();
- }
- catch(const std::exception& ex)
- {
- Warning out(_stream->instance()->initializationData().logger);
- out << "std::exception raised by ice_preMarshal:\n" << ex;
+ exceptionFactory->createAndThrow(_typeId);
}
- catch(...)
+ catch(UserException& ex)
{
- Warning out(_stream->instance()->initializationData().logger);
- out << "unknown exception raised by ice_preMarshal";
+ ex.__read(_stream);
+ if(usesClasses)
+ {
+ readPendingObjects();
+ }
+ throw;
+
+ // Never reached.
}
+ }
- p->first->__write(_stream);
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+ try
+ {
+ startSlice();
+ }
+ catch(UnmarshalOutOfBoundsException& ex)
+ {
+ //
+ // An oversight in the 1.0 encoding means there is no marker to indicate
+ // the last slice of an exception. As a result, we just try to read the
+ // next type ID, which raises UnmarshalOutOfBoundsException when the
+ // input buffer underflows.
+ //
+ // Set the reason member to a more helpful message.
+ //
+ ex.reason = "unknown exception type `" + mostDerivedId + "'";
+ throw;
}
}
- _stream->writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
}
-void
-IceInternal::BasicStream::EncapsEncoder::writeSlicedData(const SlicedDataPtr& slicedData)
+void
+IceInternal::BasicStream::EncapsDecoder10::startInstance(SliceType sliceType)
{
- assert(slicedData);
+ assert(_sliceType == sliceType);
+ _skipFirstSlice = true;
+}
+SlicedDataPtr
+IceInternal::BasicStream::EncapsDecoder10::endInstance(bool)
+{
//
- // We only remarshal preserved slices if the target encoding is > 1.0 and we are
- // using the sliced format. Otherwise, we ignore the preserved slices, which
- // essentially "slices" the object into the most-derived type known by the sender.
+ // Read the Ice::Object slice.
//
- if(_encaps->encoding == Encoding_1_0 || _encaps->format != SlicedFormat)
- {
- return;
- }
-
- for(SliceInfoSeq::const_iterator p = slicedData->slices.begin(); p != slicedData->slices.end(); ++p)
+ if(_sliceType == ObjectSlice)
{
- startSlice((*p)->typeId, (*p)->compactId, (*p)->isLastSlice);
-
- //
- // Write the bytes associated with this slice.
- //
- _stream->writeBlob((*p)->bytes);
-
- if((*p)->hasOptionalMembers)
- {
- _sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
- }
-
- //
- // Assemble and write the indirection table. The table must have the same order
- // as the list of objects.
- //
- for(vector<ObjectPtr>::const_iterator q = (*p)->objects.begin(); q != (*p)->objects.end(); ++q)
+ startSlice();
+ Int sz = _stream->readSize(); // For compatibility with the old AFM.
+ if(sz != 0)
{
- _indirectionTable.push_back(registerObject(*q));
+ throw MarshalException(__FILE__, __LINE__, "invalid Object slice");
}
-
endSlice();
}
+ _sliceType = NoSlice;
+ return 0;
}
-Int
-IceInternal::BasicStream::EncapsEncoder::registerObject(const ObjectPtr& v)
+const std::string&
+IceInternal::BasicStream::EncapsDecoder10::startSlice()
{
- assert(v);
-
//
- // Look for this instance in the to-be-marshaled map.
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
//
- PtrToIndexMap::const_iterator p = _toBeMarshaledMap.find(v);
- if(p != _toBeMarshaledMap.end())
+ if(_skipFirstSlice)
{
- return p->second;
+ _skipFirstSlice = false;
+ return _typeId;
}
//
- // Didn't find it, try the marshaled map next.
+ // For objects, first read the type ID boolean which indicates
+ // whether or not the type ID is encoded as a string or as an
+ // index. For exceptions, the type ID is always encoded as a
+ // string.
//
- PtrToIndexMap::const_iterator q = _marshaledMap.find(v);
- if(q != _marshaledMap.end())
+ if(_sliceType == ObjectSlice)
{
- return q->second;
+ bool isIndex;
+ _stream->read(isIndex);
+ _typeId = readTypeId(isIndex);
+ }
+ else
+ {
+ _stream->read(_typeId, false);
}
- //
- // We haven't seen this instance previously, create a new
- // index, and insert it into the to-be-marshaled map.
- //
- _toBeMarshaledMap.insert(make_pair(v, ++_objectIdIndex));
- return _objectIdIndex;
+ _stream->read(_sliceSize);
+ if(_sliceSize < 4)
+ {
+ throw UnmarshalOutOfBoundsException(__FILE__, __LINE__);
+ }
+ return _typeId;
}
void
-IceInternal::BasicStream::EncapsDecoder::read(PatchFunc patchFunc, void* patchAddr)
+IceInternal::BasicStream::EncapsDecoder10::endSlice()
{
- ObjectPtr v;
+}
+
+void
+IceInternal::BasicStream::EncapsDecoder10::skipSlice()
+{
+ if(_stream->instance()->traceLevels()->slicing > 0)
+ {
+ const Ice::LoggerPtr& logger = _stream->instance()->initializationData().logger;
+ if(_sliceType == ExceptionSlice)
+ {
+ traceSlicing("exception", _typeId, _stream->instance()->traceLevels()->slicingCat, logger);
+ }
+ else
+ {
+ traceSlicing("object", _typeId, _stream->instance()->traceLevels()->slicingCat, logger);
+ }
+ }
+ assert(_sliceSize >= 4);
+ _stream->skip(_sliceSize - sizeof(Int));
+}
+
+void
+IceInternal::BasicStream::EncapsDecoder10::readPendingObjects()
+{
+ Int num;
+ do
+ {
+ num = _stream->readSize();
+ for(Int k = num; k > 0; --k)
+ {
+ readInstance();
+ }
+ }
+ while(num);
+
+ if(!_patchMap.empty())
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw MarshalException(__FILE__, __LINE__, "index for class received, but no instance");
+ }
+}
+void
+IceInternal::BasicStream::EncapsDecoder10::readInstance()
+{
Int index;
- if(_encaps->encoding == Encoding_1_0)
+ _stream->read(index);
+
+ if(index <= 0)
+ {
+ throw MarshalException(__FILE__, __LINE__, "invalid object id");
+ }
+
+ _sliceType = ObjectSlice;
+ _skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ startSlice();
+ const string mostDerivedId = _typeId;
+ ObjectPtr v;
+ while(true)
{
//
- // Object references are encoded as a negative integer in 1.0.
+ // For the 1.0 encoding, the type ID for the base Object class
+ // marks the last slice.
//
- _stream->read(index);
- if(index > 0)
+ if(_typeId == Object::ice_staticId())
{
- throw MarshalException(__FILE__, __LINE__, "invalid object id");
+ throw NoObjectFactoryException(__FILE__, __LINE__, "", mostDerivedId);
}
- index = -index;
- }
- else
- {
+
+ v = newInstance(_typeId);
+
//
- // Later versions use a size.
+ // We found a factory, we get out of this loop.
//
- index = _stream->readSize();
- if(index < 0)
+ if(v)
+ {
+ break;
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!_sliceObjects)
{
- throw MarshalException(__FILE__, __LINE__, "invalid object id");
+ throw NoObjectFactoryException(__FILE__, __LINE__, "object slicing is disabled", _typeId);
}
+
+ //
+ // Slice off what we don't understand.
+ //
+ skipSlice();
+ startSlice(); // Read next Slice header for next iteration.
}
- if(index == 0)
+ //
+ // Un-marshal the object and add-it to the map of un-marshaled objects.
+ //
+ unmarshal(index, v);
+}
+
+void
+IceInternal::BasicStream::EncapsDecoder11::read(PatchFunc patchFunc, void* patchAddr)
+{
+ Int index = _stream->readSize();
+ if(index < 0)
+ {
+ throw MarshalException(__FILE__, __LINE__, "invalid object id");
+ }
+ else if(index == 0)
{
//
// Calling the patch function for null instances is necessary for correct functioning of Ice for
// Python and Ruby.
//
- ObjectPtr nil;
- patchFunc(patchAddr, nil);
+ if(patchFunc)
+ {
+ ObjectPtr nil;
+ patchFunc(patchAddr, nil);
+ }
}
- else if(_sliceType != NoSlice && _sliceFlags & FLAG_HAS_INDIRECTION_TABLE)
+ else if(_current && _current->sliceFlags & FLAG_HAS_INDIRECTION_TABLE)
{
//
- // Maintain a list of indirect references. Note that the indirect index
- // starts at 1, so we decrement it by one to derive an index into
- // the indirection table that we'll read at the end of the slice.
+ // When reading an object within a slice and there's an
+ // indirect object table, always read an indirect reference
+ // that points to an object from the indirect object table
+ // marshaled at the end of the Slice.
+ //
+ // Maintain a list of indirect references. Note that the
+ // indirect index starts at 1, so we decrement it by one to
+ // derive an index into the indirection table that we'll read
+ // at the end of the slice.
//
- IndirectPatchEntry e;
- e.index = index - 1;
- e.patchFunc = patchFunc;
- e.patchAddr = patchAddr;
- _indirectPatchList.push_back(e);
+ if(patchFunc)
+ {
+ IndirectPatchEntry e;
+ e.index = index - 1;
+ e.patchFunc = patchFunc;
+ e.patchAddr = patchAddr;
+ _current->indirectPatchList.push_back(e);
+ }
}
else
{
- addPatchEntry(index, patchFunc, patchAddr);
+ readInstance(index, patchFunc, patchAddr);
}
}
void
-IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFactoryPtr& factory)
+IceInternal::BasicStream::EncapsDecoder11::throwException(const UserExceptionFactoryPtr& factory)
{
- assert(_sliceType == NoSlice);
-
- //
- // User exception with the 1.0 encoding start with a boolean flag
- // that indicates whether or not the exception has classes.
- //
- // This allows reading the pending objects even if some part of
- // the exception was sliced. With encoding > 1.0, we don't need
- // this, each slice indirect patch table indicates the presence of
- // objects.
- //
- bool usesClasses;
- if(_encaps->encoding == Encoding_1_0)
- {
- _stream->read(usesClasses);
- }
- else
- {
- usesClasses = true; // Always call readPendingObjects.
- }
+ assert(!_current);
- _sliceType = ExceptionSlice;
- _skipFirstSlice = false;
+ push(ExceptionSlice);
//
// Read the first slice header.
//
startSlice();
- const string mostDerivedId = _typeId;
+ const string mostDerivedId = _current->typeId;
UserExceptionFactoryPtr exceptionFactory = factory;
while(true)
{
@@ -2381,7 +2401,7 @@ IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFacto
//
if(!exceptionFactory)
{
- exceptionFactory = factoryTable->getExceptionFactory(_typeId);
+ exceptionFactory = factoryTable->getExceptionFactory(_current->typeId);
}
//
@@ -2396,15 +2416,11 @@ IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFacto
//
try
{
- exceptionFactory->createAndThrow(_typeId);
+ exceptionFactory->createAndThrow(_current->typeId);
}
catch(UserException& ex)
{
ex.__read(_stream);
- if(usesClasses)
- {
- readPendingObjects();
- }
throw;
// Never reached.
@@ -2412,20 +2428,6 @@ IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFacto
}
//
- // Performance sensitive, so we use lazy initialization for
- // tracing.
- //
- if(_traceSlicing == -1)
- {
- _traceSlicing = _stream->instance()->traceLevels()->slicing;
- _slicingCat = _stream->instance()->traceLevels()->slicingCat;
- }
- if(_traceSlicing > 0)
- {
- traceSlicing("exception", _typeId, _slicingCat, _stream->instance()->initializationData().logger);
- }
-
- //
// Slice off what we don't understand.
//
skipSlice();
@@ -2433,7 +2435,7 @@ IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFacto
//
// If this is the last slice, raise an exception and stop un-marshalling.
//
- if(_sliceFlags & FLAG_IS_LAST_SLICE)
+ if(_current->sliceFlags & FLAG_IS_LAST_SLICE)
{
if(mostDerivedId.length() > 2 && mostDerivedId[0] == ':' && mostDerivedId[1] == ':')
{
@@ -2445,217 +2447,123 @@ IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFacto
}
}
- try
- {
- startSlice();
- }
- catch(UnmarshalOutOfBoundsException& ex)
- {
- //
- // An oversight in the 1.0 encoding means there is no marker to indicate
- // the last slice of an exception. As a result, we just try to read the
- // next type ID, which raises UnmarshalOutOfBoundsException when the
- // input buffer underflows.
- //
- if(_encaps->encoding == Encoding_1_0)
- {
- // Set the reason member to a more helpful message.
- ex.reason = "unknown exception type `" + mostDerivedId + "'";
- }
- throw;
- }
- }
-}
-
-void
-IceInternal::BasicStream::EncapsDecoder::startObject()
-{
- assert(_sliceType == ObjectSlice);
- _skipFirstSlice = true;
-}
-
-SlicedDataPtr
-IceInternal::BasicStream::EncapsDecoder::endObject(bool preserve)
-{
- if(_encaps->encoding == Encoding_1_0)
- {
- //
- // Read the Ice::Object slice.
- //
startSlice();
-
- //
- // For compatibility with the old AFM.
- //
- Int sz = _stream->readSize();
- if(sz != 0)
- {
- throw MarshalException(__FILE__, __LINE__, "invalid Object slice");
- }
-
- endSlice();
}
-
- _sliceType = NoSlice;
- SlicedDataPtr slicedData;
- if(preserve)
- {
- slicedData = readSlicedData();
- }
- _slices.clear();
- _indirectionTables.clear();
- return slicedData;
}
void
-IceInternal::BasicStream::EncapsDecoder::startException()
+IceInternal::BasicStream::EncapsDecoder11::startInstance(SliceType sliceType)
{
- assert(_sliceType == ExceptionSlice);
- _skipFirstSlice = true;
+ assert(_current->sliceType == sliceType);
+ _current->skipFirstSlice = true;
}
-SlicedDataPtr
-IceInternal::BasicStream::EncapsDecoder::endException(bool preserve)
+SlicedDataPtr
+IceInternal::BasicStream::EncapsDecoder11::endInstance(bool preserve)
{
- _sliceType = NoSlice;
SlicedDataPtr slicedData;
if(preserve)
{
slicedData = readSlicedData();
}
- _slices.clear();
- _indirectionTables.clear();
+ _current->slices.clear();
+ _current->indirectionTables.clear();
+ _current = _current->previous;
return slicedData;
}
-const string&
-IceInternal::BasicStream::EncapsDecoder::startSlice()
+const std::string&
+IceInternal::BasicStream::EncapsDecoder11::startSlice()
{
//
// If first slice, don't read the header, it was already read in
// readInstance or throwException to find the factory.
//
- if(_skipFirstSlice)
+ if(_current->skipFirstSlice)
{
- _skipFirstSlice = false;
- return _typeId;
+ _current->skipFirstSlice = false;
+ return _current->typeId;
}
- //
- // Read the slice flags. For the 1.0 encoding there's no flag but
- // just a boolean for object slices. The boolean indicates whether
- // or not the type ID is encoded as a string or as an index.
- //
- if(_encaps->encoding == Encoding_1_0)
- {
- _sliceFlags = FLAG_HAS_SLICE_SIZE;
- if(_sliceType == ObjectSlice) // For exceptions, the type ID is always encoded as a string
- {
- bool isIndex;
- _stream->read(isIndex);
- _sliceFlags |= isIndex ? FLAG_HAS_TYPE_ID_INDEX : FLAG_HAS_TYPE_ID_STRING;
- }
- }
- else
- {
- _stream->read(_sliceFlags);
- }
+ _stream->read(_current->sliceFlags);
//
// Read the type ID, for object slices the type ID is encoded as a
// string or as an index, for exceptions it's always encoded as a
// string.
//
- if(_sliceType == ObjectSlice)
+ if(_current->sliceType == ObjectSlice)
{
- if((_sliceFlags & FLAG_HAS_TYPE_ID_COMPACT) == FLAG_HAS_TYPE_ID_COMPACT) // Must be checked first!
+ if((_current->sliceFlags & FLAG_HAS_TYPE_ID_COMPACT) == FLAG_HAS_TYPE_ID_COMPACT) // Must be checked first!
{
- _typeId.clear();
- _compactId = _stream->readSize();
+ _current->typeId.clear();
+ _current->compactId = _stream->readSize();
}
- else if(_sliceFlags & FLAG_HAS_TYPE_ID_INDEX)
+ else if(_current->sliceFlags & (FLAG_HAS_TYPE_ID_STRING | FLAG_HAS_TYPE_ID_INDEX))
{
- Int index = _stream->readSize();
- TypeIdReadMap::const_iterator k = _typeIdMap.find(index);
- if(k == _typeIdMap.end())
- {
- throw UnmarshalOutOfBoundsException(__FILE__, __LINE__);
- }
- _typeId = k->second;
- _compactId = -1;
- }
- else if(_sliceFlags & FLAG_HAS_TYPE_ID_STRING)
- {
- _stream->read(_typeId, false);
- _typeIdMap.insert(make_pair(++_typeIdIndex, _typeId));
- _compactId = -1;
+ _current->typeId = readTypeId(_current->sliceFlags & FLAG_HAS_TYPE_ID_INDEX);
+ _current->compactId = -1;
}
else
{
- // Only the most derived slice encodes the type ID for the
- // compact format.
- _typeId.clear();
- _compactId = -1;
+ // Only the most derived slice encodes the type ID for the compact format.
+ _current->typeId.clear();
+ _current->compactId = -1;
}
}
else
{
- _stream->read(_typeId, false);
+ _stream->read(_current->typeId, false);
}
//
// Read the slice size if necessary.
//
- if(_sliceFlags & FLAG_HAS_SLICE_SIZE)
+ if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE)
{
- _stream->read(_sliceSize);
- if(_sliceSize < 4)
+ _stream->read(_current->sliceSize);
+ if(_current->sliceSize < 4)
{
throw UnmarshalOutOfBoundsException(__FILE__, __LINE__);
}
}
else
{
- _sliceSize = 0;
+ _current->sliceSize = 0;
}
- //
- // Reset the indirect patch list for this new slice.
- //
- _indirectPatchList.clear();
- return _typeId;
+ return _current->typeId;
}
void
-IceInternal::BasicStream::EncapsDecoder::endSlice()
+IceInternal::BasicStream::EncapsDecoder11::endSlice()
{
- if(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)
+ if(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)
{
_stream->skipOpts();
}
//
- // Read the indirection table if one is present and transform the
- // indirect patch list into patch entries with direct references.
+ // Read the indirect object table if one is present.
//
- if(_sliceFlags & FLAG_HAS_INDIRECTION_TABLE)
+ if(_current->sliceFlags & FLAG_HAS_INDIRECTION_TABLE)
{
- //
- // The table is written as a sequence<size> to conserve space.
- //
- IndexList indirectionTable;
- _stream->readSizeSeq(indirectionTable);
+ IndexList indirectionTable(_stream->readAndCheckSeqSize(1));
+ for(IndexList::iterator p = indirectionTable.begin(); p != indirectionTable.end(); ++p)
+ {
+ *p = readInstance(_stream->readSize(), 0, 0);
+ }
//
// Sanity checks. If there are optional members, it's possible
// that not all object references were read if they are from
// unknown optional data members.
//
- if(indirectionTable.empty() && !_indirectPatchList.empty())
+ if(indirectionTable.empty())
{
throw MarshalException(__FILE__, __LINE__, "empty indirection table");
}
- else if(!indirectionTable.empty() && _indirectPatchList.empty() && !(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS))
+ if(_current->indirectPatchList.empty() && !(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS))
{
throw MarshalException(__FILE__, __LINE__, "no references to indirection table");
}
@@ -2663,147 +2571,166 @@ IceInternal::BasicStream::EncapsDecoder::endSlice()
//
// Convert indirect references into direct references.
//
- for(IndirectPatchList::iterator p = _indirectPatchList.begin(); p != _indirectPatchList.end(); ++p)
+ IndirectPatchList::iterator p;
+ for(p = _current->indirectPatchList.begin(); p != _current->indirectPatchList.end(); ++p)
{
assert(p->index >= 0);
if(p->index >= static_cast<Int>(indirectionTable.size()))
{
throw MarshalException(__FILE__, __LINE__, "indirection out of range");
}
- const Int id = indirectionTable[p->index];
- if(id <= 0)
- {
- //
- // Entries in the table must be positive, just like a regular object reference.
- //
- throw MarshalException(__FILE__, __LINE__, "invalid id in object indirection table");
- }
- addPatchEntry(id, p->patchFunc, p->patchAddr);
+ addPatchEntry(indirectionTable[p->index], p->patchFunc, p->patchAddr);
}
+ _current->indirectPatchList.clear();
}
}
void
-IceInternal::BasicStream::EncapsDecoder::readPendingObjects()
+IceInternal::BasicStream::EncapsDecoder11::skipSlice()
{
- //
- // With the 1.0 encoding, we read pending objects if the marshaled
- // data uses classes. Otherwise, only read pending objects if some
- // non-nil references were read.
- //
- if(_encaps->encoding != Encoding_1_0)
- {
- if(_patchMap.empty())
+ if(_stream->instance()->traceLevels()->slicing > 0)
+ {
+ const Ice::LoggerPtr& logger = _stream->instance()->initializationData().logger;
+ if(_current->sliceType == ExceptionSlice)
{
- return;
+ traceSlicing("exception", _current->typeId, _stream->instance()->traceLevels()->slicingCat, logger);
}
else
{
- //
- // Read unread encapsulation optionals before reading the
- // pending objects.
- //
- _stream->skipOpts();
+ traceSlicing("object", _current->typeId, _stream->instance()->traceLevels()->slicingCat, logger);
}
}
- Int num;
- ObjectList objectList;
- do
+ Container::iterator start = _stream->i;
+
+ if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE)
{
- num = _stream->readSize();
- for(Int k = num; k > 0; --k)
+ assert(_current->sliceSize >= 4);
+ _stream->skip(_current->sliceSize - sizeof(Int));
+ }
+ else
+ {
+ if(_current->sliceType == ObjectSlice)
{
- objectList.push_back(readInstance());
+ throw NoObjectFactoryException(
+ __FILE__, __LINE__,
+ "compact format prevents slicing (the sender should use the sliced format instead)",
+ _current->typeId);
+ }
+ else
+ {
+ if(_current->typeId.length() > 2 && _current->typeId[0] == ':' && _current->typeId[1] == ':')
+ {
+ throw UnknownUserException(__FILE__, __LINE__, _current->typeId.substr(2));
+ }
+ else
+ {
+ throw UnknownUserException(__FILE__, __LINE__, _current->typeId);
+ }
}
}
- while(num);
- if(!_patchMap.empty())
+ //
+ // Preserve this slice.
+ //
+ SliceInfoPtr info = new SliceInfo;
+ info->typeId = _current->typeId;
+ info->compactId = _current->compactId;
+ info->hasOptionalMembers = _current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS;
+ info->isLastSlice = _current->sliceFlags & FLAG_IS_LAST_SLICE;
+ if(info->hasOptionalMembers)
{
//
- // If any entries remain in the patch map, the sender has sent an index for an object, but failed
- // to supply the object.
+ // Don't include the optional member end marker. It will be re-written by
+ // endSlice when the sliced data is re-written.
//
- throw MarshalException(__FILE__, __LINE__, "index for class received, but no instance");
+ vector<Byte>(start, _stream->i - 1).swap(info->bytes);
+ }
+ else
+ {
+ vector<Byte>(start, _stream->i).swap(info->bytes);
}
+ _current->indirectionTables.push_back(IndexList());
+
//
- // Iterate over the object list and invoke ice_postUnmarshal on
- // each object. We must do this after all objects have been
- // unmarshaled in order to ensure that any object data members
- // have been properly patched.
+ // Read the indirect object table. We read the instances or their
+ // IDs if the instance is a reference to an already un-marhsaled
+ // object.
//
- for(ObjectList::iterator p = objectList.begin(); p != objectList.end(); ++p)
+ // The SliceInfo object sequence is initialized only if
+ // readSlicedData is called.
+ //
+ if(_current->sliceFlags & FLAG_HAS_INDIRECTION_TABLE)
{
- try
+ IndexList& table = _current->indirectionTables.back();
+ table.resize(_stream->readAndCheckSeqSize(1));
+ for(IndexList::iterator p = table.begin(); p != table.end(); ++p)
{
- (*p)->ice_postUnmarshal();
- }
- catch(const std::exception& ex)
- {
- Warning out(_stream->instance()->initializationData().logger);
- out << "std::exception raised by ice_postUnmarshal:\n" << ex;
- }
- catch(...)
- {
- Warning out(_stream->instance()->initializationData().logger);
- out << "unknown exception raised by ice_postUnmarshal";
+ *p = readInstance(_stream->readSize(), 0, 0);
}
}
+
+ _current->slices.push_back(info);
}
-ObjectPtr
-IceInternal::BasicStream::EncapsDecoder::readInstance()
+bool
+IceInternal::BasicStream::EncapsDecoder11::readOpt(Ice::Int readTag, Ice::OptionalFormat expectedFormat)
{
- Int index;
- if(_encaps->encoding == Encoding_1_0)
+ if(!_current)
{
- _stream->read(index);
+ return _stream->readOptImpl(readTag, expectedFormat);
}
- else
+ else if(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)
{
- index = _stream->readSize();
+ return _stream->readOptImpl(readTag, expectedFormat);
}
+ return false;
+}
- ObjectPtr v;
- if(index <= 0)
+Int
+IceInternal::BasicStream::EncapsDecoder11::readInstance(Int index, PatchFunc patchFunc, void* patchAddr)
+{
+ assert(index > 0);
+
+ if(index > 1)
{
- throw MarshalException(__FILE__, __LINE__, "invalid object id");
+ if(patchFunc)
+ {
+ addPatchEntry(index, patchFunc, patchAddr);
+ }
+ return index;
}
- _sliceType = ObjectSlice;
- _skipFirstSlice = false;
+ push(ObjectSlice);
+
+ //
+ // Get the object ID before we start reading slices. If some
+ // slices are skiped, the indirect object table are still read and
+ // might read other objects.
+ //
+ index = ++_objectIdIndex;
//
// Read the first slice header.
//
startSlice();
- const string mostDerivedId = _typeId;
- const ObjectFactoryManagerPtr servantFactoryManager = _stream->instance()->servantFactoryManager();
- const CompactIdResolverPtr compactIdResolver = _stream->instance()->initializationData().compactIdResolver;
+ const string mostDerivedId = _current->typeId;
+ Ice::ObjectPtr v;
+ const CompactIdResolverPtr& compactIdResolver = _stream->instance()->initializationData().compactIdResolver;
while(true)
{
- //
- // For the 1.0 encoding, the type ID for the base Object class
- // marks the last slice.
- //
- if(_typeId == Object::ice_staticId())
- {
- throw NoObjectFactoryException(__FILE__, __LINE__, "", mostDerivedId);
- }
-
- if(_compactId >= 0)
+ if(_current->compactId >= 0)
{
//
// Translate a compact (numeric) type ID into a string type ID.
//
- _typeId.clear();
+ _current->typeId.clear();
if(compactIdResolver)
{
try
{
- _typeId = compactIdResolver->resolve(_compactId);
+ _current->typeId = compactIdResolver->resolve(_current->compactId);
}
catch(const LocalException&)
{
@@ -2812,7 +2739,7 @@ IceInternal::BasicStream::EncapsDecoder::readInstance()
catch(const std::exception& ex)
{
ostringstream ostr;
- ostr << "exception in CompactIdResolver for ID " << _compactId;
+ ostr << "exception in CompactIdResolver for ID " << _current->compactId;
string msg = ostr.str();
string what = ex.what();
if(!what.empty())
@@ -2824,19 +2751,19 @@ IceInternal::BasicStream::EncapsDecoder::readInstance()
catch(...)
{
ostringstream ostr;
- ostr << "unknown exception in CompactIdResolver for ID " << _compactId;
+ ostr << "unknown exception in CompactIdResolver for ID " << _current->compactId;
throw MarshalException(__FILE__, __LINE__, ostr.str());
}
}
- if(_typeId.empty())
+ if(_current->typeId.empty())
{
- _typeId = IceInternal::factoryTable->getTypeId(_compactId);
+ _current->typeId = IceInternal::factoryTable->getTypeId(_current->compactId);
}
}
- if(!_typeId.empty())
+ if(!_current->typeId.empty())
{
- v = newInstance(servantFactoryManager, _typeId);
+ v = newInstance(_current->typeId);
//
// We found a factory, we get out of this loop.
@@ -2848,24 +2775,11 @@ IceInternal::BasicStream::EncapsDecoder::readInstance()
}
//
- // Performance sensitive, so we use lazy initialization for tracing.
- //
- if(_traceSlicing == -1)
- {
- _traceSlicing = _stream->instance()->traceLevels()->slicing;
- _slicingCat = _stream->instance()->traceLevels()->slicingCat;
- }
- if(_traceSlicing > 0)
- {
- traceSlicing("class", _typeId, _slicingCat, _stream->instance()->initializationData().logger);
- }
-
- //
// If object slicing is disabled, stop un-marshalling.
//
if(!_sliceObjects)
{
- throw NoObjectFactoryException(__FILE__, __LINE__, "object slicing is disabled", _typeId);
+ throw NoObjectFactoryException(__FILE__, __LINE__, "object slicing is disabled", _current->typeId);
}
//
@@ -2876,14 +2790,14 @@ IceInternal::BasicStream::EncapsDecoder::readInstance()
//
// If this is the last slice, keep the object as an opaque UnknownSlicedObject.
//
- if(_sliceFlags & FLAG_IS_LAST_SLICE)
+ if(_current->sliceFlags & FLAG_IS_LAST_SLICE)
{
//
// Provide a factory with an opportunity to supply the object.
// We pass the "::Ice::Object" ID to indicate that this is the
// last chance to preserve the object.
//
- v = newInstance(servantFactoryManager, Object::ice_staticId());
+ v = newInstance(Object::ice_staticId());
if(!v)
{
v = new UnknownSlicedObject(mostDerivedId);
@@ -2894,230 +2808,537 @@ IceInternal::BasicStream::EncapsDecoder::readInstance()
startSlice(); // Read next Slice header for next iteration.
}
-
- //
- // Add the object to the map of un-marshalled objects, this must
- // be done before reading the objects (for circular references).
- //
- _unmarshaledMap.insert(make_pair(index, v));
//
- // Read the object.
+ // Un-marshal the object
//
- v->__read(_stream);
+ unmarshal(index, v);
+
+ if(!_current && !_patchMap.empty())
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw MarshalException(__FILE__, __LINE__, "index for class received, but no instance");
+ }
+
+ if(patchFunc)
+ {
+ patchFunc(patchAddr, v);
+ }
+ return index;
+}
+
+SlicedDataPtr
+IceInternal::BasicStream::EncapsDecoder11::readSlicedData()
+{
+ if(_current->slices.empty()) // No preserved slices.
+ {
+ return 0;
+ }
//
- // Patch all instances now that the object is un-marshalled.
+ // The indirectionTables member holds the indirection table for
+ // each slice in slices.
//
- PatchMap::iterator patchPos = _patchMap.find(index);
- if(patchPos != _patchMap.end())
+ assert(_current->slices.size() == _current->indirectionTables.size());
+ for(SliceInfoSeq::size_type n = 0; n < _current->slices.size(); ++n)
{
- assert(patchPos->second.size() > 0);
-
//
- // Patch all pointers that refer to the instance.
+ // We use the "objects" list in SliceInfo to hold references
+ // to the target objects. Note that the objects might not have
+ // been read yet in the case of a circular reference to an
+ // enclosing object.
//
- for(PatchList::iterator k = patchPos->second.begin(); k != patchPos->second.end(); ++k)
+ const IndexList& table = _current->indirectionTables[n];
+ vector<ObjectPtr>& objects = _current->slices[n]->objects;
+ objects.resize(table.size());
+ IndexList::size_type j = 0;
+ for(IndexList::const_iterator p = table.begin(); p != table.end(); ++p)
{
- (*k->patchFunc)(k->patchAddr, v);
+ addPatchEntry(*p, &patchHandle<Object>, &objects[j++]);
}
-
- //
- // Clear out the patch map for that index -- there is nothing left
- // to patch for that index for the time being.
- //
- _patchMap.erase(patchPos);
}
+ return new SlicedData(_current->slices);
+}
- return v;
+Int
+IceInternal::BasicStream::EncapsEncoder::registerTypeId(const string& typeId)
+{
+ TypeIdWriteMap::const_iterator p = _typeIdMap.find(typeId);
+ if(p != _typeIdMap.end())
+ {
+ return p->second;
+ }
+ else
+ {
+ _typeIdMap.insert(make_pair(typeId, ++_typeIdIndex));
+ return -1;
+ }
}
void
-IceInternal::BasicStream::EncapsDecoder::addPatchEntry(Int index, PatchFunc patchFunc, void* patchAddr)
+IceInternal::BasicStream::EncapsEncoder10::write(const ObjectPtr& v)
{
- assert(index > 0);
-
//
- // Check if already un-marshalled the object. If that's the case,
- // just patch the object smart pointer and we're done.
+ // Object references are encoded as a negative integer in 1.0.
//
- IndexToPtrMap::iterator p = _unmarshaledMap.find(index);
- if(p != _unmarshaledMap.end())
+ if(v)
{
- (*patchFunc)(patchAddr, p->second);
- return;
+ _stream->write(-registerObject(v));
}
-
- //
- // Add patch entry if the object isn't un-marshalled yet, the
- // smart pointer will be patched when the instance is
- // un-marshalled.
- //
-
- PatchMap::iterator q = _patchMap.find(index);
- if(q == _patchMap.end())
+ else
{
- //
- // We have no outstanding instances to be patched for this
- // index, so make a new entry in the patch map.
- //
- q = _patchMap.insert(make_pair(index, PatchList())).first;
+ _stream->write(0);
}
+}
+void
+IceInternal::BasicStream::EncapsEncoder10::write(const UserException& v)
+{
//
- // Append a patch entry for this instance.
+ // User exception with the 1.0 encoding start with a boolean
+ // flag that indicates whether or not the exception uses
+ // classes.
//
- PatchEntry e;
- e.patchFunc = patchFunc;
- e.patchAddr = patchAddr;
- q->second.push_back(e);
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ bool usesClasses = v.__usesClasses();
+ _stream->write(usesClasses);
+ v.__write(_stream);
+ if(usesClasses)
+ {
+ writePendingObjects();
+ }
}
void
-IceInternal::BasicStream::EncapsDecoder::skipSlice()
+IceInternal::BasicStream::EncapsEncoder10::startInstance(SliceType sliceType, const SlicedDataPtr&)
{
- Container::iterator start = _stream->i;
+ _sliceType = sliceType;
+ _firstSlice = true;
+}
- if(_sliceFlags & FLAG_HAS_SLICE_SIZE)
+void
+IceInternal::BasicStream::EncapsEncoder10::endInstance()
+{
+ if(_sliceType == ObjectSlice)
{
- assert(_sliceSize >= 4);
- _stream->skip(_sliceSize - sizeof(Int));
+ //
+ // Write the Object slice.
+ //
+ startSlice(Object::ice_staticId(), -1, true);
+ _stream->writeSize(0); // For compatibility with the old AFM.
+ endSlice();
}
- else
+ _sliceType = NoSlice;
+}
+
+void
+IceInternal::BasicStream::EncapsEncoder10::startSlice(const string& typeId, int, bool last)
+{
+ //
+ // For object slices, encode a boolean to indicate how the type ID
+ // is encoded and the type ID either as a string or index. For
+ // exception slices, always encode the type ID as a string.
+ //
+ if(_sliceType == ObjectSlice)
{
- if(_sliceType == ObjectSlice)
+ Int index = registerTypeId(typeId);
+ if(index < 0)
{
- throw NoObjectFactoryException(
- __FILE__, __LINE__,
- "compact format prevents slicing (the sender should use the sliced format instead)",
- _typeId);
+ _stream->write(false);
+ _stream->write(typeId, false);
}
else
{
- throw UnknownUserException(__FILE__, __LINE__, _typeId.substr(2));
+ _stream->write(true);
+ _stream->writeSize(index);
}
}
+ else
+ {
+ _stream->write(typeId, false);
+ }
- if(_encaps->encoding != Encoding_1_0)
+ _stream->write(Int(0)); // Placeholder for the slice length.
+
+ _writeSlice = _stream->b.size();
+ _firstSlice = false;
+}
+
+void
+IceInternal::BasicStream::EncapsEncoder10::endSlice()
+{
+ //
+ // Write the slice length.
+ //
+ Int sz = static_cast<Int>(_stream->b.size() - _writeSlice + sizeof(Int));
+ Byte* dest = &(*(_stream->b.begin() + _writeSlice - sizeof(Int)));
+ _stream->write(sz, dest);
+}
+
+void
+IceInternal::BasicStream::EncapsEncoder10::writePendingObjects()
+{
+ while(!_toBeMarshaledMap.empty())
{
//
- // Preserve this slice.
+ // Consider the to be marshalled objects as marshalled now,
+ // this is necessary to avoid adding again the "to be
+ // marshalled objects" into _toBeMarshaledMap while writing
+ // objects.
//
- SliceInfoPtr info = new SliceInfo;
- info->typeId = _typeId;
- info->compactId = _compactId;
- info->hasOptionalMembers = _sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS;
- info->isLastSlice = _sliceFlags & FLAG_IS_LAST_SLICE;
- if(info->hasOptionalMembers)
+ _marshaledMap.insert(_toBeMarshaledMap.begin(), _toBeMarshaledMap.end());
+
+ PtrToIndexMap savedMap;
+ savedMap.swap(_toBeMarshaledMap);
+ _stream->writeSize(static_cast<Int>(savedMap.size()));
+ for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p)
{
//
- // Don't include the optional member end marker. It will be re-written by
- // endSlice when the sliced data is re-written.
+ // Ask the instance to marshal itself. Any new class
+ // instances that are triggered by the classes marshaled
+ // are added to toBeMarshaledMap.
//
- vector<Byte>(start, _stream->i - 1).swap(info->bytes);
+ _stream->write(p->second);
+
+ try
+ {
+ p->first->ice_preMarshal();
+ }
+ catch(const std::exception& ex)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "std::exception raised by ice_preMarshal:\n" << ex;
+ }
+ catch(...)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "unknown exception raised by ice_preMarshal";
+ }
+
+ p->first->__write(_stream);
+ }
+ }
+ _stream->writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
+}
+
+Int
+IceInternal::BasicStream::EncapsEncoder10::registerObject(const ObjectPtr& v)
+{
+ assert(v);
+
+ //
+ // Look for this instance in the to-be-marshaled map.
+ //
+ PtrToIndexMap::const_iterator p = _toBeMarshaledMap.find(v);
+ if(p != _toBeMarshaledMap.end())
+ {
+ return p->second;
+ }
+
+ //
+ // Didn't find it, try the marshaled map next.
+ //
+ PtrToIndexMap::const_iterator q = _marshaledMap.find(v);
+ if(q != _marshaledMap.end())
+ {
+ return q->second;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new
+ // index, and insert it into the to-be-marshaled map.
+ //
+ _toBeMarshaledMap.insert(make_pair(v, ++_objectIdIndex));
+ return _objectIdIndex;
+}
+
+void
+IceInternal::BasicStream::EncapsEncoder11::write(const ObjectPtr& v)
+{
+ if(!v)
+ {
+ _stream->writeSize(0); // Nil reference.
+ }
+ else if(_current && _encaps->format == SlicedFormat)
+ {
+ //
+ // If writting an object within a slice and using the sliced
+ // format, write an index from the object indirection
+ // table. The indirect object table is encoded at the end of
+ // each slice and is always read (even if the Slice is
+ // unknown).
+ //
+ PtrToIndexMap::const_iterator p = _current->indirectionMap.find(v);
+ if(p == _current->indirectionMap.end())
+ {
+ _current->indirectionTable.push_back(v);
+ Int idx = static_cast<Int>(_current->indirectionTable.size()); // Position + 1 (0 is reserved for nil)
+ _current->indirectionMap.insert(make_pair(v, idx));
+ _stream->writeSize(idx);
}
else
{
- vector<Byte>(start, _stream->i).swap(info->bytes);
+ _stream->writeSize(p->second);
}
- _slices.push_back(info);
+ }
+ else
+ {
+ writeInstance(v); // Write the instance or a reference if already marshaled.
+ }
+}
- _indirectionTables.push_back(IndexList());
+void
+IceInternal::BasicStream::EncapsEncoder11::write(const UserException& v)
+{
+ v.__write(_stream);
+}
- if(_sliceFlags & FLAG_HAS_INDIRECTION_TABLE)
- {
- //
- // Read the indirection table, which is written as a sequence<size> to conserve space.
- //
- _stream->readSizeSeq(_indirectionTables.back());
- }
+void
+IceInternal::BasicStream::EncapsEncoder11::startInstance(SliceType sliceType, const SlicedDataPtr& data)
+{
+ if(!_current)
+ {
+ _current = &_preAllocatedInstanceData;
+ }
+ else
+ {
+ _current = _current->next ? _current->next : new InstanceData(_current);
+ }
+ _current->sliceType = sliceType;
+ _current->firstSlice = true;
+
+ if(data)
+ {
+ writeSlicedData(data);
}
}
-SlicedDataPtr
-IceInternal::BasicStream::EncapsDecoder::readSlicedData()
+void
+IceInternal::BasicStream::EncapsEncoder11::endInstance()
+{
+ _current = _current->previous;
+}
+
+void
+IceInternal::BasicStream::EncapsEncoder11::startSlice(const string& typeId, int compactId, bool last)
{
- if(_slices.empty()) // No preserved slices.
+ assert(_current->indirectionTable.empty() && _current->indirectionMap.empty());
+
+ _current->sliceFlagsPos = _stream->b.size();
+
+ _current->sliceFlags = 0;
+ if(_encaps->format == SlicedFormat)
{
- return 0;
+ _current->sliceFlags |= FLAG_HAS_SLICE_SIZE; // Encode the slice size if using the sliced format.
}
+ if(last)
+ {
+ _current->sliceFlags |= FLAG_IS_LAST_SLICE; // This is the last slice.
+ }
+
+ _stream->write(Byte(0)); // Placeholder for the slice flags
//
- // The _indirectionTables member holds the indirection table for each slice
- // in _slices.
+ // For object slices, encode the flag and the type ID either as a
+ // string or index. For exception slices, always encode the type
+ // ID a string.
//
- assert(_slices.size() == _indirectionTables.size());
-
- for(SliceInfoSeq::size_type n = 0; n < _slices.size(); ++n)
+ if(_current->sliceType == ObjectSlice)
{
//
- // We use the "objects" list in SliceInfo to hold references to the target
- // objects. Note however that we may not have actually read these objects
- // yet, so they need to be treated just like we had read the object references
- // directly (i.e., we add them to the patch list).
- //
- // Another important note: the SlicedData object that we return here must
- // not be destroyed before readPendingObjects is called, otherwise the
- // patch references will refer to invalid addresses.
- //
- const IndexList& table = _indirectionTables[n];
- _slices[n]->objects.resize(table.size());
- IndexList::size_type j = 0;
- for(IndexList::const_iterator p = table.begin(); p != table.end(); ++p)
+ // Encode the type ID (only in the first slice for the compact
+ // encoding).
+ //
+ if(_encaps->format == SlicedFormat || _current->firstSlice)
{
- const Int id = *p;
- if(id <= 0)
+ if(compactId >= 0)
{
- throw MarshalException(__FILE__, __LINE__, "invalid id in object indirection table");
+ _current->sliceFlags |= FLAG_HAS_TYPE_ID_COMPACT;
+ _stream->writeSize(compactId);
+ }
+ else
+ {
+ Int index = registerTypeId(typeId);
+ if(index < 0)
+ {
+ _current->sliceFlags |= FLAG_HAS_TYPE_ID_STRING;
+ _stream->write(typeId, false);
+ }
+ else
+ {
+ _current->sliceFlags |= FLAG_HAS_TYPE_ID_INDEX;
+ _stream->writeSize(index);
+ }
}
- addPatchEntry(id, &patchHandle<Object>, &_slices[n]->objects[j++]);
}
}
+ else
+ {
+ _stream->write(typeId, false);
+ }
- return new SlicedData(_slices);
+ if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE)
+ {
+ _stream->write(Int(0)); // Placeholder for the slice length.
+ }
+
+ _current->writeSlice = _stream->b.size();
+ _current->firstSlice = false;
}
-Ice::ObjectPtr
-IceInternal::BasicStream::EncapsDecoder::newInstance(const ObjectFactoryManagerPtr& servantFactoryManager,
- const string& typeId)
+void
+IceInternal::BasicStream::EncapsEncoder11::endSlice()
{
- Ice::ObjectPtr v;
+ //
+ // Write the optional member end marker if some optional members
+ // were encoded. Note that the optional members are encoded before
+ // the indirection table and are included in the slice size.
+ //
+ if(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)
+ {
+ _stream->write(OPTIONAL_END_MARKER);
+ }
//
- // Try to find a factory registered for the specific type.
+ // Write the slice length if necessary.
//
- ObjectFactoryPtr userFactory = servantFactoryManager->find(typeId);
- if(userFactory)
+ if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE)
{
- v = userFactory->create(typeId);
+ Int sz = static_cast<Int>(_stream->b.size() - _current->writeSlice + sizeof(Int));
+ Byte* dest = &(*(_stream->b.begin() + _current->writeSlice - sizeof(Int)));
+ _stream->write(sz, dest);
}
//
- // If that fails, invoke the default factory if one has been
- // registered.
+ // Only write the indirection table if it contains entries.
//
- if(!v)
+ if(!_current->indirectionTable.empty())
{
- userFactory = servantFactoryManager->find("");
- if(userFactory)
+ assert(_encaps->format == SlicedFormat);
+ _current->sliceFlags |= FLAG_HAS_INDIRECTION_TABLE;
+
+ //
+ // Write the indirection object table.
+ //
+ _stream->writeSize(static_cast<Int>(_current->indirectionTable.size()));
+ ObjectList::const_iterator p;
+ for(p = _current->indirectionTable.begin(); p != _current->indirectionTable.end(); ++p)
{
- v = userFactory->create(typeId);
+ writeInstance(*p);
}
+ _current->indirectionTable.clear();
+ _current->indirectionMap.clear();
}
//
- // Last chance: check the table of static factories (i.e.,
- // automatically generated factories for concrete classes).
+ // Finally, update the slice flags.
//
- if(!v)
+ Byte* dest = &(*(_stream->b.begin() + _current->sliceFlagsPos));
+ *dest = _current->sliceFlags;
+}
+
+bool
+IceInternal::BasicStream::EncapsEncoder11::writeOpt(Ice::Int tag, Ice::OptionalFormat format)
+{
+ if(!_current)
{
- ObjectFactoryPtr of = IceInternal::factoryTable->getObjectFactory(typeId);
- if(of)
+ return _stream->writeOptImpl(tag, format);
+ }
+ else
+ {
+ if(_stream->writeOptImpl(tag, format))
{
- v = of->create(typeId);
- assert(v);
+ _current->sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ return true;
+ }
+ else
+ {
+ return false;
}
}
+}
- return v;
+void
+IceInternal::BasicStream::EncapsEncoder11::writeSlicedData(const SlicedDataPtr& slicedData)
+{
+ assert(slicedData);
+
+ //
+ // We only remarshal preserved slices if we are using the sliced
+ // format. Otherwise, we ignore the preserved slices, which
+ // essentially "slices" the object into the most-derived type
+ // known by the sender.
+ //
+ if(_encaps->format != SlicedFormat)
+ {
+ return;
+ }
+
+ for(SliceInfoSeq::const_iterator p = slicedData->slices.begin(); p != slicedData->slices.end(); ++p)
+ {
+ startSlice((*p)->typeId, (*p)->compactId, (*p)->isLastSlice);
+
+ //
+ // Write the bytes associated with this slice.
+ //
+ _stream->writeBlob((*p)->bytes);
+
+ if((*p)->hasOptionalMembers)
+ {
+ _current->sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ }
+
+ //
+ // Make sure to also re-write the object indirection table.
+ //
+ _current->indirectionTable = (*p)->objects;
+
+ endSlice();
+ }
}
+
+void
+IceInternal::BasicStream::EncapsEncoder11::writeInstance(const ObjectPtr& v)
+{
+ assert(v);
+
+ //
+ // If the instance was already marshaled, just write it's ID.
+ //
+ PtrToIndexMap::const_iterator q = _marshaledMap.find(v);
+ if(q != _marshaledMap.end())
+ {
+ _stream->writeSize(q->second);
+ return;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new ID,
+ // insert it into the marshaled map, and write the instance.
+ //
+ _marshaledMap.insert(make_pair(v, ++_objectIdIndex));
+
+ try
+ {
+ v->ice_preMarshal();
+ }
+ catch(const std::exception& ex)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "std::exception raised by ice_preMarshal:\n" << ex;
+ }
+ catch(...)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "unknown exception raised by ice_preMarshal";
+ }
+
+ _stream->writeSize(1); // Object instance marker.
+ v->__write(_stream);
+}
+
diff --git a/cpp/src/Ice/Object.cpp b/cpp/src/Ice/Object.cpp
index 93256b730d0..5d472d8f542 100644
--- a/cpp/src/Ice/Object.cpp
+++ b/cpp/src/Ice/Object.cpp
@@ -23,7 +23,7 @@ using namespace IceInternal;
Object* Ice::upCast(Object* p) { return p; }
void
-Ice::__patch(ObjectPtr& obj, ObjectPtr& v)
+Ice::__patch(ObjectPtr& obj, const ObjectPtr& v)
{
obj = v;
}
diff --git a/cpp/src/Ice/StreamI.cpp b/cpp/src/Ice/StreamI.cpp
index c6db6768358..5df5ec83b38 100644
--- a/cpp/src/Ice/StreamI.cpp
+++ b/cpp/src/Ice/StreamI.cpp
@@ -169,7 +169,7 @@ namespace
{
void
-patchObject(void* addr, ObjectPtr& v)
+patchObject(void* addr, const ObjectPtr& v)
{
ReadObjectCallback* cb = static_cast<ReadObjectCallback*>(addr);
assert(cb);
diff --git a/cpp/src/Slice/CsUtil.cpp b/cpp/src/Slice/CsUtil.cpp
index 699bcb37c0e..0bfc5b7c519 100644
--- a/cpp/src/Slice/CsUtil.cpp
+++ b/cpp/src/Slice/CsUtil.cpp
@@ -180,7 +180,7 @@ Slice::CsGenerator::getOptionalFormat(const TypePtr& type)
}
case Builtin::KindObject:
{
- return "Ice.OptionalFormat.Size";
+ return "Ice.OptionalFormat.Class";
}
case Builtin::KindObjectProxy:
{
@@ -225,7 +225,7 @@ Slice::CsGenerator::getOptionalFormat(const TypePtr& type)
ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
assert(cl);
- return "Ice.OptionalFormat.Size";
+ return "Ice.OptionalFormat.Class";
}
string
diff --git a/cpp/src/Slice/JavaUtil.cpp b/cpp/src/Slice/JavaUtil.cpp
index 6b6559b4f2f..e98b2d8aa05 100644
--- a/cpp/src/Slice/JavaUtil.cpp
+++ b/cpp/src/Slice/JavaUtil.cpp
@@ -613,7 +613,7 @@ Slice::JavaGenerator::getOptionalFormat(const TypePtr& type)
}
case Builtin::KindObject:
{
- return "Ice.OptionalFormat.Size";
+ return "Ice.OptionalFormat.Class";
}
case Builtin::KindObjectProxy:
{
@@ -658,7 +658,7 @@ Slice::JavaGenerator::getOptionalFormat(const TypePtr& type)
ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
assert(cl);
- return "Ice.OptionalFormat.Size";
+ return "Ice.OptionalFormat.Class";
}
string
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp
index 4867c3af593..71b55d05b14 100644
--- a/cpp/src/Slice/Parser.cpp
+++ b/cpp/src/Slice/Parser.cpp
@@ -283,7 +283,7 @@ Slice::Builtin::minWireSize() const
4, // KindFloat
8, // KindDouble
1, // KindString: at least one byte for an empty string.
- 4, // KindObject: at least 4 bytes (to marshal an index instead of an instance).
+ 1, // KindObject: at least 4 bytes (to marshal an index instead of an instance).
2 // KindObjectProxy: at least an empty identity for a nil proxy, that is, 2 bytes.
};
diff --git a/cpp/src/slice2cpp/Gen.cpp b/cpp/src/slice2cpp/Gen.cpp
index d2d650df4e6..336cd1e6cbe 100644
--- a/cpp/src/slice2cpp/Gen.cpp
+++ b/cpp/src/slice2cpp/Gen.cpp
@@ -3229,7 +3229,7 @@ Slice::Gen::ObjectDeclVisitor::visitClassDecl(const ClassDeclPtr& p)
H << nl << _dllExport << "::Ice::Object* upCast(" << scoped << "*);";
H << nl << "typedef ::IceInternal::Handle< " << scoped << "> " << p->name() << "Ptr;";
H << nl << "typedef ::IceInternal::ProxyHandle< ::IceProxy" << scoped << "> " << p->name() << "Prx;";
- H << nl << _dllExport << "void __patch(" << p->name() << "Ptr&, ::Ice::ObjectPtr&);";
+ H << nl << _dllExport << "void __patch(" << p->name() << "Ptr&, const ::Ice::ObjectPtr&);";
}
else
{
@@ -4105,7 +4105,7 @@ Slice::Gen::ObjectVisitor::visitClassDefEnd(const ClassDefPtr& p)
{
C << sp << nl << "void "
<< (_dllExport.empty() ? "" : "ICE_DECLSPEC_EXPORT ");
- C << nl << scope.substr(2) << "__patch(" << p->name() << "Ptr& handle, ::Ice::ObjectPtr& v)";
+ C << nl << scope.substr(2) << "__patch(" << p->name() << "Ptr& handle, const ::Ice::ObjectPtr& v)";
C << sb;
C << nl << "handle = " << scope << p->name() << "Ptr::dynamicCast(v);";
C << nl << "if(v && !handle)";