/*
 * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the Classpath exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package org.openjdk.btrace.core;

import java.io.Serializable;
import java.lang.management.MemoryUsage;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import jdk.jfr.Event;
import org.openjdk.btrace.core.aggregation.Aggregation;
import org.openjdk.btrace.core.aggregation.AggregationFunction;
import org.openjdk.btrace.core.aggregation.AggregationKey;
import org.openjdk.btrace.core.annotations.OnMethod;
import org.openjdk.btrace.core.annotations.ProbeClassName;
import org.openjdk.btrace.core.annotations.ProbeMethodName;
import org.openjdk.btrace.core.annotations.Self;
import org.openjdk.btrace.core.jfr.JfrEvent;
import org.openjdk.btrace.core.types.AnyType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class is an all-in-one wrapper for BTrace DSL methods
 *
 * @author A. Sundararajan
 * @author Jaroslav Bachorik
 */
public class BTraceUtils {
  private static final Logger log = LoggerFactory.getLogger(BTraceUtils.class);

  // standard stack depth decrement for figuring out the caller class calls
  private static final int STACK_DEC = 2;

  static {
    BTraceRuntime.initUnsafe();
  }

  // do not allow object creation!
  private BTraceUtils() {}

  // Thread and stack access

  /**
   * Tests whether this thread has been interrupted. The <i>interrupted status</i> of the thread is
   * unaffected by this method.
   *
   * <p>A thread interruption ignored because a thread was not alive at the time of the interrupt
   * will be reflected by this method returning false.
   *
   * @return <code>true</code> if this thread has been interrupted; <code>false</code> otherwise.
   */
  public static boolean isInteruppted() {
    return Threads.isInteruppted();
  }

  /** Prints the java stack trace of the current thread. */
  public static void jstack() {
    Threads.jstack(2, -1);
  }

  /**
   * Prints the java stack trace of the current thread. But, at most given number of frames.
   *
   * @param numFrames number of frames to be printed. When this is negative all frames are printed.
   */
  public static void jstack(int numFrames) {
    Threads.jstack(2, numFrames);
  }

  /** Prints Java stack traces of all the Java threads. */
  public static void jstackAll() {
    Threads.jstackAll(2, -1);
  }

  /**
   * Prints Java stack traces of all the Java threads. But, at most given number of frames.
   *
   * @param numFrames number of frames to be printed. When this is negative all frames are printed.
   */
  public static void jstackAll(int numFrames) {
    Threads.jstackAll(2, numFrames);
  }

  /**
   * Returns the stack trace of current thread as a String.
   *
   * @return the stack trace as a String.
   */
  public static String jstackStr() {
    return Threads.jstackStr(2, -1);
  }

  /**
   * Returns the stack trace of the current thread as a String but includes at most the given number
   * of frames.
   *
   * @param numFrames number of frames to be included. When this is negative all frames are
   *     included.
   * @return the stack trace as a String.
   */
  public static String jstackStr(int numFrames) {
    return Threads.jstackStr(2, numFrames);
  }

  /**
   * Returns the stack traces of all Java threads as a String.
   *
   * @return the stack traces as a String.
   */
  public static String jstackAllStr() {
    return Threads.jstackAllStr();
  }

  /**
   * Returns at most given number of frames in stack traces of all threads as a String.
   *
   * @param numFrames number of frames to be included. When this is negative all frames are
   *     included.
   * @return the stack traces as a String.
   */
  public static String jstackAllStr(int numFrames) {
    return Threads.jstackAllStr(numFrames);
  }

  /**
   * Prints the stack trace of the given exception object.
   *
   * @param exception throwable for which stack trace is printed.
   */
  public static void jstack(Throwable exception) {
    Threads.jstack(exception);
  }

  /**
   * Prints the stack trace of the given exception object. But, prints atmost given number of
   * frames.
   *
   * @param exception throwable for which stack trace is printed.
   * @param numFrames maximum number of frames to be printed.
   */
  public static void jstack(Throwable exception, int numFrames) {
    Threads.jstack(exception, numFrames);
  }

  /**
   * Returns the stack trace of given exception object as a String.
   *
   * @param exception the throwable for which stack trace is returned.
   */
  public static String jstackStr(Throwable exception) {
    return Threads.jstackStr(exception);
  }

  /**
   * Returns stack trace of given exception object as a String.
   *
   * @param exception throwable for which stack trace is returned.
   * @param numFrames maximum number of frames to be returned.
   */
  public static String jstackStr(Throwable exception, int numFrames) {
    return Threads.jstackStr(exception, numFrames);
  }

  /**
   * Returns a reference to the currently executing thread object.
   *
   * @return the currently executing thread.
   */
  public static Thread currentThread() {
    return Threads.currentThread();
  }

  /**
   * Returns the identifier of the given Thread. The thread ID is a positive <tt>long</tt> number
   * generated when the given thread was created. The thread ID is unique and remains unchanged
   * during its lifetime. When a thread is terminated, the thread ID may be reused.
   */
  public static long threadId(Thread thread) {
    return Threads.threadId(thread);
  }

  /**
   * Returns the state of the given thread. This method is designed for use in monitoring of the
   * system state, not for synchronization control.
   */
  public static Thread.State threadState(Thread thread) {
    return Threads.threadState(thread);
  }

  /**
   * Returns <tt>true</tt> if and only if the current thread holds the monitor lock on the specified
   * object.
   *
   * <p>This method is designed to allow a program to assert that the current thread already holds a
   * specified lock:
   *
   * <pre>
   *     assert Thread.holdsLock(obj);
   * </pre>
   *
   * @param obj the object on which to test lock ownership
   * @return <tt>true</tt> if the current thread holds the monitor lock on the specified object.
   * @throws NullPointerException if obj is <tt>null</tt>
   */
  public static boolean holdsLock(Object obj) {
    return Threads.holdsLock(obj);
  }

  /** Prints the Java level deadlocks detected (if any). */
  public static void deadlocks() {
    Threads.deadlocks();
  }

  /**
   * Prints deadlocks detected (if any). Optionally prints stack trace of the deadlocked threads.
   *
   * @param stackTrace boolean flag to specify whether to print stack traces of deadlocked threads
   *     or not.
   */
  public static void deadlocks(boolean stackTrace) {
    Threads.deadlocks(stackTrace);
  }

  /**
   * Returns the name of the given thread.
   *
   * @param thread thread whose name is returned
   */
  public static String name(Thread thread) {
    return Threads.name(thread);
  }

  // class loader access

  /**
   * Returns the class loader for the given class. Some implementations may use null to represent
   * the bootstrap class loader. This method will return null in such implementations if this class
   * was loaded by the bootstrap class loader.
   *
   * @param clazz the Class for which the class loader is returned
   */
  public static ClassLoader loader(Class<?> clazz) {
    return clazz.getClassLoader();
  }

  /**
   * Returns the parent class loader of the given loader. Some implementations may use <tt>null</tt>
   * to represent the bootstrap class loader. This method will return <tt>null</tt> in such
   * implementations if this class loader's parent is the bootstrap class loader.
   *
   * @param loader the loader for which the parent loader is returned
   * @return The parent <tt>ClassLoader</tt>
   */
  public static ClassLoader parentLoader(ClassLoader loader) {
    return loader.getParent();
  }

  // java.lang.Object methods

  /**
   * Returns a string representation of the object. In general, the <code>toString</code> method
   * returns a string that "textually represents" this object. The result should be a concise but
   * informative representation that is easy for a person to read. For bootstrap classes, returns
   * the result of calling Object.toString() override. For non-bootstrap classes, default toString()
   * value [className@hashCode] is returned.
   *
   * @param obj the object whose string representation is returned
   * @return a string representation of the given object.
   */
  public static String str(Object obj) {
    return Strings.str(obj);
  }

  /**
   * Returns identity string of the form class-name@identity-hash
   *
   * @param obj object for which identity string is returned
   * @return identity string
   */
  public static String identityStr(Object obj) {
    int hashCode = java.lang.System.identityHashCode(obj);
    return obj.getClass().getName() + "@" + Integer.toHexString(hashCode);
  }

  /**
   * Returns a hash code value for the object. This method is supported for the benefit of
   * hashtables such as those provided by <code>java.util.Hashtable</code>. For bootstrap classes,
   * returns the result of calling Object.hashCode() override. For non-bootstrap classes, the
   * identity hash code is returned.
   *
   * @param obj the Object whose hash code is returned.
   * @return a hash code value for the given object.
   */
  public static int hash(Object obj) {
    if (obj.getClass().getClassLoader() == null) {
      return obj.hashCode();
    } else {
      return java.lang.System.identityHashCode(obj);
    }
  }

  /**
   * Returns the same hash code for the given object as would be returned by the default method
   * hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the
   * null reference is zero.
   *
   * @param obj object for which the hashCode is to be calculated
   * @return the hashCode
   */
  public static int identityHashCode(Object obj) {
    return java.lang.System.identityHashCode(obj);
  }

  /**
   * Indicates whether two given objects are "equal to" one another. For bootstrap classes, returns
   * the result of calling Object.equals() override. For non-bootstrap classes, the reference
   * identity comparison is done.
   *
   * @param obj1 first object to compare equality
   * @param obj2 second object to compare equality
   * @return <code>true</code> if the given objects are equal; <code>false</code> otherwise.
   */
  public static boolean compare(Object obj1, Object obj2) {
    return BTraceRuntime.compare(obj1, obj2);
  }

  // reflection

  /**
   * Returns the runtime class of the given Object.
   *
   * @param obj the Object whose Class is returned
   * @return the Class object of given object
   */
  public static Class<?> classOf(Object obj) {
    return Reflective.classOf(obj);
  }

  /**
   * Checks whether the provided object is an instance of the named class. <cite>Note: this method
   * can be rather CPU intensive, use with caution</cite>
   *
   * @param obj the object to check
   * @param className the class name; as a special case {@code void} can be provided to check
   *     whether the instance is a void value wrapper - {@linkplain AnyType#VOID}
   * @return {@code true} if the object can be assigned to an instance of 'className' type
   * @since 1.3.5
   */
  public static boolean instanceOf(Object obj, String className) {
    return BTraceRuntime.instanceOf(obj, className);
  }

  /**
   * Returns the Class object representing the class or interface that declares the field
   * represented by the given Field object.
   *
   * @param field whose declaring Class is returned
   */
  public static Class<?> declaringClass(Field field) {
    return Reflective.declaringClass(field);
  }

  /** Returns the name of the given Class object. */
  public static String name(Class<?> clazz) {
    return Reflective.name(clazz);
  }

  /**
   * Returns the name of the Field object.
   *
   * @param field Field for which name is returned
   * @return name of the given field
   */
  public static String name(Field field) {
    return Reflective.name(field);
  }

  /**
   * Returns the type of the Field object.
   *
   * @param field Field for which type is returned
   * @return type of the given field
   */
  public static Class<?> type(Field field) {
    return Reflective.type(field);
  }

  /** Returns the access flags of the given Class. */
  public static int accessFlags(Class<?> clazz) {
    return Reflective.accessFlags(clazz);
  }

  /** Returns the access flags of the given Field. */
  public static int accessFlags(Field field) {
    return Reflective.accessFlags(field);
  }

  /** Returns the current context class loader */
  public static ClassLoader contextClassLoader() {
    return Reflective.contextClassLoader();
  }

  // get Class of the given name

  /** Returns Class object for given class name. */
  public static Class classForName(String name) {
    return Reflective.classForName(name);
  }

  /** Returns the Class for the given class name using the given class loader. */
  public static Class classForName(String name, ClassLoader cl) {
    return Reflective.classForName(name, cl);
  }

  /**
   * Determines if the class or interface represented by the first <code>Class</code> object is
   * either the same as, or is a superclass or superinterface of, the class or interface represented
   * by the second <code>Class</code> parameter. It returns <code>true</code> if so; otherwise it
   * returns <code>false</code>.
   */
  public static boolean isAssignableFrom(Class<?> a, Class<?> b) {
    return Reflective.isAssignableFrom(a, b);
  }

  /**
   * Determines if the specified <code>Object</code> is assignment-compatible with the object
   * represented by the specified <code>Class</code>. This method is the dynamic equivalent of the
   * Java language <code>instanceof</code> operator. The method returns <code>true</code> if the
   * specified <code>Object</code> argument is non-null and can be cast to the reference type
   * represented by this <code>Class</code> object without raising a <code>ClassCastException.
   * </code> It returns <code>false</code> otherwise.
   *
   * @param clazz the class that is checked.
   * @param obj the object to check.
   * @return true if <code>obj</code> is an instance of the given class.
   */
  public static boolean isInstance(Class<?> clazz, Object obj) {
    return Reflective.isInstance(clazz, obj);
  }

  /**
   * Returns the <code>Class</code> representing the superclass of the entity (class, interface,
   * primitive type or void) represented by the given <code>Class</code>. If the given <code>Class
   * </code> represents either the <code>Object</code> class, an interface, a primitive type, or
   * void, then null is returned. If the given object represents an array class then the <code>Class
   * </code> object representing the <code>Object</code> class is returned.
   *
   * @param clazz the Class whose super class is returned.
   * @return the superclass of the class represented by the given object.
   */
  public static Class<?> getSuperclass(Class<?> clazz) {
    return Reflective.getSuperclass(clazz);
  }

  /**
   * Determines if the specified <code>Class</code> object represents an interface type.
   *
   * @param clazz the Class object to check.
   * @return <code>true</code> if the Class represents an interface; <code>false</code> otherwise.
   */
  public static boolean isInterface(Class<?> clazz) {
    return Reflective.isInterface(clazz);
  }

  /**
   * Determines if the given <code>Class</code> object represents an array class.
   *
   * @param clazz Class object to check.
   * @return <code>true</code> if the given object represents an array class; <code>false</code>
   *     otherwise.
   */
  public static boolean isArray(Class<?> clazz) {
    return Reflective.isArray(clazz);
  }

  /** Returns whether the given Class represent primitive type or not. */
  public static boolean isPrimitive(Class<?> clazz) {
    return Reflective.isPrimitive(clazz);
  }

  /** returns component type of an array Class. */
  public static Class<?> getComponentType(Class<?> clazz) {
    return Reflective.getComponentType(clazz);
  }

  // Accessing fields by reflection

  /**
   * Returns a <code>Field</code> object that reflects the specified declared field of the class or
   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter
   * is a <code>String</code> that specifies the simple name of the desired field. Returns <code>
   * null</code> on not finding field if throwException parameter is <code>false</code>. Else throws
   * a <code>RuntimeException</code> when field is not found.
   *
   * @param clazz Class whose field is returned
   * @param name the name of the field
   * @param throwException whether to throw exception on failing to find field or not
   * @return the <code>Field</code> object for the specified field in this class
   */
  public static Field field(Class<?> clazz, String name, boolean throwException) {
    return Reflective.field(clazz, name, throwException);
  }

  /**
   * Returns a <code>Field</code> object that reflects the specified declared field of the class or
   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter
   * is a <code>String</code> that specifies the simple name of the desired field. Throws a <code>
   * RuntimeException</code> when field is not found.
   *
   * @param clazz Class whose field is returned
   * @param name the name of the field
   * @return the <code>Field</code> object for the specified field in this class
   */
  public static Field field(Class<?> clazz, String name) {
    return Reflective.field(clazz, name);
  }

