diff options
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/include/Ice/BasicStream.h | 481 | ||||
-rw-r--r-- | cpp/include/Ice/ObjectF.h | 2 | ||||
-rw-r--r-- | cpp/include/Ice/StreamHelpers.h | 8 | ||||
-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 | ||||
-rw-r--r-- | cpp/test/Ice/optional/AllTests.cpp | 80 | ||||
-rw-r--r-- | cpp/test/Ice/optional/Test.ice | 10 | ||||
-rw-r--r-- | cpp/test/Ice/slicing/exceptions/AllTests.cpp | 15 | ||||
-rw-r--r-- | cpp/test/Ice/slicing/objects/AllTests.cpp | 45 |
14 files changed, 1524 insertions, 1042 deletions
diff --git a/cpp/include/Ice/BasicStream.h b/cpp/include/Ice/BasicStream.h index bf343b01ff5..b5036a79528 100644 --- a/cpp/include/Ice/BasicStream.h +++ b/cpp/include/Ice/BasicStream.h @@ -41,7 +41,7 @@ namespace IceInternal { template<typename T> inline void -patchHandle(void* addr, Ice::ObjectPtr& v) +patchHandle(void* addr, const Ice::ObjectPtr& v) { IceInternal::Handle<T>* p = static_cast<IceInternal::Handle<T>*>(addr); __patch(*p, v); // Generated __patch method, necessary for forward declarations. @@ -52,7 +52,7 @@ class ICE_API BasicStream : public Buffer public: typedef size_t size_type; - typedef void (*PatchFunc)(void*, Ice::ObjectPtr&); + typedef void (*PatchFunc)(void*, const Ice::ObjectPtr&); BasicStream(Instance*, const Ice::EncodingVersion&, bool = false); ~BasicStream() @@ -95,45 +95,45 @@ public: void startWriteObject(const Ice::SlicedDataPtr& data) { assert(_currentWriteEncaps && _currentWriteEncaps->encoder); - _currentWriteEncaps->encoder->startObject(data); + _currentWriteEncaps->encoder->startInstance(ObjectSlice, data); } void endWriteObject() { assert(_currentWriteEncaps && _currentWriteEncaps->encoder); - _currentWriteEncaps->encoder->endObject(); + _currentWriteEncaps->encoder->endInstance(); } void startReadObject() { assert(_currentReadEncaps && _currentReadEncaps->decoder); - _currentReadEncaps->decoder->startObject(); + _currentReadEncaps->decoder->startInstance(ObjectSlice); } Ice::SlicedDataPtr endReadObject(bool preserve) { assert(_currentReadEncaps && _currentReadEncaps->decoder); - return _currentReadEncaps->decoder->endObject(preserve); + return _currentReadEncaps->decoder->endInstance(preserve); } void startWriteException(const Ice::SlicedDataPtr& data) { assert(_currentWriteEncaps && _currentWriteEncaps->encoder); - _currentWriteEncaps->encoder->startException(data); + _currentWriteEncaps->encoder->startInstance(ExceptionSlice, data); } void endWriteException() { assert(_currentWriteEncaps && _currentWriteEncaps->encoder); - _currentWriteEncaps->encoder->endException(); + _currentWriteEncaps->encoder->endInstance(); } void startReadException() { assert(_currentReadEncaps && _currentReadEncaps->decoder); - _currentReadEncaps->decoder->startException(); + _currentReadEncaps->decoder->startInstance(ExceptionSlice); } Ice::SlicedDataPtr endReadException(bool preserve) { assert(_currentReadEncaps && _currentReadEncaps->decoder); - return _currentReadEncaps->decoder->endException(preserve); + return _currentReadEncaps->decoder->endInstance(preserve); } void startWriteEncaps(); @@ -163,11 +163,6 @@ public: { assert(_currentWriteEncaps); - if(_currentWriteEncaps->encoder) - { - _currentWriteEncaps->encoder->writePendingObjects(); - } - // Size includes size and version. const Ice::Int sz = static_cast<Ice::Int>(b.size() - _currentWriteEncaps->start); write(sz, &(*(b.begin() + _currentWriteEncaps->start))); @@ -250,34 +245,21 @@ public: { assert(_currentReadEncaps); - if(_currentReadEncaps->decoder) - { - _currentReadEncaps->decoder->readPendingObjects(); - } - else if(i < b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz && - _currentReadEncaps->encoding != Ice::Encoding_1_0) + if(_currentReadEncaps->encoding != Ice::Encoding_1_0) { - // - // Read remaining encapsulation optionals. This returns - // true if the optionals end with the end marker. The end - // marker indicates that there are more to read from the - // encapsulation: object instances. In this case, don't - // bother reading the objects, just skip to the end of the - // encapsulation. - // - if(skipOpts()) + skipOpts(); + if(i != b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz) { - i = b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz; + throwEncapsulationException(__FILE__, __LINE__); } } - - if(i != b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz) + else if(i != b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz) { if(i + 1 != b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz) { throwEncapsulationException(__FILE__, __LINE__); } - + // // Ice version < 3.3 had a bug where user exceptions with // class members could be encoded with a trailing byte @@ -355,7 +337,7 @@ public: _currentWriteEncaps->encoder->endSlice(); } - std::string startReadSlice() // Returns type ID of next slice + std::string startReadSlice() { assert(_currentReadEncaps && _currentReadEncaps->decoder); return _currentReadEncaps->decoder->startSlice(); @@ -387,14 +369,6 @@ public: write(static_cast<Ice::Byte>(v)); } } - void writeSizeSeq(const std::vector<Ice::Int>& v) - { - writeSize(static_cast<Ice::Int>(v.size())); - for(std::vector<Ice::Int>::const_iterator p = v.begin(); p != v.end(); ++p) - { - writeSize(*p); - } - } void rewriteSize(Ice::Int v, Container::iterator dest) { assert(v >= 0); @@ -428,22 +402,6 @@ public: return static_cast<Ice::Int>(static_cast<unsigned char>(byte)); } } - void readSizeSeq(std::vector<Ice::Int>& v) - { - Ice::Int sz = readAndCheckSeqSize(1); - if(sz > 0) - { - v.resize(sz); - for(Ice::Int n = 0; n < sz; ++n) - { - v[n] = readSize(); - } - } - else - { - v.clear(); - } - } Ice::Int readAndCheckSeqSize(int); @@ -510,7 +468,9 @@ public: Ice::StreamableTraits<T>::helper, Ice::StreamableTraits<T>::fixedLength>::optionalFormat)) { - Ice::StreamOptionalHelper<T, Ice::StreamableTraits<T>::helper, Ice::StreamableTraits<T>::fixedLength>::write(this, *v); + Ice::StreamOptionalHelper<T, + Ice::StreamableTraits<T>::helper, + Ice::StreamableTraits<T>::fixedLength>::write(this, *v); } } template<typename T> void read(Ice::Int tag, IceUtil::Optional<T>& v) @@ -520,7 +480,9 @@ public: Ice::StreamableTraits<T>::fixedLength>::optionalFormat)) { v.__setIsSet(); - Ice::StreamOptionalHelper<T, Ice::StreamableTraits<T>::helper, Ice::StreamableTraits<T>::fixedLength>::read(this, *v); + Ice::StreamOptionalHelper<T, + Ice::StreamableTraits<T>::helper, + Ice::StreamableTraits<T>::fixedLength>::read(this, *v); } else { @@ -778,7 +740,6 @@ public: } void read(PatchFunc patchFunc, void* patchAddr) { - assert(patchFunc && patchAddr); initReadEncaps(); _currentReadEncaps->decoder->read(patchFunc, patchAddr); } @@ -800,8 +761,8 @@ public: // Read/write/skip optionals bool readOptImpl(Ice::Int, Ice::OptionalFormat); bool writeOptImpl(Ice::Int, Ice::OptionalFormat); - bool skipOpt(Ice::OptionalFormat); - bool skipOpts(); + void skipOpt(Ice::OptionalFormat); + void skipOpts(); // Skip bytes from the stream void skip(size_type size) @@ -831,35 +792,6 @@ public: write(value, b.begin() + p); } - struct IndirectPatchEntry - { - Ice::Int index; - PatchFunc patchFunc; - void* patchAddr; - }; - - struct PatchEntry - { - PatchFunc patchFunc; - void* patchAddr; - }; - - typedef std::vector<PatchEntry> PatchList; - typedef std::map<Ice::Int, PatchList> PatchMap; - typedef std::map<Ice::Int, Ice::ObjectPtr> IndexToPtrMap; - typedef std::map<Ice::Int, std::string> TypeIdReadMap; - - typedef std::map<Ice::ObjectPtr, Ice::Int> PtrToIndexMap; - typedef std::map<std::string, Ice::Int> TypeIdWriteMap; - - typedef std::vector<Ice::ObjectPtr> ObjectList; - - typedef std::vector<IndirectPatchEntry> IndirectPatchList; - typedef std::vector<Ice::Int> IndexList; - typedef std::map<Ice::Int, Ice::Int> IndirectionMap; - - typedef std::vector<IndexList> IndexListList; - private: // @@ -886,147 +818,338 @@ private: class WriteEncaps; enum SliceType { NoSlice, ObjectSlice, ExceptionSlice }; + typedef std::vector<Ice::ObjectPtr> ObjectList; + class ICE_API EncapsDecoder : private ::IceUtil::noncopyable { public: - EncapsDecoder(BasicStream* stream, ReadEncaps* encaps, bool sliceObjects) : - _stream(stream), _encaps(encaps), _sliceObjects(sliceObjects), _traceSlicing(-1), _sliceType(NoSlice), - _compactId(-1), _typeIdIndex(0) - { - } - - void read(PatchFunc, void*); - void throwException(const UserExceptionFactoryPtr&); - void startObject(); - Ice::SlicedDataPtr endObject(bool); + virtual ~EncapsDecoder() { } - void startException(); - Ice::SlicedDataPtr endException(bool); + virtual void read(PatchFunc, void*) = 0; + virtual void throwException(const UserExceptionFactoryPtr&) = 0; - const std::string& startSlice(); - void endSlice(); - void skipSlice(); + virtual void startInstance(SliceType) = 0; + virtual Ice::SlicedDataPtr endInstance(bool) = 0; + virtual const std::string& startSlice() = 0; + virtual void endSlice() = 0; + virtual void skipSlice() = 0; - bool readOpt(Ice::Int readTag, Ice::OptionalFormat expectedFormat) + virtual bool readOpt(Ice::Int, Ice::OptionalFormat) { - if(_sliceType == NoSlice) - { - return _stream->readOptImpl(readTag, expectedFormat); - } - else if(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) - { - return _stream->readOptImpl(readTag, expectedFormat); - } return false; } - void readPendingObjects(); + virtual void readPendingObjects() + { + } + + protected: - private: + EncapsDecoder(BasicStream* stream, ReadEncaps* encaps, bool sliceObjects, const ObjectFactoryManagerPtr& f) : + _stream(stream), _encaps(encaps), _sliceObjects(sliceObjects), _servantFactoryManager(f), _typeIdIndex(0) + { + } + + std::string readTypeId(bool); + Ice::ObjectPtr newInstance(const std::string&); - const std::string& readTypeId() const; - Ice::ObjectPtr readInstance(); void addPatchEntry(Ice::Int, PatchFunc, void*); - Ice::SlicedDataPtr readSlicedData(); - Ice::ObjectPtr newInstance(const IceInternal::ObjectFactoryManagerPtr&, const std::string&); + void unmarshal(Ice::Int, const Ice::ObjectPtr&); + + typedef std::map<Ice::Int, Ice::ObjectPtr> IndexToPtrMap; + typedef std::map<Ice::Int, std::string> TypeIdReadMap; + + struct PatchEntry + { + PatchFunc patchFunc; + void* patchAddr; + }; + typedef std::vector<PatchEntry> PatchList; + typedef std::map<Ice::Int, PatchList> PatchMap; BasicStream* _stream; ReadEncaps* _encaps; const bool _sliceObjects; + ObjectFactoryManagerPtr _servantFactoryManager; + + // Encapsulation attributes for object un-marshalling + PatchMap _patchMap; + + private: + + // Encapsulation attributes for object un-marshalling + IndexToPtrMap _unmarshaledMap; + TypeIdReadMap _typeIdMap; + Ice::Int _typeIdIndex; + ObjectList _objectList; + }; + + class ICE_API EncapsDecoder10 : public EncapsDecoder + { + public: + + EncapsDecoder10(BasicStream* stream, ReadEncaps* encaps, bool sliceObjects, const ObjectFactoryManagerPtr& f) : + EncapsDecoder(stream, encaps, sliceObjects, f), _sliceType(NoSlice) + { + } + + virtual void read(PatchFunc, void*); + virtual void throwException(const UserExceptionFactoryPtr&); + + virtual void startInstance(SliceType); + virtual Ice::SlicedDataPtr endInstance(bool); + virtual const std::string& startSlice(); + virtual void endSlice(); + virtual void skipSlice(); + + virtual void readPendingObjects(); + + private: - int _traceSlicing; - const char* _slicingCat; + void readInstance(); - // Object/exception attributes + // Instance attributes SliceType _sliceType; bool _skipFirstSlice; - Ice::SliceInfoSeq _slices; // Preserved slices. - IndexListList _indirectionTables; // Indirection tables for the preserved slices. // Slice attributes - Ice::Byte _sliceFlags; Ice::Int _sliceSize; std::string _typeId; - Ice::Int _compactId; - IndirectPatchList _indirectPatchList; - - // Encapsulation attributes for object un-marshalling - PatchMap _patchMap; - IndexToPtrMap _unmarshaledMap; - TypeIdReadMap _typeIdMap; - Ice::Int _typeIdIndex; }; - class ICE_API EncapsEncoder : private ::IceUtil::noncopyable + class ICE_API EncapsDecoder11 : public EncapsDecoder { public: - EncapsEncoder(BasicStream* stream, WriteEncaps* encaps) : - _stream(stream), _encaps(encaps), _sliceType(NoSlice), _objectIdIndex(0), - _typeIdIndex(0) + + EncapsDecoder11(BasicStream* stream, ReadEncaps* encaps, bool sliceObjects, const ObjectFactoryManagerPtr& f) : + EncapsDecoder(stream, encaps, sliceObjects, f), _preAllocatedInstanceData(0), _current(0), _objectIdIndex(1) { - } + } - void write(const Ice::ObjectPtr&); - void write(const Ice::UserException&); + virtual void read(PatchFunc, void*); + virtual void throwException(const UserExceptionFactoryPtr&); - void startObject(const Ice::SlicedDataPtr&); - void endObject(); + virtual void startInstance(SliceType); + virtual Ice::SlicedDataPtr endInstance(bool); + virtual const std::string& startSlice(); + virtual void endSlice(); + virtual void skipSlice(); - void startException(const Ice::SlicedDataPtr&); - void endException(); + virtual bool readOpt(Ice::Int, Ice::OptionalFormat); - void startSlice(const std::string&, int, bool); - void endSlice(); + private: - bool writeOpt(Ice::Int tag, Ice::OptionalFormat format) + Ice::Int readInstance(Ice::Int, PatchFunc, void*); + Ice::SlicedDataPtr readSlicedData(); + + struct IndirectPatchEntry { - if(_sliceType == NoSlice) - { - return _stream->writeOptImpl(tag, format); - } - else + Ice::Int index; + PatchFunc patchFunc; + void* patchAddr; + }; + typedef std::vector<IndirectPatchEntry> IndirectPatchList; + + typedef std::vector<Ice::Int> IndexList; + typedef std::vector<IndexList> IndexListList; + + struct InstanceData + { + InstanceData(InstanceData* previous) : previous(previous), next(0) { - if(_stream->writeOptImpl(tag, format)) + if(previous) { - _sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS; - return true; + previous->next = this; } - else + } + + ~InstanceData() + { + if(next) { - return false; + delete next; } } + + // Instance attributes + SliceType sliceType; + bool skipFirstSlice; + Ice::SliceInfoSeq slices; // Preserved slices. + IndexListList indirectionTables; + + // Slice attributes + Ice::Byte sliceFlags; + Ice::Int sliceSize; + std::string typeId; + int compactId; + IndirectPatchList indirectPatchList; + + InstanceData* previous; + InstanceData* next; + }; + InstanceData _preAllocatedInstanceData; + InstanceData* _current; + + void push(SliceType sliceType) + { + if(!_current) + { + _current = &_preAllocatedInstanceData; + } + else + { + _current = _current->next ? _current->next : new InstanceData(_current); + } + _current->sliceType = sliceType; + _current->skipFirstSlice = false; } - void writePendingObjects(); + Ice::Int _objectIdIndex; // The ID of the next object to un-marshal. + }; - private: + class ICE_API EncapsEncoder : private ::IceUtil::noncopyable + { + public: - void writeTypeId(const std::string&); - void writeSlicedData(const Ice::SlicedDataPtr&); - Ice::Int registerObject(const Ice::ObjectPtr&); + virtual ~EncapsEncoder() { } + + virtual void write(const Ice::ObjectPtr&) = 0; + virtual void write(const Ice::UserException&) = 0; + + virtual void startInstance(SliceType, const Ice::SlicedDataPtr&) = 0; + virtual void endInstance() = 0; + virtual void startSlice(const std::string&, int, bool) = 0; + virtual void endSlice() = 0; + + virtual bool writeOpt(Ice::Int, Ice::OptionalFormat) + { + return false; + } + + virtual void writePendingObjects() + { + } + + protected: + + EncapsEncoder(BasicStream* stream, WriteEncaps* encaps) : _stream(stream), _encaps(encaps), _typeIdIndex(0) + { + } + + Ice::Int registerTypeId(const std::string&); BasicStream* _stream; WriteEncaps* _encaps; - // Object/exception attributes + typedef std::map<Ice::ObjectPtr, Ice::Int> PtrToIndexMap; + typedef std::map<std::string, Ice::Int> TypeIdWriteMap; + + // Encapsulation attributes for object marshalling. + PtrToIndexMap _marshaledMap; + + private: + + // Encapsulation attributes for object marshalling. + TypeIdWriteMap _typeIdMap; + Ice::Int _typeIdIndex; + }; + + class ICE_API EncapsEncoder10 : public EncapsEncoder + { + public: + + EncapsEncoder10(BasicStream* stream, WriteEncaps* encaps) : + EncapsEncoder(stream, encaps), _sliceType(NoSlice), _objectIdIndex(0) + { + } + + virtual void write(const Ice::ObjectPtr&); + virtual void write(const Ice::UserException&); + + virtual void startInstance(SliceType, const Ice::SlicedDataPtr&); + virtual void endInstance(); + virtual void startSlice(const std::string&, int, bool); + virtual void endSlice(); + + virtual void writePendingObjects(); + + private: + + Ice::Int registerObject(const Ice::ObjectPtr&); + + // Instance attributes SliceType _sliceType; bool _firstSlice; // Slice attributes - Ice::Byte _sliceFlags; - Container::size_type _writeSlice; // Position of the slice data members - Container::size_type _sliceFlagsPos; // Position of the slice flags - IndexList _indirectionTable; - IndirectionMap _indirectionMap; + Container::size_type _writeSlice; // Position of the slice data members // Encapsulation attributes for object marshalling. Ice::Int _objectIdIndex; PtrToIndexMap _toBeMarshaledMap; - PtrToIndexMap _marshaledMap; - TypeIdWriteMap _typeIdMap; - Ice::Int _typeIdIndex; + }; + + class ICE_API EncapsEncoder11 : public EncapsEncoder + { + public: + + EncapsEncoder11(BasicStream* stream, WriteEncaps* encaps) : + EncapsEncoder(stream, encaps), _preAllocatedInstanceData(0), _current(0), _objectIdIndex(1) + { + } + + virtual void write(const Ice::ObjectPtr&); + virtual void write(const Ice::UserException&); + + virtual void startInstance(SliceType, const Ice::SlicedDataPtr&); + virtual void endInstance(); + virtual void startSlice(const std::string&, int, bool); + virtual void endSlice(); + + virtual bool writeOpt(Ice::Int, Ice::OptionalFormat); + + private: + + void writeSlicedData(const Ice::SlicedDataPtr&); + void writeInstance(const Ice::ObjectPtr&); + + struct InstanceData + { + InstanceData(InstanceData* previous) : previous(previous), next(0) + { + if(previous) + { + previous->next = this; + } + } + + ~InstanceData() + { + if(next) + { + delete next; + } + } + + // Instance attributes + SliceType sliceType; + bool firstSlice; + + // Slice attributes + Ice::Byte sliceFlags; + Container::size_type writeSlice; // Position of the slice data members + Container::size_type sliceFlagsPos; // Position of the slice flags + PtrToIndexMap indirectionMap; + ObjectList indirectionTable; + + InstanceData* previous; + InstanceData* next; + }; + InstanceData _preAllocatedInstanceData; + InstanceData* _current; + + Ice::Int _objectIdIndex; // The ID of the next object to marhsal }; class ReadEncaps : private ::IceUtil::noncopyable @@ -1121,14 +1244,6 @@ private: int _minSeqSize; int _sizePos; - - static const Ice::Byte FLAG_HAS_TYPE_ID_STRING; - static const Ice::Byte FLAG_HAS_TYPE_ID_INDEX; - static const Ice::Byte FLAG_HAS_TYPE_ID_COMPACT; - static const Ice::Byte FLAG_HAS_OPTIONAL_MEMBERS; - static const Ice::Byte FLAG_HAS_INDIRECTION_TABLE; - static const Ice::Byte FLAG_HAS_SLICE_SIZE; - static const Ice::Byte FLAG_IS_LAST_SLICE; }; } // End namespace IceInternal diff --git a/cpp/include/Ice/ObjectF.h b/cpp/include/Ice/ObjectF.h index 5946be23dd0..e74e5ad50c0 100644 --- a/cpp/include/Ice/ObjectF.h +++ b/cpp/include/Ice/ObjectF.h @@ -19,7 +19,7 @@ namespace Ice class Object; ICE_API Object* upCast(Object*); typedef IceInternal::Handle< Object > ObjectPtr; -ICE_API void __patch(ObjectPtr&, ObjectPtr&); +ICE_API void __patch(ObjectPtr&, const ObjectPtr&); } diff --git a/cpp/include/Ice/StreamHelpers.h b/cpp/include/Ice/StreamHelpers.h index 81d30f4d543..ef6b8bf6510 100644 --- a/cpp/include/Ice/StreamHelpers.h +++ b/cpp/include/Ice/StreamHelpers.h @@ -51,10 +51,10 @@ enum OptionalFormat OptionalFormatF4 = 2, // Fixed 4 bytes encoding OptionalFormatF8 = 3, // Fixed 8 bytes encoding OptionalFormatSize = 4, // "Size encoding" on 1 to 5 bytes, e.g. enum, class identifier - OptionalFormatVSize = 5, // "Size encoding" on 1 to 5 bytes followed by data, e.g. string, fixed size struct, - // or containers whose size can be computed prior to marshaling + OptionalFormatVSize = 5, // "Size encoding" on 1 to 5 bytes followed by data, e.g. string, fixed size + // struct, or containers whose size can be computed prior to marshaling OptionalFormatFSize = 6, // Fixed size on 4 bytes followed by data, e.g. variable-size struct, container. - OptionalFormatEndMarker = 7 + OptionalFormatClass = 7 }; @@ -566,7 +566,7 @@ struct GetOptionalFormat<StreamHelperCategoryBuiltin, 1, false> template<> struct GetOptionalFormat<StreamHelperCategoryClass, 1, false> { - static const OptionalFormat value = OptionalFormatSize; + static const OptionalFormat value = OptionalFormatClass; }; template<int minWireSize> 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)"; diff --git a/cpp/test/Ice/optional/AllTests.cpp b/cpp/test/Ice/optional/AllTests.cpp index 0d2abc181fd..d0145d44212 100644 --- a/cpp/test/Ice/optional/AllTests.cpp +++ b/cpp/test/Ice/optional/AllTests.cpp @@ -145,7 +145,36 @@ public: private: IceUtil::Optional<APtr> a; +}; + +class FObjectReader : public Ice::ObjectReader +{ +public: + virtual void + read(const Ice::InputStreamPtr& in) + { + _f = new F(); + in->startObject(); + in->startSlice(); + // Don't read af on purpose + //in->read(1, _f->af); + in->endSlice(); + in->startSlice(); + in->read(_f->ae); + in->endSlice(); + in->endObject(false); + } + + FPtr + getF() + { + return _f; + } + +private: + + FPtr _f; }; class FactoryI : public Ice::ObjectFactory @@ -186,6 +215,10 @@ public: { return new DObjectReader; } + else if(typeId == "::Test::F") + { + return new FObjectReader; + } return 0; } @@ -657,6 +690,33 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated) cout << "ok" << endl; + cout << "testing marshalling of objects with optional objects..." << flush; + { + FPtr f = new F(); + + f->af = new A(); + f->ae = *f->af; + + FPtr rf = FPtr::dynamicCast(initial->pingPong(f)); + test(rf->ae == *rf->af); + + factory->setEnabled(true); + out = Ice::createOutputStream(communicator); + out->startEncapsulation(); + out->write(f); + out->endEncapsulation(); + out->finished(inEncaps); + in = Ice::createInputStream(communicator, inEncaps); + in->startEncapsulation(); + in->read(obj); + in->endEncapsulation(); + factory->setEnabled(false); + + rf = dynamic_cast<FObjectReader*>(obj.get())->getF(); + test(rf->ae && !rf->af); + } + cout << "ok" << endl; + cout << "testing optional with default values... " << flush; WDPtr wd = WDPtr::dynamicCast(initial->pingPong(new WD())); test(*wd->a == 5); @@ -867,6 +927,26 @@ allTests(const Ice::CommunicatorPtr& communicator, bool collocated) in->endEncapsulation(); } + { + FPtr f = new F(); + f->af = new A(); + (*f->af)->requiredA = 56; + f->ae = *f->af; + + out = Ice::createOutputStream(communicator); + out->startEncapsulation(); + out->write(1, makeOptional(f)); + out->write(2, makeOptional(f->ae)); + out->endEncapsulation(); + out->finished(inEncaps); + + in = Ice::createInputStream(communicator, inEncaps); + in->startEncapsulation(); + IceUtil::Optional<APtr> a; + in->read(2, a); + in->endEncapsulation(); + test(a && *a && (*a)->requiredA == 56); + } cout << "ok" << endl; cout << "testing optional parameters and custom sequences... " << flush; diff --git a/cpp/test/Ice/optional/Test.ice b/cpp/test/Ice/optional/Test.ice index d693ae649a2..269a8ea4bfa 100644 --- a/cpp/test/Ice/optional/Test.ice +++ b/cpp/test/Ice/optional/Test.ice @@ -163,6 +163,16 @@ class OptionalWithCustom optional(3) ClassVarStruct s; }; +class E +{ + A ae; +}; + +class F extends E +{ + optional(1) A af; +}; + class Initial { void shutdown(); diff --git a/cpp/test/Ice/slicing/exceptions/AllTests.cpp b/cpp/test/Ice/slicing/exceptions/AllTests.cpp index 0ea733dde2c..69bfcb491b3 100644 --- a/cpp/test/Ice/slicing/exceptions/AllTests.cpp +++ b/cpp/test/Ice/slicing/exceptions/AllTests.cpp @@ -781,6 +781,9 @@ allTests(const Ice::CommunicatorPtr& communicator) // test(test->ice_getEncodingVersion() != Ice::Encoding_1_0); } + catch(const Ice::OperationNotExistException&) + { + } catch(...) { test(false); @@ -805,6 +808,9 @@ allTests(const Ice::CommunicatorPtr& communicator) test(ex.kp == "preserved"); test(ex.kpd == "derived"); } + catch(const Ice::OperationNotExistException&) + { + } catch(...) { test(false); @@ -821,6 +827,9 @@ allTests(const Ice::CommunicatorPtr& communicator) test(ex.kp == "preserved"); test(ex.kpd == "derived"); } + catch(const Ice::OperationNotExistException&) + { + } catch(...) { test(false); @@ -842,6 +851,9 @@ allTests(const Ice::CommunicatorPtr& communicator) test(pc->pc == "pc"); test(ex.p2 == ex.p1); } + catch(const Ice::OperationNotExistException&) + { + } catch(const KnownPreservedDerived& ex) { // @@ -862,6 +874,9 @@ allTests(const Ice::CommunicatorPtr& communicator) test->relayUnknownPreservedAsKnownPreserved(relay); test(false); } + catch(const Ice::OperationNotExistException&) + { + } catch(const Preserved2& ex) { test(ex.b == "base"); diff --git a/cpp/test/Ice/slicing/objects/AllTests.cpp b/cpp/test/Ice/slicing/objects/AllTests.cpp index 5d07fa30fcc..b4415e1a625 100644 --- a/cpp/test/Ice/slicing/objects/AllTests.cpp +++ b/cpp/test/Ice/slicing/objects/AllTests.cpp @@ -477,9 +477,16 @@ public: } void - exception(const ::Ice::Exception&) + exception(const ::Ice::Exception& ex) { - test(false); + if(!dynamic_cast<const Ice::OperationNotExistException*>(&ex)) + { + test(false); + } + else + { + called(); + } } BPtr rb; @@ -724,6 +731,9 @@ allTests(const Ice::CommunicatorPtr& communicator) SBasePtr sb = test->SBSUnknownDerivedAsSBaseCompact(); test(sb->sb == "SBSUnknownDerived.sb"); } + catch(const Ice::OperationNotExistException&) + { + } catch(...) { test(false); @@ -740,6 +750,9 @@ allTests(const Ice::CommunicatorPtr& communicator) SBasePtr sb = test->SBSUnknownDerivedAsSBaseCompact(); test(false); } + catch(const Ice::OperationNotExistException&) + { + } catch(const Ice::NoObjectFactoryException&) { // Expected. @@ -1964,6 +1977,7 @@ allTests(const Ice::CommunicatorPtr& communicator) cout << "ok" << endl; cout << "preserved classes... " << flush; + try { // // Server knows the most-derived class PDerived. @@ -1980,7 +1994,11 @@ allTests(const Ice::CommunicatorPtr& communicator) test(p2->ps == "preserved"); test(p2->pb == p2); } + catch(const Ice::OperationNotExistException&) + { + } + try { // // Server only knows the base (non-preserved) type, so the object is sliced. @@ -1994,7 +2012,11 @@ allTests(const Ice::CommunicatorPtr& communicator) test(!p2); test(r->pi == 3); } + catch(const Ice::OperationNotExistException&) + { + } + try { // // Server only knows the intermediate type Preserved. The object will be sliced to @@ -2018,7 +2040,11 @@ allTests(const Ice::CommunicatorPtr& communicator) test(p2->pbs[0] == p2); } } + catch(const Ice::OperationNotExistException&) + { + } + try { // // Server only knows the intermediate type CompactPDerived. The object will be sliced to @@ -2042,7 +2068,11 @@ allTests(const Ice::CommunicatorPtr& communicator) test(p2->pbs[0] == p2); } } + catch(const Ice::OperationNotExistException&) + { + } + try { // // Send an object that will have multiple preserved slices in the server. @@ -2089,7 +2119,11 @@ allTests(const Ice::CommunicatorPtr& communicator) test(p3->pcd3 == p3->pbs[10]); } } + catch(const Ice::OperationNotExistException&) + { + } + try { // // Obtain an object with preserved slices and send it back to the server. @@ -2103,6 +2137,9 @@ allTests(const Ice::CommunicatorPtr& communicator) test->ice_encodingVersion(Ice::Encoding_1_0)->checkPBSUnknown(p); } } + catch(const Ice::OperationNotExistException&) + { + } cout << "ok" << endl; @@ -2223,6 +2260,7 @@ allTests(const Ice::CommunicatorPtr& communicator) cout << "ok" << endl; cout << "garbage collection for preserved classes... " << flush; + try { // // Register a factory in order to substitute our own subclass of PNode. This provides @@ -2351,6 +2389,9 @@ allTests(const Ice::CommunicatorPtr& communicator) test(false); } } + catch(const Ice::OperationNotExistException&) + { + } cout << "ok" << endl; return test; |