001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.mm.mmtk.gcspy;
014    
015    import org.mmtk.utility.Constants;
016    import org.mmtk.utility.Log;
017    import org.mmtk.plan.Plan;
018    import org.mmtk.vm.VM;
019    
020    import org.jikesrvm.runtime.Magic;
021    import static org.jikesrvm.runtime.SysCall.sysCall;
022    import org.jikesrvm.classloader.RVMArray;
023    import org.jikesrvm.objectmodel.ObjectModel;
024    import org.jikesrvm.runtime.RuntimeEntrypoints;
025    
026    import org.vmmagic.unboxed.*;
027    import org.vmmagic.pragma.*;
028    
029    /**
030     * This class provides generally useful methods.
031     */
032    @Uninterruptible public class Util extends org.mmtk.vm.gcspy.Util implements Constants {
033      private static final boolean DEBUG_ = false;
034      public static final int KILOBYTE = 1024;
035      public static final int MEGABYTE = 1024 * 1024;
036    
037      /**
038       * Allocate an array of bytes with malloc
039       *
040       * @param size The size to allocate
041       * @return The start address of the memory allocated in C space
042       * @see #free
043       */
044      public final Address malloc(int size) {
045        if (org.jikesrvm.VM.BuildWithGCSpy) {
046          Address rtn  = sysCall.sysMalloc(size);
047          if (rtn.isZero()) VM.assertions.fail("GCspy malloc failure");
048          return rtn;
049        } else
050          return Address.zero();
051      }
052    
053      /**
054       * Free an array of bytes previously allocated with malloc
055       *
056       * @param addr The address of some memory previously allocated with malloc
057       * @see #malloc
058       */
059      public final void free(Address addr) {
060        if (org.jikesrvm.VM.BuildWithGCSpy)
061          if (!addr.isZero())
062            sysCall.sysFree(addr);
063      }
064    
065      /**
066       * Convert a String to a 0-terminated array of bytes
067       *
068       * @param str The string to convert
069       * @return The address of a null-terminated array in C-space
070       *
071       * WARNING: we call out to String.length and String.charAt, both of
072       * which are interruptible. We protect these calls with a
073       * swLock/swUnlock mechanism, as per VM.sysWrite on String
074       */
075      public final Address getBytes(String str) {
076        if (org.jikesrvm.VM.BuildWithGCSpy) {
077          if (str == null)
078            return Address.zero();
079    
080          if (DEBUG_) {
081            Log.write("getBytes: "); Log.write(str); Log.write("->");
082          }
083    
084          // Grab some memory sufficient to hold the null terminated string,
085          // rounded up to an integral number of ints.
086          char[] str_backing = java.lang.JikesRVMSupport.getBackingCharArray(str);
087          int str_length = java.lang.JikesRVMSupport.getStringLength(str);
088          int str_offset = java.lang.JikesRVMSupport.getStringOffset(str);
089          int size = (str_length + 4) & -4;
090          Address rtn = malloc(size);
091    
092          // Write the string into it, one byte at a time (dodgy conversion)
093          for (int i=0; i < str_length; i++)  {
094            rtn.store((byte)str_backing[str_offset+i], Offset.fromIntSignExtend(i));
095          }
096          // Zero rest of byte[]
097          for (int i=str_length; i < size; i++)  {
098            rtn.store((byte)0, Offset.fromIntSignExtend(i-str_offset));
099          }
100          if (DEBUG_) {
101            sysCall.sysWriteBytes(2/*SysTraceFd*/, rtn, size); Log.write("\n");
102          }
103          return rtn;
104        } else {
105          return Address.zero();
106        }
107      }
108    
109      /**
110       * Pretty print a size, converting from bytes to kilo- or mega-bytes as appropriate
111       *
112       * @param buffer The buffer (in C space) in which to place the formatted size
113       * @param size The size in bytes
114       */
115      public final void formatSize(Address buffer, int size) {
116        if (org.jikesrvm.VM.BuildWithGCSpy)
117          sysCall.gcspyFormatSize(buffer, size);
118      }
119    
120    
121      /**
122       * Pretty print a size, converting from bytes to kilo- or mega-bytes as appropriate
123       *
124       * @param format A format string
125       * @param bufsize The size of a buffer large enough to hold the formatted result
126       * @param size The size in bytes
127       */
128      public final Address formatSize(String format, int bufsize, int size) {
129        if (org.jikesrvm.VM.BuildWithGCSpy) {
130          // - sprintf(tmp, "Current Size: %s\n", gcspy_formatSize(size));
131          Address tmp = malloc(bufsize);
132          Address formattedSize = malloc(bufsize);
133          Address currentSize = getBytes(format);
134          formatSize(formattedSize, size);
135          sprintf(tmp, currentSize, formattedSize);
136          return tmp;
137        } else {
138          return Address.zero();
139        }
140      }
141    
142      /**
143       * Create an array of a particular type.
144       * The easiest way to use this is:
145       *     Foo[] x = (Foo [])Stream.createDataArray(new Foo[0], numElements);
146       * @param templ a data array to use as a template
147       * @param numElements number of elements in new array
148       * @return the new array
149       */
150      @Interruptible
151      public Object createDataArray(Object templ, int numElements) {
152        if (org.jikesrvm.VM.BuildWithGCSpy) {
153          RVMArray array = Magic.getObjectType(templ).asArray();
154          return RuntimeEntrypoints.resolvedNewArray(numElements,
155                                  array.getLogElementSize(),
156                                  ObjectModel.computeArrayHeaderSize(array),
157                                  array.getTypeInformationBlock(),
158                                  Plan.ALLOC_GCSPY,
159                                  ObjectModel.getAlignment(array),
160                                  ObjectModel.getOffsetForAlignment(array, false),
161                                  0);
162        } else {
163          return null;
164        }
165      }
166    
167      //----------- Various methods modelled on string.c ---------------------//
168    
169      /**
170       * sprintf(char *str, char *format, char* value)
171       *
172       * @param str The destination 'string' (memory in C space)
173       * @param format The format 'string' (memory in C space)
174       * @param value The value 'string' (memory in C space)
175       * @return The number of characters printed (as returned by C's sprintf
176       */
177      public final int sprintf(Address str, Address format, Address value) {
178        if (org.jikesrvm.VM.BuildWithGCSpy)
179          return sysCall.gcspySprintf(str, format, value);
180        else
181          return 0;
182      }
183    }