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