/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.parser.scanner;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.llvm.runtime.LLVMLanguage;
public final class BitStream {
private static final long BYTE_MASK = 0xffL;
private final byte[] bitstream;
private BitStream(byte[] bitstream) {
this.bitstream = bitstream;
}
public static BitStream create(Source source) {
byte[] bytes;
switch (source.getMimeType()) {
case LLVMLanguage.LLVM_BITCODE_MIME_TYPE:
bytes = read(source.getPath());
break;
case LLVMLanguage.LLVM_BITCODE_BASE64_MIME_TYPE:
bytes = Base64.getDecoder().decode(source.getCode());
break;
default:
throw new UnsupportedOperationException();
}
return new BitStream(bytes);
}
public static BitStream createFromBlob(long[] args, int blobStartIndex) {
final byte[] blob = new byte[(args.length - 2) * Long.BYTES];
int to = 0;
for (int from = blobStartIndex; from < args.length; from++) {
final long l = args[from];
for (int i = 0; i < Long.BYTES; i++) {
blob[to++] = (byte) ((l >> (Byte.SIZE * i)) & BYTE_MASK);
}
}
return new BitStream(blob);
}
private static byte[] read(String filename) {
try {
return Files.readAllBytes(Paths.get(filename));
} catch (IOException ignore) {
return new byte[0];
}
}
public static long widthVBR(long value, long width) {
long total = 0;
long v = value;
do {
total += width;
v >>>= (width - 1);
} while (v != 0);
return total;
}
public long read(long offset, long bits) {
final long l = read(offset);
if (bits < Long.SIZE) {
// shifting 1L << 64 would cause an overflow
return l & ((1L << bits) - 1L);
} else {
return l;
}
}
public long readVBR(long offset, long width) {
long value = 0;
long shift = 0;
long datum;
long o = offset;
long dmask = 1 << (width - 1);
do {
datum = read(o, width);
o += width;
value += (datum & (dmask - 1)) << shift;
shift += width - 1;
} while ((datum & dmask) != 0);
return value;
}
public long size() {
return bitstream.length * Byte.SIZE;
}
private long read(long offset) {
long div = offset / Byte.SIZE;
long value = 0;
for (int i = 0; i < Byte.SIZE; i++) {
value += readAlignedByte(div + i) << (i * Byte.SIZE);
}
long mod = offset & (Byte.SIZE - 1L);
if (mod != 0) {
value >>>= mod;
value += readAlignedByte(div + Byte.SIZE) << (Long.SIZE - mod);
}
return value;
}
private long readAlignedByte(long i) {
return i < bitstream.length ? bitstream[(int) i] & BYTE_MASK : 0;
}
}