diff options
author | Benoit Foucher <benoit@zeroc.com> | 2013-01-04 10:50:28 +0100 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2013-01-04 10:50:28 +0100 |
commit | 8b4674dbca704b9ffb48cd9a4fee43211e774cce (patch) | |
tree | ac55936ef4ba7b52ed8835c011b7c59cf2d1d3ee /cpp/src | |
parent | Fixed(ICE-5147) - Fix python scripts to not raise strings anymore (diff) | |
download | ice-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.cpp | 1907 | ||||
-rw-r--r-- | cpp/src/Ice/Object.cpp | 2 | ||||
-rw-r--r-- | cpp/src/Ice/StreamI.cpp | 2 | ||||
-rw-r--r-- | cpp/src/Slice/CsUtil.cpp | 4 | ||||
-rw-r--r-- | cpp/src/Slice/JavaUtil.cpp | 4 | ||||
-rw-r--r-- | cpp/src/Slice/Parser.cpp | 2 | ||||
-rw-r--r-- | cpp/src/slice2cpp/Gen.cpp | 4 |
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)"; |