jdk/src/share/native/sun/tracing/dtrace/JVM.c
author jbachorik
Tue, 29 Jul 2014 10:06:02 +0200
changeset 25754 2fc68d1b7c03
parent 23056 af6eda86177e
child 25755 49d8c933dd62
permissions -rw-r--r--
8030115: [parfait] warnings from b119 for jdk.src.share.native.sun.tracing.dtrace: JNI exception pending Reviewed-by: dholmes, dsamersoff, sspitsyn

/*
 * Copyright (c) 2008, 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.
 */

#include <stdlib.h>

#include "jvm.h"
#include "jni.h"
#include "jni_util.h"

#include "jvm_symbols.h"
#include "sun_tracing_dtrace_JVM.h"

#ifdef __cplusplus
extern "C" {
#endif

static JvmSymbols* jvm_symbols = NULL;

static void initialize() {
    static int initialized = 0;
    if (initialized == 0) {
        jvm_symbols = lookupJvmSymbols();
        initialized = 1;
    }
}

/*
 * Class:     sun_tracing_dtrace_JVM
 * Method:    isSupported0
 * Signature: ()I
 */
JNIEXPORT jboolean JNICALL Java_sun_tracing_dtrace_JVM_isSupported0(
        JNIEnv* env, jclass cls) {
    initialize();
    if (jvm_symbols != NULL) {
        return jvm_symbols->IsSupported(env) ? JNI_TRUE : JNI_FALSE;
    } else {
        return JNI_FALSE;
    }
}

// Macros that cause an immediate return if we detect an exception
#define CHECK if ((*env)->ExceptionOccurred(env)) { return; }
#define CHECK_(x) if ((*env)->ExceptionOccurred(env)) { return x; }

static void readProbeData (
        JNIEnv* env, jobject probe, JVM_DTraceProbe* jvm_probe) {
    jclass clazz;
    jmethodID mid;
    jobject method;

    if (jvm_probe == NULL) {
        return; // just in case
    }

    clazz = (*env)->GetObjectClass(env, probe); CHECK

    mid = (*env)->GetMethodID(
        env, clazz, "getFunctionName", "()Ljava/lang/String;"); CHECK
    jvm_probe->function = (jstring)(*env)->CallObjectMethod(
        env, probe, mid); CHECK

    mid = (*env)->GetMethodID(
        env, clazz, "getProbeName", "()Ljava/lang/String;"); CHECK
    jvm_probe->name = (jstring)(*env)->CallObjectMethod(env, probe, mid); CHECK

    mid = (*env)->GetMethodID(
        env, clazz, "getMethod", "()Ljava/lang/reflect/Method;"); CHECK
    method = (*env)->CallObjectMethod(env, probe, mid); CHECK
    jvm_probe->method = (*env)->FromReflectedMethod(env, method); CHECK
}

static void readFieldInterfaceAttributes(
        char* annotationName, JNIEnv* env, jobject provider,
        JVM_DTraceInterfaceAttributes* attrs) {
    jobject result;
    jobject result_clazz;
    jclass provider_clazz;
    jclass annotation_clazz;
    jmethodID get;
    jmethodID enc;

    provider_clazz = (*env)->GetObjectClass(env, provider); CHECK
    annotation_clazz = (*env)->FindClass(env, annotationName); CHECK

    get = (*env)->GetMethodID(env, provider_clazz, "getNameStabilityFor",
        "(Ljava/lang/Class;)Lcom/sun/tracing/dtrace/StabilityLevel;"); CHECK
    result = (*env)->CallObjectMethod(
        env, provider, get, annotation_clazz); CHECK
    result_clazz = (*env)->GetObjectClass(env, result); CHECK
    enc = (*env)->GetMethodID(env, result_clazz, "getEncoding", "()I"); CHECK
    attrs->nameStability = (*env)->CallIntMethod(env, result, enc); CHECK

    get = (*env)->GetMethodID(env, provider_clazz, "getDataStabilityFor",
        "(Ljava/lang/Class;)Lcom/sun/tracing/dtrace/StabilityLevel;"); CHECK
    result = (*env)->CallObjectMethod(
        env, provider, get, annotation_clazz); CHECK
    result_clazz = (*env)->GetObjectClass(env, result); CHECK
    enc = (*env)->GetMethodID(env, result_clazz, "getEncoding", "()I"); CHECK
    attrs->dataStability = (*env)->CallIntMethod(env, result, enc); CHECK

    get = (*env)->GetMethodID(env, provider_clazz, "getDependencyClassFor",
        "(Ljava/lang/Class;)Lcom/sun/tracing/dtrace/DependencyClass;"); CHECK
    result = (*env)->CallObjectMethod(
        env, provider, get, annotation_clazz); CHECK
    result_clazz = (*env)->GetObjectClass(env, result); CHECK
    enc = (*env)->GetMethodID(env, result_clazz, "getEncoding", "()I"); CHECK
    attrs->dependencyClass = (*env)->CallIntMethod(env, result, enc); CHECK
}

static void readInterfaceAttributes(
        JNIEnv* env, jobject provider, JVM_DTraceProvider* jvm_provider) {
    readFieldInterfaceAttributes("com/sun/tracing/dtrace/ProviderAttributes",
        env, provider, &(jvm_provider->providerAttributes));
    readFieldInterfaceAttributes("com/sun/tracing/dtrace/ModuleAttributes",
        env, provider, &(jvm_provider->moduleAttributes));
    readFieldInterfaceAttributes("com/sun/tracing/dtrace/FunctionAttributes",
        env, provider, &(jvm_provider->functionAttributes));
    readFieldInterfaceAttributes("com/sun/tracing/dtrace/NameAttributes",
        env, provider, &(jvm_provider->nameAttributes));
    readFieldInterfaceAttributes("com/sun/tracing/dtrace/ArgsAttributes",
        env, provider, &(jvm_provider->argsAttributes));
}

static int readProviderData(
        JNIEnv* env, jobject provider, JVM_DTraceProvider* jvm_provider) {
    jmethodID mid;
    jobjectArray probes;
    jsize i;
    jclass clazz = (*env)->GetObjectClass(env, provider); CHECK_(0)
    mid = (*env)->GetMethodID(
        env, clazz, "getProbes", "()[Lsun/tracing/dtrace/DTraceProbe;"); CHECK_(0)
    probes = (jobjectArray)(*env)->CallObjectMethod(
        env, provider, mid); CHECK_(0)

    // Fill JVM structure, describing provider
    jvm_provider->probe_count = (*env)->GetArrayLength(env, probes); CHECK_(0)
    jvm_provider->probes = (JVM_DTraceProbe*)calloc(
        jvm_provider->probe_count, sizeof(*jvm_provider->probes));
    mid = (*env)->GetMethodID(
        env, clazz, "getProviderName", "()Ljava/lang/String;"); CHECK_(0)
    jvm_provider->name = (jstring)(*env)->CallObjectMethod(
        env, provider, mid); CHECK_(0)

    readInterfaceAttributes(env, provider, jvm_provider); CHECK_(0)

    for (i = 0; i < jvm_provider->probe_count; ++i) {
        jobject probe = (*env)->GetObjectArrayElement(env, probes, i); CHECK_(0)
        readProbeData(env, probe, &jvm_provider->probes[i]); CHECK_(0)
    }

    return 1;
}

/*
 * Class:     sun_tracing_dtrace_JVM
 * Method:    activate0
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_sun_tracing_dtrace_JVM_activate0(
        JNIEnv* env, jclass cls, jstring moduleName, jobjectArray providers) {
    jlong handle = 0;
    jsize num_providers;
    jsize i;
    JVM_DTraceProvider* jvm_providers;

    initialize();

    if (jvm_symbols == NULL) {
      return 0;
    }

    num_providers = (*env)->GetArrayLength(env, providers); CHECK_(0L)

    jvm_providers = (JVM_DTraceProvider*)calloc(
        num_providers, sizeof(*jvm_providers));

    int count = 0;
    for (; count < num_providers; ++count) {
        JVM_DTraceProvider* p = &(jvm_providers[count]);
        jobject provider = (*env)->GetObjectArrayElement(
            env, providers, count);
        if ((*env)->ExceptionOccurred(env) ||
            ! readProviderData(env, provider, p)) {
            // got an error, bail out!
            break;
        }
    }

    if (count == num_providers) {
        // all providers successfully loaded - get the handle
        handle = jvm_symbols->Activate(
            env, JVM_TRACING_DTRACE_VERSION, moduleName,
            num_providers, jvm_providers);
    }

    for (i = 0; i < num_providers; ++i) {
        JVM_DTraceProvider* p = &(jvm_providers[i]);
        free(p->probes);
    }
    free(jvm_providers);

    return handle;
}

/*
 * Class:     sun_tracing_dtrace_JVM
 * Method:    dispose0
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_sun_tracing_dtrace_JVM_dispose0(
        JNIEnv* env, jclass cls, jlong handle) {
    if (jvm_symbols != NULL && handle != 0) {
        jvm_symbols->Dispose(env, handle);
    }
}

/*
 * Class:     sun_tracing_dtrace_JVM
 * Method:    isEnabled0
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_sun_tracing_dtrace_JVM_isEnabled0(
        JNIEnv* env, jclass cls, jobject method) {
    jmethodID mid;
    if (jvm_symbols != NULL && method != NULL) {
        mid = (*env)->FromReflectedMethod(env, method);
        return jvm_symbols->IsProbeEnabled(env, mid);
    }
    return JNI_FALSE;
}

/*
 * Class:     sun_tracing_dtrace_JVM
 * Method:    defineClass0
 * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BII)Ljava/lang/Class;
 *
 * The implementation of this native static method is a copy of that of
 * the native instance method Java_java_lang_ClassLoader_defineClass0()
 * with the implicit "this" parameter becoming the "loader" parameter.
 *
 * This code was cloned and modified from java_lang_reflect_Proxy
 */
JNIEXPORT jclass JNICALL
Java_sun_tracing_dtrace_JVM_defineClass0(
        JNIEnv *env, jclass ignore, jobject loader, jstring name, jbyteArray data,
        jint offset, jint length)
{
    jbyte *body;
    char *utfName;
    jclass result = 0;
    char buf[128];

    if (data == NULL) {
        return 0;
    }

    /* Work around 4153825. malloc crashes on Solaris when passed a
     * negative size.
     */
    if (length < 0) {
        return 0;
    }

    body = (jbyte *)malloc(length);

    if (body == 0) {
        return 0;
    }

    (*env)->GetByteArrayRegion(env, data, offset, length, body);

    if ((*env)->ExceptionOccurred(env))
        goto free_body;

    if (name != NULL) {
        int i;
        jsize len = (*env)->GetStringUTFLength(env, name);
        int unicode_len = (*env)->GetStringLength(env, name);
        if (len >= (jsize)sizeof(buf)) {
            utfName = malloc(len + 1);
            if (utfName == NULL) {
                goto free_body;
            }
        } else {
            utfName = buf;
        }
        (*env)->GetStringUTFRegion(env, name, 0, unicode_len, utfName);

        // Convert '.' to '/' in the package name
        for (i = 0; i < unicode_len; ++i) {
            if (utfName[i] == '.') {
                utfName[i] = '/';
            }
        }
    } else {
        utfName = NULL;
    }

    result = (*env)->DefineClass(env, utfName, loader, body, length);

    if (utfName && utfName != buf)
        free(utfName);

 free_body:
    free(body);
    return result;
}

#ifdef __cplusplus
}
#endif