  /**
   * Returns a <code>Field</code> object that reflects the specified declared field of the class or
   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter
   * is a <code>String</code> that specifies the simple name of the desired field. Returns <code>
   * null</code> on not finding field if throwException parameter is <code>false</code>. Else throws
   * a <code>RuntimeException</code> when field is not found.
   *
   * @param clazz Class whose field is returned
   * @param name the name of the field
   * @param throwException whether to throw exception on failing to find field or not
   * @return the <code>Field</code> object for the specified field in this class
   */
  public static Field field(String clazz, String name, boolean throwException) {
    ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);
    return Reflective.field(classForName(clazz, callerLoader), name, throwException);
  }

  /**
   * Returns a <code>Field</code> object that reflects the specified declared field of the class or
   * interface represented by the given <code>Class</code> object. The <code>name</code> parameter
   * is a <code>String</code> that specifies the simple name of the desired field. Throws a <code>
   * RuntimeException</code> when field is not found.
   *
   * @param clazz Class whose field is returned
   * @param name the name of the field
   * @return the <code>Field</code> object for the specified field in this class
   */
  public static Field field(String clazz, String name) {
    ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);
    return Reflective.field(classForName(clazz, callerLoader), name);
  }

  // field value get methods

  /**
   * Gets the value of a static <code>byte</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>byte</code> field
   */
  public static byte getByte(Field field) {
    return Reflective.getByte(field);
  }

  /**
   * Gets the value of an instance <code>byte</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>byte</code> value from
   * @return the value of the <code>byte</code> field
   */
  public static byte getByte(Field field, Object obj) {
    return Reflective.getByte(field, obj);
  }

  /**
   * Gets the value of a static <code>short</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>short</code> field
   */
  public static short getShort(Field field) {
    return Reflective.getShort(field);
  }

  /**
   * Gets the value of an instance <code>short</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>short</code> value from
   * @return the value of the <code>short</code> field
   */
  public static short getShort(Field field, Object obj) {
    return Reflective.getShort(field, obj);
  }

  /**
   * Gets the value of a static <code>int</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>int</code> field
   */
  public static int getInt(Field field) {
    return Reflective.getInt(field);
  }

  /**
   * Gets the value of an instance <code>int</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>int</code> value from
   * @return the value of the <code>int</code> field
   */
  public static int getInt(Field field, Object obj) {
    return Reflective.getInt(field, obj);
  }

  /**
   * Gets the value of a static <code>long</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>long</code> field
   */
  public static long getLong(Field field) {
    return Reflective.getLong(field);
  }

  /**
   * Gets the value of an instance <code>long</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>long</code> value from
   * @return the value of the <code>long</code> field
   */
  public static long getLong(Field field, Object obj) {
    return Reflective.getLong(field, obj);
  }

  /**
   * Gets the value of a static <code>float</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>float</code> field
   */
  public static float getFloat(Field field) {
    return Reflective.getFloat(field);
  }

  /**
   * Gets the value of an instance <code>float</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>float</code> value from
   * @return the value of the <code>float</code> field
   */
  public static float getFloat(Field field, Object obj) {
    return Reflective.getFloat(field, obj);
  }

  /**
   * Gets the value of a static <code>double</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>double</code> field
   */
  public static double getDouble(Field field) {
    return Reflective.getDouble(field);
  }

  /**
   * Gets the value of an instance <code>double</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>double</code> value from
   * @return the value of the <code>double</code> field
   */
  public static double getDouble(Field field, Object obj) {
    return Reflective.getDouble(field, obj);
  }

  /**
   * Gets the value of a static <code>boolean</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>boolean</code> field
   */
  public static boolean getBoolean(Field field) {
    return Reflective.getBoolean(field);
  }

  /**
   * Gets the value of an instance <code>boolean</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>boolean</code> value from
   * @return the value of the <code>boolean</code> field
   */
  public static boolean getBoolean(Field field, Object obj) {
    return Reflective.getBoolean(field, obj);
  }

  /**
   * Gets the value of a static <code>char</code> field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the <code>char</code> field
   */
  public static char getChar(Field field) {
    return Reflective.getChar(field);
  }

  /**
   * Gets the value of an instance <code>char</code> field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the <code>char</code> value from
   * @return the value of the <code>char</code> field
   */
  public static char getChar(Field field, Object obj) {
    return Reflective.getChar(field, obj);
  }

  /**
   * Gets the value of a static reference field.
   *
   * @param field Field object whose value is returned.
   * @return the value of the reference field
   */
  public static Object get(Field field) {
    return Reflective.get(field);
  }

  /**
   * Gets the value of an instance reference field.
   *
   * @param field Field object whose value is returned.
   * @param obj the object to extract the reference value from
   * @return the value of the reference field
   */
  public static Object get(Field field, Object obj) {
    return Reflective.get(field, obj);
  }

  // weak, soft references

  /**
   * Creates and returns a weak reference to the given object.
   *
   * @param obj object for which a weak reference is created.
   * @return a weak reference to the given object.
   */
  public static WeakReference weakRef(Object obj) {
    return References.weakRef(obj);
  }

  /**
   * Creates and returns a soft reference to the given object.
   *
   * @param obj object for which a soft reference is created.
   * @return a soft reference to the given object.
   */
  public static SoftReference softRef(Object obj) {
    return References.softRef(obj);
  }

  /**
   * Returns the given reference object's referent. If the reference object has been cleared, either
   * by the program or by the garbage collector, then this method returns <code>null</code>.
   *
   * @param ref reference object whose referent is returned.
   * @return The object to which the reference refers, or <code>null</code> if the reference object
   *     has been cleared.
   */
  public static Object deref(Reference ref) {
    return References.deref(ref);
  }

  // probe point access

  /**
   * Returns the Class object of the currently probed (or traced) class.
   *
   * @deprecated Since 1.1. Use {@linkplain ProbeClassName} and {@linkplain Self} annotations
   *     instead
   */
  @Deprecated
  public static Class<?> probeClass() {
    return BTraceRuntime.getCallerClass(STACK_DEC);
  }

  /**
   * Returns the currently probed method's name.
   *
   * @deprecated Since 1.1. Use {@linkplain ProbeMethodName} annotation instead
   */
  @Deprecated
  public static String probeMethod() {
    StackTraceElement[] stack = Thread.currentThread().getStackTrace();
    if (stack.length >= 4) {
      return stack[3].getMethodName();
    } else {
      return null;
    }
  }

  /** Returns the currently probed source line number (if available). */
  public static int probeLine() {
    StackTraceElement[] stack = Thread.currentThread().getStackTrace();
    if (stack.length >= 4) {
      return stack[3].getLineNumber();
    } else {
      return -1;
    }
  }

  // printing values

  /**
   * Prints the given Map.
   *
   * @param map Map that is printed.
   */
  public static void printMap(Map map) {
    BTraceRuntime.printMap(map);
  }

  /**
   * Prints the given Map.
   *
   * @param name - the name of the map
   * @param data - the map data
   */
  public static void printStringMap(String name, Map<String, String> data) {
    BTraceRuntime.printStringMap(name, data);
  }

  /**
   * Prints the given Map.
   *
   * @param name - the name of the map
   * @param data - the map data
   */
  public static void printNumberMap(String name, Map<String, ? extends Number> data) {
    BTraceRuntime.printNumberMap(name, data);
  }

  /**
   * Prints a number.
   *
   * @param name - name of the number data
   * @param value - value of the numerical data
   */
  public static void printNumber(String name, Number value) {
    BTraceRuntime.printNumber(name, value);
  }

  /** Prints the elements of the given array as comma separated line bounded by '[' and ']'. */
  public static void printArray(Object[] array) {
    StringBuilder buf = new StringBuilder();
    buf.append('[');
    for (Object obj : array) {
      buf.append(Strings.str(obj));
      buf.append(", ");
    }
    buf.append(']');
    println(buf.toString());
  }

  /**
   * Print all instance fields of an object as name-value pairs. Includes the inherited fields as
   * well.
   *
   * @param obj Object whose fields are printed.
   */
  public static void printFields(Object obj) {
    Reflective.printFields(obj, false);
  }

  /**
   * Print all instance fields of an object as name-value pairs. Includes the inherited fields as
   * well. Optionally, prints name of the declaring class before each field - so that if same named
   * field in super class chain may be disambiguated.
   *
   * @param obj Object whose fields are printed.
   * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.
   */
  public static void printFields(Object obj, boolean classNamePrefix) {
    Reflective.printFields(obj, classNamePrefix);
  }

  /**
   * Print all static fields of the class as name-value pairs. Includes the inherited fields as
   * well.
   *
   * @param clazz Class whose static fields are printed.
   */
  public static void printStaticFields(Class<?> clazz) {
    Reflective.printStaticFields(clazz, false);
  }

  /**
   * Print all static fields of the class as name-value pairs. Includes the inherited fields as
   * well. Optionally, prints name of the declaring class before each field - so that if same named
   * field in super class chain may be disambiguated.
   *
   * @param clazz Class whose static fields are printed.
   * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.
   */
  public static void printStaticFields(Class<?> clazz, boolean classNamePrefix) {
    Reflective.printStaticFields(clazz, classNamePrefix);
  }

  // various print methods
  public static void print(Object obj) {
    BTraceRuntime.print(Strings.str(obj));
  }

  /**
   * Prints a boolean value. The string produced by <code>{@link
   * java.lang.String#valueOf(boolean)}</code> is sent to BTrace client for "printing".
   *
   * @param b The <code>boolean</code> to be printed
   */
  public static void print(boolean b) {
    print(Boolean.valueOf(b));
  }

  /**
   * Prints a character. The string produced by <code>{@link
   * java.lang.Character#valueOf(char)}</code> is sent to BTrace client for "printing".
   *
   * @param c The <code>char</code> to be printed
   */
  public static void print(char c) {
    print(Character.valueOf(c));
  }

  /**
   * Prints an integer. The string produced by <code>{@link
   * java.lang.String#valueOf(int)}</code> is sent to BTrace client for "printing".
   *
   * @param i The <code>int</code> to be printed
   * @see java.lang.Integer#toString(int)
   */
  public static void print(int i) {
    print(Integer.valueOf(i));
  }

  /**
   * Prints a long integer. The string produced by <code>{@link
   * java.lang.String#valueOf(long)}</code> is sent to BTrace client for "printing".
   *
   * @param l The <code>long</code> to be printed
   * @see java.lang.Long#toString(long)
   */
  public static void print(long l) {
    print(Long.valueOf(l));
  }

  /**
   * Prints a floating-point number. The string produced by <code>{@link
   * java.lang.String#valueOf(float)}</code> is sent to BTrace client for "printing".
   *
   * @param f The <code>float</code> to be printed
   * @see java.lang.Float#toString(float)
   */
  public static void print(float f) {
    print(Float.valueOf(f));
  }

  /**
   * Prints a double-precision floating-point number. The string produced by <code>
   * {@link java.lang.String#valueOf(double)}</code> is sent to BTrace client for "printing".
   *
   * @param d The <code>double</code> to be printed
   * @see java.lang.Double#toString(double)
   */
  public static void print(double d) {
    print(Double.valueOf(d));
  }

  /** Prints the given object and then prints a newline */
  public static void println(Object obj) {
    BTraceRuntime.println(Strings.str(obj));
  }

  /**
   * Prints a boolean and then terminate the line. This method behaves as though it invokes <code>
   * {@link #print(boolean)}</code> and then <code>{@link #println()}</code>.
   *
   * @param b The <code>boolean</code> to be printed
   */
  public static void println(boolean b) {
    println(Boolean.valueOf(b));
  }

  /**
   * Prints a character and then terminate the line. This method behaves as though it invokes <code>
   * {@link #print(char)}</code> and then <code>{@link #println()}</code>.
   *
   * @param c The <code>char</code> to be printed.
   */
  public static void println(char c) {
    println(Character.valueOf(c));
  }

  /**
   * Prints an integer and then terminate the line. This method behaves as though it invokes <code>
   * {@link #print(int)}</code> and then <code>{@link #println()}</code>.
   *
   * @param i The <code>int</code> to be printed.
   */
  public static void println(int i) {
    println(Integer.valueOf(i));
  }

  /**
   * Prints a long and then terminate the line. This method behaves as though it invokes <code>
   * {@link #print(long)}</code> and then <code>{@link #println()}</code>.
   *
   * @param l a The <code>long</code> to be printed.
   */
  public static void println(long l) {
    println(Long.valueOf(l));
  }

  /**
   * Prints a float and then terminate the line. This method behaves as though it invokes <code>
   * {@link #print(float)}</code> and then <code>{@link #println()}</code>.
   *
   * @param f The <code>float</code> to be printed.
   */
  public static void println(float f) {
    println(Float.valueOf(f));
  }

  /**
   * Prints a double and then terminate the line. This method behaves as though it invokes <code>
   * {@link #print(double)}</code> and then <code>{@link #println()}</code>.
   *
   * @param d The <code>double</code> to be printed.
   */
  public static void println(double d) {
    println(Double.valueOf(d));
  }

  /**
   * Terminates the current line by writing the line separator string. The line separator string is
   * defined by the system property <code>line.separator</code>, and is not necessarily a single
   * newline character (<code>'\n'</code>).
   */
  public static void println() {
    BTraceRuntime.println();
  }

  /**
   * Returns the start time of the Java virtual machine in milliseconds. This method returns the
   * approximate time when the Java virtual machine started.
   *
   * @return start time of the Java virtual machine in milliseconds.
   */
  public static long vmStartTime() {
    return Sys.VM.vmStartTime();
  }

  /**
   * Returns the uptime of the Java virtual machine in milliseconds.
   *
   * @return uptime of the Java virtual machine in milliseconds.
   */
  public static long vmUptime() {
    return Sys.VM.vmUptime();
  }

  /**
   * Returns the current time in milliseconds. Note that while the unit of time of the return value
   * is a millisecond, the granularity of the value depends on the underlying operating system and
   * may be larger. For example, many operating systems measure time in units of tens of
   * milliseconds.
   *
   * @return the difference, measured in milliseconds, between the current time and midnight,
   *     January 1, 1970 UTC.
   */
  public static long timeMillis() {
    return Time.millis();
  }

  /**
   * Returns the current value of the most precise available system timer, in nanoseconds.
   *
   * <p>This method can only be used to measure elapsed time and is not related to any other notion
   * of system or wall-clock time. The value returned represents nanoseconds since some fixed but
   * arbitrary time (perhaps in the future, so values may be negative). This method provides
   * nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how
   * frequently values change. Differences in successive calls that span greater than approximately
   * 292 years (2<sup>63</sup> nanoseconds) will not accurately compute elapsed time due to
   * numerical overflow.
   *
   * @return The current value of the system timer, in nanoseconds.
   */
  public static long timeNanos() {
    return Time.nanos();
  }

  /**
   * Generates a string getTimestamp (current date&amp;time)
   *
   * @param format The format to be used - see {@linkplain SimpleDateFormat}
   * @return Returns a string representing current date&amp;time
   * @since 1.1
   */
  public static String timestamp(String format) {
    return Time.timestamp(format);
  }

  /**
   * Generates a string getTimestamp (current date&amp;time) in the default system format
   *
   * @return Returns a string representing current date&amp;time
   * @since 1.1
   */
  public static String timestamp() {
    return Time.timestamp();
  }

  // String utilities
  public static boolean startsWith(String s, String start) {
    return Strings.startsWith(s, start);
  }

  public static boolean endsWith(String s, String end) {
    return Strings.endsWith(s, end);
  }

  /**
   * This is synonym to "concat".
   *
   * @see #concat(String, String)
   */
  public static String strcat(String str1, String str2) {
    return Strings.strcat(str1, str2);
  }

  /** Concatenates the specified strings together. */
  public static String concat(String str1, String str2) {
    return Strings.concat(str1, str2);
  }

  /**
   * Compares two strings lexicographically. The comparison is based on the Unicode value of each
   * character in the strings. The character sequence represented by the first <code>String</code>
   * object is compared lexicographically to the character sequence represented by the second
   * string. The result is a negative integer if the first <code>String</code> object
   * lexicographically precedes the second string. The result is a positive integer if the first
   * <code>String</code> object lexicographically follows the second string. The result is zero if
   * the strings are equal; <code>compareTo</code> returns <code>0</code> exactly when the {@link
   * String#equals(Object)} method would return <code>true</code>.
   */
  public static int compareTo(String str1, String str2) {
    return Strings.compareTo(str1, str2);
  }

  /**
   * This is synonym to "compareTo" method.
   *
   * @see #compareTo
   */
  public static int strcmp(String str1, String str2) {
    return Strings.strcmp(str1, str2);
  }

  /**
   * Compares two strings lexicographically, ignoring case differences. This method returns an
   * integer whose sign is that of calling <code>compareTo</code> with normalized versions of the
   * strings where case differences have been eliminated by calling <code>
   * Character.toLowerCase(Character.toUpperCase(character))</code> on each character.
   */
  public static int compareToIgnoreCase(String str1, String str2) {
    return Strings.compareToIgnoreCase(str1, str2);
  }

  /**
   * This is synonym to "compareToIgnoreCase".
   *
   * @see #compareToIgnoreCase
   */
  public static int stricmp(String str1, String str2) {
    return Strings.stricmp(str1, str2);
  }

  /** Find String within String */
  public static int strstr(String str1, String str2) {
    return Strings.strstr(str1, str2);
  }

  public static int indexOf(String str1, String str2) {
    return Strings.indexOf(str1, str2);
  }

  public static int lastIndexOf(String str1, String str2) {
    return Strings.lastIndexOf(str1, str2);
  }

  /** Substring */
  public static String substr(String str, int start, int length) {
    return Strings.substr(str, start, length);
  }

  public static String substr(String str, int start) {
    return Strings.substr(str, start);
  }

  /**
   * Returns the length of the given string. The length is equal to the number of <a
   * href="Character.html#unicode">Unicode code units</a> in the string.
   *
   * @param str String whose length is calculated.
   * @return the length of the sequence of characters represented by this object.
   */
  public static int length(String str) {
    return Strings.length(str);
  }

  /**
   * This is synonym for "length".
   *
   * @see #length(String)
   */
  public static int strlen(String str) {
    return Strings.strlen(str);
  }

  // regular expression matching

  /**
   * Compiles the given regular expression into a pattern.
   *
   * @param regex The expression to be compiled
   * @throws PatternSyntaxException If the expression's syntax is invalid
   */
  public static Pattern regexp(String regex) {
    return Strings.regexp(regex);
  }

  /**
   * This is synonym for "regexp".
   *
   * @see #regexp(String)
   */
  public static Pattern pattern(String regex) {
    return Strings.pattern(regex);
  }

  /**
   * Compiles the given regular expression into a pattern with the given flags.
   *
   * @param regex The expression to be compiled
   * @param flags Match flags, a bit mask that may include {@link Pattern#CASE_INSENSITIVE}, {@link
   *     Pattern#MULTILINE}, {@link Pattern#DOTALL}, {@link Pattern#UNICODE_CASE}, {@link
   *     Pattern#CANON_EQ}, {@link Pattern#UNIX_LINES}, {@link Pattern#LITERAL} and {@link
   *     Pattern#COMMENTS}
   * @throws IllegalArgumentException If bit values other than those corresponding to the defined
   *     match flags are set in <tt>flags</tt>
   * @throws PatternSyntaxException If the expression's syntax is invalid
   */
  public static Pattern regexp(String regex, int flags) {
    return Strings.regexp(regex, flags);
  }

  /**
   * This is synonym for "regexp".
   *
   * @see #regexp(String, int)
   */
  public static Pattern pattern(String regex, int flags) {
    return Strings.pattern(regex, flags);
  }

  /**
   * Matches the given (precompiled) regular expression and attempts to match the given input
   * against it.
   */
  public static boolean matches(Pattern regex, String input) {
    return Strings.matches(regex, input);
  }

  /**
   * Compiles the given regular expression and attempts to match the given input against it.
   *
   * <p>An invocation of this convenience method of the form
   *
   * <blockquote>
   *
   * <pre>
   * Pattern.matches(regex, input);</pre>
   *
   * </blockquote>
   *
   * <p>behaves in exactly the same way as the expression
   *
   * <blockquote>
   *
   * <pre>
   * Pattern.compile(regex).matcher(input).matches()</pre>
   *
   * </blockquote>
   *
   * <p>If a pattern is to be used multiple times, compiling it once and reusing it will be more
   * efficient than invoking this method each time.
   *
   * @param regex The expression to be compiled
   * @param input The character sequence to be matched
   * @throws PatternSyntaxException If the expression's syntax is invalid
   */
  public static boolean matches(String regex, String input) {
    return Strings.matches(regex, input);
  }

  // Numbers utilities

  /**
   * Returns a <code>double</code> value with a positive sign, greater than or equal to <code>0.0
   * </code> and less than <code>1.0</code>. Returned values are chosen pseudorandomly with
   * (approximately) uniform distribution from that range.
   */
  public static double random() {
    return Numbers.random();
  }

  /**
   * Returns the natural logarithm (base <i>e</i>) of a <code>double</code> value. Special cases:
   *
   * <ul>
   *   <li>If the argument is NaN or less than zero, then the result is NaN.
   *   <li>If the argument is positive infinity, then the result is positive infinity.
   *   <li>If the argument is positive zero or negative zero, then the result is negative infinity.
   * </ul>
   *
   * <p>The computed result must be within 1 ulp of the exact result. Results must be
   * semi-monotonic.
   *
   * @param a a value
   * @return the value ln&nbsp;<code>a</code>, the natural logarithm of <code>a</code>.
   */
  public static strictfp double log(double a) {
    return Numbers.log(a);
  }

  /**
   * Returns the base 10 logarithm of a <code>double</code> value. Special cases:
   *
   * <ul>
   *   <li>If the argument is NaN or less than zero, then the result is NaN.
   *   <li>If the argument is positive infinity, then the result is positive infinity.
   *   <li>If the argument is positive zero or negative zero, then the result is negative infinity.
   *   <li>If the argument is equal to 10<sup><i>n</i></sup> for integer <i>n</i>, then the result
   *       is <i>n</i>.
   * </ul>
   *
   * <p>The computed result must be within 1 ulp of the exact result. Results must be
   * semi-monotonic.
   *
   * @param a a value
   * @return the base 10 logarithm of <code>a</code>.
   */
  public static strictfp double log10(double a) {
    return Numbers.log10(a);
  }

  /**
   * Returns Euler's number <i>e</i> raised to the power of a <code>double</code> value. Special
   * cases:
   *
   * <ul>
   *   <li>If the argument is NaN, the result is NaN.
   *   <li>If the argument is positive infinity, then the result is positive infinity.
   *   <li>If the argument is negative infinity, then the result is positive zero.
   * </ul>
   *
   * <p>The computed result must be within 1 ulp of the exact result. Results must be
   * semi-monotonic.
   *
   * @param a the exponent to raise <i>e</i> to.
   * @return the value <i>e</i><sup><code>a</code></sup>, where <i>e</i> is the base of the natural
   *     logarithms.
   */
  public static strictfp double exp(double a) {
    return Numbers.exp(a);
  }

  /**
   * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false
   * </code> otherwise.
   *
   * @param d the value to be tested.
   * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.
   */
  public static boolean isNaN(double d) {
    return Numbers.isNaN(d);
  }

  /**
   * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false
   * </code> otherwise.
   *
   * @param f the value to be tested.
   * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.
   */
  public static boolean isNaN(float f) {
    return Numbers.isNaN(f);
  }

  /**
   * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>false
   * </code> otherwise.
   *
   * @param d the value to be tested.
   * @return <code>true</code> if the value of the argument is positive infinity or negative
   *     infinity; <code>false</code> otherwise.
   */
  public static boolean isInfinite(double d) {
    return Numbers.isInfinite(d);
  }

  /**
   * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>false
   * </code> otherwise.
   *
   * @param f the value to be tested.
   * @return <code>true</code> if the value of the argument is positive infinity or negative
   *     infinity; <code>false</code> otherwise.
   */
  public static boolean isInfinite(float f) {
    return Numbers.isInfinite(f);
  }

  // string parsing methods

  /**
   * Parses the string argument as a boolean. The <code>boolean</code> returned represents the value
   * <code>true</code> if the string argument is not <code>null</code> and is equal, ignoring case,
   * to the string {@code "true"}.
   *
   * <p>Example: {@code Boolean.parseBoolean("True")} returns <tt>true</tt>.<br>
   * Example: {@code Boolean.parseBoolean("yes")} returns <tt>false</tt>.
   *
   * @param s the <code>String</code> containing the boolean representation to be parsed
   * @return the boolean represented by the string argument
   */
  public static boolean parseBoolean(String s) {
    return Numbers.parseBoolean(s);
  }

  /**
   * Parses the string argument as a signed decimal <code>byte</code>. The characters in the string
   * must all be decimal digits, except that the first character may be an ASCII minus sign <code>
   * '-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting <code>byte
   * </code> value is returned.
   *
   * @param s a <code>String</code> containing the <code>byte</code> representation to be parsed
   * @return the <code>byte</code> value represented by the argument in decimal
   */
  public static byte parseByte(String s) {
    return Numbers.parseByte(s);
  }

  /**
   * Parses the string argument as a signed decimal <code>short</code>. The characters in the string
   * must all be decimal digits, except that the first character may be an ASCII minus sign <code>
   * '-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting <code>short
   * </code> value is returned.
   *
   * @param s a <code>String</code> containing the <code>short</code> representation to be parsed
   * @return the <code>short</code> value represented by the argument in decimal.
   */
  public static short parseShort(String s) {
    return Numbers.parseShort(s);
  }

  /**
   * Parses the string argument as a signed decimal integer. The characters in the string must all
   * be decimal digits, except that the first character may be an ASCII minus sign <code>'-'</code>
   * (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting integer value is
   * returned.
   *
   * @param s a <code>String</code> containing the <code>int</code> representation to be parsed
   * @return the integer value represented by the argument in decimal.
   */
  public static int parseInt(String s) {
    return Numbers.parseInt(s);
  }

  /**
   * Parses the string argument as a signed decimal <code>long</code>. The characters in the string
   * must all be decimal digits, except that the first character may be an ASCII minus sign <code>
   * '-'</code> (<code>&#92;u002D'</code>) to indicate a negative value. The resulting <code>long
   * </code> value is returned.
   *
   * <p>Note that neither the character <code>L</code> (<code>'&#92;u004C'</code>) nor <code>l
   * </code> (<code>'&#92;u006C'</code>) is permitted to appear at the end of the string as a type
   * indicator, as would be permitted in Java programming language source code.
   *
   * @param s a <code>String</code> containing the <code>long</code> representation to be parsed
   * @return the <code>long</code> represented by the argument in decimal.
   */
  public static long parseLong(String s) {
    return Numbers.parseLong(s);
  }

  /**
   * Returns a new <code>float</code> initialized to the value represented by the specified <code>
   * String</code>, as performed by the <code>valueOf</code> method of class <code>Float</code>.
   *
   * @param s the string to be parsed.
   * @return the <code>float</code> value represented by the string argument.
   */
  public static float parseFloat(String s) {
    return Numbers.parseFloat(s);
  }

  /**
   * Returns a new <code>double</code> initialized to the value represented by the specified <code>
   * String</code>, as performed by the <code>valueOf</code> methcod of class <code>Double</code>.
   *
   * @param s the string to be parsed.
   * @return the <code>double</code> value represented by the string argument.
   */
  public static double parseDouble(String s) {
    return Numbers.parseDouble(s);
  }

  // boxing methods

  /**
   * Returns a <tt>Boolean</tt> instance representing the specified <tt>boolean</tt> value. If the
   * specified <tt>boolean</tt> value is <tt>true</tt>, this method returns <tt>Boolean.TRUE</tt>;
   * if it is <tt>false</tt>, this method returns <tt>Boolean.FALSE</tt>.
   *
   * @param b a boolean value.
   * @return a <tt>Boolean</tt> instance representing <tt>b</tt>.
   */
  public static Boolean box(boolean b) {
    return Numbers.box(b);
  }

  /**
   * Returns a <tt>Character</tt> instance representing the specified <tt>char</tt> value.
   *
   * @param c a char value.
   * @return a <tt>Character</tt> instance representing <tt>c</tt>.
   */
  public static Character box(char c) {
    return Numbers.box(c);
  }

  /**
   * Returns a <tt>Byte</tt> instance representing the specified <tt>byte</tt> value.
   *
   * @param b a byte value.
   * @return a <tt>Byte</tt> instance representing <tt>b</tt>.
   */
  public static Byte box(byte b) {
    return Numbers.box(b);
  }

  /**
   * Returns a <tt>Short</tt> instance representing the specified <tt>short</tt> value.
   *
   * @param s a short value.
   * @return a <tt>Short</tt> instance representing <tt>s</tt>.
   */
  public static Short box(short s) {
    return Numbers.box(s);
  }

  /**
   * Returns a <tt>Integer</tt> instance representing the specified <tt>int</tt> value.
   *
   * @param i an <code>int</code> value.
   * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
   */
  public static Integer box(int i) {
    return Numbers.box(i);
  }

  /**
   * Returns a <tt>Long</tt> instance representing the specified <tt>long</tt> value.
   *
   * @param l a long value.
   * @return a <tt>Long</tt> instance representing <tt>l</tt>.
   */
  public static Long box(long l) {
    return Numbers.box(l);
  }

  /**
   * Returns a <tt>Float</tt> instance representing the specified <tt>float</tt> value.
   *
   * @param f a float value.
   * @return a <tt>Float</tt> instance representing <tt>f</tt>.
   */
  public static Float box(float f) {
    return Numbers.box(f);
  }

  /**
   * Returns a <tt>Double</tt> instance representing the specified <tt>double</tt> value.
   *
   * @param d a double value.
   * @return a <tt>Double</tt> instance representing <tt>d</tt>.
   */
  public static Double box(double d) {
    return Numbers.box(d);
  }

  // unboxing methods

  /**
   * Returns the value of the given <tt>Boolean</tt> object as a boolean primitive.
   *
   * @param b the Boolean object whose value is returned.
   * @return the primitive <code>boolean</code> value of the object.
   */
  public static boolean unbox(Boolean b) {
    return Numbers.unbox(b);
  }

  /**
   * Returns the value of the given <tt>Character</tt> object as a char primitive.
   *
   * @param ch the Character object whose value is returned.
   * @return the primitive <code>char</code> value of the object.
   */
  public static char unbox(Character ch) {
    return Numbers.unbox(ch);
  }

  /**
   * Returns the value of the specified Byte as a <code>byte</code>.
   *
   * @param b Byte that is unboxed
   * @return the byte value represented by the <code>Byte</code>.
   */
  public static byte unbox(Byte b) {
    return Numbers.unbox(b);
  }

  /**
   * Returns the short value represented by <code>Short</code>.
   *
   * @param s Short that is unboxed.
   * @return the short value represented by the <code>Short</code>.
   */
  public static short unbox(Short s) {
    return Numbers.unbox(s);
  }

  /**
   * Returns the value of represented by <code>Integer</code>.
   *
   * @param i Integer that is unboxed.
   * @return the int value represented by the <code>Integer</code>.
   */
  public static int unbox(Integer i) {
    return Numbers.unbox(i);
  }

  /**
   * Returns the long value represented by the specified <code>Long</code>.
   *
   * @param l Long to be unboxed.
   * @return the long value represented by the <code>Long</code>.
   */
  public static long unbox(Long l) {
    return Numbers.unbox(l);
  }

  /**
   * Returns the float value represented by the specified <code>Float</code>.
   *
   * @param f Float to be unboxed.
   * @return the float value represented by the <code>Float</code>.
   */
  public static float unbox(Float f) {
    return Numbers.unbox(f);
  }

  /**
   * Returns the double value represented by the specified <code>Double</code>.
   *
   * @param d Double to be unboxed.
   */
  public static double unbox(Double d) {
    return Numbers.unbox(d);
  }

  // primitive types to String conversion

  /**
   * Returns a <tt>String</tt> object representing the specified boolean. If the specified boolean
   * is <code>true</code>, then the string {@code "true"} will be returned, otherwise the string
   * {@code "false"} will be returned.
   *
   * @param b the boolean to be converted
   * @return the string representation of the specified <code>boolean</code>
   */
  public static String str(boolean b) {
    return Strings.str(b);
  }

  /**
   * Returns a <code>String</code> object representing the specified <code>char</code>. The result
   * is a string of length 1 consisting solely of the specified <code>char</code>.
   *
   * @param c the <code>char</code> to be converted
   * @return the string representation of the specified <code>char</code>
   */
  public static String str(char c) {
    return Strings.str(c);
  }

  /**
   * Returns a <code>String</code> object representing the specified integer. The argument is
   * converted to signed decimal representation and returned as a string.
   *
   * @param i an integer to be converted.
   * @return a string representation of the argument in base&nbsp;10.
   */
  public static String str(int i) {
    return Strings.str(i);
  }

  /**
   * Returns a string representation of the integer argument as an unsigned integer in base&nbsp;16.
   *
   * <p>The unsigned integer value is the argument plus 2<sup>32</sup> if the argument is negative;
   * otherwise, it is equal to the argument. This value is converted to a string of ASCII digits in
   * hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the unsigned magnitude is
   * zero, it is represented by a single zero character <code>'0'</code> (<code>'&#92;u0030'</code>
   * ); otherwise, the first character of the representation of the unsigned magnitude will not be
   * the zero character. The following characters are used as hexadecimal digits:
   *
   * <blockquote>
   *
   * <pre>
   * 0123456789abcdef
   * </pre>
   *
   * </blockquote>
   *
   * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and <code>
   * '&#92;u0061'</code> through <code>'&#92;u0066'</code>.
   *
   * @param i an integer to be converted to a string.
   * @return the string representation of the unsigned integer value represented by the argument in
   *     hexadecimal (base&nbsp;16).
   */
  public static String toHexString(int i) {
    return Strings.toHexString(i);
  }

  /**
   * Returns a <code>String</code> object representing the specified <code>long</code>. The argument
   * is converted to signed decimal representation and returned as a string.
   *
   * @param l a <code>long</code> to be converted.
   * @return a string representation of the argument in base&nbsp;10.
   */
  public static String str(long l) {
    return Strings.str(l);
  }

  /**
   * Returns a string representation of the <code>long</code> argument as an unsigned integer in
   * base&nbsp;16.
   *
   * <p>The unsigned <code>long</code> value is the argument plus 2<sup>64</sup> if the argument is
   * negative; otherwise, it is equal to the argument. This value is converted to a string of ASCII
   * digits in hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the unsigned
   * magnitude is zero, it is represented by a single zero character <code>'0'</code> (<code>
   * '&#92;u0030'</code>); otherwise, the first character of the representation of the unsigned
   * magnitude will not be the zero character. The following characters are used as hexadecimal
   * digits:
   *
   * <blockquote>
   *
   * <pre>
   * 0123456789abcdef
   * </pre>
   *
   * </blockquote>
   *
   * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and <code>
   * '&#92;u0061'</code> through <code>'&#92;u0066'</code>.
   *
   * @param l a <code>long</code> to be converted to a string.
   * @return the string representation of the unsigned <code>long</code> value represented by the
   *     argument in hexadecimal (base&nbsp;16).
   */
  public static String toHexString(long l) {
    return Strings.toHexString(l);
  }

  /**
   * Returns a string representation of the <code>float</code> argument. All characters mentioned
   * below are ASCII characters.
   *
   * <ul>
   *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.
   *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute value)
   *       of the argument. If the sign is negative, the first character of the result is '<code>-
   *       </code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character appears
   *       in the result. As for the magnitude <i>m</i>:
   *       <ul>
   *         <li>If <i>m</i> is infinity, it is represented by the characters <code>"Infinity"
   *             </code>; thus, positive infinity produces the result <code>"Infinity"</code> and
   *             negative infinity produces the result <code>"-Infinity"</code>.
   *         <li>If <i>m</i> is zero, it is represented by the characters <code>"0.0"</code>; thus,
   *             negative zero produces the result <code>"-0.0"</code> and positive zero produces
   *             the result <code>"0.0"</code>.
   *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than
   *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in decimal
   *             form with no leading zeroes, followed by '<code>.</code>' (<code>'&#92;u002E'
   *             </code>), followed by one or more decimal digits representing the fractional part
   *             of <i>m</i>.
   *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to
   *             10<sup>7</sup>, then it is represented in so-called "computerized scientific
   *             notation." Let <i>n</i> be the unique integer such that 10<sup><i>n</i> </sup>&lt;=
   *             <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the mathematically
   *             exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1 &lt;= <i>a</i> &lt;
   *             10. The magnitude is then represented as the integer part of <i>a</i>, as a single
   *             decimal digit, followed by '<code>.</code>' (<code>'&#92;u002E'</code>), followed
   *             by decimal digits representing the fractional part of <i>a</i>, followed by the
   *             letter '<code>E</code>' (<code>'&#92;u0045'</code>), followed by a representation
   *             of <i>n</i> as a decimal integer, as produced by the method <code>{@link
   *      java.lang.Integer#toString(int)}</code>.
   *       </ul>
   * </ul>
   *
   * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must be
   * at least one digit to represent the fractional part, and beyond that as many, but only as many,
   * more digits as are needed to uniquely distinguish the argument value from adjacent values of
   * type <code>float</code>. That is, suppose that <i>x</i> is the exact mathematical value
   * represented by the decimal representation produced by this method for a finite nonzero argument
   * <i>f</i>. Then <i>f</i> must be the <code>float</code> value nearest to <i>x</i>; or, if two
   * <code>float</code> values are equally close to <i>x</i>, then <i>f</i> must be one of them and
   * the least significant bit of the significand of <i>f</i> must be <code>0</code>.
   *
   * <p>
   *
   * @param f the float to be converted.
   * @return a string representation of the argument.
   */
  public static String str(float f) {
    return Strings.str(f);
  }

  /**
   * Returns a string representation of the <code>double</code> argument. All characters mentioned
   * below are ASCII characters.
   *
   * <ul>
   *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.
   *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute value)
   *       of the argument. If the sign is negative, the first character of the result is '<code>-
   *       </code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character appears
   *       in the result. As for the magnitude <i>m</i>:
   *       <ul>
   *         <li>If <i>m</i> is infinity, it is represented by the characters <code>"Infinity"
   *             </code>; thus, positive infinity produces the result <code>"Infinity"</code> and
   *             negative infinity produces the result <code>"-Infinity"</code>.
   *         <li>If <i>m</i> is zero, it is represented by the characters <code>"0.0"</code>; thus,
   *             negative zero produces the result <code>"-0.0"</code> and positive zero produces
   *             the result <code>"0.0"</code>.
   *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than
   *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in decimal
   *             form with no leading zeroes, followed by '<code>.</code>' (<code>'&#92;u002E'
   *             </code>), followed by one or more decimal digits representing the fractional part
   *             of <i>m</i>.
   *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to
   *             10<sup>7</sup>, then it is represented in so-called "computerized scientific
   *             notation." Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup> &lt;=
   *             <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the mathematically
   *             exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1 &lt;= <i>a</i> &lt;
   *             10. The magnitude is then represented as the integer part of <i>a</i>, as a single
   *             decimal digit, followed by '<code>.</code>' (<code>'&#92;u002E'</code>), followed
   *             by decimal digits representing the fractional part of <i>a</i>, followed by the
   *             letter '<code>E</code>' (<code>'&#92;u0045'</code>), followed by a representation
   *             of <i>n</i> as a decimal integer, as produced by the method {@link
   *             Integer#toString(int)}.
   *       </ul>
   * </ul>
   *
   * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must be
   * at least one digit to represent the fractional part, and beyond that as many, but only as many,
   * more digits as are needed to uniquely distinguish the argument value from adjacent values of
   * type <code>double</code>. That is, suppose that <i>x</i> is the exact mathematical value
   * represented by the decimal representation produced by this method for a finite nonzero argument
   * <i>d</i>. Then <i>d</i> must be the <code>double</code> value nearest to <i>x</i>; or if two
   * <code>double</code> values are equally close to <i>x</i>, then <i>d</i> must be one of them and
   * the least significant bit of the significand of <i>d</i> must be <code>0</code>.
   *
   * <p>
   *
   * @param d the <code>double</code> to be converted.
   * @return a string representation of the argument.
   */
  public static String str(double d) {
    return Strings.str(d);
  }

  /**
   * Exits the BTrace session -- note that the particular client's tracing session exits and not the
   * observed/traced program! After exit call, the trace action method terminates immediately and no
   * other probe action method (of that client) will be called after that.
   *
   * @param exitCode exit value sent to the client
   */
  public static void exit(int exitCode) {
    Sys.exit(exitCode);
  }

  /**
   * This is same as exit(int) except that the exit code is zero.
   *
   * @see #exit(int)
   */
  public static void exit() {
    Sys.exit();
  }

  /** accessing jvmstat (perf) int counter */
  public static long perfInt(String name) {
    return Counters.perfInt(name);
  }

  /** accessing jvmstat (perf) long counter */
  public static long perfLong(String name) {
    return Counters.perfLong(name);
  }

  /** accessing jvmstat (perf) String counter */
  public static String perfString(String name) {
    return Counters.perfString(name);
  }

  /** Operating on maps */
  // Create a new map
  public static <K, V> Map<K, V> newHashMap() {
    return Collections.newHashMap();
  }

  public static <K, V> Map<K, V> newWeakMap() {
    return Collections.newWeakMap();
  }

  public static <V> Deque<V> newDeque() {
    return Collections.newDeque();
  }

  // get a particular item from a Map
  public static <K, V> V get(Map<K, V> map, K key) {
    return Collections.get(map, key);
  }

  // check whether an item exists
  public static <K, V> boolean containsKey(Map<K, V> map, K key) {
    return Collections.containsKey(map, key);
  }

  public static <K, V> boolean containsValue(Map<K, V> map, V value) {
    return Collections.containsValue(map, value);
  }

  // put a particular item into a Map
  public static <K, V> V put(Map<K, V> map, K key, V value) {
    return Collections.put(map, key, value);
  }

  // remove a particular item from a Map
  public static <K, V> V remove(Map<K, V> map, K key) {
    return Collections.remove(map, key);
  }

  // clear all items from a Map
  public static <K, V> void clear(Map<K, V> map) {
    Collections.clear(map);
  }

  // return the size of a Map
  public static <K, V> int size(Map<K, V> map) {
    return Collections.size(map);
  }

  public static <K, V> boolean isEmpty(Map<K, V> map) {
    return Collections.isEmpty(map);
  }

  // operations on collections
  public static <E> int size(Collection<E> coll) {
    return Collections.size(coll);
  }

  public static <E> boolean isEmpty(Collection<E> coll) {
    return Collections.isEmpty(coll);
  }

  public static <E> boolean contains(Collection<E> coll, Object obj) {
    return Collections.contains(coll, obj);
  }

  public static boolean contains(Object[] array, Object value) {
    return Collections.contains(array, value);
  }

  // operations on Deque
  public static <V> void push(Deque<V> queue, V value) {
    Collections.push(queue, value);
  }

  public static <V> V poll(Deque<V> queue) {
    return Collections.poll(queue);
  }

  public static <V> V peek(Deque<V> queue) {
    return Collections.peek(queue);
  }

  public static <V> void addLast(Deque<V> queue, V value) {
    Collections.addLast(queue, value);
  }

  public static <V> V peekFirst(Deque<V> queue) {
    return Collections.peekFirst(queue);
  }

  public static <V> V peekLast(Deque<V> queue) {
    return Collections.peekLast(queue);
  }

  public static <V> V removeLast(Deque<V> queue) {
    return Collections.removeLast(queue);
  }

  public static <V> V removeFirst(Deque<V> queue) {
    return Collections.removeFirst(queue);
  }

  /**
   * Returns the current instrumentation level.
   *
   * <p>Instrumentation level is used in evaluating {@linkplain OnMethod#enableAt()} expressions to
   * enable/disable the probe handler.
   *
   * @return the instrumentation level (non negative integer)
   * @since 1.3.4
   */
  public static int getInstrumentationLevel() {
    return BTraceRuntime.getInstrumentationLevel();
  }

  /**
   * Sets the current instrumentation level.
   *
   * <p>Instrumentation level is used in evaluating {@linkplain OnMethod#enableAt()} expressions to
   * enable/disable the probe handler.
   *
   * @param level an arbitrary non negative integer number
   * @since 1.3.4
   */
  public static void setInstrumentationLevel(int level) {
    if (level >= 0) {
      BTraceRuntime.setInstrumentationLevel(level);
    }
  }

  /**
   * Returns n'th command line argument. <code>null</code> if not available.
   *
   * @param n command line argument index
   * @return n'th command line argument
   */
  public static String $(int n) {
    return Sys.$(n);
  }

  /** Returns the process id of the currently BTrace'd process. */
  public static int getpid() {
    return Sys.getpid();
  }

  /** Returns the number of command line arguments. */
  public static int $length() {
    return Sys.$length();
  }

  // atomic stuff

  /**
   * Creates a new AtomicInteger with the given initial value.
   *
   * @param initialValue the initial value
   */
  public static AtomicInteger newAtomicInteger(int initialValue) {
    return Atomic.newAtomicInteger(initialValue);
  }

  /**
   * Gets the current value of the given AtomicInteger.
   *
   * @param ai AtomicInteger whose value is returned.
   * @return the current value
   */
  public static int get(AtomicInteger ai) {
    return Atomic.get(ai);
  }

  /**
   * Sets to the given value to the given AtomicInteger.
   *
   * @param ai AtomicInteger whose value is set.
   * @param newValue the new value
   */
  public static void set(AtomicInteger ai, int newValue) {
    Atomic.set(ai, newValue);
  }

  /**
   * Eventually sets to the given value to the given AtomicInteger.
   *
   * @param ai AtomicInteger whose value is lazily set.
   * @param newValue the new value
   */
  public static void lazySet(AtomicInteger ai, int newValue) {
    Atomic.lazySet(ai, newValue);
  }

  /**
   * Atomically sets the value of given AtomitInteger to the given updated value if the current
   * value {@code ==} the expected value.
   *
   * @param ai AtomicInteger whose value is compared and set.
   * @param expect the expected value
   * @param update the new value
   * @return true if successful. False return indicates that the actual value was not equal to the
   *     expected value.
   */
  public static boolean compareAndSet(AtomicInteger ai, int expect, int update) {
    return Atomic.compareAndSet(ai, expect, update);
  }

  /**
   * Atomically sets the value to the given updated value if the current value {@code ==} the
   * expected value.
   *
   * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> and does not provide
   * ordering guarantees, so is only rarely an appropriate alternative to {@code compareAndSet}.
   *
   * @param ai AtomicInteger whose value is weakly compared and set.
   * @param expect the expected value
   * @param update the new value
   * @return true if successful.
   */
  public static boolean weakCompareAndSet(AtomicInteger ai, int expect, int update) {
    return Atomic.weakCompareAndSet(ai, expect, update);
  }

  /**
   * Atomically increments by one the current value of given AtomicInteger.
   *
   * @param ai AtomicInteger that is incremented.
   * @return the previous value
   */
  public static int getAndIncrement(AtomicInteger ai) {
    return Atomic.getAndIncrement(ai);
  }

  /**
   * Atomically decrements by one the current value of given AtomicInteger.
   *
   * @param ai AtomicInteger that is decremented.
   * @return the previous value
   */
  public static int getAndDecrement(AtomicInteger ai) {
    return Atomic.getAndDecrement(ai);
  }

  /**
   * Atomically increments by one the current value of given AtomicInteger.
   *
   * @param ai AtomicInteger that is incremented.
   * @return the updated value
   */
  public static int incrementAndGet(AtomicInteger ai) {
    return Atomic.incrementAndGet(ai);
  }

  /**
   * Atomically decrements by one the current value of given AtomicInteger.
   *
   * @param ai AtomicInteger whose value is decremented.
   * @return the updated value
   */
  public static int decrementAndGet(AtomicInteger ai) {
    return Atomic.decrementAndGet(ai);
  }

  /**
   * Atomically adds the given value to the current value.
   *
   * @param ai AtomicInteger whose value is added to.
   * @param delta the value to add
   * @return the previous value
   */
  public static int getAndAdd(AtomicInteger ai, int delta) {
    return Atomic.getAndAdd(ai, delta);
  }

  /**
   * Atomically adds the given value to the current value.
   *
   * @param ai AtomicInteger whose value is added to.
   * @param delta the value to add
   * @return the updated value
   */
  public static int addAndGet(AtomicInteger ai, int delta) {
    return Atomic.addAndGet(ai, delta);
  }

  /**
   * Atomically sets to the given value and returns the old value.
   *
   * @param ai AtomicInteger whose value is set.
   * @param newValue the new value
   * @return the previous value
   */
  public static int getAndSet(AtomicInteger ai, int newValue) {
    return Atomic.getAndSet(ai, newValue);
  }

  /**
   * Creates a new AtomicLong with the given initial value.
   *
   * @param initialValue the initial value
   */
  public static AtomicLong newAtomicLong(long initialValue) {
    return Atomic.newAtomicLong(initialValue);
  }

  /**
   * Gets the current value the given AtomicLong.
   *
   * @param al AtomicLong whose value is returned.
   * @return the current value
   */
  public static long get(AtomicLong al) {
    return Atomic.get(al);
  }

  /**
   * Sets to the given value.
   *
   * @param al AtomicLong whose value is set.
   * @param newValue the new value
   */
  public static void set(AtomicLong al, long newValue) {
    Atomic.set(al, newValue);
  }

  /**
   * Eventually sets to the given value to the given AtomicLong.
   *
   * @param al AtomicLong whose value is set.
   * @param newValue the new value
   */
  public static void lazySet(AtomicLong al, long newValue) {
    Atomic.lazySet(al, newValue);
  }

  /**
   * Atomically sets the value to the given updated value if the current value {@code ==} the
   * expected value.
   *
   * @param al AtomicLong whose value is compared and set.
   * @param expect the expected value
   * @param update the new value
   * @return true if successful. False return indicates that the actual value was not equal to the
   *     expected value.
   */
  public static boolean compareAndSet(AtomicLong al, long expect, long update) {
    return Atomic.compareAndSet(al, expect, update);
  }

  /**
   * Atomically sets the value to the given updated value if the current value {@code ==} the
   * expected value.
   *
   * <p>May fail spuriously and does not provide ordering guarantees, so is only rarely an
   * appropriate alternative to {@code compareAndSet}.
   *
   * @param al AtomicLong whose value is compared and set.
   * @param expect the expected value
   * @param update the new value
   * @return true if successful.
   */
  public static boolean weakCompareAndSet(AtomicLong al, long expect, long update) {
    return Atomic.weakCompareAndSet(al, expect, update);
  }

  /**
   * Atomically increments by one the current value.
   *
   * @param al AtomicLong whose value is incremented.
   * @return the previous value
   */
  public static long getAndIncrement(AtomicLong al) {
    return Atomic.getAndIncrement(al);
  }

  /**
   * Atomically decrements by one the current value.
   *
   * @param al AtomicLong whose value is decremented.
   * @return the previous value
   */
  public static long getAndDecrement(AtomicLong al) {
    return Atomic.getAndDecrement(al);
  }

  /**
   * Atomically increments by one the current value.
   *
   * @param al AtomicLong whose value is incremented.
   * @return the updated value
   */
  public static long incrementAndGet(AtomicLong al) {
    return Atomic.incrementAndGet(al);
  }

  /**
   * Atomically decrements by one the current value.
   *
   * @param al AtomicLong whose value is decremented.
   * @return the updated value
   */
  public static long decrementAndGet(AtomicLong al) {
    return Atomic.decrementAndGet(al);
  }

  /**
   * Atomically adds the given value to the current value.
   *
   * @param al AtomicLong whose value is added to.
   * @param delta the value to add
   * @return the previous value
   */
  public static long getAndAdd(AtomicLong al, long delta) {
    return Atomic.getAndAdd(al, delta);
  }

  /**
   * Atomically adds the given value to the current value.
   *
   * @param al AtomicLong whose value is added to
   * @param delta the value to add
   * @return the updated value
   */
  public static long addAndGet(AtomicLong al, long delta) {
    return Atomic.addAndGet(al, delta);
  }

  /**
   * Atomically sets to the given value and returns the old value.
   *
   * @param al AtomicLong that is set.
   * @param newValue the new value
   * @return the previous value
   */
  public static long getAndSet(AtomicLong al, long newValue) {
    return Atomic.getAndSet(al, newValue);
  }

  /**
   * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.
   *
   * @see #dtraceProbe(String, String, int, int)
   */
  public static int dtraceProbe(String str1, String str2) {
    return D.probe(str1, str2);
  }

  /**
   * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.
   *
   * @see #dtraceProbe(String, String, int, int)
   */
  public static int dtraceProbe(String str1, String str2, int i1) {
    return D.probe(str1, str2, i1);
  }

  /**
   * BTrace to DTrace communication channel. Raise DTrace USDT probe from BTrace.
   *
   * @param str1 first String param to DTrace probe
   * @param str2 second String param to DTrace probe
   * @param i1 first int param to DTrace probe
   * @param i2 second int param to DTrace probe
   */
  public static int dtraceProbe(String str1, String str2, int i1, int i2) {
    return D.probe(str1, str2, i1, i2);
  }

  /**
   * Gets the system property indicated by the specified key.
   *
   * @param key the name of the system property.
   * @return the string value of the system property, or <code>null</code> if there is no property
   *     with that key.
   * @throws NullPointerException if <code>key</code> is <code>null</code>.
   * @throws IllegalArgumentException if <code>key</code> is empty.
   */
  public static String property(String key) {
    return Sys.Env.property(key);
  }

  /**
   * Returns all Sys properties.
   *
   * @return the system properties
   */
  public static Properties properties() {
    return Sys.Env.properties();
  }

  /** Prints all Sys properties. */
  public static void printProperties() {
    Sys.Env.printProperties();
  }

  /**
   * Gets the value of the specified environment variable. An environment variable is a
   * system-dependent external named value.
   *
   * @param name the name of the environment variable
   * @return the string value of the variable, or <code>null</code> if the variable is not defined
   *     in the system environment
   * @throws NullPointerException if <code>name</code> is <code>null</code>
   */
  public static String getenv(String name) {
    return Sys.Env.getenv(name);
  }

  /**
   * Returns an unmodifiable string map view of the current system environment. The environment is a
   * system-dependent mapping from names to values which is passed from parent to child processes.
   *
   * @return the environment as a map of variable names to values
   */
  public static Map<String, String> getenv() {
    return Sys.Env.getenv();
  }

  /** Prints all system environment values. */
  public static void printEnv() {
    Sys.Env.printEnv();
  }

  /**
   * Returns the number of processors available to the Java virtual machine.
   *
   * <p>This value may change during a particular invocation of the virtual machine. Applications
   * that are sensitive to the number of available processors should therefore occasionally poll
   * this property and adjust their resource usage appropriately.
   *
   * @return the maximum number of processors available to the virtual machine; never smaller than
   *     one
   */
  public static long availableProcessors() {
    return Sys.Env.availableProcessors();
  }

  // memory usage

  /**
   * Returns the amount of free memory in the Java Virtual Machine. Calling the <code>gc</code>
   * method may result in increasing the value returned by <code>freeMemory.</code>
   *
   * @return an approximation to the total amount of memory currently available for future allocated
   *     objects, measured in bytes.
   */
  public static long freeMemory() {
    return Sys.Memory.freeMemory();
  }

  /**
   * Returns the total amount of memory in the Java virtual machine. The value returned by this
   * method may vary over time, depending on the host environment.
   *
   * <p>Note that the amount of memory required to hold an object of any given type may be
   * implementation-dependent.
   *
   * @return the total amount of memory currently available for current and future objects, measured
   *     in bytes.
   */
  public static long totalMemory() {
    return Sys.Memory.totalMemory();
  }

  /**
   * Returns the maximum amount of memory that the Java virtual machine will attempt to use. If
   * there is no inherent limit then the value {@link java.lang.Long#MAX_VALUE} will be returned.
   *
   * @return the maximum amount of memory that the virtual machine will attempt to use, measured in
   *     bytes
   */
  public static long maxMemory() {
    return Sys.Memory.maxMemory();
  }

  /** Returns heap memory usage */
  public static MemoryUsage heapUsage() {
    return Sys.Memory.heapUsage();
  }

  /** Returns non-heap memory usage */
  public static MemoryUsage nonHeapUsage() {
    return Sys.Memory.nonHeapUsage();
  }

  /**
   * Returns the amount of memory in bytes that the Java virtual machine initially requests from the
   * operating system for memory management.
   */
  public static long init(MemoryUsage mu) {
    return Sys.Memory.init(mu);
  }

  /**
   * Returns the amount of memory in bytes that is committed for the Java virtual machine to use.
   * This amount of memory is guaranteed for the Java virtual machine to use.
   */
  public static long committed(MemoryUsage mu) {
    return Sys.Memory.committed(mu);
  }

  /**
   * Returns the maximum amount of memory in bytes that can be used for memory management. This
   * method returns -1 if the maximum memory size is undefined.
   */
  public static long max(MemoryUsage mu) {
    return Sys.Memory.max(mu);
  }

  /** Returns the amount of used memory in bytes. */
  public static long used(MemoryUsage mu) {
    return Sys.Memory.used(mu);
  }

  /** Returns the approximate number of objects for which finalization is pending. */
  public static long finalizationCount() {
    return Sys.Memory.finalizationCount();
  }

  /**
   * Returns the input arguments passed to the Java virtual machine which does not include the
   * arguments to the <tt>main</tt> method. This method returns an empty list if there is no input
   * argument to the Java virtual machine.
   *
   * <p>Some Java virtual machine implementations may take input arguments from multiple different
   * sources: for examples, arguments passed from the application that launches the Java virtual
   * machine such as the 'java' command, environment variables, configuration files, etc.
   *
   * <p>Typically, not all command-line options to the 'java' command are passed to the Java virtual
   * machine. Thus, the returned input arguments may not include all command-line options.
   *
   * @return a list of <tt>String</tt> objects; each element is an argument passed to the Java
   *     virtual machine.
   */
  public static List<String> vmArguments() {
    return Sys.VM.vmArguments();
  }

  /**
   * Prints VM input arguments list.
   *
   * @see #vmArguments
   */
  public static void printVmArguments() {
    Sys.VM.printVmArguments();
  }

  /**
   * Returns the Java virtual machine implementation version. This method is equivalent to
   * <b>Sys.getProperty("java.vm.version")</b>.
   *
   * @return the Java virtual machine implementation version.
   */
  public static String vmVersion() {
    return Sys.VM.vmVersion();
  }

  /**
   * Tests if the Java virtual machine supports the boot class path mechanism used by the bootstrap
   * class loader to search for class files.
   *
   * @return <tt>true</tt> if the Java virtual machine supports the class path mechanism;
   *     <tt>false</tt> otherwise.
   */
  public static boolean isBootClassPathSupported() {
    return Sys.VM.isBootClassPathSupported();
  }

  /**
   * Returns the boot class path that is used by the bootstrap class loader to search for class
   * files.
   *
   * <p>Multiple paths in the boot class path are separated by the path separator character of the
   * platform on which the Java virtual machine is running.
   *
   * <p>A Java virtual machine implementation may not support the boot class path mechanism for the
   * bootstrap class loader to search for class files. The {@link #isBootClassPathSupported} method
   * can be used to determine if the Java virtual machine supports this method.
   *
   * @return the boot class path.
   * @throws java.lang.UnsupportedOperationException if the Java virtual machine does not support
   *     this operation.
   */
  public static String bootClassPath() {
    return Sys.VM.bootClassPath();
  }

  /**
   * Returns the Java class path that is used by the system class loader to search for class files.
   * This method is equivalent to <b>Sys.getProperty("java.class.path")</b>.
   *
   * @return the Java class path.
   */
  public static String classPath() {
    return Sys.VM.classPath();
  }

  /**
   * Returns the Java library path. This method is equivalent to
   * <b>Sys.getProperty("java.library.path")</b>.
   *
   * <p>Multiple paths in the Java library path are separated by the path separator character of the
   * platform of the Java virtual machine being monitored.
   *
   * @return the Java library path.
   */
  public static String libraryPath() {
    return Sys.VM.libraryPath();
  }

  /**
   * Returns the current number of live threads including both daemon and non-daemon threads.
   *
   * @return the current number of live threads.
   */
  public static long threadCount() {
    return Sys.VM.threadCount();
  }

  /**
   * Returns the peak live thread count since the Java virtual machine started or peak was reset.
   *
   * @return the peak live thread count.
   */
  public static long peakThreadCount() {
    return Sys.VM.peakThreadCount();
  }

  /**
   * Returns the total number of threads created and also started since the Java virtual machine
   * started.
   *
   * @return the total number of threads started.
   */
  public static long totalStartedThreadCount() {
    return Sys.VM.totalStartedThreadCount();
  }

  /**
   * Returns the current number of live daemon threads.
   *
   * @return the current number of live daemon threads.
   */
  public static long daemonThreadCount() {
    return Sys.VM.daemonThreadCount();
  }

  /**
   * Returns the total CPU time for the current thread in nanoseconds. The returned value is of
   * nanoseconds precision but not necessarily nanoseconds accuracy. If the implementation
   * distinguishes between user mode time and system mode time, the returned CPU time is the amount
   * of time that the current thread has executed in user mode or system mode.
   */
  public static long currentThreadCpuTime() {
    return Sys.VM.currentThreadCpuTime();
  }

  /**
   * Returns the CPU time that the current thread has executed in user mode in nanoseconds. The
   * returned value is of nanoseconds precision but not necessarily nanoseconds accuracy.
   */
  public static long currentThreadUserTime() {
    return Sys.VM.currentThreadUserTime();
  }

  /**
   * Returns the total amount of time spent in GarbageCollection up to this point since the
   * application was started.
   *
   * @return Returns the amount of overall time spent in GC
   */
  public static long getTotalGcTime() {
    return Sys.Memory.getTotalGcTime();
  }

  /**
   * Returns an implementation-specific approximation of the amount of storage consumed by the
   * specified object. The result may include some or all of the object's overhead, and thus is
   * useful for comparison within an implementation but not between implementations.
   *
   * <p>The estimate may change during a single invocation of the JVM.
   *
   * @param objectToSize the object to size
   * @return an implementation-specific approximation of the amount of storage consumed by the
   *     specified object
   * @throws java.lang.NullPointerException if the supplied Object is <code>null</code>.
   */
  public static long sizeof(Object objectToSize) {
    return BTraceRuntime.sizeof(objectToSize);
  }

  /**
   * Dump the snapshot of the Java heap to a file in hprof binary format. Only the live objects are
   * dumped. Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/ directory is
   * created. Under that directory, a file of given fileName is created.
   *
   * @param fileName name of the file to which heap is dumped
   */
  public static void dumpHeap(String fileName) {
    Sys.Memory.dumpHeap(fileName);
  }

  /**
   * Dump the snapshot of the Java heap to a file in hprof binary format. Under the current dir of
   * traced app, ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a
   * file of given fileName is created.
   *
   * @param fileName name of the file to which heap is dumped
   * @param live flag that tells whether only live objects are to be dumped or all objects are to be
   *     dumped.
   */
  public static void dumpHeap(String fileName, boolean live) {
    Sys.Memory.dumpHeap(fileName, live);
  }

  /**
   * Runs the garbage collector.
   *
   * <p>Calling the <code>gc</code> method suggests that the Java Virtual Machine expend effort
   * toward recycling unused objects in order to make the memory they currently occupy available for
   * quick reuse. When control returns from the method call, the Java Virtual Machine has made a
   * best effort to reclaim space from all discarded objects. This method calls Sys.gc() to perform
   * GC.
   */
  public static void gc() {
    Sys.Memory.gc();
  }

  /**
   * Runs the finalization methods of any objects pending finalization.
   *
   * <p>Calling this method suggests that the Java Virtual Machine expend effort toward running the
   * <code>finalize</code> methods of objects that have been found to be discarded but whose <code>
   * finalize</code> methods have not yet been run. When control returns from the method call, the
   * Java Virtual Machine has made a best effort to complete all outstanding finalizations. This
   * method calls Sys.runFinalization() to run finalization.
   */
  public static void runFinalization() {
    Sys.Memory.runFinalization();
  }

  /**
   * Serialize a given object into the given file. Under the current dir of traced app,
   * ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a file of given
   * fileName is created.
   *
   * @param obj object that has to be serialized.
   * @param fileName name of the file to which the object is serialized.
   */
  public static void serialize(Serializable obj, String fileName) {
    Export.serialize(obj, fileName);
  }

  /**
   * Creates an XML document to persist the tree of the all transitively reachable objects from
   * given "root" object.
   */
  public static String toXML(Object obj) {
    return Export.toXML(obj);
  }

  /**
   * Writes an XML document to persist the tree of the all the transitively reachable objects from
   * the given "root" object. Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/
   * directory is created. Under that directory, a file of the given fileName is created.
   */
  public static void writeXML(Object obj, String fileName) {
    Export.writeXML(obj, fileName);
  }

  /**
   * Writes a .dot document to persist the tree of the all the transitively reachable objects from
   * the given "root" object. .dot documents can be viewed by Graphviz application
   * (www.graphviz.org) Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/
   * directory is created. Under that directory, a file of the given fileName is created.
   *
   * @since 1.1
   */
  public static void writeDOT(Object obj, String fileName) {
    Export.writeDOT(obj, fileName);
  }

  // speculative buffer management

  /**
   * Returns an identifier for a new speculative buffer.
   *
   * @return new speculative buffer id
   */
  public static int speculation() {
    return Speculation.speculation();
  }

  /**
   * Sets current speculative buffer id.
   *
   * @param id the speculative buffer id
   */
  public static void speculate(int id) {
    Speculation.speculate(id);
  }

  /**
   * Commits the speculative buffer associated with id.
   *
   * @param id the speculative buffer id
   */
  public static void commit(int id) {
    Speculation.commit(id);
  }

  /**
   * Discards the speculative buffer associated with id.
   *
   * @param id the speculative buffer id
   */
  public static void discard(int id) {
    Speculation.discard(id);
  }

  // aggregation support

  /**
   * Creates a new aggregation based on the given aggregation function type.
   *
   * @param type the aggregating function to be performed on the data being added to the
   *     aggregation.
   */
  public static Aggregation newAggregation(AggregationFunction type) {
    return Aggregations.newAggregation(type);
  }

  /**
   * Creates a grouping aggregation key with the provided value. The value must be a String or
   * Number type.
   *
   * @param element1 the value of the aggregation key
   */
  public static AggregationKey newAggregationKey(Object element1) {
    return Aggregations.newAggregationKey(element1);
  }

  /**
   * Creates a composite grouping aggregation key with the provided values. The values must be
   * String or Number types.
   *
   * @param element1 the first element of the composite aggregation key
   * @param element2 the second element of the composite aggregation key
   */
  public static AggregationKey newAggregationKey(Object element1, Object element2) {
    return Aggregations.newAggregationKey(element1, element2);
  }

  /**
   * Creates a composite grouping aggregation key with the provided values. The values must be
   * String or Number types.
   *
   * @param element1 the first element of the composite aggregation key
   * @param element2 the second element of the composite aggregation key
   * @param element3 the third element of the composite aggregation key
   */
  public static AggregationKey newAggregationKey(
      Object element1, Object element2, Object element3) {
    return Aggregations.newAggregationKey(element1, element2, element3);
  }

  /**
   * Creates a composite grouping aggregation key with the provided values. The values must be
   * String or Number types.
   *
   * @param element1 the first element of the composite aggregation key
   * @param element2 the second element of the composite aggregation key
   * @param element3 the third element of the composite aggregation key
   * @param element4 the fourth element of the composite aggregation key
   */
  public static AggregationKey newAggregationKey(
      Object element1, Object element2, Object element3, Object element4) {
    return Aggregations.newAggregationKey(element1, element2, element3, element4);
  }

  /**
   * Adds a value to the aggregation with no grouping key. This method should be used when the
   * aggregation is to calculate only a single aggregated value.
   *
   * @param aggregation the aggregation to which the value should be added
   */
  public static void addToAggregation(Aggregation aggregation, long value) {
    Aggregations.addToAggregation(aggregation, value);
  }

  /**
   * Adds a value to the aggregation with a grouping key. This method should be used when the
   * aggregation should effectively perform a "group by" on the key value. The aggregation will
   * calculate a separate aggregated value for each unique aggregation key.
   *
   * @param aggregation the aggregation to which the value should be added
   * @param key the grouping aggregation key
   */
  public static void addToAggregation(Aggregation aggregation, AggregationKey key, long value) {
    Aggregations.addToAggregation(aggregation, key, value);
  }

  /**
   * Resets values within the aggregation to the default. This will affect all values within the
   * aggregation when multiple aggregation keys have been used.
   *
   * @param aggregation the aggregation to be cleared
   */
  public static void clearAggregation(Aggregation aggregation) {
    Aggregations.clearAggregation(aggregation);
  }

  /**
   * Removes all aggregated values from the aggregation except for the largest or smallest <code>
   * abs(count)</code> elements.
   *
   * <p>If <code>count</code> is positive, the largest aggregated values in the aggregation will be
   * preserved. If <code>count</code> is negative the smallest values will be preserved. If <code>
   * count</code> is zero then all elements will be removed.
   *
   * <p>Behavior is intended to be similar to the dtrace <code>trunc()</code> function.
   *
   * @param aggregation the aggregation to be truncated
   * @param count the number of elements to preserve. If negative, the smallest <code>abs(count)
   *     </code> elements are preserved.
   */
  public static void truncateAggregation(Aggregation aggregation, int count) {
    Aggregations.truncateAggregation(aggregation, count);
  }

  /** Prints the aggregation. */
  public static void printAggregation(String name, Aggregation aggregation) {
    Aggregations.printAggregation(name, aggregation);
  }

  /**
   * Prints aggregation using the provided format
   *
   * @param name The name of the aggregation to be used in the textual output
   * @param aggregation The aggregation to print
   * @param format The format to use. It mimics {@linkplain String#format(java.lang.String,
   *     java.lang.Object[]) } behaviour with the addition of the ability to address the key title
   *     as a 0-indexed item
   * @see String#format(java.lang.String, java.lang.Object[])
   * @since 1.1
   */
  public static void printAggregation(String name, Aggregation aggregation, String format) {
    Aggregations.printAggregation(name, aggregation, format);
  }

  // Internals only below this point
  private static void checkStatic(Field field) {
    if (!Modifier.isStatic(field.getModifiers())) {
      throw new IllegalArgumentException(field.getName() + " is not a static field");
    }
  }

  private static Field getField(Class<?> clazz, String name, boolean throwError) {
    return AccessController.doPrivileged(
        (PrivilegedAction<Field>)
            () -> {
              Field field = null;
              Class<?> cClass = clazz;
              try {
                while (Objects.isNull(field) && Objects.nonNull(cClass)) {
                  try {
                    field = cClass.getDeclaredField(name);
                  } catch (NoSuchFieldException exp) {
                    // Ignore the exception and continue looking for the parent class
                    cClass = cClass.getSuperclass();
                  }
                }

                if (Objects.isNull(cClass)) {
                  throw new NoSuchFieldException(name);
                }

                field.setAccessible(true);

                return field;
              } catch (Exception exp) {
                if (throwError) {
                  throw translate(exp);
                } else {
                  return null;
                }
              }
            });
  }

  private static Field[] getAllFields(Class<?> clazz) {
    return AccessController.doPrivileged(
        (PrivilegedAction<Field[]>)
            () -> {
              try {
                Field[] fields = clazz.getDeclaredFields();
                for (Field f : fields) {
                  f.setAccessible(true);
                }
                return fields;
              } catch (Exception exp) {
                throw translate(exp);
              }
            });
  }

  private static void addFieldValues(
      StringBuilder buf, Object obj, Class<?> clazz, boolean classNamePrefix) {
    Field[] fields = getAllFields(clazz);
    for (Field f : fields) {
      int modifiers = f.getModifiers();
      if (!Modifier.isStatic(modifiers)) {
        if (classNamePrefix) {
          buf.append(f.getDeclaringClass().getName());
          buf.append('.');
        }
        buf.append(f.getName());
        buf.append('=');
        try {
          buf.append(Strings.str(f.get(obj)));
        } catch (Exception exp) {
          throw translate(exp);
        }
        buf.append(", ");
      }
    }
    Class<?> sc = clazz.getSuperclass();
    if (sc != null) {
      addFieldValues(buf, obj, sc, classNamePrefix);
    }
  }

  private static void addStaticFieldValues(
      StringBuilder buf, Class<?> clazz, boolean classNamePrefix) {
    Field[] fields = getAllFields(clazz);
    for (Field f : fields) {
      int modifiers = f.getModifiers();
      if (Modifier.isStatic(modifiers)) {
        if (classNamePrefix) {
          buf.append(f.getDeclaringClass().getName());
          buf.append('.');
        }
        buf.append(f.getName());
        buf.append('=');
        try {
          buf.append(Strings.str(f.get(null)));
        } catch (Exception exp) {
          throw translate(exp);
        }
        buf.append(", ");
      }
    }
    Class<?> sc = clazz.getSuperclass();
    if (sc != null) {
      addStaticFieldValues(buf, sc, classNamePrefix);
    }
  }

  private static RuntimeException translate(Exception exp) {
    if (exp instanceof RuntimeException) {
      return (RuntimeException) exp;
    } else {
      return new RuntimeException(exp);
    }
  }

  /** ******** Namespaced methods ***************** */

  /*
   * Wraps the threads related BTrace utility methods
   * @since 1.2
   */
  public static class Threads {
    // Thread and stack access

    /**
     * Tests whether this thread has been interrupted. The <i>interrupted status</i> of the thread
     * is unaffected by this method.
     *
     * <p>A thread interruption ignored because a thread was not alive at the time of the interrupt
     * will be reflected by this method returning false.
     *
     * @return <code>true</code> if this thread has been interrupted; <code>false</code> otherwise.
     */
    public static boolean isInteruppted() {
      return Thread.currentThread().isInterrupted();
    }

    /** Prints the java stack trace of the current thread. */
    public static void jstack() {
      jstack(1, -1);
    }

    /**
     * Prints the java stack trace of the current thread. But, atmost given number of frames.
     *
     * @param numFrames number of frames to be printed. When this is negative all frames are
     *     printed.
     */
    public static void jstack(int numFrames) {
      // passing '5' to skip our own frames to generate stack trace
      jstack(1, numFrames);
    }

    private static void jstack(int strip, int numFrames) {
      if (numFrames == 0) return;
      StackTraceElement[] st = Thread.currentThread().getStackTrace();
      BTraceRuntime.stackTrace(st, strip + 2, numFrames);
    }

    /** Prints Java stack traces of all the Java threads. */
    public static void jstackAll() {
      jstackAll(1, -1);
    }

    /**
     * Prints Java stack traces of all the Java threads. But, at most given number of frames.
     *
     * @param numFrames number of frames to be printed. When this is negative all frames are
     *     printed.
     */
    public static void jstackAll(int numFrames) {
      jstackAll(1, numFrames);
    }

    private static void jstackAll(int strip, int numFrames) {
      BTraceRuntime.stackTraceAll(numFrames);
    }

    /**
     * Returns the stack trace of current thread as a String.
     *
     * @return the stack trace as a String.
     */
    public static String jstackStr() {
      return jstackStr(1, -1);
    }

    /**
     * Returns the stack trace of the current thread as a String but includes atmost the given
     * number of frames.
     *
     * @param numFrames number of frames to be included. When this is negative all frames are
     *     included.
     * @return the stack trace as a String.
     */
    public static String jstackStr(int numFrames) {
      if (numFrames == 0) {
        return "";
      }
      return jstackStr(1, numFrames);
    }

    private static String jstackStr(int strip, int numFrames) {
      if (numFrames == 0) {
        return "";
      }
      StackTraceElement[] st = Thread.currentThread().getStackTrace();
      return BTraceRuntime.stackTraceStr(st, strip + 2, numFrames);
    }

    /**
     * Returns the stack traces of all Java threads as a String.
     *
     * @return the stack traces as a String.
     */
    public static String jstackAllStr() {
      return jstackAllStr(-1);
    }

    /**
     * Returns atmost given number of frames in stack traces of all threads as a String.
     *
     * @param numFrames number of frames to be included. When this is negative all frames are
     *     included.
     * @return the stack traces as a String.
     */
    public static String jstackAllStr(int numFrames) {
      if (numFrames == 0) {
        return "";
      }
      return BTraceRuntime.stackTraceAllStr(numFrames);
    }

    /**
     * Prints the stack trace of the given exception object.
     *
     * @param exception throwable for which stack trace is printed.
     */
    public static void jstack(Throwable exception) {
      jstack(exception, -1);
    }

    /**
     * Prints the stack trace of the given exception object. But, prints atmost given number of
     * frames.
     *
     * @param exception throwable for which stack trace is printed.
     * @param numFrames maximum number of frames to be printed.
     */
    public static void jstack(Throwable exception, int numFrames) {
      if (numFrames == 0) {
        return;
      }
      StackTraceElement[] st = exception.getStackTrace();
      println(exception.toString());
      BTraceRuntime.stackTrace("\t", st, 0, numFrames);
      Throwable cause = exception.getCause();
      while (cause != null) {
        print("Caused by: ");
        println(cause.toString());
        st = cause.getStackTrace();
        BTraceRuntime.stackTrace("\t", st, 0, numFrames);
        cause = cause.getCause();
      }
    }

    /**
     * Returns the stack trace of given exception object as a String.
     *
     * @param exception the throwable for which stack trace is returned.
     */
    public static String jstackStr(Throwable exception) {
      return jstackStr(exception, -1);
    }

    /**
     * Returns stack trace of given exception object as a String.
     *
     * @param exception throwable for which stack trace is returned.
     * @param numFrames maximum number of frames to be returned.
     */
    public static String jstackStr(Throwable exception, int numFrames) {
      if (numFrames == 0) {
        return "";
      }
      StackTraceElement[] st = exception.getStackTrace();
      StringBuilder buf = new StringBuilder();
      buf.append(Strings.str(exception));
      buf.append(BTraceRuntime.stackTraceStr("\t", st, 0, numFrames));
      Throwable cause = exception.getCause();
      while (cause != null) {
        buf.append("Caused by:");
        st = cause.getStackTrace();
        buf.append(BTraceRuntime.stackTraceStr("\t", st, 0, numFrames));
        cause = cause.getCause();
      }
      return buf.toString();
    }

    /**
     * Returns a reference to the currently executing thread object.
     *
     * @return the currently executing thread.
     */
    public static Thread currentThread() {
      return Thread.currentThread();
    }

    /**
     * Returns the identifier of the given Thread. The thread ID is a positive <tt>long</tt> number
     * generated when the given thread was created. The thread ID is unique and remains unchanged
     * during its lifetime. When a thread is terminated, the thread ID may be reused.
     */
    public static long threadId(Thread thread) {
      return thread.getId();
    }

    /**
     * Returns the state of the given thread. This method is designed for use in monitoring of the
     * system state, not for synchronization control.
     */
    public static Thread.State threadState(Thread thread) {
      return thread.getState();
    }

    /**
     * Returns <tt>true</tt> if and only if the current thread holds the monitor lock on the
     * specified object.
     *
     * <p>This method is designed to allow a program to assert that the current thread already holds
     * a specified lock:
     *
     * <pre>
     *     assert Thread.holdsLock(obj);
     * </pre>
     *
     * @param obj the object on which to test lock ownership
     * @return <tt>true</tt> if the current thread holds the monitor lock on the specified object.
     * @throws NullPointerException if obj is <tt>null</tt>
     */
    public static boolean holdsLock(Object obj) {
      return Thread.holdsLock(obj);
    }

    /** Prints the Java level deadlocks detected (if any). */
    public static void deadlocks() {
      deadlocks(true);
    }

    /**
     * Prints deadlocks detected (if any). Optionally prints stack trace of the deadlocked threads.
     *
     * @param stackTrace boolean flag to specify whether to print stack traces of deadlocked threads
     *     or not.
     */
    public static void deadlocks(boolean stackTrace) {
      BTraceRuntime.deadlocks(stackTrace);
    }

    /**
     * Returns the name of the given thread.
     *
     * @param thread thread whose name is returned
     */
    public static String name(Thread thread) {
      return thread.getName();
    }
  }

  /*
   * Wraps the strings related BTrace utility methods
   * @since 1.2
   */
  public static class Strings {
    public static boolean startsWith(String s, String start) {
      return s.startsWith(start);
    }

    public static boolean endsWith(String s, String end) {
      return s.endsWith(end);
    }

    /**
     * This is synonym to "concat".
     *
     * @see #concat(String, String)
     */
    public static String strcat(String str1, String str2) {
      return concat(str1, str2);
    }

    /** Concatenates the specified strings together. */
    public static String concat(String str1, String str2) {
      return str1.concat(str2);
    }

    /**
     * Compares two strings lexicographically. The comparison is based on the Unicode value of each
     * character in the strings. The character sequence represented by the first <code>String</code>
     * object is compared lexicographically to the character sequence represented by the second
     * string. The result is a negative integer if the first <code>String</code> object
     * lexicographically precedes the second string. The result is a positive integer if the first
     * <code>String</code> object lexicographically follows the second string. The result is zero if
     * the strings are equal; <code>compareTo</code> returns <code>0</code> exactly when the {@link
     * String#equals(Object)} method would return <code>true</code>.
     */
    public static int compareTo(String str1, String str2) {
      return str1.compareTo(str2);
    }

    /**
     * This is synonym to "compareTo" method.
     *
     * @see #compareTo
     */
    public static int strcmp(String str1, String str2) {
      return str1.compareTo(str2);
    }

    /**
     * Compares two strings lexicographically, ignoring case differences. This method returns an
     * integer whose sign is that of calling <code>compareTo</code> with normalized versions of the
     * strings where case differences have been eliminated by calling <code>
     * Character.toLowerCase(Character.toUpperCase(character))</code> on each character.
     */
    public static int compareToIgnoreCase(String str1, String str2) {
      return str1.compareToIgnoreCase(str2);
    }

    /**
     * This is synonym to "compareToIgnoreCase".
     *
     * @see #compareToIgnoreCase
     */
    public static int stricmp(String str1, String str2) {
      return str1.compareToIgnoreCase(str2);
    }

    /** Find String within String */
    public static int strstr(String str1, String str2) {
      return str1.indexOf(str2);
    }

    public static int indexOf(String str1, String str2) {
      return str1.indexOf(str2);
    }

    public static int lastIndexOf(String str1, String str2) {
      return str1.lastIndexOf(str2);
    }

    /** Substring */
    public static String substr(String str, int start, int length) {
      return str.substring(start, length);
    }

    public static String substr(String str, int start) {
      return str.substring(start);
    }

    /**
     * Returns the length of the given string. The length is equal to the number of <a
     * href="Character.html#unicode">Unicode code units</a> in the string.
     *
     * @param str String whose length is calculated.
     * @return the length of the sequence of characters represented by this object.
     */
    public static int length(String str) {
      return str.length();
    }

    /**
     * This is synonym for "length".
     *
     * @see #length(String)
     */
    public static int strlen(String str) {
      return str.length();
    }

    // regular expression matching

    /**
     * Compiles the given regular expression into a pattern.
     *
     * @param regex The expression to be compiled
     * @throws PatternSyntaxException If the expression's syntax is invalid
     */
    public static Pattern regexp(String regex) {
      return Pattern.compile(regex);
    }

    /**
     * This is synonym for "regexp".
     *
     * @see #regexp(String)
     */
    public static Pattern pattern(String regex) {
      return regexp(regex);
    }

    /**
     * Compiles the given regular expression into a pattern with the given flags.
     *
     * @param regex The expression to be compiled
     * @param flags Match flags, a bit mask that may include {@link Pattern#CASE_INSENSITIVE},
     *     {@link Pattern#MULTILINE}, {@link Pattern#DOTALL}, {@link Pattern#UNICODE_CASE}, {@link
     *     Pattern#CANON_EQ}, {@link Pattern#UNIX_LINES}, {@link Pattern#LITERAL} and {@link
     *     Pattern#COMMENTS}
     * @throws IllegalArgumentException If bit values other than those corresponding to the defined
     *     match flags are set in <tt>flags</tt>
     * @throws PatternSyntaxException If the expression's syntax is invalid
     */
    public static Pattern regexp(String regex, int flags) {
      return Pattern.compile(regex, flags);
    }

    /**
     * This is synonym for "regexp".
     *
     * @see #regexp(String, int)
     */
    public static Pattern pattern(String regex, int flags) {
      return regexp(regex, flags);
    }

    /**
     * Matches the given (precompiled) regular expression and attempts to match the given input
     * against it.
     */
    public static boolean matches(Pattern regex, String input) {
      return regex.matcher(input).matches();
    }

    /**
     * Compiles the given regular expression and attempts to match the given input against it.
     *
     * <p>An invocation of this convenience method of the form
     *
     * <blockquote>
     *
     * <pre>
     * Pattern.matches(regex, input);</pre>
     *
     * </blockquote>
     *
     * <p>behaves in exactly the same way as the expression
     *
     * <blockquote>
     *
     * <pre>
     * Pattern.compile(regex).matcher(input).matches()</pre>
     *
     * </blockquote>
     *
     * <p>If a pattern is to be used multiple times, compiling it once and reusing it will be more
     * efficient than invoking this method each time.
     *
     * @param regex The expression to be compiled
     * @param input The character sequence to be matched
     * @throws PatternSyntaxException If the expression's syntax is invalid
     */
    public static boolean matches(String regex, String input) {
      return Pattern.matches(regex, input);
    }

    /**
     * Returns a <tt>String</tt> object representing the specified boolean. If the specified boolean
     * is <code>true</code>, then the string {@code "true"} will be returned, otherwise the string
     * {@code "false"} will be returned.
     *
     * @param b the boolean to be converted
     * @return the string representation of the specified <code>boolean</code>
     */
    public static String str(boolean b) {
      return Boolean.toString(b);
    }

    /**
     * Returns a <code>String</code> object representing the specified <code>char</code>. The result
     * is a string of length 1 consisting solely of the specified <code>char</code>.
     *
     * @param c the <code>char</code> to be converted
     * @return the string representation of the specified <code>char</code>
     */
    public static String str(char c) {
      return Character.toString(c);
    }

    /**
     * Returns a <code>String</code> object representing the specified integer. The argument is
     * converted to signed decimal representation and returned as a string.
     *
     * @param i an integer to be converted.
     * @return a string representation of the argument in base&nbsp;10.
     */
    public static String str(int i) {
      return Integer.toString(i);
    }

    /**
     * Returns a string representation of the integer argument as an unsigned integer in
     * base&nbsp;16.
     *
     * <p>The unsigned integer value is the argument plus 2<sup>32</sup> if the argument is
     * negative; otherwise, it is equal to the argument. This value is converted to a string of
     * ASCII digits in hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the
     * unsigned magnitude is zero, it is represented by a single zero character <code>'0'</code> (
     * <code>'&#92;u0030'</code>); otherwise, the first character of the representation of the
     * unsigned magnitude will not be the zero character. The following characters are used as
     * hexadecimal digits:
     *
     * <blockquote>
     *
     * <pre>
     * 0123456789abcdef
     * </pre>
     *
     * </blockquote>
     *
     * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and
     * <code>'&#92;u0061'</code> through <code>'&#92;u0066'</code>.
     *
     * @param i an integer to be converted to a string.
     * @return the string representation of the unsigned integer value represented by the argument
     *     in hexadecimal (base&nbsp;16).
     */
    public static String toHexString(int i) {
      return Integer.toHexString(i);
    }

    /**
     * Returns a <code>String</code> object representing the specified <code>long</code>. The
     * argument is converted to signed decimal representation and returned as a string.
     *
     * @param l a <code>long</code> to be converted.
     * @return a string representation of the argument in base&nbsp;10.
     */
    public static String str(long l) {
      return Long.toString(l);
    }

    /**
     * Returns a string representation of the object. In general, the <code>toString</code> method
     * returns a string that "textually represents" this object. The result should be a concise but
     * informative representation that is easy for a person to read. For bootstrap classes, returns
     * the result of calling Object.toString() override. For non-bootstrap classes, default
     * toString() value [className@hashCode] is returned.
     *
     * @param obj the object whose string representation is returned
     * @return a string representation of the given object.
     */
    public static String str(Object obj) {
      if (obj == null) {
        return "null";
      } else if (obj instanceof String) {
        return (String) obj;
      } else if (obj.getClass().getClassLoader() == null) {
        try {
          return obj.toString();
        } catch (NullPointerException e) {
          // NPE can be thrown from inside the toString() method we have no control over
          return "null";
        }
      } else {
        return identityStr(obj);
      }
    }

    /**
     * Returns a string representation of the <code>long</code> argument as an unsigned integer in
     * base&nbsp;16.
     *
     * <p>The unsigned <code>long</code> value is the argument plus 2<sup>64</sup> if the argument
     * is negative; otherwise, it is equal to the argument. This value is converted to a string of
     * ASCII digits in hexadecimal (base&nbsp;16) with no extra leading <code>0</code>s. If the
     * unsigned magnitude is zero, it is represented by a single zero character <code>'0'</code> (
     * <code>'&#92;u0030'</code>); otherwise, the first character of the representation of the
     * unsigned magnitude will not be the zero character. The following characters are used as
     * hexadecimal digits:
     *
     * <blockquote>
     *
     * <pre>
     * 0123456789abcdef
     * </pre>
     *
     * </blockquote>
     *
     * These are the characters <code>'&#92;u0030'</code> through <code>'&#92;u0039'</code> and
     * <code>'&#92;u0061'</code> through <code>'&#92;u0066'</code>.
     *
     * @param l a <code>long</code> to be converted to a string.
     * @return the string representation of the unsigned <code>long</code> value represented by the
     *     argument in hexadecimal (base&nbsp;16).
     */
    public static String toHexString(long l) {
      return Long.toHexString(l);
    }

    /**
     * Returns a string representation of the <code>float</code> argument. All characters mentioned
     * below are ASCII characters.
     *
     * <ul>
     *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.
     *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute
     *       value) of the argument. If the sign is negative, the first character of the result is '
     *       <code>-</code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character
     *       appears in the result. As for the magnitude <i>m</i>:
     *       <ul>
     *         <li>If <i>m</i> is infinity, it is represented by the characters <code>"Infinity"
     *             </code>; thus, positive infinity produces the result <code>"Infinity"</code> and
     *             negative infinity produces the result <code>"-Infinity"</code>.
     *         <li>If <i>m</i> is zero, it is represented by the characters <code>"0.0"</code>;
     *             thus, negative zero produces the result <code>"-0.0"</code> and positive zero
     *             produces the result <code>"0.0"</code>.
     *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than
     *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in
     *             decimal form with no leading zeroes, followed by '<code>.</code>' (<code>
     *             '&#92;u002E'</code>), followed by one or more decimal digits representing the
     *             fractional part of <i>m</i>.
     *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to
     *             10<sup>7</sup>, then it is represented in so-called "computerized scientific
     *             notation." Let <i>n</i> be the unique integer such that 10<sup><i>n</i>
     *             </sup>&lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
     *             mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1
     *             &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the integer part of
     *             <i>a</i>, as a single decimal digit, followed by '<code>.</code>' (<code>
     *             '&#92;u002E'</code>), followed by decimal digits representing the fractional part
     *             of <i>a</i>, followed by the letter '<code>E</code>' (<code>'&#92;u0045'</code>),
     *             followed by a representation of <i>n</i> as a decimal integer, as produced by the
     *             method <code>{@link
     *      java.lang.Integer#toString(int)}</code>.
     *       </ul>
     * </ul>
     *
     * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must
     * be at least one digit to represent the fractional part, and beyond that as many, but only as
     * many, more digits as are needed to uniquely distinguish the argument value from adjacent
     * values of type <code>float</code>. That is, suppose that <i>x</i> is the exact mathematical
     * value represented by the decimal representation produced by this method for a finite nonzero
     * argument <i>f</i>. Then <i>f</i> must be the <code>float</code> value nearest to <i>x</i>;
     * or, if two <code>float</code> values are equally close to <i>x</i>, then <i>f</i> must be one
     * of them and the least significant bit of the significand of <i>f</i> must be <code>0</code>.
     *
     * <p>
     *
     * @param f the float to be converted.
     * @return a string representation of the argument.
     */
    public static String str(float f) {
      return Float.toString(f);
    }

    /**
     * Returns a string representation of the <code>double</code> argument. All characters mentioned
     * below are ASCII characters.
     *
     * <ul>
     *   <li>If the argument is NaN, the result is the string &quot;<code>NaN</code>&quot;.
     *   <li>Otherwise, the result is a string that represents the sign and magnitude (absolute
     *       value) of the argument. If the sign is negative, the first character of the result is '
     *       <code>-</code>' (<code>'&#92;u002D'</code>); if the sign is positive, no sign character
     *       appears in the result. As for the magnitude <i>m</i>:
     *       <ul>
     *         <li>If <i>m</i> is infinity, it is represented by the characters <code>"Infinity"
     *             </code>; thus, positive infinity produces the result <code>"Infinity"</code> and
     *             negative infinity produces the result <code>"-Infinity"</code>.
     *         <li>If <i>m</i> is zero, it is represented by the characters <code>"0.0"</code>;
     *             thus, negative zero produces the result <code>"-0.0"</code> and positive zero
     *             produces the result <code>"0.0"</code>.
     *         <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less than
     *             10<sup>7</sup>, then it is represented as the integer part of <i>m</i>, in
     *             decimal form with no leading zeroes, followed by '<code>.</code>' (<code>
     *             '&#92;u002E'</code>), followed by one or more decimal digits representing the
     *             fractional part of <i>m</i>.
     *         <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or equal to
     *             10<sup>7</sup>, then it is represented in so-called "computerized scientific
     *             notation." Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
     *             &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
     *             mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so that 1
     *             &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the integer part of
     *             <i>a</i>, as a single decimal digit, followed by '<code>.</code>' (<code>
     *             '&#92;u002E'</code>), followed by decimal digits representing the fractional part
     *             of <i>a</i>, followed by the letter '<code>E</code>' (<code>'&#92;u0045'</code>),
     *             followed by a representation of <i>n</i> as a decimal integer, as produced by the
     *             method {@link Integer#toString(int)}.
     *       </ul>
     * </ul>
     *
     * How many digits must be printed for the fractional part of <i>m</i> or <i>a</i>? There must
     * be at least one digit to represent the fractional part, and beyond that as many, but only as
     * many, more digits as are needed to uniquely distinguish the argument value from adjacent
     * values of type <code>double</code>. That is, suppose that <i>x</i> is the exact mathematical
     * value represented by the decimal representation produced by this method for a finite nonzero
     * argument <i>d</i>. Then <i>d</i> must be the <code>double</code> value nearest to <i>x</i>;
     * or if two <code>double</code> values are equally close to <i>x</i>, then <i>d</i> must be one
     * of them and the least significant bit of the significand of <i>d</i> must be <code>0</code>.
     *
     * <p>
     *
     * @param d the <code>double</code> to be converted.
     * @return a string representation of the argument.
     */
    public static String str(double d) {
      return Double.toString(d);
    }

    /**
     * Safely creates a new instance of an appendable string buffer <br>
     *
     * @param threadSafe Specifies whether the buffer should be thread safe
     * @return Returns either {@linkplain StringBuilder} or {@linkplain StringBuffer} instance
     *     depending on whether the instance is required to be thread safe or not, respectively.
     * @since 1.2
     */
    public static Appendable newStringBuilder(boolean threadSafe) {
      return BTraceRuntime.newStringBuilder(threadSafe);
    }

    /**
     * Safely creates a new instance of an appendable string buffer <br>
     * The buffer will not be thread safe.
     *
     * @return Returns a new instance of {@linkplain StringBuilder} class
     * @since 1.2
     */
    public static Appendable newStringBuilder() {
      return BTraceRuntime.newStringBuilder();
    }

    /**
     * Appends a string to an appendable buffer created by {@linkplain
     * BTraceUtils.Strings#newStringBuilder()}
     *
     * @param buffer The appendable buffer to append to
     * @param strToAppend The string to append
     * @return Returns the same appendable buffer instance
     * @since 1.2
     */
    public static Appendable append(Appendable buffer, String strToAppend) {
      return BTraceRuntime.append(buffer, strToAppend);
    }

    /**
     * Checks the length of an appendable buffer created by {@linkplain
     * BTraceUtils.Strings#newStringBuilder()}
     *
     * @param buffer The appendable buffer instance
     * @return Returns the length of the text contained by the buffer
     * @since 1.2
     */
    public static int length(Appendable buffer) {
      return BTraceRuntime.length(buffer);
    }
  }

  /*
   * Wraps the numbers related BTrace utility methods
   * @since 1.2
   */
  public static class Numbers {
    /**
     * Returns a <code>double</code> value with a positive sign, greater than or equal to <code>0.0
     * </code> and less than <code>1.0</code>. Returned values are chosen pseudorandomly with
     * (approximately) uniform distribution from that range.
     */
    public static double random() {
      return Math.random();
    }

    /**
     * Returns the natural logarithm (base <i>e</i>) of a <code>double</code> value. Special cases:
     *
     * <ul>
     *   <li>If the argument is NaN or less than zero, then the result is NaN.
     *   <li>If the argument is positive infinity, then the result is positive infinity.
     *   <li>If the argument is positive zero or negative zero, then the result is negative
     *       infinity.
     * </ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result. Results must be
     * semi-monotonic.
     *
     * @param a a value
     * @return the value ln&nbsp;<code>a</code>, the natural logarithm of <code>a</code>.
     */
    public static strictfp double log(double a) {
      return Math.log(a);
    }

    /**
     * Returns the base 10 logarithm of a <code>double</code> value. Special cases:
     *
     * <ul>
     *   <li>If the argument is NaN or less than zero, then the result is NaN.
     *   <li>If the argument is positive infinity, then the result is positive infinity.
     *   <li>If the argument is positive zero or negative zero, then the result is negative
     *       infinity.
     *   <li>If the argument is equal to 10<sup><i>n</i></sup> for integer <i>n</i>, then the result
     *       is <i>n</i>.
     * </ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result. Results must be
     * semi-monotonic.
     *
     * @param a a value
     * @return the base 10 logarithm of <code>a</code>.
     */
    public static strictfp double log10(double a) {
      return Math.log10(a);
    }

    /**
     * Returns Euler's number <i>e</i> raised to the power of a <code>double</code> value. Special
     * cases:
     *
     * <ul>
     *   <li>If the argument is NaN, the result is NaN.
     *   <li>If the argument is positive infinity, then the result is positive infinity.
     *   <li>If the argument is negative infinity, then the result is positive zero.
     * </ul>
     *
     * <p>The computed result must be within 1 ulp of the exact result. Results must be
     * semi-monotonic.
     *
     * @param a the exponent to raise <i>e</i> to.
     * @return the value <i>e</i><sup><code>a</code></sup>, where <i>e</i> is the base of the
     *     natural logarithms.
     */
    public static strictfp double exp(double a) {
      return Math.exp(a);
    }

    /**
     * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false
     * </code> otherwise.
     *
     * @param d the value to be tested.
     * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.
     */
    public static boolean isNaN(double d) {
      return Double.isNaN(d);
    }

    /**
     * Returns <code>true</code> if the specified number is a Not-a-Number (NaN) value, <code>false
     * </code> otherwise.
     *
     * @param f the value to be tested.
     * @return <code>true</code> if the value of the argument is NaN; <code>false</code> otherwise.
     */
    public static boolean isNaN(float f) {
      return Float.isNaN(f);
    }

    /**
     * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>
     * false</code> otherwise.
     *
     * @param d the value to be tested.
     * @return <code>true</code> if the value of the argument is positive infinity or negative
     *     infinity; <code>false</code> otherwise.
     */
    public static boolean isInfinite(double d) {
      return Double.isInfinite(d);
    }

    /**
     * Returns <code>true</code> if the specified number is infinitely large in magnitude, <code>
     * false</code> otherwise.
     *
     * @param f the value to be tested.
     * @return <code>true</code> if the value of the argument is positive infinity or negative
     *     infinity; <code>false</code> otherwise.
     */
    public static boolean isInfinite(float f) {
      return Float.isInfinite(f);
    }

    // string parsing methods

    /**
     * Parses the string argument as a boolean. The <code>boolean</code> returned represents the
     * value <code>true</code> if the string argument is not <code>null</code> and is equal,
     * ignoring case, to the string {@code "true"}.
     *
     * <p>Example: {@code Boolean.parseBoolean("True")} returns <tt>true</tt>.<br>
     * Example: {@code Boolean.parseBoolean("yes")} returns <tt>false</tt>.
     *
     * @param s the <code>String</code> containing the boolean representation to be parsed
     * @return the boolean represented by the string argument
     */
    public static boolean parseBoolean(String s) {
      return Boolean.parseBoolean(s);
    }

    /**
     * Parses the string argument as a signed decimal <code>byte</code>. The characters in the
     * string must all be decimal digits, except that the first character may be an ASCII minus sign
     * <code>'-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting
     * <code>byte</code> value is returned.
     *
     * @param s a <code>String</code> containing the <code>byte</code> representation to be parsed
     * @return the <code>byte</code> value represented by the argument in decimal
     */
    public static byte parseByte(String s) {
      return Byte.parseByte(s);
    }

    /**
     * Parses the string argument as a signed decimal <code>short</code>. The characters in the
     * string must all be decimal digits, except that the first character may be an ASCII minus sign
     * <code>'-'</code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting
     * <code>short</code> value is returned.
     *
     * @param s a <code>String</code> containing the <code>short</code> representation to be parsed
     * @return the <code>short</code> value represented by the argument in decimal.
     */
    public static short parseShort(String s) {
      return Short.parseShort(s);
    }

    /**
     * Parses the string argument as a signed decimal integer. The characters in the string must all
     * be decimal digits, except that the first character may be an ASCII minus sign <code>'-'
     * </code> (<code>'&#92;u002D'</code>) to indicate a negative value. The resulting integer value
     * is returned.
     *
     * @param s a <code>String</code> containing the <code>int</code> representation to be parsed
     * @return the integer value represented by the argument in decimal.
     */
    public static int parseInt(String s) {
      return Integer.parseInt(s);
    }

    /**
     * Parses the string argument as a signed decimal <code>long</code>. The characters in the
     * string must all be decimal digits, except that the first character may be an ASCII minus sign
     * <code>'-'</code> (<code>&#92;u002D'</code>) to indicate a negative value. The resulting
     * <code>long</code> value is returned.
     *
     * <p>Note that neither the character <code>L</code> (<code>'&#92;u004C'</code>) nor <code>l
     * </code> (<code>'&#92;u006C'</code>) is permitted to appear at the end of the string as a type
     * indicator, as would be permitted in Java programming language source code.
     *
     * @param s a <code>String</code> containing the <code>long</code> representation to be parsed
     * @return the <code>long</code> represented by the argument in decimal.
     */
    public static long parseLong(String s) {
      return Long.parseLong(s);
    }

    /**
     * Returns a new <code>float</code> initialized to the value represented by the specified <code>
     * String</code>, as performed by the <code>valueOf</code> method of class <code>Float</code>.
     *
     * @param s the string to be parsed.
     * @return the <code>float</code> value represented by the string argument.
     */
    public static float parseFloat(String s) {
      return Float.parseFloat(s);
    }

    /**
     * Returns a new <code>double</code> initialized to the value represented by the specified
     * <code>String</code>, as performed by the <code>valueOf</code> methcod of class <code>Double
     * </code>.
     *
     * @param s the string to be parsed.
     * @return the <code>double</code> value represented by the string argument.
     */
    public static double parseDouble(String s) {
      return Double.parseDouble(s);
    }

    // boxing methods

    /**
     * Returns a <tt>Boolean</tt> instance representing the specified <tt>boolean</tt> value. If the
     * specified <tt>boolean</tt> value is <tt>true</tt>, this method returns <tt>Boolean.TRUE</tt>;
     * if it is <tt>false</tt>, this method returns <tt>Boolean.FALSE</tt>.
     *
     * @param b a boolean value.
     * @return a <tt>Boolean</tt> instance representing <tt>b</tt>.
     */
    public static Boolean box(boolean b) {
      return b;
    }

    /**
     * Returns a <tt>Character</tt> instance representing the specified <tt>char</tt> value.
     *
     * @param c a char value.
     * @return a <tt>Character</tt> instance representing <tt>c</tt>.
     */
    public static Character box(char c) {
      return c;
    }

    /**
     * Returns a <tt>Byte</tt> instance representing the specified <tt>byte</tt> value.
     *
     * @param b a byte value.
     * @return a <tt>Byte</tt> instance representing <tt>b</tt>.
     */
    public static Byte box(byte b) {
      return b;
    }

    /**
     * Returns a <tt>Short</tt> instance representing the specified <tt>short</tt> value.
     *
     * @param s a short value.
     * @return a <tt>Short</tt> instance representing <tt>s</tt>.
     */
    public static Short box(short s) {
      return s;
    }

    /**
     * Returns a <tt>Integer</tt> instance representing the specified <tt>int</tt> value.
     *
     * @param i an <code>int</code> value.
     * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
     */
    public static Integer box(int i) {
      return i;
    }

    /**
     * Returns a <tt>Long</tt> instance representing the specified <tt>long</tt> value.
     *
     * @param l a long value.
     * @return a <tt>Long</tt> instance representing <tt>l</tt>.
     */
    public static Long box(long l) {
      return l;
    }

    /**
     * Returns a <tt>Float</tt> instance representing the specified <tt>float</tt> value.
     *
     * @param f a float value.
     * @return a <tt>Float</tt> instance representing <tt>f</tt>.
     */
    public static Float box(float f) {
      return f;
    }

    /**
     * Returns a <tt>Double</tt> instance representing the specified <tt>double</tt> value.
     *
     * @param d a double value.
     * @return a <tt>Double</tt> instance representing <tt>d</tt>.
     */
    public static Double box(double d) {
      return d;
    }

    // unboxing methods

    /**
     * Returns the value of the given <tt>Boolean</tt> object as a boolean primitive.
     *
     * @param b the Boolean object whose value is returned.
     * @return the primitive <code>boolean</code> value of the object.
     */
    public static boolean unbox(Boolean b) {
      return b;
    }

    /**
     * Returns the value of the given <tt>Character</tt> object as a char primitive.
     *
     * @param ch the Character object whose value is returned.
     * @return the primitive <code>char</code> value of the object.
     */
    public static char unbox(Character ch) {
      return ch;
    }

    /**
     * Returns the value of the specified Byte as a <code>byte</code>.
     *
     * @param b Byte that is unboxed
     * @return the byte value represented by the <code>Byte</code>.
     */
    public static byte unbox(Byte b) {
      return b;
    }

    /**
     * Returns the short value represented by <code>Short</code>.
     *
     * @param s Short that is unboxed.
     * @return the short value represented by the <code>Short</code>.
     */
    public static short unbox(Short s) {
      return s;
    }

    /**
     * Returns the value of represented by <code>Integer</code>.
     *
     * @param i Integer that is unboxed.
     * @return the int value represented by the <code>Integer</code>.
     */
    public static int unbox(Integer i) {
      return i;
    }

    /**
     * Returns the long value represented by the specified <code>Long</code>.
     *
     * @param l Long to be unboxed.
     * @return the long value represented by the <code>Long</code>.
     */
    public static long unbox(Long l) {
      return l;
    }

    /**
     * Returns the float value represented by the specified <code>Float</code>.
     *
     * @param f Float to be unboxed.
     * @return the float value represented by the <code>Float</code>.
     */
    public static float unbox(Float f) {
      return f;
    }

    /**
     * Returns the double value represented by the specified <code>Double</code>.
     *
     * @param d Double to be unboxed.
     */
    public static double unbox(Double d) {
      return d;
    }
  }

  /*
   * Wraps the time related BTrace utility methods
   * @since 1.2
   */
  public static class Time {
    /**
     * Returns the current time in milliseconds. Note that while the unit of time of the return
     * value is a millisecond, the granularity of the value depends on the underlying operating
     * system and may be larger. For example, many operating systems measure time in units of tens
     * of milliseconds.
     *
     * @return the difference, measured in milliseconds, between the current time and midnight,
     *     January 1, 1970 UTC.
     */
    public static long millis() {
      return java.lang.System.currentTimeMillis();
    }

    /**
     * Returns the current value of the most precise available system timer, in nanoseconds.
     *
     * <p>This method can only be used to measure elapsed time and is not related to any other
     * notion of system or wall-clock time. The value returned represents nanoseconds since some
     * fixed but arbitrary time (perhaps in the future, so values may be negative). This method
     * provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are
     * made about how frequently values change. Differences in successive calls that span greater
     * than approximately 292 years (2<sup>63</sup> nanoseconds) will not accurately compute elapsed
     * time due to numerical overflow.
     *
     * @return The current value of the system timer, in nanoseconds.
     */
    public static long nanos() {
      return java.lang.System.nanoTime();
    }

    /**
     * Generates a string timestamp (current date&amp;time)
     *
     * @param format The format to be used - see {@linkplain SimpleDateFormat}
     * @return Returns a string representing current date&amp;time
     * @since 1.1
     */
    public static String timestamp(String format) {
      return new SimpleDateFormat(format).format(Calendar.getInstance().getTime());
    }

    /**
     * Generates a string timestamp (current date&amp;time) in the default system format
     *
     * @return Returns a string representing current date&amp;time
     * @since 1.1
     */
    public static String timestamp() {
      return new SimpleDateFormat().format(Calendar.getInstance().getTime());
    }
  }

  /*
   * Wraps the collections related BTrace utility methods
   * @since 1.2
   */
  @SuppressWarnings("EmptyMethod")
  public static class Collections {
    // Create a new map
    public static <K, V> Map<K, V> newHashMap() {
      return BTraceRuntime.newHashMap();
    }

    public static <K, V> Map<K, V> newWeakMap() {
      return BTraceRuntime.newWeakMap();
    }

    public static <V> Deque<V> newDeque() {
      return BTraceRuntime.newDeque();
    }

    public static <K, V> void putAll(Map<K, V> src, Map<K, V> dst) {
      BTraceRuntime.putAll(src, dst);
    }

    public static <K, V> void copy(Map<K, V> src, Map<K, V> dst) {
      BTraceRuntime.copy(src, dst);
    }

    public static <V> void copy(Collection<V> src, Collection<V> dst) {}

    // get a particular item from a Map
    public static <K, V> V get(Map<K, V> map, K key) {
      return BTraceRuntime.get(map, key);
    }

    // check whether an item exists
    public static <K, V> boolean containsKey(Map<K, V> map, K key) {
      return BTraceRuntime.containsKey(map, key);
    }

    public static <K, V> boolean containsValue(Map<K, V> map, V value) {
      return BTraceRuntime.containsValue(map, value);
    }

    // put a particular item into a Map
    public static <K, V> V put(Map<K, V> map, K key, V value) {
      return BTraceRuntime.put(map, key, value);
    }

    // remove a particular item from a Map
    public static <K, V> V remove(Map<K, V> map, K key) {
      return BTraceRuntime.remove(map, key);
    }

    // clear all items from a Map
    public static <K, V> void clear(Map<K, V> map) {
      BTraceRuntime.clear(map);
    }

    // return the size of a Map
    public static <K, V> int size(Map<K, V> map) {
      return BTraceRuntime.size(map);
    }

    public static <K, V> boolean isEmpty(Map<K, V> map) {
      return BTraceRuntime.isEmpty(map);
    }

    // operations on collections
    public static <E> int size(Collection<E> coll) {
      return BTraceRuntime.size(coll);
    }

    public static <E> boolean isEmpty(Collection<E> coll) {
      return BTraceRuntime.isEmpty(coll);
    }

    public static <E> boolean contains(Collection<E> coll, Object obj) {
      return BTraceRuntime.contains(coll, obj);
    }

    public static boolean contains(Object[] array, Object value) {
      for (Object each : array) {
        if (compare(each, value)) {
          return true;
        }
      }
      return false;
    }

    public static <E> Object[] toArray(Collection<E> collection) {
      return BTraceRuntime.toArray(collection);
    }

    // operations on Deque
    public static <V> void push(Deque<V> queue, V value) {
      BTraceRuntime.push(queue, value);
    }

    public static <V> V poll(Deque<V> queue) {
      return BTraceRuntime.poll(queue);
    }

    public static <V> V peek(Deque<V> queue) {
      return BTraceRuntime.peek(queue);
    }

    public static <V> void addLast(Deque<V> queue, V value) {
      BTraceRuntime.addLast(queue, value);
    }

    public static <V> V peekFirst(Deque<V> queue) {
      return BTraceRuntime.peekFirst(queue);
    }

    public static <V> V peekLast(Deque<V> queue) {
      return BTraceRuntime.peekLast(queue);
    }

    public static <V> V removeLast(Deque<V> queue) {
      return BTraceRuntime.removeLast(queue);
    }

    public static <V> V removeFirst(Deque<V> queue) {
      return BTraceRuntime.removeFirst(queue);
    }
  }

  /*
   * Wraps the atomicity related BTrace utility methods
   * @since 1.2
   */
  public static class Atomic {
    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public static AtomicInteger newAtomicInteger(int initialValue) {
      return BTraceRuntime.newAtomicInteger(initialValue);
    }

    /**
     * Gets the current value of the given AtomicInteger.
     *
     * @param ai AtomicInteger whose value is returned.
     * @return the current value
     */
    public static int get(AtomicInteger ai) {
      return BTraceRuntime.get(ai);
    }

    /**
     * Sets to the given value to the given AtomicInteger.
     *
     * @param ai AtomicInteger whose value is set.
     * @param newValue the new value
     */
    public static void set(AtomicInteger ai, int newValue) {
      BTraceRuntime.set(ai, newValue);
    }

    /**
     * Eventually sets to the given value to the given AtomicInteger.
     *
     * @param ai AtomicInteger whose value is lazily set.
     * @param newValue the new value
     */
    public static void lazySet(AtomicInteger ai, int newValue) {
      BTraceRuntime.lazySet(ai, newValue);
    }

    /**
     * Atomically sets the value of given AtomitInteger to the given updated value if the current
     * value {@code ==} the expected value.
     *
     * @param ai AtomicInteger whose value is compared and set.
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that the actual value was not equal to the
     *     expected value.
     */
    public static boolean compareAndSet(AtomicInteger ai, int expect, int update) {
      return BTraceRuntime.compareAndSet(ai, expect, update);
    }

    /**
     * Atomically sets the value to the given updated value if the current value {@code ==} the
     * expected value.
     *
     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> and does not provide
     * ordering guarantees, so is only rarely an appropriate alternative to {@code compareAndSet}.
     *
     * @param ai AtomicInteger whose value is weakly compared and set.
     * @param expect the expected value
     * @param update the new value
     * @return true if successful.
     */
    public static boolean weakCompareAndSet(AtomicInteger ai, int expect, int update) {
      return BTraceRuntime.weakCompareAndSet(ai, expect, update);
    }

    /**
     * Atomically increments by one the current value of given AtomicInteger.
     *
     * @param ai AtomicInteger that is incremented.
     * @return the previous value
     */
    public static int getAndIncrement(AtomicInteger ai) {
      return BTraceRuntime.getAndIncrement(ai);
    }

    /**
     * Atomically decrements by one the current value of given AtomicInteger.
     *
     * @param ai AtomicInteger that is decremented.
     * @return the previous value
     */
    public static int getAndDecrement(AtomicInteger ai) {
      return BTraceRuntime.getAndDecrement(ai);
    }

    /**
     * Atomically increments by one the current value of given AtomicInteger.
     *
     * @param ai AtomicInteger that is incremented.
     * @return the updated value
     */
    public static int incrementAndGet(AtomicInteger ai) {
      return BTraceRuntime.incrementAndGet(ai);
    }

    /**
     * Atomically decrements by one the current value of given AtomicInteger.
     *
     * @param ai AtomicInteger whose value is decremented.
     * @return the updated value
     */
    public static int decrementAndGet(AtomicInteger ai) {
      return BTraceRuntime.decrementAndGet(ai);
    }

    /**
     * Atomically adds the given value to the current value.
     *
     * @param ai AtomicInteger whose value is added to.
     * @param delta the value to add
     * @return the previous value
     */
    public static int getAndAdd(AtomicInteger ai, int delta) {
      return BTraceRuntime.getAndAdd(ai, delta);
    }

    /**
     * Atomically adds the given value to the current value.
     *
     * @param ai AtomicInteger whose value is added to.
     * @param delta the value to add
     * @return the updated value
     */
    public static int addAndGet(AtomicInteger ai, int delta) {
      return BTraceRuntime.addAndGet(ai, delta);
    }

    /**
     * Atomically sets to the given value and returns the old value.
     *
     * @param ai AtomicInteger whose value is set.
     * @param newValue the new value
     * @return the previous value
     */
    public static int getAndSet(AtomicInteger ai, int newValue) {
      return BTraceRuntime.getAndSet(ai, newValue);
    }

    /**
     * Creates a new AtomicLong with the given initial value.
     *
     * @param initialValue the initial value
     */
    public static AtomicLong newAtomicLong(long initialValue) {
      return BTraceRuntime.newAtomicLong(initialValue);
    }

    /**
     * Gets the current value the given AtomicLong.
     *
     * @param al AtomicLong whose value is returned.
     * @return the current value
     */
    public static long get(AtomicLong al) {
      return BTraceRuntime.get(al);
    }

    /**
     * Sets to the given value.
     *
     * @param al AtomicLong whose value is set.
     * @param newValue the new value
     */
    public static void set(AtomicLong al, long newValue) {
      BTraceRuntime.set(al, newValue);
    }

    /**
     * Eventually sets to the given value to the given AtomicLong.
     *
     * @param al AtomicLong whose value is set.
     * @param newValue the new value
     */
    public static void lazySet(AtomicLong al, long newValue) {
      BTraceRuntime.lazySet(al, newValue);
    }

    /**
     * Atomically sets the value to the given updated value if the current value {@code ==} the
     * expected value.
     *
     * @param al AtomicLong whose value is compared and set.
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that the actual value was not equal to the
     *     expected value.
     */
    public static boolean compareAndSet(AtomicLong al, long expect, long update) {
      return BTraceRuntime.compareAndSet(al, expect, update);
    }

    /**
     * Atomically sets the value to the given updated value if the current value {@code ==} the
     * expected value.
     *
     * <p>May fail spuriously and does not provide ordering guarantees, so is only rarely an
     * appropriate alternative to {@code compareAndSet}.
     *
     * @param al AtomicLong whose value is compared and set.
     * @param expect the expected value
     * @param update the new value
     * @return true if successful.
     */
    public static boolean weakCompareAndSet(AtomicLong al, long expect, long update) {
      return BTraceRuntime.weakCompareAndSet(al, expect, update);
    }

    /**
     * Atomically increments by one the current value.
     *
     * @param al AtomicLong whose value is incremented.
     * @return the previous value
     */
    public static long getAndIncrement(AtomicLong al) {
      return BTraceRuntime.getAndIncrement(al);
    }

    /**
     * Atomically decrements by one the current value.
     *
     * @param al AtomicLong whose value is decremented.
     * @return the previous value
     */
    public static long getAndDecrement(AtomicLong al) {
      return BTraceRuntime.getAndDecrement(al);
    }

    /**
     * Atomically increments by one the current value.
     *
     * @param al AtomicLong whose value is incremented.
     * @return the updated value
     */
    public static long incrementAndGet(AtomicLong al) {
      return BTraceRuntime.incrementAndGet(al);
    }

    /**
     * Atomically decrements by one the current value.
     *
     * @param al AtomicLong whose value is decremented.
     * @return the updated value
     */
    public static long decrementAndGet(AtomicLong al) {
      return BTraceRuntime.decrementAndGet(al);
    }

    /**
     * Atomically adds the given value to the current value.
     *
     * @param al AtomicLong whose value is added to.
     * @param delta the value to add
     * @return the previous value
     */
    public static long getAndAdd(AtomicLong al, long delta) {
      return BTraceRuntime.getAndAdd(al, delta);
    }

    /**
     * Atomically adds the given value to the current value.
     *
     * @param al AtomicLong whose value is added to
     * @param delta the value to add
     * @return the updated value
     */
    public static long addAndGet(AtomicLong al, long delta) {
      return BTraceRuntime.addAndGet(al, delta);
    }

    /**
     * Atomically sets to the given value and returns the old value.
     *
     * @param al AtomicLong that is set.
     * @param newValue the new value
     * @return the previous value
     */
    public static long getAndSet(AtomicLong al, long newValue) {
      return BTraceRuntime.getAndSet(al, newValue);
    }
  }

  /*
   * Wraps the aggregations related BTrace utility methods
   * @since 1.2
   */
  public static class Aggregations {
    /**
     * Creates a new aggregation based on the given aggregation function type.
     *
     * @param type the aggregating function to be performed on the data being added to the
     *     aggregation.
     */
    public static Aggregation newAggregation(AggregationFunction type) {
      return BTraceRuntime.newAggregation(type);
    }

    /**
     * Creates a grouping aggregation key with the provided value. The value must be a String or
     * Number type.
     *
     * @param element1 the value of the aggregation key
     */
    public static AggregationKey newAggregationKey(Object element1) {
      return BTraceRuntime.newAggregationKey(element1);
    }

    /**
     * Creates a composite grouping aggregation key with the provided values. The values must be
     * String or Number types.
     *
     * @param element1 the first element of the composite aggregation key
     * @param element2 the second element of the composite aggregation key
     */
    public static AggregationKey newAggregationKey(Object element1, Object element2) {
      return BTraceRuntime.newAggregationKey(element1, element2);
    }

    /**
     * Creates a composite grouping aggregation key with the provided values. The values must be
     * String or Number types.
     *
     * @param element1 the first element of the composite aggregation key
     * @param element2 the second element of the composite aggregation key
     * @param element3 the third element of the composite aggregation key
     */
    public static AggregationKey newAggregationKey(
        Object element1, Object element2, Object element3) {
      return BTraceRuntime.newAggregationKey(element1, element2, element3);
    }

    /**
     * Creates a composite grouping aggregation key with the provided values. The values must be
     * String or Number types.
     *
     * @param element1 the first element of the composite aggregation key
     * @param element2 the second element of the composite aggregation key
     * @param element3 the third element of the composite aggregation key
     * @param element4 the fourth element of the composite aggregation key
     */
    public static AggregationKey newAggregationKey(
        Object element1, Object element2, Object element3, Object element4) {
      return BTraceRuntime.newAggregationKey(element1, element2, element3, element4);
    }

    /**
     * Adds a value to the aggregation with no grouping key. This method should be used when the
     * aggregation is to calculate only a single aggregated value.
     *
     * @param aggregation the aggregation to which the value should be added
     */
    public static void addToAggregation(Aggregation aggregation, long value) {
      BTraceRuntime.addToAggregation(aggregation, value);
    }

    /**
     * Adds a value to the aggregation with a grouping key. This method should be used when the
     * aggregation should effectively perform a "group by" on the key value. The aggregation will
     * calculate a separate aggregated value for each unique aggregation key.
     *
     * @param aggregation the aggregation to which the value should be added
     * @param key the grouping aggregation key
     */
    public static void addToAggregation(Aggregation aggregation, AggregationKey key, long value) {
      BTraceRuntime.addToAggregation(aggregation, key, value);
    }

    /**
     * Resets values within the aggregation to the default. This will affect all values within the
     * aggregation when multiple aggregation keys have been used.
     *
     * @param aggregation the aggregation to be cleared
     */
    public static void clearAggregation(Aggregation aggregation) {
      BTraceRuntime.clearAggregation(aggregation);
    }

    /**
     * Removes all aggregated values from the aggregation except for the largest or smallest <code>
     * abs(count)</code> elements.
     *
     * <p>If <code>count</code> is positive, the largest aggregated values in the aggregation will
     * be preserved. If <code>count</code> is negative the smallest values will be preserved. If
     * <code>count</code> is zero then all elements will be removed.
     *
     * <p>Behavior is intended to be similar to the dtrace <code>trunc()</code> function.
     *
     * @param aggregation the aggregation to be truncated
     * @param count the number of elements to preserve. If negative, the smallest <code>abs(count)
     *     </code> elements are preserved.
     */
    public static void truncateAggregation(Aggregation aggregation, int count) {
      BTraceRuntime.truncateAggregation(aggregation, count);
    }

    public static void printAggregation(String name, Aggregation aggregation) {
      BTraceRuntime.printAggregation(name, aggregation);
    }

    public static void printAggregation(String name, Aggregation aggregation, String format) {
      BTraceRuntime.printAggregation(name, aggregation, format);
    }

    public static void printAggregation(
        String name, String format, Collection<Aggregation> aggregationList) {
      Aggregation[] aggregationArray = new Aggregation[aggregationList.size()];
      int index = 0;
      for (Aggregation a : aggregationList) {
        aggregationArray[index] = a;
        index++;
      }
      BTraceRuntime.printAggregation(name, format, aggregationArray);
    }
  }

  /**
   * Profiling support. It is a highly specialized aggregation (therefore not included in the
   * generic aggregations support) which is able to calculate clean self time spent in
   * hierarchically called methods (or bigger parts of code)
   */
  public static class Profiling {
    /**
     * Creates a new {@linkplain Profiler} instance
     *
     * @return A new {@linkplain Profiler} instance
     */
    public static Profiler newProfiler() {
      return BTraceRuntime.newProfiler();
    }

    /**
     * Creates a new {@linkplain Profiler} instance with the specified expected count of the
     * distinct methods to be recorded.
     *
     * @param expectedBlockCnt The expected count of the distinct blocks to be recorded.
     * @return Returns a new {@linkplain Profiler} instance
     */
    public static Profiler newProfiler(int expectedBlockCnt) {
      return BTraceRuntime.newProfiler(expectedBlockCnt);
    }

    /**
     * Records the entry to a particular code block
     *
     * @param profiler The {@linkplain Profiler} instance to use
     * @param blockName The block identifier
     */
    public static void recordEntry(Profiler profiler, String blockName) {
      BTraceRuntime.recordEntry(profiler, blockName);
    }

    /**
     * Records the exit out of a particular code block
     *
     * @param profiler The {@linkplain Profiler} instance to use
     * @param blockName The block identifier
     * @param duration The time spent in the mentioned block
     */
    public static void recordExit(Profiler profiler, String blockName, long duration) {
      BTraceRuntime.recordExit(profiler, blockName, duration);
    }

    /**
     * Creates a new snapshot of the profiling metrics collected sofar
     *
     * @param profiler The {@linkplain Profiler} instance to use
     * @return Returns an immutable snapshot of the profiling metrics in the form of a map where the
     *     key is the block name and the value is a map of metrics names and the appropriate values
     *     <br>
     *     The supported metrics names are: "selfTime", "wallTime" and "invocations"
     */
    public static Profiler.Snapshot snapshot(Profiler profiler) {
      return BTraceRuntime.snapshot(profiler);
    }

    public static Profiler.Snapshot snapshotAndReset(Profiler profiler) {
      return BTraceRuntime.snapshotAndReset(profiler);
    }

    public static void reset(Profiler profiler) {
      BTraceRuntime.resetProfiler(profiler);
    }

    public static void printSnapshot(String name, Profiler profiler) {
      BTraceRuntime.printSnapshot(name, profiler.snapshot());
    }

    public static void printSnapshot(String name, Profiler profiler, String format) {
      BTraceRuntime.printSnapshot(name, profiler.snapshot(), format);
    }
  }

  /*
   * Wraps the speculation related BTrace utility methods
   * @since 1.2
   */
  public static class Speculation {
    /**
     * Returns an identifier for a new speculative buffer.
     *
     * @return new speculative buffer id
     */
    public static int speculation() {
      return BTraceRuntime.speculation();
    }

    /**
     * Sets current speculative buffer id.
     *
     * @param id the speculative buffer id
     */
    public static void speculate(int id) {
      BTraceRuntime.speculate(id);
    }

    /**
     * Commits the speculative buffer associated with id.
     *
     * @param id the speculative buffer id
     */
    public static void commit(int id) {
      BTraceRuntime.commit(id);
    }

    /**
     * Discards the speculative buffer associated with id.
     *
     * @param id the speculative buffer id
     */
    public static void discard(int id) {
      BTraceRuntime.discard(id);
    }
  }

  /*
   * Wraps the references related BTrace utility methods
   * @since 1.2
   */
  public static class References {
    /**
     * Creates and returns a weak reference to the given object.
     *
     * @param obj object for which a weak reference is created.
     * @return a weak reference to the given object.
     */
    public static WeakReference weakRef(Object obj) {
      return new WeakReference<>(obj);
    }

    /**
     * Creates and returns a soft reference to the given object.
     *
     * @param obj object for which a soft reference is created.
     * @return a soft reference to the given object.
     */
    public static SoftReference softRef(Object obj) {
      return new SoftReference<>(obj);
    }

    /**
     * Returns the given reference object's referent. If the reference object has been cleared,
     * either by the program or by the garbage collector, then this method returns <code>null</code>
     * .
     *
     * @param ref reference object whose referent is returned.
     * @return The object to which the reference refers, or <code>null</code> if the reference
     *     object has been cleared.
     */
    public static Object deref(Reference ref) {
      if (ref.getClass().getClassLoader() == null) {
        return ref.get();
      } else {
        throw new IllegalArgumentException();
      }
    }
  }

  /*
   * Wraps the reflection related BTrace utility methods
   * @since 1.2
   */
  public static class Reflective {
    /**
     * Returns the runtime class of the given Object.
     *
     * @param obj the Object whose Class is returned
     * @return the Class object of given object
     */
    public static Class<?> classOf(Object obj) {
      return obj.getClass();
    }

    /**
     * Returns the Class object representing the class or interface that declares the field
     * represented by the given Field object.
     *
     * @param field whose declaring Class is returned
     */
    public static Class<?> declaringClass(Field field) {
      return field.getDeclaringClass();
    }

    /** Returns the name of the given Class object. */
    public static String name(Class<?> clazz) {
      return clazz.getName();
    }

    /**
     * Returns the name of the Field object.
     *
     * @param field Field for which name is returned
     * @return name of the given field
     */
    public static String name(Field field) {
      return field.getName();
    }

    /**
     * Returns the type of the Field object.
     *
     * @param field Field for which type is returned
     * @return type of the given field
     */
    public static Class<?> type(Field field) {
      return field.getType();
    }

    /** Returns the access flags of the given Class. */
    public static int accessFlags(Class<?> clazz) {
      return clazz.getModifiers();
    }

    /** Returns the access flags of the given Field. */
    public static int accessFlags(Field field) {
      return field.getModifiers();
    }

    /** Returns the current context class loader */
    public static ClassLoader contextClassLoader() {
      return Thread.currentThread().getContextClassLoader();
    }

    // get Class of the given name

    /** Returns Class object for given class name. */
    public static Class<?> classForName(String name) {
      ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);
      return classForName(name, callerLoader);
    }

    /** Returns the Class for the given class name using the given class loader. */
    public static Class<?> classForName(String name, ClassLoader cl) {
      try {
        return Class.forName(name, false, cl);
      } catch (ClassNotFoundException exp) {
        throw translate(exp);
      }
    }

    /**
     * Determines if the class or interface represented by the first <code>Class</code> object is
     * either the same as, or is a superclass or superinterface of, the class or interface
     * represented by the second <code>Class</code> parameter. It returns <code>true</code> if so;
     * otherwise it returns <code>false</code>.
     */
    public static boolean isAssignableFrom(Class<?> a, Class<?> b) {
      return a.isAssignableFrom(b);
    }

    /**
     * Determines if the specified <code>Object</code> is assignment-compatible with the object
     * represented by the specified <code>Class</code>. This method is the dynamic equivalent of the
     * Java language <code>instanceof</code> operator. The method returns <code>true</code> if the
     * specified <code>Object</code> argument is non-null and can be cast to the reference type
     * represented by this <code>Class</code> object without raising a <code>ClassCastException.
     * </code> It returns <code>false</code> otherwise.
     *
     * @param clazz the class that is checked.
     * @param obj the object to check.
     * @return true if <code>obj</code> is an instance of the given class.
     */
    public static boolean isInstance(Class<?> clazz, Object obj) {
      return clazz.isInstance(obj);
    }

    /**
     * Returns the <code>Class</code> representing the superclass of the entity (class, interface,
     * primitive type or void) represented by the given <code>Class</code>. If the given <code>Class
     * </code> represents either the <code>Object</code> class, an interface, a primitive type, or
     * void, then null is returned. If the given object represents an array class then the <code>
     * Class</code> object representing the <code>Object</code> class is returned.
     *
     * @param clazz the Class whose super class is returned.
     * @return the superclass of the class represented by the given object.
     */
    public static Class<?> getSuperclass(Class<?> clazz) {
      return clazz.getSuperclass();
    }

    /**
     * Determines if the specified <code>Class</code> object represents an interface type.
     *
     * @param clazz the Class object to check.
     * @return <code>true</code> if the Class represents an interface; <code>false</code> otherwise.
     */
    public static boolean isInterface(Class<?> clazz) {
      return clazz.isInterface();
    }

    /**
     * Determines if the given <code>Class</code> object represents an array class.
     *
     * @param clazz Class object to check.
     * @return <code>true</code> if the given object represents an array class; <code>false</code>
     *     otherwise.
     */
    public static boolean isArray(Class<?> clazz) {
      return clazz.isArray();
    }

    /** Returns whether the given Class represent primitive type or not. */
    public static boolean isPrimitive(Class<?> clazz) {
      return clazz.isPrimitive();
    }

    /** returns component type of an array Class. */
    public static Class<?> getComponentType(Class<?> clazz) {
      return clazz.getComponentType();
    }

    // Accessing fields by reflection

    /**
     * Returns a <code>Field</code> object that reflects the specified declared field of the class
     * or interface represented by the given <code>Class</code> object. The <code>name</code>
     * parameter is a <code>String</code> that specifies the simple name of the desired field.
     * Returns <code>null</code> on not finding field if throwException parameter is <code>false
     * </code>. Else throws a <code>RuntimeException</code> when field is not found.
     *
     * @param clazz Class whose field is returned
     * @param name the name of the field
     * @param throwException whether to throw exception on failing to find field or not
     * @return the <code>Field</code> object for the specified field in this class
     */
    public static Field field(Class clazz, String name, boolean throwException) {
      return getField(clazz, name, throwException);
    }

    /**
     * Returns a <code>Field</code> object that reflects the specified declared field of the class
     * or interface represented by the given <code>Class</code> object. The <code>name</code>
     * parameter is a <code>String</code> that specifies the simple name of the desired field.
     * Throws a <code>RuntimeException</code> when field is not found.
     *
     * @param clazz Class whose field is returned
     * @param name the name of the field
     * @return the <code>Field</code> object for the specified field in this class
     */
    public static Field field(Class clazz, String name) {
      return field(clazz, name, true);
    }

    /**
     * Returns a <code>Field</code> object that reflects the specified declared field of the class
     * or interface represented by the given <code>Class</code> object. The <code>name</code>
     * parameter is a <code>String</code> that specifies the simple name of the desired field.
     * Returns <code>null</code> on not finding field if throwException parameter is <code>false
     * </code>. Else throws a <code>RuntimeException</code> when field is not found.
     *
     * @param clazz Class whose field is returned
     * @param name the name of the field
     * @param throwException whether to throw exception on failing to find field or not
     * @return the <code>Field</code> object for the specified field in this class
     */
    public static Field field(String clazz, String name, boolean throwException) {
      ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);
      return field(classForName(clazz, callerLoader), name, throwException);
    }

    /**
     * Returns a <code>Field</code> object that reflects the specified declared field of the class
     * or interface represented by the given <code>Class</code> object. The <code>name</code>
     * parameter is a <code>String</code> that specifies the simple name of the desired field.
     * Throws a <code>RuntimeException</code> when field is not found.
     *
     * @param clazz Class whose field is returned
     * @param name the name of the field
     * @return the <code>Field</code> object for the specified field in this class
     */
    public static Field field(String clazz, String name) {
      ClassLoader callerLoader = BTraceRuntime.getCallerClassloader(STACK_DEC);
      return field(classForName(clazz, callerLoader), name);
    }

    // field value get methods

    /**
     * Gets the value of a static <code>byte</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>byte</code> field
     */
    public static byte getByte(Field field) {
      checkStatic(field);
      try {
        return field.getByte(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>byte</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>byte</code> value from
     * @return the value of the <code>byte</code> field
     */
    public static byte getByte(Field field, Object obj) {
      try {
        return field.getByte(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>byte</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>byte</code> value from
     * @return the value of the <code>byte</code> field
     * @since 1.3.5
     */
    public static byte getByte(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getByte(f, instance);
    }

    /**
     * Gets the value of a static <code>byte</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>byte</code> value from
     * @return the value of the <code>byte</code> field
     * @since 1.3.5
     */
    public static byte getByteStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getByte(f, null);
    }

    /**
     * Gets the value of a static <code>short</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>short</code> field
     */
    public static short getShort(Field field) {
      checkStatic(field);
      try {
        return field.getShort(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>short</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>short</code> value from
     * @return the value of the <code>short</code> field
     */
    public static short getShort(Field field, Object obj) {
      try {
        return field.getShort(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>short</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>short</code> value from
     * @return the value of the <code>short</code> field
     * @since 1.3.5
     */
    public static short getShort(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getShort(f, instance);
    }

    /**
     * Gets the value of a static <code>short</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>short</code> value from
     * @return the value of the <code>short</code> field
     * @since 1.3.5
     */
    public static short getShortStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getShort(f, null);
    }

    /**
     * Gets the value of a static <code>int</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>int</code> field
     */
    public static int getInt(Field field) {
      checkStatic(field);
      try {
        return field.getInt(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>int</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>int</code> value from
     * @return the value of the <code>int</code> field
     */
    public static int getInt(Field field, Object obj) {
      try {
        return field.getInt(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>int</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>int</code> value from
     * @return the value of the <code>int</code> field
     * @since 1.3.5
     */
    public static int getInt(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getInt(f, instance);
    }

    /**
     * Gets the value of a sttaic <code>int</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>int</code> value from
     * @return the value of the <code>int</code> field
     * @since 1.3.5
     */
    public static int getIntStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getInt(f, null);
    }

    /**
     * Gets the value of a static <code>long</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>long</code> field
     */
    public static long getLong(Field field) {
      checkStatic(field);
      try {
        return field.getLong(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>long</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>long</code> value from
     * @return the value of the <code>long</code> field
     */
    public static long getLong(Field field, Object obj) {
      try {
        return field.getLong(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>long</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>long</code> value from
     * @return the value of the <code>long</code> field
     * @since 1.3.5
     */
    public static long getLong(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getLong(f, instance);
    }

    /**
     * Gets the value of a static <code>long</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>long</code> value from
     * @return the value of the <code>long</code> field
     * @since 1.3.5
     */
    public static long getLongStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getLong(f, null);
    }

    /**
     * Gets the value of a static <code>float</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>float</code> field
     */
    public static float getFloat(Field field) {
      checkStatic(field);
      try {
        return field.getFloat(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>float</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>float</code> value from
     * @return the value of the <code>float</code> field
     */
    public static float getFloat(Field field, Object obj) {
      try {
        return field.getFloat(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>float</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>float</code> value from
     * @return the value of the <code>float</code> field
     * @since 1.3.5
     */
    public static float getFloat(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getFloat(f, instance);
    }

    /**
     * Gets the value of a static <code>float</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>float</code> value from
     * @return the value of the <code>float</code> field
     * @since 1.3.5
     */
    public static float getFloatStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getFloat(f, null);
    }

    /**
     * Gets the value of a static <code>double</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>double</code> field
     */
    public static double getDouble(Field field) {
      checkStatic(field);
      try {
        return field.getDouble(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>double</code> field.
     *
     * @param field Field object whose value is returned.
     * @param instance the object to extract the <code>double</code> value from
     * @return the value of the <code>double</code> field
     */
    public static double getDouble(Field field, Object instance) {
      try {
        return field.getDouble(instance);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>double</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>double</code> value from
     * @return the value of the <code>double</code> field
     * @since 1.3.5
     */
    public static double getDouble(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getDouble(f, instance);
    }

    /**
     * Gets the value of a static <code>double</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>double</code> value from
     * @return the value of the <code>double</code> field
     * @since 1.3.5
     */
    public static double getDouble(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getDouble(f, null);
    }

    /**
     * Gets the value of a static <code>boolean</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>boolean</code> field
     */
    public static boolean getBoolean(Field field) {
      checkStatic(field);
      try {
        return field.getBoolean(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>boolean</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>boolean</code> value from
     * @return the value of the <code>boolean</code> field
     */
    public static boolean getBoolean(Field field, Object obj) {
      try {
        return field.getBoolean(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>boolean</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>boolean</code> value from
     * @return the value of the <code>boolean</code> field
     * @since 1.3.5
     */
    public static boolean getBoolean(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getBoolean(f, instance);
    }

    /**
     * Gets the value of a static <code>boolean</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>boolean</code> value from
     * @return the value of the <code>boolean</code> field
     * @since 1.3.5
     */
    public static boolean getBooleanStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getBoolean(f, null);
    }

    /**
     * Gets the value of a static <code>char</code> field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the <code>char</code> field
     */
    public static char getChar(Field field) {
      checkStatic(field);
      try {
        return field.getChar(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>char</code> field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the <code>char</code> value from
     * @return the value of the <code>char</code> field
     */
    public static char getChar(Field field, Object obj) {
      try {
        return field.getChar(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance <code>char</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the <code>char</code> value from
     * @return the value of the <code>char</code> field
     * @since 1.3.5
     */
    public static char getChar(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return getChar(f, instance);
    }

    /**
     * Gets the value of a static <code>char</code> field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the <code>char</code> value from
     * @return the value of the <code>char</code> field
     * @since 1.3.5
     */
    public static char getCharStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return getChar(f, null);
    }

    /**
     * Gets the value of a static reference field.
     *
     * @param field Field object whose value is returned.
     * @return the value of the reference field
     */
    public static Object get(Field field) {
      checkStatic(field);
      try {
        return field.get(null);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance reference field.
     *
     * @param field Field object whose value is returned.
     * @param obj the object to extract the reference value from
     * @return the value of the reference field
     */
    public static Object get(Field field, Object obj) {
      try {
        return field.get(obj);
      } catch (Exception exp) {
        throw translate(exp);
      }
    }

    /**
     * Gets the value of an instance reference field.
     *
     * @param name name of the field whose value is returned.
     * @param instance the object to extract the reference value from
     * @return the value of the reference field
     * @since 1.3.5
     */
    public static Object get(String name, Object instance) {
      Field f = getField(instance.getClass(), name, true);
      return get(f, instance);
    }

    /**
     * Gets the value of a static reference field.
     *
     * @param name name of the field whose value is returned.
     * @param clazz the class to extract the reference value from
     * @return the value of the reference field
     * @since 1.3.5
     */
    public static Object getStatic(String name, Class clazz) {
      Field f = getField(clazz, name, true);
      return get(f, null);
    }

    /**
     * Print all instance fields of an object as name-value pairs. Includes the inherited fields as
     * well.
     *
     * @param obj Object whose fields are printed.
     */
    public static void printFields(Object obj) {
      printFields(obj, false);
    }

    /**
     * Print all instance fields of an object as name-value pairs. Includes the inherited fields as
     * well. Optionally, prints name of the declaring class before each field - so that if same
     * named field in super class chain may be disambiguated.
     *
     * @param obj Object whose fields are printed.
     * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.
     */
    public static void printFields(Object obj, boolean classNamePrefix) {
      StringBuilder buf = new StringBuilder();
      buf.append('{');
      addFieldValues(buf, obj, obj.getClass(), classNamePrefix);
      buf.append('}');
      println(buf.toString());
    }

    /**
     * Print all static fields of the class as name-value pairs. Includes the inherited fields as
     * well.
     *
     * @param clazz Class whose static fields are printed.
     */
    public static void printStaticFields(Class clazz) {
      printStaticFields(clazz, false);
    }

    /**
     * Print all static fields of the class as name-value pairs. Includes the inherited fields as
     * well. Optionally, prints name of the declaring class before each field - so that if same
     * named field in super class chain may be disambigated.
     *
     * @param clazz Class whose static fields are printed.
     * @param classNamePrefix flag to tell whether to prefix field names names by class name or not.
     */
    public static void printStaticFields(Class clazz, boolean classNamePrefix) {
      StringBuilder buf = new StringBuilder();
      buf.append('{');
      addStaticFieldValues(buf, clazz, classNamePrefix);
      buf.append('}');
      println(buf.toString());
    }
  }

  /*
   * Wraps the data export related BTrace utility methods
   * @since 1.2
   */
  public static class Export {
    /**
     * Serialize a given object into the given file. Under the current dir of traced app,
     * ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a file of given
     * fileName is created.
     *
     * @param obj object that has to be serialized.
     * @param fileName name of the file to which the object is serialized.
     */
    public static void serialize(Serializable obj, String fileName) {
      BTraceRuntime.serialize(obj, fileName);
    }

    /**
     * Creates an XML document to persist the tree of the all transitively reachable objects from
     * given "root" object.
     */
    public static String toXML(Object obj) {
      return BTraceRuntime.toXML(obj);
    }

    /**
     * Writes an XML document to persist the tree of the all the transitively reachable objects from
     * the given "root" object. Under the current dir of traced app,
     * ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that directory, a file of the
     * given fileName is created.
     */
    public static void writeXML(Object obj, String fileName) {
      BTraceRuntime.writeXML(obj, fileName);
    }

    /**
     * Writes a .dot document to persist the tree of the all the transitively reachable objects from
     * the given "root" object. .dot documents can be viewed by Graphviz application
     * (www.graphviz.org) Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/
     * directory is created. Under that directory, a file of the given fileName is created.
     *
     * @since 1.1
     */
    public static void writeDOT(Object obj, String fileName) {
      BTraceRuntime.writeDOT(obj, fileName);
    }
  }

  /*
   * Wraps the OS related BTrace utility methods
   * @since 1.2
   */
  public static class Sys {
    /**
     * Returns n'th command line argument. <code>null</code> if not available.
     *
     * @param n command line argument index
     * @return n'th command line argument
     */
    public static String $(int n) {
      return BTraceRuntime.$(n);
    }

    /**
     * Returns a command line argument value for the given key. {@code null} if not available.<br>
     * In order to provide a key-value pair on the command line it must have the following syntax -
     * &lt;key&gt;=&lt;value&gt;
     *
     * @param key the argument key
     * @return the corresponding value or {@code null}
     */
    public static String $(String key) {
      return BTraceRuntime.$(key);
    }

    /** Returns the process id of the currently BTrace'd process. */
    public static int getpid() {
      int pid = -1;
      try {
        pid = Integer.parseInt($(0));
      } catch (Exception ignored) {
      }
      return pid;
    }

    /** Returns the number of command line arguments. */
    public static int $length() {
      return BTraceRuntime.$length();
    }

    /**
     * Exits the BTrace session -- note that the particular client's tracing session exits and not
     * the observed/traced program! After exit call, the trace action method terminates immediately
     * and no other probe action method (of that client) will be called after that.
     *
     * @param exitCode exit value sent to the client
     */
    public static void exit(int exitCode) {
      BTraceRuntime.exit(exitCode);
    }

    /**
     * This is same as exit(int) except that the exit code is zero.
     *
     * @see #exit(int)
     */
    public static void exit() {
      exit(0);
    }

    /*
     * Wraps the environment related BTrace utility methods
     * @since 1.2
     */
    public static class Env {
      /**
       * Gets the system property indicated by the specified key.
       *
       * @param key the name of the system property.
       * @return the string value of the system property, or <code>null</code> if there is no
       *     property with that key.
       * @throws NullPointerException if <code>key</code> is <code>null</code>.
       * @throws IllegalArgumentException if <code>key</code> is empty.
       */
      public static String property(String key) {
        return BTraceRuntime.property(key);
      }

      /**
       * Returns all Sys properties.
       *
       * @return the system properties
       */
      public static Properties properties() {
        return BTraceRuntime.properties();
      }

      /** Prints all Sys properties. */
      public static void printProperties() {
        BTraceRuntime.printMap(properties());
      }

      /**
       * Gets the value of the specified environment variable. An environment variable is a
       * system-dependent external named value.
       *
       * @param name the name of the environment variable
       * @return the string value of the variable, or <code>null</code> if the variable is not
       *     defined in the system environment
       * @throws NullPointerException if <code>name</code> is <code>null</code>
       */
      public static String getenv(String name) {
        return BTraceRuntime.getenv(name);
      }

      /**
       * Returns an unmodifiable string map view of the current system environment. The environment
       * is a system-dependent mapping from names to values which is passed from parent to child
       * processes.
       *
       * @return the environment as a map of variable names to values
       */
      public static Map<String, String> getenv() {
        return BTraceRuntime.getenv();
      }

      /** Prints all system environment values. */
      public static void printEnv() {
        BTraceRuntime.printMap(getenv());
      }

      /**
       * Returns the number of processors available to the Java virtual machine.
       *
       * <p>This value may change during a particular invocation of the virtual machine.
       * Applications that are sensitive to the number of available processors should therefore
       * occasionally poll this property and adjust their resource usage appropriately.
       *
       * @return the maximum number of processors available to the virtual machine; never smaller
       *     than one
       */
      public static long availableProcessors() {
        return Runtime.getRuntime().availableProcessors();
      }
    }

    /*
     * Wraps the memory related BTrace utility methods
     * @since 1.2
     */
    public static class Memory {
      // memory usage

      /**
       * Returns the amount of free memory in the Java Virtual Machine. Calling the <code>gc</code>
       * method may result in increasing the value returned by <code>freeMemory.</code>
       *
       * @return an approximation to the total amount of memory currently available for future
       *     allocated objects, measured in bytes.
       */
      public static long freeMemory() {
        return Runtime.getRuntime().freeMemory();
      }

      /**
       * Returns the total amount of memory in the Java virtual machine. The value returned by this
       * method may vary over time, depending on the host environment.
       *
       * <p>Note that the amount of memory required to hold an object of any given type may be
       * implementation-dependent.
       *
       * @return the total amount of memory currently available for current and future objects,
       *     measured in bytes.
       */
      public static long totalMemory() {
        return Runtime.getRuntime().totalMemory();
      }

      /**
       * Returns the maximum amount of memory that the Java virtual machine will attempt to use. If
       * there is no inherent limit then the value {@link java.lang.Long#MAX_VALUE} will be
       * returned.
       *
       * @return the maximum amount of memory that the virtual machine will attempt to use, measured
       *     in bytes
       */
      public static long maxMemory() {
        return Runtime.getRuntime().maxMemory();
      }

      /** Returns heap memory usage */
      public static MemoryUsage heapUsage() {
        return BTraceRuntime.heapUsage();
      }

      /** Returns non-heap memory usage */
      public static MemoryUsage nonHeapUsage() {
        return BTraceRuntime.nonHeapUsage();
      }

      /**
       * Returns the amount of memory in bytes that the Java virtual machine initially requests from
       * the operating system for memory management.
       */
      public static long init(MemoryUsage mu) {
        return mu.getInit();
      }

      /**
       * Returns the amount of memory in bytes that is committed for the Java virtual machine to
       * use. This amount of memory is guaranteed for the Java virtual machine to use.
       */
      public static long committed(MemoryUsage mu) {
        return mu.getCommitted();
      }

      /**
       * Returns the maximum amount of memory in bytes that can be used for memory management. This
       * method returns -1 if the maximum memory size is undefined.
       */
      public static long max(MemoryUsage mu) {
        return mu.getMax();
      }

      /** Returns the amount of used memory in bytes. */
      public static long used(MemoryUsage mu) {
        return mu.getUsed();
      }

      /** Returns the approximate number of objects for which finalization is pending. */
      public static long finalizationCount() {
        return BTraceRuntime.finalizationCount();
      }

      /**
       * Dump the snapshot of the Java heap to a file in hprof binary format. Only the live objects
       * are dumped. Under the current dir of traced app, ./btrace&lt;pid&gt;/btrace-class/
       * directory is created. Under that directory, a file of given fileName is created.
       *
       * @param fileName name of the file to which heap is dumped
       */
      public static void dumpHeap(String fileName) {
        dumpHeap(fileName, true);
      }

      /**
       * Dump the snapshot of the Java heap to a file in hprof binary format. Under the current dir
       * of traced app, ./btrace&lt;pid&gt;/btrace-class/ directory is created. Under that
       * directory, a file of given fileName is created.
       *
       * @param fileName name of the file to which heap is dumped
       * @param live flag that tells whether only live objects are to be dumped or all objects are
       *     to be dumped.
       */
      public static void dumpHeap(String fileName, boolean live) {
        BTraceRuntime.dumpHeap(fileName, live);
      }

      /**
       * Runs the garbage collector.
       *
       * <p>Calling the <code>gc</code> method suggests that the Java Virtual Machine expend effort
       * toward recycling unused objects in order to make the memory they currently occupy available
       * for quick reuse. When control returns from the method call, the Java Virtual Machine has
       * made a best effort to reclaim space from all discarded objects. This method calls Sys.gc()
       * to perform GC.
       */
      public static void gc() {
        java.lang.System.gc();
      }

      /**
       * Returns the total amount of time spent in GarbageCollection up to this point since the
       * application was started.
       *
       * @return Returns the amount of overall time spent in GC
       */
      public static long getTotalGcTime() {
        return BTraceRuntime.getTotalGcTime();
      }

      /**
       * Returns an overview of available memory pools <br>
       * It is possible to provide a text format the overview will use
       *
       * @param poolFormat The text format string to format the overview. <br>
       *     Exactly 5 arguments are passed to the format function. <br>
       *     The format defaults to ";%1$s;%2$d;%3$d;%4$d;%5$d;Memory]"
       * @return Returns the formatted value of memory pools overview
       * @since 1.2
       */
      public static String getMemoryPoolUsage(String poolFormat) {
        return BTraceRuntime.getMemoryPoolUsage(poolFormat);
      }

      /**
       * Runs the finalization methods of any objects pending finalization.
       *
       * <p>Calling this method suggests that the Java Virtual Machine expend effort toward running
       * the <code>finalize</code> methods of objects that have been found to be discarded but whose
       * <code>finalize</code> methods have not yet been run. When control returns from the method
       * call, the Java Virtual Machine has made a best effort to complete all outstanding
       * finalizations. This method calls Sys.runFinalization() to run finalization.
       */
      public static void runFinalization() {
        java.lang.System.runFinalization();
      }
    }

    /*
     * Wraps the VM related BTrace utility methods
     * @since 1.2
     */
    public static class VM {
      /**
       * Returns the input arguments passed to the Java virtual machine which does not include the
       * arguments to the <tt>main</tt> method. This method returns an empty list if there is no
       * input argument to the Java virtual machine.
       *
       * <p>Some Java virtual machine implementations may take input arguments from multiple
       * different sources: for examples, arguments passed from the application that launches the
       * Java virtual machine such as the 'java' command, environment variables, configuration
       * files, etc.
       *
       * <p>Typically, not all command-line options to the 'java' command are passed to the Java
       * virtual machine. Thus, the returned input arguments may not include all command-line
       * options.
       *
       * @return a list of <tt>String</tt> objects; each element is an argument passed to the Java
       *     virtual machine.
       */
      public static List<String> vmArguments() {
        return BTraceRuntime.getInputArguments();
      }

      /**
       * Prints VM input arguments list.
       *
       * @see #vmArguments
       */
      public static void printVmArguments() {
        println(vmArguments());
      }

      /**
       * Returns the Java virtual machine implementation version. This method is equivalent to
       * <b>Sys.getProperty("java.vm.version")}</b>.
       *
       * @return the Java virtual machine implementation version.
       */
      public static String vmVersion() {
        return BTraceRuntime.getVmVersion();
      }

      /**
       * Tests if the Java virtual machine supports the boot class path mechanism used by the
       * bootstrap class loader to search for class files.
       *
       * @return <tt>true</tt> if the Java virtual machine supports the class path mechanism;
       *     <tt>false</tt> otherwise.
       */
      public static boolean isBootClassPathSupported() {
        return BTraceRuntime.isBootClassPathSupported();
      }

      /**
       * Returns the boot class path that is used by the bootstrap class loader to search for class
       * files.
       *
       * <p>Multiple paths in the boot class path are separated by the path separator character of
       * the platform on which the Java virtual machine is running.
       *
       * <p>A Java virtual machine implementation may not support the boot class path mechanism for
       * the bootstrap class loader to search for class files. The {@link #isBootClassPathSupported}
       * method can be used to determine if the Java virtual machine supports this method.
       *
       * @return the boot class path.
       * @throws java.lang.UnsupportedOperationException if the Java virtual machine does not
       *     support this operation.
       */
      public static String bootClassPath() {
        return BTraceRuntime.getBootClassPath();
      }

      /**
       * Returns the Java class path that is used by the system class loader to search for class
       * files. This method is equivalent to <b>Sys.getProperty("java.class.path")</b>.
       *
       * @return the Java class path.
       */
      public static String classPath() {
        return Sys.Env.property("java.class.path");
      }

      /**
       * Returns the Java library path. This method is equivalent to
       * <b>Sys.getProperty("java.library.path")</b>.
       *
       * <p>Multiple paths in the Java library path are separated by the path separator character of
       * the platform of the Java virtual machine being monitored.
       *
       * @return the Java library path.
       */
      public static String libraryPath() {
        return Sys.Env.property("java.library.path");
      }

      /**
       * Returns the current number of live threads including both daemon and non-daemon threads.
       *
       * @return the current number of live threads.
       */
      public static long threadCount() {
        return BTraceRuntime.getThreadCount();
      }

      /**
       * Returns the peak live thread count since the Java virtual machine started or peak was
       * reset.
       *
       * @return the peak live thread count.
       */
      public static long peakThreadCount() {
        return BTraceRuntime.getPeakThreadCount();
      }

      /**
       * Returns the total number of threads created and also started since the Java virtual machine
       * started.
       *
       * @return the total number of threads started.
       */
      public static long totalStartedThreadCount() {
        return BTraceRuntime.getTotalStartedThreadCount();
      }

      /**
       * Returns the current number of live daemon threads.
       *
       * @return the current number of live daemon threads.
       */
      public static long daemonThreadCount() {
        return BTraceRuntime.getDaemonThreadCount();
      }

      /**
       * Returns the system load average for the last minute
       *
       * @return the system load average for the last minute
       */
      public static double systemLoadAverage() {
        return BTraceRuntime.getSystemLoadAverage();
      }

      /**
       * Returns the CPU time used by the process on which the Java virtual machine is running in
       * nanoseconds.
       *
       * @return the CPU time used by the process on which the JVM is running in nanoseconds.
       *     Returns -1 if this operation is not supported on this platform
       */
      public static long processCPUTime() {
        return BTraceRuntime.getProcessCPUTime();
      }

      /**
       * Returns the start time of the Java virtual machine in milliseconds. This method returns the
       * approximate time when the Java virtual machine started.
       *
       * @return start time of the Java virtual machine in milliseconds.
       */
      public static long vmStartTime() {
        return BTraceRuntime.vmStartTime();
      }

      /**
       * Returns the uptime of the Java virtual machine in milliseconds.
       *
       * @return uptime of the Java virtual machine in milliseconds.
       */
      public static long vmUptime() {
        return BTraceRuntime.vmUptime();
      }

      /**
       * Returns the total CPU time for the current thread in nanoseconds. The returned value is of
       * nanoseconds precision but not necessarily nanoseconds accuracy. If the implementation
       * distinguishes between user mode time and system mode time, the returned CPU time is the
       * amount of time that the current thread has executed in user mode or system mode.
       */
      public static long currentThreadCpuTime() {
        return BTraceRuntime.getCurrentThreadCpuTime();
      }

      /**
       * Returns the CPU time that the current thread has executed in user mode in nanoseconds. The
       * returned value is of nanoseconds precision but not necessarily nanoseconds accuracy.
       */
      public static long currentThreadUserTime() {
        return BTraceRuntime.getCurrentThreadUserTime();
      }
    }
  }

  /*
   * Wraps the jvmstat counters related BTrace utility methods
   * @since 1.2
   */
  public static class Counters {
    /** accessing jvmstat (perf) int counter */
    public static long perfInt(String name) {
      return BTraceRuntime.perfInt(name);
    }

    /** accessing jvmstat (perf) long counter */
    public static long perfLong(String name) {
      return BTraceRuntime.perfLong(name);
    }

    /** accessing jvmstat (perf) String counter */
    public static String perfString(String name) {
      return BTraceRuntime.perfString(name);
    }
  }

  /*
   * Wraps the dtrace related BTrace utility methods
   * @since 1.2
   */
  public static class D {
    /**
     * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.
     *
     * @see #dtraceProbe(String, String, int, int)
     */
    public static int probe(String str1, String str2) {
      return probe(str1, str2, -1, -1);
    }

    /**
     * BTrace to DTrace communication chennal. Raise DTrace USDT probe from BTrace.
     *
     * @see #dtraceProbe(String, String, int, int)
     */
    public static int probe(String str1, String str2, int i1) {
      return probe(str1, str2, i1, -1);
    }

    /**
     * BTrace to DTrace communication channel. Raise DTrace USDT probe from BTrace.
     *
     * @param str1 first String param to DTrace probe
     * @param str2 second String param to DTrace probe
     * @param i1 first int param to DTrace probe
     * @param i2 second int param to DTrace probe
     */
    public static int probe(String str1, String str2, int i1, int i2) {
      return BTraceRuntime.dtraceProbe(str1, str2, i1, i2);
    }
  }

  /**
   * Support for JFR integration.
   *
   * @since 2.1.0
   */
  public static final class Jfr {
    /**
     * Create a new event instance using the factory field annotated by {@linkplain
     * org.openjdk.btrace.core.annotations.Event}
     *
     * @param eventFactory the event factory
     * @return new event instance
     */
    public static JfrEvent prepareEvent(JfrEvent.Factory eventFactory) {
      return eventFactory.newEvent();
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, byte fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, char fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, short fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, int fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, long fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, float fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, double fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, boolean fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Set an event field value
     *
     * @param event event instance
     * @param fieldName field name
     * @param fieldValue field value
     */
    public static void setEventField(JfrEvent event, String fieldName, String fieldValue) {
      event.withValue(fieldName, fieldValue);
    }

    /**
     * Check whether the event should be committed.
     *
     * @see Event#shouldCommit()
     * @param event event to check
     * @return {@literal true} if the event should be committed
     */
    public static boolean shouldCommit(JfrEvent event) {
      return event.shouldCommit();
    }

    /**
     * Commit the event
     *
     * @see Event#commit()
     * @param event the event to commit
     */
    public static void commit(JfrEvent event) {
      event.commit();
    }

    public static void begin(JfrEvent event) {
      event.begin();
    }

    public static void end(JfrEvent event) {
      event.end();
    }
  }
}
