001/*
002 * Copyright (c) 2009, 2014, 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.asm;
024
025import java.util.*;
026
027/**
028 * Code buffer management for the assembler. Support for little endian and big endian architectures
029 * is implemented using subclasses.
030 */
031abstract class Buffer {
032
033    protected byte[] data;
034    protected int position;
035
036    public Buffer() {
037        data = new byte[AsmOptions.InitialCodeBufferSize];
038    }
039
040    public int position() {
041        return position;
042    }
043
044    public void setPosition(int position) {
045        assert position >= 0 && position <= data.length;
046        this.position = position;
047    }
048
049    /**
050     * Closes this buffer. No extra data can be written to this buffer after this call.
051     *
052     * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
053     *            including) {@code position()} is returned
054     * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
055     */
056    public byte[] close(boolean trimmedCopy) {
057        byte[] result = trimmedCopy ? Arrays.copyOf(data, position()) : data;
058        data = null;
059        return result;
060    }
061
062    public byte[] copyData(int start, int end) {
063        if (data == null) {
064            return null;
065        }
066        return Arrays.copyOfRange(data, start, end);
067    }
068
069    /**
070     * Copies the data from this buffer into a given array.
071     *
072     * @param dst the destination array
073     * @param off starting position in {@code dst}
074     * @param len number of bytes to copy
075     */
076    public void copyInto(byte[] dst, int off, int len) {
077        System.arraycopy(data, 0, dst, off, len);
078    }
079
080    protected void ensureSize(int length) {
081        if (length >= data.length) {
082            data = Arrays.copyOf(data, length * 4);
083        }
084    }
085
086    public void emitBytes(byte[] arr, int off, int len) {
087        ensureSize(position + len);
088        System.arraycopy(arr, off, data, position, len);
089        position += len;
090    }
091
092    public void emitByte(int b) {
093        position = emitByte(b, position);
094    }
095
096    public void emitShort(int b) {
097        position = emitShort(b, position);
098    }
099
100    public void emitInt(int b) {
101        position = emitInt(b, position);
102    }
103
104    public void emitLong(long b) {
105        position = emitLong(b, position);
106    }
107
108    public int emitBytes(byte[] arr, int pos) {
109        final int len = arr.length;
110        final int newPos = pos + len;
111        ensureSize(newPos);
112        System.arraycopy(arr, 0, data, pos, len);
113        return newPos;
114    }
115
116    public int emitByte(int b, int pos) {
117        assert NumUtil.isUByte(b) || NumUtil.isByte(b);
118        int newPos = pos + 1;
119        ensureSize(newPos);
120        data[pos] = (byte) (b & 0xFF);
121        return newPos;
122    }
123
124    public abstract int emitShort(int b, int pos);
125
126    public abstract int emitInt(int b, int pos);
127
128    public abstract int emitLong(long b, int pos);
129
130    public int getByte(int pos) {
131        return data[pos] & 0xff;
132    }
133
134    public abstract int getShort(int pos);
135
136    public abstract int getInt(int pos);
137
138    public static final class BigEndian extends Buffer {
139
140        @Override
141        public int emitShort(int b, int pos) {
142            assert NumUtil.isUShort(b) || NumUtil.isShort(b);
143            int newPos = pos + 2;
144            ensureSize(pos + 2);
145            data[pos] = (byte) ((b >> 8) & 0xFF);
146            data[pos + 1] = (byte) (b & 0xFF);
147            return newPos;
148        }
149
150        @Override
151        public int emitInt(int b, int pos) {
152            int newPos = pos + 4;
153            ensureSize(newPos);
154            data[pos] = (byte) ((b >> 24) & 0xFF);
155            data[pos + 1] = (byte) ((b >> 16) & 0xFF);
156            data[pos + 2] = (byte) ((b >> 8) & 0xFF);
157            data[pos + 3] = (byte) (b & 0xFF);
158            return newPos;
159        }
160
161        @Override
162        public int emitLong(long b, int pos) {
163            int newPos = pos + 8;
164            ensureSize(newPos);
165            data[pos] = (byte) ((b >> 56) & 0xFF);
166            data[pos + 1] = (byte) ((b >> 48) & 0xFF);
167            data[pos + 2] = (byte) ((b >> 40) & 0xFF);
168            data[pos + 3] = (byte) ((b >> 32) & 0xFF);
169            data[pos + 4] = (byte) ((b >> 24) & 0xFF);
170            data[pos + 5] = (byte) ((b >> 16) & 0xFF);
171            data[pos + 6] = (byte) ((b >> 8) & 0xFF);
172            data[pos + 7] = (byte) (b & 0xFF);
173            return newPos;
174        }
175
176        @Override
177        public int getShort(int pos) {
178            return (data[pos + 0] & 0xff) << 8 | (data[pos + 1] & 0xff) << 0;
179        }
180
181        @Override
182        public int getInt(int pos) {
183            return (data[pos + 0] & 0xff) << 24 | (data[pos + 1] & 0xff) << 16 | (data[pos + 2] & 0xff) << 8 | (data[pos + 3] & 0xff) << 0;
184        }
185    }
186
187    public static final class LittleEndian extends Buffer {
188
189        @Override
190        public int emitShort(int b, int pos) {
191            assert NumUtil.isUShort(b) || NumUtil.isShort(b);
192            int newPos = pos + 2;
193            ensureSize(newPos);
194            data[pos] = (byte) (b & 0xFF);
195            data[pos + 1] = (byte) ((b >> 8) & 0xFF);
196            return newPos;
197        }
198
199        @Override
200        public int emitInt(int b, int pos) {
201            int newPos = pos + 4;
202            ensureSize(newPos);
203            data[pos] = (byte) (b & 0xFF);
204            data[pos + 1] = (byte) ((b >> 8) & 0xFF);
205            data[pos + 2] = (byte) ((b >> 16) & 0xFF);
206            data[pos + 3] = (byte) ((b >> 24) & 0xFF);
207            return newPos;
208        }
209
210        @Override
211        public int emitLong(long b, int pos) {
212            int newPos = pos + 8;
213            ensureSize(newPos);
214            data[pos] = (byte) (b & 0xFF);
215            data[pos + 1] = (byte) ((b >> 8) & 0xFF);
216            data[pos + 2] = (byte) ((b >> 16) & 0xFF);
217            data[pos + 3] = (byte) ((b >> 24) & 0xFF);
218            data[pos + 4] = (byte) ((b >> 32) & 0xFF);
219            data[pos + 5] = (byte) ((b >> 40) & 0xFF);
220            data[pos + 6] = (byte) ((b >> 48) & 0xFF);
221            data[pos + 7] = (byte) ((b >> 56) & 0xFF);
222            return newPos;
223        }
224
225        @Override
226        public int getShort(int pos) {
227            return (data[pos + 1] & 0xff) << 8 | (data[pos + 0] & 0xff) << 0;
228        }
229
230        @Override
231        public int getInt(int pos) {
232            return (data[pos + 3] & 0xff) << 24 | (data[pos + 2] & 0xff) << 16 | (data[pos + 1] & 0xff) << 8 | (data[pos + 0] & 0xff) << 0;
233        }
234    }
235
236    public void reset() {
237        position = 0;
238    }
239}