1 /*
   2  * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.asm;
  24 
  25 import java.nio.ByteBuffer;
  26 import java.nio.ByteOrder;
  27 import java.util.Arrays;
  28 
  29 /**
  30  * Code buffer management for the assembler.
  31  */
  32 final class Buffer {
  33 
  34     protected ByteBuffer data;
  35 
  36     Buffer(ByteOrder order) {
  37         data = ByteBuffer.allocate(AsmOptions.InitialCodeBufferSize);
  38         data.order(order);
  39     }
  40 
  41     public int position() {
  42         return data.position();
  43     }
  44 
  45     public void setPosition(int position) {
  46         assert position >= 0 && position <= data.limit();
  47         data.position(position);
  48     }
  49 
  50     /**
  51      * Closes this buffer. Any further operations on a closed buffer will result in a
  52      * {@link NullPointerException}.
  53      *
  54      * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
  55      *            including) {@code position()} is returned
  56      * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
  57      */
  58     public byte[] close(boolean trimmedCopy) {
  59         byte[] result = data.array();
  60         if (trimmedCopy) {
  61             // Make a copy even if result.length == data.position() since
  62             // the API for trimmedCopy states a copy is always made
  63             result = Arrays.copyOf(result, data.position());
  64         }
  65         data = null;
  66         return result;
  67     }
  68 
  69     public byte[] copyData(int start, int end) {
  70         if (data == null) {
  71             return null;
  72         }
  73         return Arrays.copyOfRange(data.array(), start, end);
  74     }
  75 
  76     /**
  77      * Copies the data from this buffer into a given array.
  78      *
  79      * @param dst the destination array
  80      * @param off starting position in {@code dst}
  81      * @param len number of bytes to copy
  82      */
  83     public void copyInto(byte[] dst, int off, int len) {
  84         System.arraycopy(data.array(), 0, dst, off, len);
  85     }
  86 
  87     protected void ensureSize(int length) {
  88         if (length >= data.limit()) {
  89             byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
  90             ByteBuffer newData = ByteBuffer.wrap(newBuf);
  91             newData.order(data.order());
  92             newData.position(data.position());
  93             data = newData;
  94         }
  95     }
  96 
  97     public void emitBytes(byte[] arr, int off, int len) {
  98         ensureSize(data.position() + len);
  99         data.put(arr, off, len);
 100     }
 101 
 102     public void emitByte(int b) {
 103         assert NumUtil.isUByte(b) || NumUtil.isByte(b);
 104         ensureSize(data.position() + 1);
 105         data.put((byte) (b & 0xFF));
 106     }
 107 
 108     public void emitShort(int b) {
 109         assert NumUtil.isUShort(b) || NumUtil.isShort(b);
 110         ensureSize(data.position() + 2);
 111         data.putShort((short) b);
 112     }
 113 
 114     public void emitInt(int b) {
 115         ensureSize(data.position() + 4);
 116         data.putInt(b);
 117     }
 118 
 119     public void emitLong(long b) {
 120         ensureSize(data.position() + 8);
 121         data.putLong(b);
 122     }
 123 
 124     public void emitBytes(byte[] arr, int pos) {
 125         final int len = arr.length;
 126         ensureSize(pos + len);
 127         // Write directly into the underlying array so as to not
 128         // change the ByteBuffer's position
 129         System.arraycopy(arr, 0, data.array(), pos, len);
 130     }
 131 
 132     public void emitByte(int b, int pos) {
 133         assert NumUtil.isUByte(b) || NumUtil.isByte(b);
 134         ensureSize(pos + 1);
 135         data.put(pos, (byte) (b & 0xFF));
 136     }
 137 
 138     public void emitShort(int b, int pos) {
 139         assert NumUtil.isUShort(b) || NumUtil.isShort(b);
 140         ensureSize(pos + 2);
 141         data.putShort(pos, (short) b).position();
 142     }
 143 
 144     public void emitInt(int b, int pos) {
 145         ensureSize(pos + 4);
 146         data.putInt(pos, b).position();
 147     }
 148 
 149     public void emitLong(long b, int pos) {
 150         ensureSize(pos + 8);
 151         data.putLong(pos, b).position();
 152     }
 153 
 154     public int getByte(int pos) {
 155         int b = data.get(pos);
 156         return b & 0xff;
 157     }
 158 
 159     public int getShort(int pos) {
 160         short s = data.getShort(pos);
 161         return s & 0xffff;
 162     }
 163 
 164     public int getInt(int pos) {
 165         return data.getInt(pos);
 166     }
 167 
 168     public void reset() {
 169         data.clear();
 170     }
 171 }