001/* 002 * Copyright 2013 Alex Kasko (alexkasko.com) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.alexkasko.unsafe.offheap; 018 019import sun.misc.Unsafe; 020 021import java.lang.reflect.Field; 022import java.util.concurrent.atomic.AtomicBoolean; 023 024/** 025 * Implementation of {@link OffHeapMemory} using {@code sun.misc.Unsafe} 026 * 027 * @author alexkasko 028 * Date: 1/14/13 029 */ 030class UnsafeOffHeapMemory extends OffHeapMemory { 031 032 private static final Unsafe UNSAFE; 033 private static final int BYTE_ARRAY_OFFSET; 034 035 static { 036 try { 037 Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); 038 theUnsafe.setAccessible(true); 039 UNSAFE = (Unsafe) theUnsafe.get(null); 040 int boo = UNSAFE.arrayBaseOffset(byte[].class); 041 // It seems not all Unsafe implementations implement the following method. 042 UNSAFE.copyMemory(new byte[1], boo, new byte[1], boo, 1); 043 BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); 044 } catch (Exception e) { 045 throw new RuntimeException(e); 046 } 047 } 048 049 private final long address; 050 private final long length; 051 private final AtomicBoolean disposed = new AtomicBoolean(false); 052 053 UnsafeOffHeapMemory(long bytes) { 054 this.address = UNSAFE.allocateMemory(bytes); 055 this.length = bytes; 056 } 057 058 /** 059 * {@inheritDoc} 060 */ 061 @Override 062 public boolean isUnsafe() { 063 return true; 064 } 065 066 /** 067 * {@inheritDoc} 068 */ 069 @Override 070 public long length() { 071 return length; 072 } 073 074 /** 075 * {@inheritDoc} 076 */ 077 @Override 078 public void free() { 079 if(!disposed.compareAndSet(false, true)) return; 080 UNSAFE.freeMemory(address); 081 } 082 083 /** 084 * {@inheritDoc} 085 */ 086 @Override 087 protected void finalize() throws Throwable { 088 free(); 089 } 090 091 /** 092 * {@inheritDoc} 093 */ 094 @Override 095 public void put(long offset, byte[] buffer, int bufferOffset, int bytes) { 096 assert !disposed.get() : "disposed"; 097 assert offset >= 0 : offset; 098 assert offset <= length - bytes : offset; 099 assert bufferOffset >= 0 : bufferOffset; 100 assert bytes > 0 : bytes; 101 assert bytes <= length : bytes; 102 assert null != buffer; 103 assert bufferOffset <= buffer.length - bytes : bufferOffset; 104 UNSAFE.copyMemory(buffer, BYTE_ARRAY_OFFSET + bufferOffset, null, address + offset, bytes); 105 } 106 107 /** 108 * {@inheritDoc} 109 */ 110 @Override 111 public void put(long offset, byte[] buffer) { 112 assert !disposed.get() : "disposed"; 113 assert offset >= 0 : offset; 114 assert null != buffer; 115 assert offset <= length - buffer.length : offset; 116 assert buffer.length <= length : buffer.length; 117 UNSAFE.copyMemory(buffer, BYTE_ARRAY_OFFSET, null, address + offset, buffer.length); 118 } 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override 124 public void get(long offset, byte[] buffer, int bufferOffset, int bytes) { 125 assert !disposed.get() : "disposed"; 126 assert offset >= 0 : offset; 127 assert offset <= length - bytes : offset; 128 assert bufferOffset >= 0 : bufferOffset; 129 assert bytes > 0 : bytes; 130 assert bytes <= length : bytes; 131 assert null != buffer; 132 assert bufferOffset <= buffer.length - bytes : bufferOffset; 133 UNSAFE.copyMemory(null, address + offset, buffer, BYTE_ARRAY_OFFSET + bufferOffset, bytes); 134 } 135 136 /** 137 * {@inheritDoc} 138 */ 139 @Override 140 public void get(long offset, byte[] buffer) { 141 assert !disposed.get() : "disposed"; 142 assert offset >= 0 : offset; 143 assert null != buffer; 144 assert offset <= length - buffer.length : offset; 145 assert buffer.length <= length : buffer.length; 146 UNSAFE.copyMemory(null, address + offset, buffer, BYTE_ARRAY_OFFSET, buffer.length); 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public byte getByte(long offset) { 154 assert !disposed.get() : "disposed"; 155 assert offset >= 0 : offset; 156 assert offset <= length - 1 : offset; 157 return UNSAFE.getByte(address + offset); 158 } 159 160 /** 161 * {@inheritDoc} 162 */ 163 @Override 164 public void putByte(long offset, byte value) { 165 assert !disposed.get() : "disposed"; 166 assert offset >= 0 : offset; 167 assert offset <= length - 1 : offset; 168 UNSAFE.putByte(address + offset, value); 169 } 170 171 /** 172 * {@inheritDoc} 173 */ 174 @Override 175 public short getUnsignedByte(long offset) { 176 assert !disposed.get() : "disposed"; 177 assert offset >= 0 : offset; 178 assert offset <= length - 1 : offset; 179 return (short) (UNSAFE.getByte(address + offset) & 0xff); 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public void putUnsignedByte(long offset, short value) { 187 assert !disposed.get() : "disposed"; 188 assert offset >= 0 : offset; 189 assert offset <= length - 1 : offset; 190 assert value >= 0 : value; 191 assert value < 1<<8 : value; 192 UNSAFE.putByte(address + offset, (byte) value); 193 } 194 195 /** 196 * {@inheritDoc} 197 */ 198 @Override 199 public short getShort(long offset) { 200 assert !disposed.get() : "disposed"; 201 assert offset >= 0 : offset; 202 assert offset <= length - 2 : offset; 203 return UNSAFE.getShort(address + offset); 204 } 205 206 /** 207 * {@inheritDoc} 208 */ 209 @Override 210 public void putShort(long offset, short value) { 211 assert !disposed.get() : "disposed"; 212 assert offset >= 0 : offset; 213 assert offset <= length - 2 : offset; 214 UNSAFE.putShort(address + offset, value); 215 } 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override 221 public int getUnsignedShort(long offset) { 222 assert !disposed.get() : "disposed"; 223 assert offset >= 0 : offset; 224 assert offset <= length - 2 : offset; 225 return UNSAFE.getShort(address + offset) & 0xffff; 226 } 227 228 /** 229 * {@inheritDoc} 230 */ 231 @Override 232 public void putUnsignedShort(long offset, int value) { 233 assert !disposed.get() : "disposed"; 234 assert offset >= 0 : offset; 235 assert offset <= length - 2 : offset; 236 assert value >= 0 : value; 237 assert value < 1<<16 : value; 238 UNSAFE.putShort(address + offset, (short) value); 239 } 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override 245 public int getInt(long offset) { 246 assert !disposed.get() : "disposed"; 247 assert offset >= 0 : offset; 248 assert offset <= length - 4 : offset; 249 return UNSAFE.getInt(address + offset); 250 } 251 252 /** 253 * {@inheritDoc} 254 */ 255 @Override 256 public void putInt(long offset, int value) { 257 assert !disposed.get() : "disposed"; 258 assert offset >= 0 : offset; 259 assert offset <= length - 4 : offset; 260 UNSAFE.putInt(address + offset, value); 261 } 262 263 /** 264 * {@inheritDoc} 265 */ 266 @Override 267 public long getUnsignedInt(long offset) { 268 assert !disposed.get() : "disposed"; 269 assert offset >= 0 : offset; 270 assert offset <= length - 4 : offset; 271 return UNSAFE.getInt(address + offset) & 0xffffffffL; 272 } 273 274 /** 275 * {@inheritDoc} 276 */ 277 @Override 278 public void putUnsignedInt(long offset, long value) { 279 assert !disposed.get() : "disposed"; 280 assert offset >= 0 : offset; 281 assert offset <= length - 4 : offset; 282 assert value >= 0 : value; 283 assert value < 1L<<32 : value; 284 UNSAFE.putInt(address + offset, (int) value); 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 @Override 291 public long getLong(long offset) { 292 assert !disposed.get() : "disposed"; 293 assert offset >= 0 : offset; 294 assert offset <= length - 8 : offset; 295 return UNSAFE.getLong(address + offset); 296 } 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override 302 public void putLong(long offset, long value) { 303 assert !disposed.get() : "disposed"; 304 assert offset >= 0 : offset; 305 assert offset <= length - 8 : offset; 306 UNSAFE.putLong(address + offset, value); 307 } 308 309 /** 310 * {@inheritDoc} 311 */ 312 @Override 313 public void copy(long offset, OffHeapMemory destination, long destOffset, long bytes) { 314 assert destination instanceof UnsafeOffHeapMemory : destination; 315 UnsafeOffHeapMemory dest = (UnsafeOffHeapMemory) destination; 316 assert !disposed.get() : "disposed"; 317 assert !dest.disposed.get() : "disposed"; 318 assert offset >= 0 : offset; 319 assert offset <= length - bytes : offset; 320 assert destOffset >= 0 : destOffset; 321 assert destOffset <= destination.length() - bytes : destOffset; 322 UNSAFE.copyMemory(address + offset, dest.address + destOffset, bytes); 323 } 324 325 /** 326 * {@inheritDoc} 327 */ 328 @Override 329 public OffHeapMemory clone() { 330 assert !disposed.get() : "disposed"; 331 UnsafeOffHeapMemory res = new UnsafeOffHeapMemory(length); 332 UNSAFE.copyMemory(address, res.address, length); 333 return res; 334 } 335 336 /** 337 * {@inheritDoc} 338 */ 339 @Override 340 public String toString() { 341 final StringBuilder sb = new StringBuilder(); 342 sb.append("UnsafeOffHeapMemory"); 343 sb.append("{address=").append(address); 344 sb.append(", length=").append(length); 345 sb.append(", disposed=").append(disposed); 346 sb.append('}'); 347 return sb.toString(); 348 } 349}