http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMetaDataImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMetaDataImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMetaDataImpl.java
new file mode 100644
index 0000000..078bb68
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableMetaDataImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.internal.util.tostring.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Portable meta data implementation.
+ */
+public class GridPortableMetaDataImpl implements PortableMetadata, 
PortableMarshalAware, Externalizable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** */
+    private String typeName;
+
+    /** */
+    @GridToStringInclude
+    private Map<String, String> fields;
+
+    /** */
+    private volatile Map<Integer, String> fldIdToName;
+
+    /** */
+    private String affKeyFieldName;
+
+    /**
+     * For {@link Externalizable}.
+     */
+    public GridPortableMetaDataImpl() {
+        // No-op.
+    }
+
+    /**
+     * @param typeName Type name.
+     * @param fields Fields map.
+     * @param affKeyFieldName Affinity key field name.
+     */
+    public GridPortableMetaDataImpl(String typeName, @Nullable Map<String, 
String> fields,
+        @Nullable String affKeyFieldName) {
+        assert typeName != null;
+
+        this.typeName = typeName;
+        this.fields = fields;
+        this.affKeyFieldName = affKeyFieldName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String typeName() {
+        return typeName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<String> fields() {
+        return fields != null ? fields.keySet() : 
Collections.<String>emptyList();
+    }
+
+    /**
+     * @return Fields.
+     */
+    public Map<String, String> fields0() {
+        return fields != null ? fields : Collections.<String, 
String>emptyMap();
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public String fieldTypeName(String fieldName) {
+        return fields != null ? fields.get(fieldName) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public String affinityKeyFieldName() {
+        return affKeyFieldName;
+    }
+
+    /**
+     * @return Fields meta data.
+     */
+    public Map<String, String> fieldsMeta() {
+        return fields != null ? fields : Collections.<String, 
String>emptyMap();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeExternal(ObjectOutput out) throws IOException {
+        U.writeString(out, typeName);
+        U.writeMap(out, fields);
+        U.writeString(out, affKeyFieldName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+        typeName = U.readString(in);
+        fields = U.readMap(in);
+        affKeyFieldName = U.readString(in);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writePortable(PortableWriter writer) throws 
PortableException {
+        PortableRawWriter raw = writer.rawWriter();
+
+        raw.writeString(typeName);
+        raw.writeString(affKeyFieldName);
+        raw.writeMap(fields);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readPortable(PortableReader reader) throws 
PortableException {
+        PortableRawReader raw = reader.rawReader();
+
+        typeName = raw.readString();
+        affKeyFieldName = raw.readString();
+        fields = raw.readMap();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(GridPortableMetaDataImpl.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectArrayLazyValue.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectArrayLazyValue.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectArrayLazyValue.java
new file mode 100644
index 0000000..773e4cb
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectArrayLazyValue.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.portable.*;
+
+/**
+ *
+ */
+class GridPortableObjectArrayLazyValue extends GridPortableAbstractLazyValue {
+    /** */
+    private Object[] lazyValsArr;
+
+    /** */
+    private int compTypeId;
+
+    /** */
+    private String clsName;
+
+    /**
+     * @param reader Reader.
+     */
+    protected GridPortableObjectArrayLazyValue(GridPortableBuilderReader 
reader) {
+        super(reader, reader.position() - 1);
+
+        int typeId = reader.readInt();
+
+        if (typeId == GridPortableMarshaller.UNREGISTERED_TYPE_ID) {
+            clsName = reader.readString();
+
+            Class cls;
+
+            try {
+                // TODO: GG-10396 - Is class loader needed here?
+                cls = U.forName(reader.readString(), null);
+            }
+            catch (ClassNotFoundException e) {
+                throw new PortableInvalidClassException("Failed to load the 
class: " + clsName, e);
+            }
+
+            compTypeId = 
reader.portableContext().descriptorForClass(cls).typeId();
+        }
+        else {
+            compTypeId = typeId;
+            clsName = null;
+        }
+
+        int size = reader.readInt();
+
+        lazyValsArr = new Object[size];
+
+        for (int i = 0; i < size; i++)
+            lazyValsArr[i] = reader.parseValue();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected Object init() {
+        for (int i = 0; i < lazyValsArr.length; i++) {
+            if (lazyValsArr[i] instanceof GridPortableLazyValue)
+                lazyValsArr[i] = 
((GridPortableLazyValue)lazyValsArr[i]).value();
+        }
+
+        return lazyValsArr;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeTo(GridPortableWriterImpl writer, 
GridPortableBuilderSerializer ctx) {
+        if (clsName == null)
+            ctx.writeArray(writer, GridPortableMarshaller.OBJ_ARR, 
lazyValsArr, compTypeId);
+        else
+            ctx.writeArray(writer, GridPortableMarshaller.OBJ_ARR, 
lazyValsArr, clsName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectEx.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectEx.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectEx.java
new file mode 100644
index 0000000..379b1b9
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectEx.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.*;
+import org.apache.ignite.internal.util.offheap.unsafe.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+import java.math.*;
+import java.util.*;
+
+/**
+ * Internal portable object interface.
+ */
+public abstract class GridPortableObjectEx implements PortableObject {
+    /**
+     * @return Length.
+     */
+    public abstract int length();
+
+    /**
+     * @return Object start.
+     */
+    public abstract int start();
+
+    /**
+     * @return {@code True} if object is array based.
+     */
+    protected abstract boolean hasArray();
+
+    /**
+     * @return Object array if object is array based, otherwise {@code null}.
+     */
+    public abstract byte[] array();
+
+    /**
+     * @return Object offheap address is object is offheap based, otherwise 0.
+     */
+    public abstract long offheapAddress();
+
+    /**
+     * @param ctx Reader context.
+     * @param fieldName Field name.
+     * @return Field name.
+     */
+    @Nullable protected abstract <F> F field(GridPortableReaderContext ctx, 
String fieldName);
+
+    /** {@inheritDoc} */
+    @Override public PortableObject clone() throws CloneNotSupportedException {
+        return (PortableObject)super.clone();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object other) {
+        if (other == this)
+            return true;
+
+        if (other == null)
+            return false;
+
+        if (!(other instanceof GridPortableObjectEx))
+            return false;
+
+        GridPortableObjectEx otherPo = (GridPortableObjectEx)other;
+
+        if (length() != otherPo.length() || typeId() != otherPo.typeId())
+            return false;
+
+        if (hasArray()) {
+            if (otherPo.hasArray()) {
+                int len = length();
+                int end = start() + len;
+
+                byte[] arr = array();
+                byte[] otherArr = otherPo.array();
+
+                for (int i = start(), j = otherPo.start(); i < end; i++, j++) {
+                    if (arr[i] != otherArr[j])
+                        return false;
+                }
+
+                return true;
+            }
+            else {
+                assert otherPo.offheapAddress() > 0;
+
+                return GridUnsafeMemory.compare(otherPo.offheapAddress() + 
otherPo.start(), array());
+            }
+        }
+        else {
+            assert offheapAddress() > 0;
+
+            if (otherPo.hasArray())
+                return GridUnsafeMemory.compare(offheapAddress() + start(), 
otherPo.array());
+            else {
+                assert otherPo.offheapAddress() > 0;
+
+                return GridUnsafeMemory.compare(offheapAddress() + start(),
+                    otherPo.offheapAddress() + otherPo.start(),
+                    length());
+            }
+        }
+    }
+
+    /**
+     * @param ctx Reader context.
+     * @param handles Handles for already traversed objects.
+     * @return String representation.
+     */
+    private String toString(GridPortableReaderContext ctx, 
IdentityHashMap<PortableObject, Integer> handles) {
+        int idHash = System.identityHashCode(this);
+
+        PortableMetadata meta;
+
+        try {
+            meta = metaData();
+        }
+        catch (PortableException ignore) {
+            meta = null;
+        }
+
+        if (meta == null)
+            return "PortableObject [hash=" + idHash + ", typeId=" + typeId() + 
']';
+
+        handles.put(this, idHash);
+
+        SB buf = new SB(meta.typeName());
+
+        if (meta.fields() != null) {
+            buf.a(" [hash=").a(idHash);
+
+            for (String name : meta.fields()) {
+                Object val = field(ctx, name);
+
+                buf.a(", ").a(name).a('=');
+
+                if (val instanceof byte[])
+                    buf.a(Arrays.toString((byte[]) val));
+                else if (val instanceof short[])
+                    buf.a(Arrays.toString((short[])val));
+                else if (val instanceof int[])
+                    buf.a(Arrays.toString((int[])val));
+                else if (val instanceof long[])
+                    buf.a(Arrays.toString((long[])val));
+                else if (val instanceof float[])
+                    buf.a(Arrays.toString((float[])val));
+                else if (val instanceof double[])
+                    buf.a(Arrays.toString((double[])val));
+                else if (val instanceof char[])
+                    buf.a(Arrays.toString((char[])val));
+                else if (val instanceof boolean[])
+                    buf.a(Arrays.toString((boolean[]) val));
+                else if (val instanceof BigDecimal[])
+                    buf.a(Arrays.toString((BigDecimal[])val));
+                else {
+                    if (val instanceof GridPortableObjectEx) {
+                        GridPortableObjectEx po = (GridPortableObjectEx)val;
+
+                        Integer idHash0 = handles.get(val);
+
+                        if (idHash0 != null) {  // Circular reference.
+                            PortableMetadata meta0 = po.metaData();
+
+                            assert meta0 != null;
+
+                            buf.a(meta0.typeName()).a(" 
[hash=").a(idHash0).a(", ...]");
+                        }
+                        else
+                            buf.a(po.toString(ctx, handles));
+                    }
+                    else
+                        buf.a(val);
+                }
+            }
+
+            buf.a(']');
+        }
+
+        return buf.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        try {
+            GridPortableReaderContext ctx = new GridPortableReaderContext();
+
+            ctx.setPortableHandler(start(), this);
+
+            return toString(ctx, new IdentityHashMap<PortableObject, 
Integer>());
+        }
+        catch (PortableException e) {
+            throw new IgniteException("Failed to create string representation 
of portable object.", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectImpl.java
new file mode 100644
index 0000000..5e50326
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectImpl.java
@@ -0,0 +1,383 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.*;
+import org.apache.ignite.internal.*;
+import org.apache.ignite.internal.portable.streams.*;
+import org.apache.ignite.internal.processors.cache.*;
+import org.apache.ignite.internal.processors.cache.portable.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.plugin.extensions.communication.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+import java.io.*;
+import java.nio.*;
+
+/**
+ * Portable object implementation.
+ */
+@IgniteCodeGeneratingFail // Fields arr and start should not be generated by 
MessageCodeGenerator.
+public final class GridPortableObjectImpl extends GridPortableObjectEx 
implements Externalizable,
+    Message, CacheObject, KeyCacheObject {
+    /** */
+    public static final byte TYPE_PORTABLE = 100;
+
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** */
+    private static final GridPortablePrimitives PRIM = 
GridPortablePrimitives.get();
+
+    /** */
+    @GridDirectTransient
+    private GridPortableContext ctx;
+
+    /** */
+    private byte[] arr;
+
+    /** */
+    private int start;
+
+    /** */
+    @GridDirectTransient
+    private Object obj;
+
+    /** */
+    @GridDirectTransient
+    private boolean detachAllowed;
+
+    /**
+     * For {@link Externalizable}.
+     */
+    public GridPortableObjectImpl() {
+        // No-op.
+    }
+
+    /**
+     * @param ctx Context.
+     * @param arr Array.
+     * @param start Start.
+     */
+    public GridPortableObjectImpl(GridPortableContext ctx, byte[] arr, int 
start) {
+        assert ctx != null;
+        assert arr != null;
+
+        this.ctx = ctx;
+        this.arr = arr;
+        this.start = start;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte type() {
+        return TYPE_PORTABLE;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean internal() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean 
cpy) {
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] valueBytes(CacheObjectContext ctx) throws 
IgniteCheckedException {
+        if (detached())
+            return array();
+
+        int len = length();
+
+        byte[] arr0 = new byte[len];
+
+        U.arrayCopy(arr, start, arr0, 0, len);
+
+        return arr0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+        if (detached())
+            return this;
+
+        return (GridPortableObjectImpl)detach();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader 
ldr) throws IgniteCheckedException {
+        this.ctx = 
((CacheObjectPortableProcessorImpl)ctx.processor()).portableContext();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(CacheObjectContext ctx) throws 
IgniteCheckedException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public int length() {
+        return PRIM.readInt(arr, start + GridPortableMarshaller.TOTAL_LEN_POS);
+    }
+
+    /**
+     * @return Detached portable object.
+     */
+    public PortableObject detach() {
+        if (!detachAllowed || detached())
+            return this;
+
+        int len = length();
+
+        byte[] arr0 = new byte[len];
+
+        U.arrayCopy(arr, start, arr0, 0, len);
+
+        return new GridPortableObjectImpl(ctx, arr0, 0);
+    }
+
+    /**
+     * @return Detached or not.
+     */
+    public boolean detached() {
+        return start == 0 && length() == arr.length;
+    }
+
+    /**
+     * @return {@code True} if detach is allowed.
+     */
+    public boolean detachAllowed() {
+        return true;
+    }
+
+    /**
+     * @param detachAllowed Detach allowed flag.
+     */
+    public void detachAllowed(boolean detachAllowed) {
+        this.detachAllowed = detachAllowed;
+    }
+
+    /**
+     * @return Context.
+     */
+    public GridPortableContext context() {
+        return ctx;
+    }
+
+    /**
+     * @param ctx Context.
+     */
+    void context(GridPortableContext ctx) {
+        this.ctx = ctx;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] array() {
+        return arr;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int start() {
+        return start;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long offheapAddress() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected boolean hasArray() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int typeId() {
+        return PRIM.readInt(arr, start + 2);
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public PortableMetadata metaData() throws 
PortableException {
+        if (ctx == null)
+            throw new PortableException("GridPortableContext is not set for 
the object.");
+
+        return ctx.metaData(typeId());
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <F> F field(String fieldName) throws 
PortableException {
+        GridGridPortableReaderImpl reader = new 
GridGridPortableReaderImpl(ctx, arr, start, null);
+
+        return (F)reader.unmarshal(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override protected <F> F field(GridPortableReaderContext rCtx, 
String fieldName) {
+        GridGridPortableReaderImpl reader = new GridGridPortableReaderImpl(ctx,
+            new GridPortableHeapInputStream(arr),
+            start,
+            null,
+            rCtx);
+
+        return (F)reader.unmarshal(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean hasField(String fieldName) {
+        GridGridPortableReaderImpl reader = new 
GridGridPortableReaderImpl(ctx, arr, start, null);
+
+        return reader.hasField(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T deserialize() throws PortableException {
+        Object obj0 = obj;
+
+        if (obj0 == null) {
+            // TODO: GG-10396 - Deserialize with proper class loader.
+            GridGridPortableReaderImpl reader = new 
GridGridPortableReaderImpl(ctx, arr, start, null);
+
+            obj0 = reader.deserialize();
+
+            GridPortableClassDescriptor desc = reader.descriptor();
+
+            assert desc != null;
+
+            if (desc.keepDeserialized())
+                obj = obj0;
+        }
+
+        return (T)obj0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public PortableObject clone() throws CloneNotSupportedException {
+        return super.clone();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return PRIM.readInt(arr, start + 6);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(ctx);
+
+        if (detachAllowed) {
+            int len = length();
+
+            out.writeInt(len);
+            out.write(arr, start, len);
+            out.writeInt(0);
+        }
+        else {
+            out.writeInt(arr.length);
+            out.write(arr);
+            out.writeInt(start);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+        ctx = (GridPortableContext)in.readObject();
+
+        arr = new byte[in.readInt()];
+
+        in.readFully(arr);
+
+        start = in.readInt();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+        writer.setBuffer(buf);
+
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(directType(), fieldsCount()))
+                return false;
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 0:
+                if (!writer.writeByteArray("arr",
+                    arr,
+                    detachAllowed ? start : 0,
+                    detachAllowed ? length() : arr.length))
+                    return false;
+
+                writer.incrementState();
+
+            case 1:
+                if (!writer.writeInt("start", detachAllowed ? 0 : start))
+                    return false;
+
+                writer.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+        reader.setBuffer(buf);
+
+        if (!reader.beforeMessageRead())
+            return false;
+
+        switch (reader.state()) {
+            case 0:
+                arr = reader.readByteArray("arr");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 1:
+                start = reader.readInt("start");
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte directType() {
+        return 123;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte fieldsCount() {
+        return 3;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectOffheapImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectOffheapImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectOffheapImpl.java
new file mode 100644
index 0000000..d02f3fd
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableObjectOffheapImpl.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.*;
+import org.apache.ignite.internal.portable.streams.*;
+import org.apache.ignite.internal.processors.cache.*;
+import org.apache.ignite.internal.util.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.plugin.extensions.communication.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+import sun.misc.*;
+
+import java.io.*;
+import java.nio.*;
+
+/**
+ *  Portable object implementation over offheap memory
+ */
+public class GridPortableObjectOffheapImpl extends GridPortableObjectEx 
implements Externalizable, CacheObject {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** */
+    private static final Unsafe UNSAFE = GridUnsafe.unsafe();
+
+    /** */
+    private final GridPortableContext ctx;
+
+    /** */
+    private final long ptr;
+
+    /** */
+    private final int start;
+
+    /** */
+    private final int size;
+
+    /**
+     * For {@link Externalizable} (not supported).
+     */
+    public GridPortableObjectOffheapImpl() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @param ctx Context.
+     * @param ptr Memory address.
+     * @param start Object start.
+     * @param size Memory size.
+     */
+    public GridPortableObjectOffheapImpl(GridPortableContext ctx, long ptr, 
int start, int size) {
+        this.ctx = ctx;
+        this.ptr = ptr;
+        this.start = start;
+        this.size = size;
+    }
+
+    /**
+     * @return Heap-based copy.
+     */
+    public PortableObject heapCopy() {
+        return new GridPortableObjectImpl(ctx, U.copyMemory(ptr, size), start);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int typeId() {
+        return UNSAFE.getInt(ptr + start + 2);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int length() {
+        return UNSAFE.getInt(ptr + start + 
GridPortableMarshaller.TOTAL_LEN_POS);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return UNSAFE.getInt(ptr + start + 6);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int start() {
+        return start;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] array() {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long offheapAddress() {
+        return ptr;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected boolean hasArray() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public PortableMetadata metaData() throws 
PortableException {
+        if (ctx == null)
+            throw new PortableException("GridPortableContext is not set for 
the object.");
+
+        return ctx.metaData(typeId());
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <F> F field(String fieldName) throws 
PortableException {
+        GridGridPortableReaderImpl reader = new GridGridPortableReaderImpl(ctx,
+            new GridPortableOffheapInputStream(ptr, size, false),
+            start,
+            null);
+
+        return (F)reader.unmarshal(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override protected <F> F field(GridPortableReaderContext rCtx, 
String fieldName) {
+        GridGridPortableReaderImpl reader = new GridGridPortableReaderImpl(ctx,
+            new GridPortableOffheapInputStream(ptr, size, false),
+            start,
+            null,
+            rCtx);
+
+        return (F)reader.unmarshal(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean hasField(String fieldName) {
+        GridGridPortableReaderImpl reader = new GridGridPortableReaderImpl(ctx,
+            new GridPortableOffheapInputStream(ptr, size, false),
+            start,
+            null);
+
+        return reader.hasField(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T deserialize() throws PortableException {
+        // TODO: GG-10396 - Deserialize with proper class loader.
+        GridGridPortableReaderImpl reader = new GridGridPortableReaderImpl(
+            ctx,
+            new GridPortableOffheapInputStream(ptr, size, false),
+            start,
+            null);
+
+        return (T)reader.deserialize();
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("CloneDoesntCallSuperClone")
+    @Override public PortableObject clone() throws CloneNotSupportedException {
+        return heapCopy();
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte type() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean 
cpy) {
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] valueBytes(CacheObjectContext ctx) throws 
IgniteCheckedException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public CacheObject prepareForCache(CacheObjectContext ctx) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader 
ldr) throws IgniteCheckedException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(CacheObjectContext ctx) throws 
IgniteCheckedException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte directType() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte fieldsCount() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeExternal(ObjectOutput out) throws IOException {
+        throw new UnsupportedOperationException(); // To make sure it is not 
marshalled.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void readExternal(ObjectInput in) throws IOException, 
ClassNotFoundException {
+        throw new UnsupportedOperationException(); // To make sure it is not 
marshalled.
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainLazyValue.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainLazyValue.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainLazyValue.java
new file mode 100644
index 0000000..beef2a2
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainLazyValue.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+/**
+ *
+ */
+class GridPortablePlainLazyValue extends GridPortableAbstractLazyValue {
+    /** */
+    protected final int len;
+
+    /**
+     * @param reader Reader
+     * @param valOff Offset
+     * @param len Length.
+     */
+    protected GridPortablePlainLazyValue(GridPortableBuilderReader reader, int 
valOff, int len) {
+        super(reader, valOff);
+
+        this.len = len;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected Object init() {
+        return reader.reader().unmarshal(valOff);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeTo(GridPortableWriterImpl writer, 
GridPortableBuilderSerializer ctx) {
+        writer.write(reader.array(), valOff, len);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainPortableObject.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainPortableObject.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainPortableObject.java
new file mode 100644
index 0000000..ff0e013
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePlainPortableObject.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.portable.*;
+
+/**
+ *
+ */
+public class GridPortablePlainPortableObject implements GridPortableLazyValue {
+    /** */
+    private final PortableObject portableObj;
+
+    /**
+     * @param portableObj Portable object.
+     */
+    public GridPortablePlainPortableObject(PortableObject portableObj) {
+        this.portableObj = portableObj;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object value() {
+        return portableObj;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void writeTo(GridPortableWriterImpl writer, 
GridPortableBuilderSerializer ctx) {
+        PortableObject val = portableObj;
+
+        if (val instanceof GridPortableObjectOffheapImpl)
+            val = ((GridPortableObjectOffheapImpl)val).heapCopy();
+
+        writer.doWritePortableObject((GridPortableObjectImpl)val);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePrimitives.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePrimitives.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePrimitives.java
new file mode 100644
index 0000000..eca91c0
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortablePrimitives.java
@@ -0,0 +1,773 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.internal.util.*;
+
+import sun.misc.*;
+
+import static java.nio.ByteOrder.*;
+
+/**
+ * Primitives writer.
+ */
+abstract class GridPortablePrimitives {
+    /** */
+    private static final GridPortablePrimitives INSTANCE =
+        nativeOrder() == LITTLE_ENDIAN ? new UnsafePrimitives() : new 
BytePrimitives();
+
+    /**
+     * @return Primitives writer.
+     */
+    static GridPortablePrimitives get() {
+        return INSTANCE;
+    }
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeByte(byte[] arr, int off, byte val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract byte readByte(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeShort(byte[] arr, int off, short val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract short readShort(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeInt(byte[] arr, int off, int val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract int readInt(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeLong(byte[] arr, int off, long val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract long readLong(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeFloat(byte[] arr, int off, float val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract float readFloat(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeDouble(byte[] arr, int off, double val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract double readDouble(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeChar(byte[] arr, int off, char val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract char readChar(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeBoolean(byte[] arr, int off, boolean val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract boolean readBoolean(byte[] arr, int off);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeByteArray(byte[] arr, int off, byte[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract byte[] readByteArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeShortArray(byte[] arr, int off, short[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract short[] readShortArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeIntArray(byte[] arr, int off, int[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract int[] readIntArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeLongArray(byte[] arr, int off, long[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract long[] readLongArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeFloatArray(byte[] arr, int off, float[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract float[] readFloatArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeDoubleArray(byte[] arr, int off, double[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract double[] readDoubleArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeCharArray(byte[] arr, int off, char[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract char[] readCharArray(byte[] arr, int off, int len);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @param val Value.
+     */
+    abstract void writeBooleanArray(byte[] arr, int off, boolean[] val);
+
+    /**
+     * @param arr Array.
+     * @param off Offset.
+     * @return Value.
+     */
+    abstract boolean[] readBooleanArray(byte[] arr, int off, int len);
+
+    /** */
+    private static class UnsafePrimitives extends GridPortablePrimitives {
+        /** */
+        private static final Unsafe UNSAFE = GridUnsafe.unsafe();
+
+        /** */
+        private static final long BYTE_ARR_OFF = 
UNSAFE.arrayBaseOffset(byte[].class);
+
+        /** */
+        private static final long SHORT_ARR_OFF = 
UNSAFE.arrayBaseOffset(short[].class);
+
+        /** */
+        private static final long INT_ARR_OFF = 
UNSAFE.arrayBaseOffset(int[].class);
+
+        /** */
+        private static final long LONG_ARR_OFF = 
UNSAFE.arrayBaseOffset(long[].class);
+
+        /** */
+        private static final long FLOAT_ARR_OFF = 
UNSAFE.arrayBaseOffset(float[].class);
+
+        /** */
+        private static final long DOUBLE_ARR_OFF = 
UNSAFE.arrayBaseOffset(double[].class);
+
+        /** */
+        private static final long CHAR_ARR_OFF = 
UNSAFE.arrayBaseOffset(char[].class);
+
+        /** */
+        private static final long BOOLEAN_ARR_OFF = 
UNSAFE.arrayBaseOffset(boolean[].class);
+
+        /** {@inheritDoc} */
+        @Override void writeByte(byte[] arr, int off, byte val) {
+            UNSAFE.putByte(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override byte readByte(byte[] arr, int off) {
+            return UNSAFE.getByte(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeShort(byte[] arr, int off, short val) {
+            UNSAFE.putShort(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override short readShort(byte[] arr, int off) {
+            return UNSAFE.getShort(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeInt(byte[] arr, int off, int val) {
+            UNSAFE.putInt(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override int readInt(byte[] arr, int off) {
+            return UNSAFE.getInt(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeLong(byte[] arr, int off, long val) {
+            UNSAFE.putLong(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override long readLong(byte[] arr, int off) {
+            return UNSAFE.getLong(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeFloat(byte[] arr, int off, float val) {
+            UNSAFE.putFloat(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override float readFloat(byte[] arr, int off) {
+            return UNSAFE.getFloat(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeDouble(byte[] arr, int off, double val) {
+            UNSAFE.putDouble(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override double readDouble(byte[] arr, int off) {
+            return UNSAFE.getDouble(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeChar(byte[] arr, int off, char val) {
+            UNSAFE.putChar(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override char readChar(byte[] arr, int off) {
+            return UNSAFE.getChar(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeBoolean(byte[] arr, int off, boolean val) {
+            UNSAFE.putBoolean(arr, BYTE_ARR_OFF + off, val);
+        }
+
+        /** {@inheritDoc} */
+        @Override boolean readBoolean(byte[] arr, int off) {
+            return UNSAFE.getBoolean(arr, BYTE_ARR_OFF + off);
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeByteArray(byte[] arr, int off, byte[] val) {
+            UNSAFE.copyMemory(val, BYTE_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length);
+        }
+
+        /** {@inheritDoc} */
+        @Override byte[] readByteArray(byte[] arr, int off, int len) {
+            byte[] arr0 = new byte[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, BYTE_ARR_OFF, 
len);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeShortArray(byte[] arr, int off, short[] val) {
+            UNSAFE.copyMemory(val, SHORT_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length << 1);
+        }
+
+        /** {@inheritDoc} */
+        @Override short[] readShortArray(byte[] arr, int off, int len) {
+            short[] arr0 = new short[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, SHORT_ARR_OFF, 
len << 1);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeIntArray(byte[] arr, int off, int[] val) {
+            UNSAFE.copyMemory(val, INT_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length << 2);
+        }
+
+        /** {@inheritDoc} */
+        @Override int[] readIntArray(byte[] arr, int off, int len) {
+            int[] arr0 = new int[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, INT_ARR_OFF, len 
<< 2);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeLongArray(byte[] arr, int off, long[] val) {
+            UNSAFE.copyMemory(val, LONG_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length << 3);
+        }
+
+        /** {@inheritDoc} */
+        @Override long[] readLongArray(byte[] arr, int off, int len) {
+            long[] arr0 = new long[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, LONG_ARR_OFF, len 
<< 3);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeFloatArray(byte[] arr, int off, float[] val) {
+            UNSAFE.copyMemory(val, FLOAT_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length << 2);
+        }
+
+        /** {@inheritDoc} */
+        @Override float[] readFloatArray(byte[] arr, int off, int len) {
+            float[] arr0 = new float[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, FLOAT_ARR_OFF, 
len << 2);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeDoubleArray(byte[] arr, int off, double[] val) {
+            UNSAFE.copyMemory(val, DOUBLE_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length << 3);
+        }
+
+        /** {@inheritDoc} */
+        @Override double[] readDoubleArray(byte[] arr, int off, int len) {
+            double[] arr0 = new double[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, DOUBLE_ARR_OFF, 
len << 3);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeCharArray(byte[] arr, int off, char[] val) {
+            UNSAFE.copyMemory(val, CHAR_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length << 1);
+        }
+
+        /** {@inheritDoc} */
+        @Override char[] readCharArray(byte[] arr, int off, int len) {
+            char[] arr0 = new char[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, CHAR_ARR_OFF, len 
<< 1);
+
+            return arr0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeBooleanArray(byte[] arr, int off, boolean[] val) {
+            UNSAFE.copyMemory(val, BOOLEAN_ARR_OFF, arr, BYTE_ARR_OFF + off, 
val.length);
+        }
+
+        /** {@inheritDoc} */
+        @Override boolean[] readBooleanArray(byte[] arr, int off, int len) {
+            boolean[] arr0 = new boolean[len];
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF + off, arr0, BOOLEAN_ARR_OFF, 
len);
+
+            return arr0;
+        }
+    }
+
+    /** */
+    private static class BytePrimitives extends GridPortablePrimitives {
+        /** {@inheritDoc} */
+        @Override void writeByte(byte[] arr, int off, byte val) {
+            arr[off] = val;
+        }
+
+        /** {@inheritDoc} */
+        @Override byte readByte(byte[] arr, int off) {
+            return arr[off];
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeShort(byte[] arr, int off, short val) {
+            arr[off++] = (byte)(val & 0xff);
+            arr[off] = (byte)((val >>> 8) & 0xff);
+        }
+
+        /** {@inheritDoc} */
+        @Override short readShort(byte[] arr, int off) {
+            short val = 0;
+
+            val |= (arr[off++] & 0xff);
+            val |= (arr[off] & 0xff) << 8;
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeInt(byte[] arr, int off, int val) {
+            arr[off++] = (byte)(val & 0xff);
+            arr[off++] = (byte)((val >>> 8) & 0xff);
+            arr[off++] = (byte)((val >>> 16) & 0xff);
+            arr[off] = (byte)((val >>> 24) & 0xff);
+        }
+
+        /** {@inheritDoc} */
+        @Override int readInt(byte[] arr, int off) {
+            int val = 0;
+
+            val |= (arr[off++] & 0xff);
+            val |= (arr[off++] & 0xff) << 8;
+            val |= (arr[off++] & 0xff) << 16;
+            val |= (arr[off] & 0xff) << 24;
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeLong(byte[] arr, int off, long val) {
+            arr[off++] = (byte)(val & 0xffL);
+            arr[off++] = (byte)((val >>> 8) & 0xffL);
+            arr[off++] = (byte)((val >>> 16) & 0xffL);
+            arr[off++] = (byte)((val >>> 24) & 0xffL);
+            arr[off++] = (byte)((val >>> 32) & 0xffL);
+            arr[off++] = (byte)((val >>> 40) & 0xffL);
+            arr[off++] = (byte)((val >>> 48) & 0xffL);
+            arr[off] = (byte)((val >>> 56) & 0xffL);
+        }
+
+        /** {@inheritDoc} */
+        @Override long readLong(byte[] arr, int off) {
+            long val = 0;
+
+            val |= (arr[off++] & 0xffL);
+            val |= (arr[off++] & 0xffL) << 8;
+            val |= (arr[off++] & 0xffL) << 16;
+            val |= (arr[off++] & 0xffL) << 24;
+            val |= (arr[off++] & 0xffL) << 32;
+            val |= (arr[off++] & 0xffL) << 40;
+            val |= (arr[off++] & 0xffL) << 48;
+            val |= (arr[off] & 0xffL) << 56;
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeFloat(byte[] arr, int off, float val) {
+            writeInt(arr, off, Float.floatToIntBits(val));
+        }
+
+        /** {@inheritDoc} */
+        @Override float readFloat(byte[] arr, int off) {
+            return Float.intBitsToFloat(readInt(arr, off));
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeDouble(byte[] arr, int off, double val) {
+            writeLong(arr, off, Double.doubleToLongBits(val));
+        }
+
+        /** {@inheritDoc} */
+        @Override double readDouble(byte[] arr, int off) {
+            return Double.longBitsToDouble(readLong(arr, off));
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeChar(byte[] arr, int off, char val) {
+            arr[off++] = (byte)(val & 0xff);
+            arr[off] = (byte)((val >>> 8) & 0xff);
+        }
+
+        /** {@inheritDoc} */
+        @Override char readChar(byte[] arr, int off) {
+            char val = 0;
+
+            val |= (arr[off++] & 0xff);
+            val |= (arr[off] & 0xff) << 8;
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeBoolean(byte[] arr, int off, boolean val) {
+            arr[off] = (byte)(val ? 1 : 0);
+        }
+
+        /** {@inheritDoc} */
+        @Override boolean readBoolean(byte[] arr, int off) {
+            return arr[off] != 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeByteArray(byte[] arr, int off, byte[] val) {
+            for (byte b : val)
+                arr[off++] = b;
+        }
+
+        /** {@inheritDoc} */
+        @Override byte[] readByteArray(byte[] arr, int off, int len) {
+            byte[] val = new byte[len];
+
+            for (int i = 0; i < len; i++)
+                val[i] = arr[off++];
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeShortArray(byte[] arr, int off, short[] val) {
+            for (short s : val) {
+                writeShort(arr, off, s);
+
+                off += 2;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override short[] readShortArray(byte[] arr, int off, int len) {
+            short[] val = new short[len];
+
+            for (int i = 0; i < len; i++) {
+                val[i] = readShort(arr, off);
+
+                off += 2;
+            }
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeIntArray(byte[] arr, int off, int[] val) {
+            for (int i : val) {
+                writeInt(arr, off, i);
+
+                off += 4;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override int[] readIntArray(byte[] arr, int off, int len) {
+            int[] val = new int[len];
+
+            for (int i = 0; i < len; i++) {
+                val[i] = readInt(arr, off);
+
+                off += 4;
+            }
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeLongArray(byte[] arr, int off, long[] val) {
+            for (long l : val) {
+                writeLong(arr, off, l);
+
+                off += 8;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override long[] readLongArray(byte[] arr, int off, int len) {
+            long[] val = new long[len];
+
+            for (int i = 0; i < len; i++) {
+                val[i] = readLong(arr, off);
+
+                off += 8;
+            }
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeFloatArray(byte[] arr, int off, float[] val) {
+            for (float f : val) {
+                writeFloat(arr, off, f);
+
+                off += 4;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override float[] readFloatArray(byte[] arr, int off, int len) {
+            float[] val = new float[len];
+
+            for (int i = 0; i < len; i++) {
+                val[i] = readFloat(arr, off);
+
+                off += 4;
+            }
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeDoubleArray(byte[] arr, int off, double[] val) {
+            for (double d : val) {
+                writeDouble(arr, off, d);
+
+                off += 8;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override double[] readDoubleArray(byte[] arr, int off, int len) {
+            double[] val = new double[len];
+
+            for (int i = 0; i < len; i++) {
+                val[i] = readDouble(arr, off);
+
+                off += 8;
+            }
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeCharArray(byte[] arr, int off, char[] val) {
+            for (char c : val) {
+                writeChar(arr, off, c);
+
+                off += 2;
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override char[] readCharArray(byte[] arr, int off, int len) {
+            char[] val = new char[len];
+
+            for (int i = 0; i < len; i++) {
+                val[i] = readChar(arr, off);
+
+                off += 2;
+            }
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override void writeBooleanArray(byte[] arr, int off, boolean[] val) {
+            for (boolean b : val)
+                writeBoolean(arr, off++, b);
+        }
+
+        /** {@inheritDoc} */
+        @Override boolean[] readBooleanArray(byte[] arr, int off, int len) {
+            boolean[] val = new boolean[len];
+
+            for (int i = 0; i < len; i++)
+                val[i] = readBoolean(arr, off++);
+
+            return val;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawReader.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawReader.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawReader.java
new file mode 100644
index 0000000..70e3849
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawReader.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+/**
+ * Extended reader interface.
+ */
+public interface GridPortableRawReader extends PortableRawReader {
+    /**
+     * @return Object.
+     * @throws PortableException In case of error.
+     */
+    @Nullable public Object readObjectDetached() throws PortableException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawWriter.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawWriter.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawWriter.java
new file mode 100644
index 0000000..11c2b55
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableRawWriter.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.internal.processors.portable.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+/**
+ * Extended writer interface.
+ */
+public interface GridPortableRawWriter extends PortableRawWriter, 
AutoCloseable {
+    /**
+     * @param obj Object to write.
+     * @throws PortableException In case of error.
+     */
+    public void writeObjectDetached(@Nullable Object obj) throws 
PortableException;
+
+    /**
+     * @return Output stream.
+     */
+    public GridPortableOutputStream out();
+
+    /**
+     * Cleans resources.
+     */
+    @Override public void close();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableReaderContext.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableReaderContext.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableReaderContext.java
new file mode 100644
index 0000000..58281d4
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableReaderContext.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+import java.util.*;
+
+/**
+ * Reader context.
+ */
+class GridPortableReaderContext {
+    /** */
+    private Map<Integer, Object> oHandles;
+
+    /** */
+    private Map<Integer, PortableObject> poHandles;
+
+    /**
+     * @param handle Handle.
+     * @param obj Object.
+     */
+    void setObjectHandler(int handle, Object obj) {
+        assert obj != null;
+
+        if (oHandles == null)
+            oHandles = new HashMap<>(3, 1.0f);
+
+        oHandles.put(handle, obj);
+    }
+
+    /**
+     * @param handle Handle.
+     * @param po Portable object.
+     */
+    void setPortableHandler(int handle, PortableObject po) {
+        assert po != null;
+
+        if (poHandles == null)
+            poHandles = new HashMap<>(3, 1.0f);
+
+        poHandles.put(handle, po);
+    }
+
+    /**
+     * @param handle Handle.
+     * @return Object.
+     */
+    @Nullable Object getObjectByHandle(int handle) {
+        return oHandles != null ? oHandles.get(handle) : null;
+    }
+
+    /**
+     * @param handle Handle.
+     * @return Object.
+     */
+    @Nullable PortableObject getPortableByHandle(int handle) {
+        return poHandles != null ? poHandles.get(handle) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(GridPortableReaderContext.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableThreadLocalMemoryAllocator.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableThreadLocalMemoryAllocator.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableThreadLocalMemoryAllocator.java
new file mode 100644
index 0000000..29d4fb6
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableThreadLocalMemoryAllocator.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.internal.portable.streams.*;
+import org.apache.ignite.internal.util.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+
+import sun.misc.*;
+
+import static org.apache.ignite.IgniteSystemProperties.*;
+
+/**
+ * Thread-local memory allocator.
+ */
+public class GridPortableThreadLocalMemoryAllocator implements 
GridPortableMemoryAllocator {
+    /** Memory allocator instance. */
+    public static final GridPortableThreadLocalMemoryAllocator 
THREAD_LOCAL_ALLOC =
+        new GridPortableThreadLocalMemoryAllocator();
+
+    /** Holders. */
+    private static final ThreadLocal<ByteArrayHolder> holders = new 
ThreadLocal<>();
+
+    /** Unsafe instance. */
+    protected static final Unsafe UNSAFE = GridUnsafe.unsafe();
+
+    /** Array offset: byte. */
+    protected static final long BYTE_ARR_OFF = 
UNSAFE.arrayBaseOffset(byte[].class);
+
+    /**
+     * Ensures singleton.
+     */
+    private GridPortableThreadLocalMemoryAllocator() {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] allocate(int size) {
+        ByteArrayHolder holder = holders.get();
+
+        if (holder == null)
+            holders.set(holder = new ByteArrayHolder());
+
+        if (holder.acquired)
+            return new byte[size];
+
+        holder.acquired = true;
+
+        if (holder.data == null || size > holder.data.length)
+            holder.data = new byte[size];
+
+        return holder.data;
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] reallocate(byte[] data, int size) {
+        ByteArrayHolder holder = holders.get();
+
+        assert holder != null;
+
+        byte[] newData = new byte[size];
+
+        if (holder.data == data)
+            holder.data = newData;
+
+        UNSAFE.copyMemory(data, BYTE_ARR_OFF, newData, BYTE_ARR_OFF, 
data.length);
+
+        return newData;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void release(byte[] data, int maxMsgSize) {
+        ByteArrayHolder holder = holders.get();
+
+        assert holder != null;
+
+        if (holder.data != data)
+            return;
+
+        holder.maxMsgSize = maxMsgSize;
+        holder.acquired = false;
+
+        holder.shrink();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long allocateDirect(int size) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long reallocateDirect(long addr, int size) {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void releaseDirect(long addr) {
+        // No-op
+    }
+
+    /**
+     * Checks whether a thread-local array is acquired or not.
+     * The function is used by Unit tests.
+     *
+     * @return {@code true} if acquired {@code false} otherwise.
+     */
+    public boolean isThreadLocalArrayAcquired() {
+        ByteArrayHolder holder = holders.get();
+
+        return holder != null && holder.acquired;
+    }
+
+    /**
+     * Thread-local byte array holder.
+     */
+    private static class ByteArrayHolder {
+        /** */
+        private static final Long CHECK_FREQ = 
Long.getLong(IGNITE_MARSHAL_BUFFERS_RECHECK, 10000);
+
+        /** Data array */
+        private byte[] data;
+
+        /** Max message size detected between checks. */
+        private int maxMsgSize;
+
+        /** Last time array size is checked. */
+        private long lastCheck = U.currentTimeMillis();
+
+        /** Whether the holder is acquired or not. */
+        private boolean acquired;
+
+        /**
+         * Shrinks array size if needed.
+         */
+        private void shrink() {
+            long now = U.currentTimeMillis();
+
+            if (now - lastCheck >= CHECK_FREQ) {
+                int halfSize = data.length >> 1;
+
+                if (maxMsgSize < halfSize)
+                    data = new byte[halfSize];
+
+                lastCheck = now;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/1f2be19d/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableUtils.java
new file mode 100644
index 0000000..a975a5e
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/GridPortableUtils.java
@@ -0,0 +1,380 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.portable;
+
+import org.apache.ignite.portable.*;
+
+import org.jetbrains.annotations.*;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.Date;
+
+import static org.apache.ignite.internal.portable.GridPortableMarshaller.*;
+
+/**
+ *
+ */
+public class GridPortableUtils {
+    /** */
+    public static final Map<Class<?>, Byte> PLAIN_CLASS_TO_FLAG = new 
HashMap<>();
+
+    /** */
+    public static final Map<Byte, Class<?>> FLAG_TO_CLASS = new HashMap<>();
+
+    /** {@code true} if serialized value of this type cannot contain 
references to objects. */
+    private static final boolean[] PLAIN_TYPE_FLAG = new boolean[102];
+
+    /** Portable classes. */
+    private static final Collection<Class<?>> PORTABLE_CLS = new HashSet<>();
+
+    /**
+     *
+     */
+    static {
+        PORTABLE_CLS.add(Byte.class);
+        PORTABLE_CLS.add(Short.class);
+        PORTABLE_CLS.add(Integer.class);
+        PORTABLE_CLS.add(Long.class);
+        PORTABLE_CLS.add(Float.class);
+        PORTABLE_CLS.add(Double.class);
+        PORTABLE_CLS.add(Character.class);
+        PORTABLE_CLS.add(Boolean.class);
+        PORTABLE_CLS.add(String.class);
+        PORTABLE_CLS.add(UUID.class);
+        PORTABLE_CLS.add(Date.class);
+        PORTABLE_CLS.add(Timestamp.class);
+        PORTABLE_CLS.add(BigDecimal.class);
+        PORTABLE_CLS.add(byte[].class);
+        PORTABLE_CLS.add(short[].class);
+        PORTABLE_CLS.add(int[].class);
+        PORTABLE_CLS.add(long[].class);
+        PORTABLE_CLS.add(float[].class);
+        PORTABLE_CLS.add(double[].class);
+        PORTABLE_CLS.add(char[].class);
+        PORTABLE_CLS.add(boolean[].class);
+        PORTABLE_CLS.add(String[].class);
+        PORTABLE_CLS.add(UUID[].class);
+        PORTABLE_CLS.add(Date[].class);
+        PORTABLE_CLS.add(Timestamp[].class);
+        PORTABLE_CLS.add(BigDecimal[].class);
+    }
+
+    /**
+     *
+     */
+    static {
+        PLAIN_CLASS_TO_FLAG.put(Byte.class, GridPortableMarshaller.BYTE);
+        PLAIN_CLASS_TO_FLAG.put(Short.class, GridPortableMarshaller.SHORT);
+        PLAIN_CLASS_TO_FLAG.put(Integer.class, GridPortableMarshaller.INT);
+        PLAIN_CLASS_TO_FLAG.put(Long.class, GridPortableMarshaller.LONG);
+        PLAIN_CLASS_TO_FLAG.put(Float.class, GridPortableMarshaller.FLOAT);
+        PLAIN_CLASS_TO_FLAG.put(Double.class, GridPortableMarshaller.DOUBLE);
+        PLAIN_CLASS_TO_FLAG.put(Character.class, GridPortableMarshaller.CHAR);
+        PLAIN_CLASS_TO_FLAG.put(Boolean.class, GridPortableMarshaller.BOOLEAN);
+        PLAIN_CLASS_TO_FLAG.put(BigDecimal.class, 
GridPortableMarshaller.DECIMAL);
+        PLAIN_CLASS_TO_FLAG.put(String.class, GridPortableMarshaller.STRING);
+        PLAIN_CLASS_TO_FLAG.put(UUID.class, GridPortableMarshaller.UUID);
+        PLAIN_CLASS_TO_FLAG.put(Date.class, GridPortableMarshaller.DATE);
+
+        PLAIN_CLASS_TO_FLAG.put(byte[].class, GridPortableMarshaller.BYTE_ARR);
+        PLAIN_CLASS_TO_FLAG.put(short[].class, 
GridPortableMarshaller.SHORT_ARR);
+        PLAIN_CLASS_TO_FLAG.put(int[].class, GridPortableMarshaller.INT_ARR);
+        PLAIN_CLASS_TO_FLAG.put(long[].class, GridPortableMarshaller.LONG_ARR);
+        PLAIN_CLASS_TO_FLAG.put(float[].class, 
GridPortableMarshaller.FLOAT_ARR);
+        PLAIN_CLASS_TO_FLAG.put(double[].class, 
GridPortableMarshaller.DOUBLE_ARR);
+        PLAIN_CLASS_TO_FLAG.put(char[].class, GridPortableMarshaller.CHAR_ARR);
+        PLAIN_CLASS_TO_FLAG.put(boolean[].class, 
GridPortableMarshaller.BOOLEAN_ARR);
+        PLAIN_CLASS_TO_FLAG.put(BigDecimal[].class, 
GridPortableMarshaller.DECIMAL_ARR);
+        PLAIN_CLASS_TO_FLAG.put(String[].class, 
GridPortableMarshaller.STRING_ARR);
+        PLAIN_CLASS_TO_FLAG.put(UUID[].class, GridPortableMarshaller.UUID_ARR);
+        PLAIN_CLASS_TO_FLAG.put(Date[].class, GridPortableMarshaller.DATE_ARR);
+
+        for (Map.Entry<Class<?>, Byte> entry : PLAIN_CLASS_TO_FLAG.entrySet())
+            FLAG_TO_CLASS.put(entry.getValue(), entry.getKey());
+
+        PLAIN_CLASS_TO_FLAG.put(byte.class, GridPortableMarshaller.BYTE);
+        PLAIN_CLASS_TO_FLAG.put(short.class, GridPortableMarshaller.SHORT);
+        PLAIN_CLASS_TO_FLAG.put(int.class, GridPortableMarshaller.INT);
+        PLAIN_CLASS_TO_FLAG.put(long.class, GridPortableMarshaller.LONG);
+        PLAIN_CLASS_TO_FLAG.put(float.class, GridPortableMarshaller.FLOAT);
+        PLAIN_CLASS_TO_FLAG.put(double.class, GridPortableMarshaller.DOUBLE);
+        PLAIN_CLASS_TO_FLAG.put(char.class, GridPortableMarshaller.CHAR);
+        PLAIN_CLASS_TO_FLAG.put(boolean.class, GridPortableMarshaller.BOOLEAN);
+
+        for (byte b : new byte[] {
+            BYTE, SHORT, INT, LONG, FLOAT, DOUBLE,
+            CHAR, BOOLEAN, DECIMAL, STRING, UUID, DATE,
+            BYTE_ARR, SHORT_ARR, INT_ARR, LONG_ARR, FLOAT_ARR, DOUBLE_ARR,
+            CHAR_ARR, BOOLEAN_ARR, DECIMAL_ARR, STRING_ARR, UUID_ARR, DATE_ARR,
+            ENUM, ENUM_ARR, NULL}) {
+
+            PLAIN_TYPE_FLAG[b] = true;
+        }
+    }
+
+    /**
+     * Write value with flag. e.g. writePlainObject(writer, (byte)77) will 
write two byte: {BYTE, 77}.
+     *
+     * @param writer W
+     * @param val Value.
+     */
+    public static void writePlainObject(GridPortableWriterImpl writer, Object 
val) {
+        Byte flag = PLAIN_CLASS_TO_FLAG.get(val.getClass());
+
+        if (flag == null)
+            throw new IllegalArgumentException("Can't write object with type: 
" + val.getClass());
+
+        switch (flag) {
+            case BYTE:
+                writer.writeByte(flag);
+                writer.writeByte((Byte)val);
+
+                break;
+
+            case SHORT:
+                writer.writeByte(flag);
+                writer.writeShort((Short)val);
+
+                break;
+
+            case INT:
+                writer.writeByte(flag);
+                writer.writeInt((Integer)val);
+
+                break;
+
+            case LONG:
+                writer.writeByte(flag);
+                writer.writeLong((Long)val);
+
+                break;
+
+            case FLOAT:
+                writer.writeByte(flag);
+                writer.writeFloat((Float)val);
+
+                break;
+
+            case DOUBLE:
+                writer.writeByte(flag);
+                writer.writeDouble((Double)val);
+
+                break;
+
+            case CHAR:
+                writer.writeByte(flag);
+                writer.writeChar((Character)val);
+
+                break;
+
+            case BOOLEAN:
+                writer.writeByte(flag);
+                writer.writeBoolean((Boolean)val);
+
+                break;
+
+            case DECIMAL:
+                writer.doWriteDecimal((BigDecimal)val);
+
+                break;
+
+            case STRING:
+                writer.doWriteString((String)val);
+
+                break;
+
+            case UUID:
+                writer.doWriteUuid((UUID)val);
+
+                break;
+
+            case DATE:
+                if (val instanceof Timestamp)
+                    writer.doWriteTimestamp((Timestamp)val);
+                else
+                    writer.doWriteDate((Date)val);
+
+                break;
+
+            case BYTE_ARR:
+                writer.doWriteByteArray((byte[])val);
+
+                break;
+
+            case SHORT_ARR:
+                writer.doWriteShortArray((short[])val);
+
+                break;
+
+            case INT_ARR:
+                writer.doWriteIntArray((int[])val);
+
+                break;
+
+            case LONG_ARR:
+                writer.doWriteLongArray((long[])val);
+
+                break;
+
+            case FLOAT_ARR:
+                writer.doWriteFloatArray((float[])val);
+
+                break;
+
+            case DOUBLE_ARR:
+                writer.doWriteDoubleArray((double[])val);
+
+                break;
+
+            case CHAR_ARR:
+                writer.doWriteCharArray((char[])val);
+
+                break;
+
+            case BOOLEAN_ARR:
+                writer.doWriteBooleanArray((boolean[])val);
+
+                break;
+
+            case DECIMAL_ARR:
+                writer.doWriteDecimalArray((BigDecimal[])val);
+
+                break;
+
+            case STRING_ARR:
+                writer.doWriteStringArray((String[])val);
+
+                break;
+
+            case UUID_ARR:
+                writer.doWriteUuidArray((UUID[])val);
+
+                break;
+
+            case DATE_ARR:
+                writer.doWriteDateArray((Date[])val);
+
+                break;
+
+            default:
+                throw new IllegalArgumentException("Can't write object with 
type: " + val.getClass());
+        }
+    }
+
+    /**
+     * @param obj Value to unwrap.
+     * @return Unwrapped value.
+     */
+    public static Object unwrapLazy(@Nullable Object obj) {
+        if (obj instanceof GridPortableLazyValue)
+            return ((GridPortableLazyValue)obj).value();
+
+        return obj;
+    }
+
+    /**
+     * @param delegate Iterator to delegate.
+     * @return New iterator.
+     */
+    public static Iterator<Object> unwrapLazyIterator(final Iterator<Object> 
delegate) {
+        return new Iterator<Object>() {
+            @Override public boolean hasNext() {
+                return delegate.hasNext();
+            }
+
+            @Override public Object next() {
+                return unwrapLazy(delegate.next());
+            }
+
+            @Override public void remove() {
+                delegate.remove();
+            }
+        };
+    }
+
+    /**
+     * @return {@code true} if content of serialized value cannot contain 
references to other object.
+     */
+    public static boolean isPlainType(int type) {
+        return type > 0 && type < PLAIN_TYPE_FLAG.length && 
PLAIN_TYPE_FLAG[type];
+    }
+
+    /**
+     * @param cls Class.
+     * @return Portable field type.
+     */
+    public static byte typeByClass(Class<?> cls) {
+        if (Date.class.isAssignableFrom(cls))
+            return DATE;
+
+        Byte type = PLAIN_CLASS_TO_FLAG.get(cls);
+
+        if (type != null)
+            return type;
+
+        if (cls.isEnum())
+            return ENUM;
+
+        if (cls.isArray())
+            return cls.getComponentType().isEnum() || cls.getComponentType() 
== Enum.class ? ENUM_ARR : OBJ_ARR;
+
+        if (Collection.class.isAssignableFrom(cls))
+            return COL;
+
+        if (Map.class.isAssignableFrom(cls))
+            return MAP;
+
+        if (Map.Entry.class.isAssignableFrom(cls))
+            return MAP;
+
+        return OBJ;
+    }
+
+    /**
+     * Tells whether provided type is portable or a collection.
+     *
+     * @param cls Class to check.
+     * @return Whether type is portable or a collection.
+     */
+    public static boolean isPortableOrCollectionType(Class<?> cls) {
+        assert cls != null;
+
+        return isPortableType(cls) ||
+            cls == Object[].class ||
+            Collection.class.isAssignableFrom(cls) ||
+            Map.class.isAssignableFrom(cls) ||
+            Map.Entry.class.isAssignableFrom(cls);
+    }
+
+    /**
+     * Tells whether provided type is portable.
+     *
+     * @param cls Class to check.
+     * @return Whether type is portable.
+     */
+    public static boolean isPortableType(Class<?> cls) {
+        assert cls != null;
+
+        return PortableObject.class.isAssignableFrom(cls) ||
+            PORTABLE_CLS.contains(cls) ||
+            cls.isEnum() ||
+            (cls.isArray() && cls.getComponentType().isEnum());
+    }
+}


Reply via email to