1 /*
   2  * Copyright (c) 2009, 2018, 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 
  24 
  25 package org.graalvm.compiler.asm;
  26 
  27 import java.nio.ByteBuffer;
  28 import java.nio.ByteOrder;
  29 import java.util.Arrays;
  30 
  31 import org.graalvm.compiler.core.common.NumUtil;
  32 import org.graalvm.compiler.serviceprovider.BufferUtil;
  33 
  34 /**
  35  * Code buffer management for the assembler.
  36  */
  37 final class Buffer {
  38 
  39     protected ByteBuffer data;
  40 
  41     Buffer(ByteOrder order) {
  42         data = ByteBuffer.allocate(AsmOptions.InitialCodeBufferSize);
  43         data.order(order);
  44     }
  45 
  46     public int position() {
  47         return data.position();
  48     }
  49 
  50     public void setPosition(int position) {
  51         assert position >= 0 && position <= data.limit();
  52         BufferUtil.asBaseBuffer(data).position(position);
  53     }
  54 
  55     /**
  56      * Closes this buffer. Any further operations on a closed buffer will result in a
  57      * {@link NullPointerException}.
  58      *
  59      * @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
  60      *            including) {@code position()} is returned
  61      * @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
  62      */
  63     public byte[] close(boolean trimmedCopy) {
  64         byte[] result = data.array();
  65         if (trimmedCopy) {
  66             // Make a copy even if result.length == data.position() since
  67             // the API for trimmedCopy states a copy is always made
  68             result = Arrays.copyOf(result, data.position());
  69         }
  70         data = null;
  71         return result;
  72     }
  73 
  74     public byte[] copyData(int start, int end) {
  75         if (data == null) {
  76             return null;
  77         }
  78         return Arrays.copyOfRange(data.array(), start, end);
  79     }
  80 
  81     /**
  82      * Copies the data from this buffer into a given array.
  83      *
  84      * @param dst the destination array
  85      * @param off starting position in {@code dst}
  86      * @param len number of bytes to copy
  87      */
  88     public void copyInto(byte[] dst, int off, int len) {
  89         System.arraycopy(data.array(), 0, dst, off, len);
  90     }
  91 
  92     protected void ensureSize(int length) {
  93         if (length >= data.limit()) {
  94             byte[] newBuf = Arrays.copyOf(data.array(), length * 4);
  95             ByteBuffer newData = ByteBuffer.wrap(newBuf);
  96             newData.order(data.order());
  97             BufferUtil.asBaseBuffer(newData).position(data.position());
  98             data = newData;
  99         }
 100     }
 101 
 102     public void emitBytes(byte[] arr, int off, int len) {
 103         ensureSize(data.position() + len);
 104         data.put(arr, off, len);
 105     }
 106 
 107     public void emitByte(int b) {
 108         assert NumUtil.isUByte(b) || NumUtil.isByte(b);
 109         ensureSize(data.position() + 1);
 110         data.put((byte) (b & 0xFF));
 111     }
 112 
 113     public void emitShort(int b) {
 114         assert NumUtil.isUShort(b) || NumUtil.isShort(b);
 115         ensureSize(data.position() + 2);
 116         data.putShort((short) b);
 117     }
 118 
 119     public void emitInt(int b) {
 120         ensureSize(data.position() + 4);
 121         data.putInt(b);
 122     }
 123 
 124     public void emitLong(long b) {
 125         ensureSize(data.position() + 8);
 126         data.putLong(b);
 127     }
 128 
 129     public void emitBytes(byte[] arr, int pos) {
 130         final int len = arr.length;
 131         ensureSize(pos + len);
 132         // Write directly into the underlying array so as to not
 133         // change the ByteBuffer's position
 134         System.arraycopy(arr, 0, data.array(), pos, len);
 135     }
 136 
 137     public void emitByte(int b, int pos) {
 138         assert NumUtil.isUByte(b) || NumUtil.isByte(b);
 139         ensureSize(pos + 1);
 140         data.put(pos, (byte) (b & 0xFF));
 141     }
 142 
 143     public void emitShort(int b, int pos) {
 144         assert NumUtil.isUShort(b) || NumUtil.isShort(b);
 145         ensureSize(pos + 2);
 146         data.putShort(pos, (short) b).position();
 147     }
 148 
 149     public void emitInt(int b, int pos) {
 150         ensureSize(pos + 4);
 151         data.putInt(pos, b).position();
 152     }
 153 
 154     public void emitLong(long b, int pos) {
 155         ensureSize(pos + 8);
 156         data.putLong(pos, b).position();
 157     }
 158 
 159     public int getByte(int pos) {
 160         int b = data.get(pos);
 161         return b & 0xff;
 162     }
 163 
 164     public int getShort(int pos) {
 165         short s = data.getShort(pos);
 166         return s & 0xffff;
 167     }
 168 
 169     public int getInt(int pos) {
 170         return data.getInt(pos);
 171     }
 172 
 173     public void reset() {
 174         BufferUtil.asBaseBuffer(data).clear();
 175     }
 176 }