1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "ArgumentEncoder.h" 28 29#include "DataReference.h" 30#include <algorithm> 31#include <stdio.h> 32 33#if OS(DARWIN) 34#include <sys/mman.h> 35#endif 36 37namespace IPC { 38 39static inline void* allocBuffer(size_t size) 40{ 41#if OS(DARWIN) 42 return mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 43#else 44 return fastMalloc(size); 45#endif 46} 47 48static inline void freeBuffer(void* addr, size_t size) 49{ 50#if OS(DARWIN) 51 munmap(addr, size); 52#else 53 UNUSED_PARAM(size); 54 fastFree(addr); 55#endif 56} 57 58ArgumentEncoder::ArgumentEncoder() 59 : m_buffer(m_inlineBuffer) 60 , m_bufferPointer(m_inlineBuffer) 61 , m_bufferSize(0) 62 , m_bufferCapacity(sizeof(m_inlineBuffer)) 63{ 64} 65 66ArgumentEncoder::~ArgumentEncoder() 67{ 68 if (m_buffer != m_inlineBuffer) 69 freeBuffer(m_buffer, m_bufferCapacity); 70 71#if !USE(UNIX_DOMAIN_SOCKETS) 72 // FIXME: We need to dispose of the attachments in cases of failure. 73#else 74 for (size_t i = 0; i < m_attachments.size(); ++i) 75 m_attachments[i].dispose(); 76#endif 77} 78 79static inline size_t roundUpToAlignment(size_t value, unsigned alignment) 80{ 81 return ((value + alignment - 1) / alignment) * alignment; 82} 83 84void ArgumentEncoder::reserve(size_t size) 85{ 86 if (size <= m_bufferCapacity) 87 return; 88 89 size_t newCapacity = roundUpToAlignment(m_bufferCapacity * 2, 4096); 90 while (newCapacity < size) 91 newCapacity *= 2; 92 93 uint8_t* newBuffer = static_cast<uint8_t*>(allocBuffer(newCapacity)); 94 if (!newBuffer) 95 CRASH(); 96 97 memcpy(newBuffer, m_buffer, m_bufferSize); 98 99 if (m_buffer != m_inlineBuffer) 100 freeBuffer(m_buffer, m_bufferCapacity); 101 102 m_buffer = newBuffer; 103 m_bufferCapacity = newCapacity; 104} 105 106uint8_t* ArgumentEncoder::grow(unsigned alignment, size_t size) 107{ 108 size_t alignedSize = roundUpToAlignment(m_bufferSize, alignment); 109 reserve(alignedSize + size); 110 111 m_bufferSize = alignedSize + size; 112 m_bufferPointer = m_buffer + alignedSize + size; 113 114 return m_buffer + alignedSize; 115} 116 117void ArgumentEncoder::encodeFixedLengthData(const uint8_t* data, size_t size, unsigned alignment) 118{ 119 ASSERT(!(reinterpret_cast<uintptr_t>(data) % alignment)); 120 121 uint8_t* buffer = grow(alignment, size); 122 memcpy(buffer, data, size); 123} 124 125void ArgumentEncoder::encodeVariableLengthByteArray(const DataReference& dataReference) 126{ 127 encode(static_cast<uint64_t>(dataReference.size())); 128 encodeFixedLengthData(dataReference.data(), dataReference.size(), 1); 129} 130 131template<typename Type> 132static void copyValueToBuffer(Type value, uint8_t* bufferPosition) 133{ 134 memcpy(bufferPosition, &value, sizeof(Type)); 135} 136 137void ArgumentEncoder::encode(bool n) 138{ 139 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 140 copyValueToBuffer(n, buffer); 141} 142 143void ArgumentEncoder::encode(uint8_t n) 144{ 145 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 146 copyValueToBuffer(n, buffer); 147} 148 149void ArgumentEncoder::encode(uint16_t n) 150{ 151 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 152 copyValueToBuffer(n, buffer); 153} 154 155void ArgumentEncoder::encode(uint32_t n) 156{ 157 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 158 copyValueToBuffer(n, buffer); 159} 160 161void ArgumentEncoder::encode(uint64_t n) 162{ 163 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 164 copyValueToBuffer(n, buffer); 165} 166 167void ArgumentEncoder::encode(int32_t n) 168{ 169 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 170 copyValueToBuffer(n, buffer); 171} 172 173void ArgumentEncoder::encode(int64_t n) 174{ 175 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 176 copyValueToBuffer(n, buffer); 177} 178 179void ArgumentEncoder::encode(float n) 180{ 181 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 182 copyValueToBuffer(n, buffer); 183} 184 185void ArgumentEncoder::encode(double n) 186{ 187 uint8_t* buffer = grow(sizeof(n), sizeof(n)); 188 copyValueToBuffer(n, buffer); 189} 190 191void ArgumentEncoder::addAttachment(const Attachment& attachment) 192{ 193 m_attachments.append(attachment); 194} 195 196Vector<Attachment> ArgumentEncoder::releaseAttachments() 197{ 198 Vector<Attachment> newList; 199 newList.swap(m_attachments); 200 return newList; 201} 202 203} // namespace IPC 204