001/* 002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.common.util; 024 025import static com.oracle.graal.compiler.common.util.TypeConversion.*; 026import jdk.internal.jvmci.common.*; 027import sun.misc.*; 028 029/** 030 * Provides low-level sequential write access to a byte[] array for signed and unsigned values of 031 * size 1, 2, 4, and 8 bytes. To avoid copying an array when the buffer size is no longer 032 * sufficient, the buffer is split into chunks of a fixed size. 033 * 034 * The flag {@code supportsUnalignedMemoryAccess} must be set according to the capabilities of the 035 * hardware architecture: the value {@code true} allows more efficient memory access on 036 * architectures that support unaligned memory accesses; the value {@code false} is the safe 037 * fallback that works on every hardware. 038 */ 039public abstract class UnsafeArrayTypeWriter implements TypeWriter { 040 041 private static final int MIN_CHUNK_LENGTH = 200; 042 private static final int MAX_CHUNK_LENGTH = 16000; 043 044 static class Chunk { 045 protected final byte[] data; 046 protected int size; 047 protected Chunk next; 048 049 protected Chunk(int arrayLength) { 050 data = new byte[arrayLength]; 051 } 052 } 053 054 protected final Chunk firstChunk; 055 protected Chunk writeChunk; 056 protected int totalSize; 057 058 public static UnsafeArrayTypeWriter create(boolean supportsUnalignedMemoryAccess) { 059 if (supportsUnalignedMemoryAccess) { 060 return new UnalignedUnsafeArrayTypeWriter(); 061 } else { 062 return new AlignedUnsafeArrayTypeWriter(); 063 } 064 } 065 066 protected UnsafeArrayTypeWriter() { 067 firstChunk = new Chunk(MIN_CHUNK_LENGTH); 068 writeChunk = firstChunk; 069 } 070 071 @Override 072 public final long getBytesWritten() { 073 return totalSize; 074 } 075 076 /** 077 * Copies the buffer into the provided byte[] array of length {@link #getBytesWritten()}. 078 */ 079 public final byte[] toArray(byte[] result) { 080 assert result.length == totalSize; 081 int resultIdx = 0; 082 for (Chunk cur = firstChunk; cur != null; cur = cur.next) { 083 System.arraycopy(cur.data, 0, result, resultIdx, cur.size); 084 resultIdx += cur.size; 085 } 086 assert resultIdx == totalSize; 087 return result; 088 } 089 090 @Override 091 public final void putS1(long value) { 092 long offset = writeOffset(Byte.BYTES); 093 UnsafeAccess.unsafe.putByte(writeChunk.data, offset, asS1(value)); 094 } 095 096 @Override 097 public final void putU1(long value) { 098 long offset = writeOffset(Byte.BYTES); 099 UnsafeAccess.unsafe.putByte(writeChunk.data, offset, asU1(value)); 100 } 101 102 @Override 103 public final void putU2(long value) { 104 putS2(asU2(value)); 105 } 106 107 @Override 108 public final void putU4(long value) { 109 putS4(asU4(value)); 110 } 111 112 protected long writeOffset(int writeBytes) { 113 if (writeChunk.size + writeBytes >= writeChunk.data.length) { 114 Chunk newChunk = new Chunk(Math.min(writeChunk.data.length * 2, MAX_CHUNK_LENGTH)); 115 writeChunk.next = newChunk; 116 writeChunk = newChunk; 117 } 118 119 assert Unsafe.ARRAY_BYTE_INDEX_SCALE == 1; 120 long result = writeChunk.size + Unsafe.ARRAY_BYTE_BASE_OFFSET; 121 122 totalSize += writeBytes; 123 writeChunk.size += writeBytes; 124 assert writeChunk.size <= writeChunk.data.length; 125 126 return result; 127 } 128} 129 130final class UnalignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter { 131 @Override 132 public void putS2(long value) { 133 long offset = writeOffset(Short.BYTES); 134 UnsafeAccess.unsafe.putShort(writeChunk.data, offset, asS2(value)); 135 } 136 137 @Override 138 public void putS4(long value) { 139 long offset = writeOffset(Integer.BYTES); 140 UnsafeAccess.unsafe.putInt(writeChunk.data, offset, asS4(value)); 141 } 142 143 @Override 144 public void putS8(long value) { 145 long offset = writeOffset(Long.BYTES); 146 UnsafeAccess.unsafe.putLong(writeChunk.data, offset, value); 147 } 148} 149 150final class AlignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter { 151 @Override 152 public void putS2(long value) { 153 long offset = writeOffset(Short.BYTES); 154 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 0, (byte) (value >> 0)); 155 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 1, (byte) (value >> 8)); 156 } 157 158 @Override 159 public void putS4(long value) { 160 long offset = writeOffset(Integer.BYTES); 161 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 0, (byte) (value >> 0)); 162 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 1, (byte) (value >> 8)); 163 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 2, (byte) (value >> 16)); 164 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 3, (byte) (value >> 24)); 165 } 166 167 @Override 168 public void putS8(long value) { 169 long offset = writeOffset(Long.BYTES); 170 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 0, (byte) (value >> 0)); 171 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 1, (byte) (value >> 8)); 172 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 2, (byte) (value >> 16)); 173 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 3, (byte) (value >> 24)); 174 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 4, (byte) (value >> 32)); 175 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 5, (byte) (value >> 40)); 176 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 6, (byte) (value >> 48)); 177 UnsafeAccess.unsafe.putByte(writeChunk.data, offset + 7, (byte) (value >> 56)); 178 } 179}