/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.mm.mmtk.gcspy;
import org.mmtk.utility.Constants;
import org.mmtk.utility.Log;
import org.mmtk.plan.Plan;
import org.mmtk.vm.VM;
import org.jikesrvm.runtime.Magic;
import static org.jikesrvm.runtime.SysCall.sysCall;
import org.jikesrvm.classloader.RVMArray;
import org.jikesrvm.objectmodel.ObjectModel;
import org.jikesrvm.runtime.RuntimeEntrypoints;
import org.vmmagic.unboxed.*;
import org.vmmagic.pragma.*;
/**
* This class provides generally useful methods.
*/
@Uninterruptible public class Util extends org.mmtk.vm.gcspy.Util implements Constants {
private static final boolean DEBUG_ = false;
public static final int KILOBYTE = 1024;
public static final int MEGABYTE = 1024 * 1024;
/**
* Allocate an array of bytes with malloc
*
* @param size The size to allocate
* @return The start address of the memory allocated in C space
* @see #free
*/
public final Address malloc(int size) {
if (org.jikesrvm.VM.BuildWithGCSpy) {
Address rtn = sysCall.sysMalloc(size);
if (rtn.isZero()) VM.assertions.fail("GCspy malloc failure");
return rtn;
} else
return Address.zero();
}
/**
* Free an array of bytes previously allocated with malloc
*
* @param addr The address of some memory previously allocated with malloc
* @see #malloc
*/
public final void free(Address addr) {
if (org.jikesrvm.VM.BuildWithGCSpy)
if (!addr.isZero())
sysCall.sysFree(addr);
}
/**
* Convert a String to a 0-terminated array of bytes
*
* @param str The string to convert
* @return The address of a null-terminated array in C-space
*
* WARNING: we call out to String.length and String.charAt, both of
* which are interruptible. We protect these calls with a
* swLock/swUnlock mechanism, as per VM.sysWrite on String
*/
public final Address getBytes(String str) {
if (org.jikesrvm.VM.BuildWithGCSpy) {
if (str == null)
return Address.zero();
if (DEBUG_) {
Log.write("getBytes: "); Log.write(str); Log.write("->");
}
// Grab some memory sufficient to hold the null terminated string,
// rounded up to an integral number of ints.
char[] str_backing = java.lang.JikesRVMSupport.getBackingCharArray(str);
int str_length = java.lang.JikesRVMSupport.getStringLength(str);
int str_offset = java.lang.JikesRVMSupport.getStringOffset(str);
int size = (str_length + 4) & -4;
Address rtn = malloc(size);
// Write the string into it, one byte at a time (dodgy conversion)
for (int i=0; i < str_length; i++) {
rtn.store((byte)str_backing[str_offset+i], Offset.fromIntSignExtend(i));
}
// Zero rest of byte[]
for (int i=str_length; i < size; i++) {
rtn.store((byte)0, Offset.fromIntSignExtend(i-str_offset));
}
if (DEBUG_) {
sysCall.sysWriteBytes(2/*SysTraceFd*/, rtn, size); Log.write("\n");
}
return rtn;
} else {
return Address.zero();
}
}
/**
* Pretty print a size, converting from bytes to kilo- or mega-bytes as appropriate
*
* @param buffer The buffer (in C space) in which to place the formatted size
* @param size The size in bytes
*/
public final void formatSize(Address buffer, int size) {
if (org.jikesrvm.VM.BuildWithGCSpy)
sysCall.gcspyFormatSize(buffer, size);
}
/**
* Pretty print a size, converting from bytes to kilo- or mega-bytes as appropriate
*
* @param format A format string
* @param bufsize The size of a buffer large enough to hold the formatted result
* @param size The size in bytes
*/
public final Address formatSize(String format, int bufsize, int size) {
if (org.jikesrvm.VM.BuildWithGCSpy) {
// - sprintf(tmp, "Current Size: %s\n", gcspy_formatSize(size));
Address tmp = malloc(bufsize);
Address formattedSize = malloc(bufsize);
Address currentSize = getBytes(format);
formatSize(formattedSize, size);
sprintf(tmp, currentSize, formattedSize);
return tmp;
} else {
return Address.zero();
}
}
/**
* Create an array of a particular type.
* The easiest way to use this is:
* Foo[] x = (Foo [])Stream.createDataArray(new Foo[0], numElements);
* @param templ a data array to use as a template
* @param numElements number of elements in new array
* @return the new array
*/
@Interruptible
public Object createDataArray(Object templ, int numElements) {
if (org.jikesrvm.VM.BuildWithGCSpy) {
RVMArray array = Magic.getObjectType(templ).asArray();
return RuntimeEntrypoints.resolvedNewArray(numElements,
array.getLogElementSize(),
ObjectModel.computeArrayHeaderSize(array),
array.getTypeInformationBlock(),
Plan.ALLOC_GCSPY,
ObjectModel.getAlignment(array),
ObjectModel.getOffsetForAlignment(array, false),
0);
} else {
return null;
}
}
//----------- Various methods modelled on string.c ---------------------//
/**
* sprintf(char *str, char *format, char* value)
*
* @param str The destination 'string' (memory in C space)
* @param format The format 'string' (memory in C space)
* @param value The value 'string' (memory in C space)
* @return The number of characters printed (as returned by C's sprintf
*/
public final int sprintf(Address str, Address format, Address value) {
if (org.jikesrvm.VM.BuildWithGCSpy)
return sysCall.gcspySprintf(str, format, value);
else
return 0;
}
}