summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2013-01-04 10:50:28 +0100
committerBenoit Foucher <benoit@zeroc.com>2013-01-04 10:50:28 +0100
commit8b4674dbca704b9ffb48cd9a4fee43211e774cce (patch)
treeac55936ef4ba7b52ed8835c011b7c59cf2d1d3ee /cpp
parentFixed(ICE-5147) - Fix python scripts to not raise strings anymore (diff)
downloadice-8b4674dbca704b9ffb48cd9a4fee43211e774cce.tar.bz2
ice-8b4674dbca704b9ffb48cd9a4fee43211e774cce.tar.xz
ice-8b4674dbca704b9ffb48cd9a4fee43211e774cce.zip
ICE-4938: Super compact enoding
Diffstat (limited to 'cpp')
-rw-r--r--cpp/include/Ice/BasicStream.h481
-rw-r--r--cpp/include/Ice/ObjectF.h2
-rw-r--r--cpp/include/Ice/StreamHelpers.h8
-rw-r--r--cpp/src/Ice/BasicStream.cpp1907
-rw-r--r--cpp/src/Ice/Object.cpp2
-rw-r--r--cpp/src/Ice/StreamI.cpp2
-rw-r--r--cpp/src/Slice/CsUtil.cpp4
-rw-r--r--cpp/src/Slice/JavaUtil.cpp4
-rw-r--r--cpp/src/Slice/Parser.cpp2
-rw-r--r--cpp/src/slice2cpp/Gen.cpp4
-rw-r--r--cpp/test/Ice/optional/AllTests.cpp80
-rw-r--r--cpp/test/Ice/optional/Test.ice10
-rw-r--r--cpp/test/Ice/slicing/exceptions/AllTests.cpp15
-rw-r--r--cpp/test/Ice/slicing/objects/AllTests.cpp45
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;