blob: 2f650c85add6e8758299d4639d66665b663d753b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Gregory Shimansky
*/
/*
* JVMTI classes API
*/
#define LOG_DOMAIN "jvmti"
#include "cxxlog.h"
#include "jvmti_direct.h"
#include "jvmti_utils.h"
#include "Class.h"
#include "object_handles.h"
#include "jni_utils.h"
#include "jvmti_internal.h"
#include "open/vm_util.h"
#include "vm_strings.h"
#include "environment.h"
#include "classloader.h"
#include "suspend_checker.h"
/*
* The static function that extracts class from the handle.
*
* Also, it checks if TI environment is valid, the function may be called
* in current phase, and the results pointers are not NULL.
*
* @param env - the TI environment this function is called for.
* @param phase_mask - the phase mask this function may be called in.
* @param handle - the handle to extract the class from.
* @param p1 - the pointer to be checked if NULL.
* @param p2 - the pointer to be checked if NULL.
* @param errorCode - keeps the error status if error has happen.
* @return the corresponding class structure or NULL if wrong handler
* is specified or class was unloaded or any pointer is NULL.
*/
static inline Class* get_class_from_handle(jvmtiEnv* UNREF env, jvmtiPhase UNREF phase_mask,
jclass handle, void* p1, void *p2, jvmtiError* errorCode)
{
assert(hythread_is_suspend_enabled());
if (NULL == handle || p1 == NULL || p2 == NULL)
{
*errorCode = JVMTI_ERROR_NULL_POINTER;
return NULL;
}
Class *cl = jclass_to_struct_Class(handle);
return cl;
}
/* It is the same to previous function, but it checks one pointer only. */
static inline Class* get_class_from_handle(jvmtiEnv* env, jvmtiPhase phase_mask,
jclass handle, void* p1, jvmtiError* errorCode)
{
return get_class_from_handle(env, phase_mask, handle, p1, (void*) 1,
errorCode);
}
/* It is the same to previous function, but it checks no pointers. */
static inline Class* get_class_from_handle(jvmtiEnv* env, jvmtiPhase phase_mask,
jclass handle, jvmtiError* errorCode)
{
return get_class_from_handle(env, phase_mask, handle, (void *) 1, (void*) 1,
errorCode);
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetLoadedClasses(jvmtiEnv* env,
jint* classes_num,
jclass** classes)
{
TRACE2("jvmti.class", "GetLoadedClasses called");
SuspendEnabledChecker sec;
Class **klass;
unsigned int index;
unsigned int count;
unsigned int number;
unsigned int cl_count;
jvmtiError errorCode;
ClassLoader* classloader;
ClassLoader *bootstrap;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (classes_num == NULL || classes == NULL)
{
return JVMTI_ERROR_NULL_POINTER;
}
ClassLoader::LockLoadersTable();
/**
* Get the number of loaded classes by bootstrap loader
*/
bootstrap = VM_Global_State::loader_env->bootstrap_class_loader;
bootstrap->Lock();
ClassTable* tbl = bootstrap->GetLoadedClasses();
count = tbl->GetItemCount();
/**
* Count classes in user class loaders which are loaded by these class loaders
*/
cl_count = ClassLoader::GetClassLoaderNumber();
for( index = 0; index < cl_count; index++ )
{
classloader = (ClassLoader::GetClassLoaderTable())[index];
classloader->Lock();
tbl = classloader->GetLoadedClasses();
ClassTable::iterator it;
for(it = tbl->begin(); it != tbl->end(); it++)
{
klass = &it->second;
if ((*klass)->get_class_loader() != classloader)
continue;
count++;
}
}
count -= 9; // number of primitive types; see JVM TI spec.
/**
* No loaded classes
*/
if (!count)
{
for(index = 0; index < cl_count; index++)
{
classloader = (ClassLoader::GetClassLoaderTable())[index];
classloader->Unlock();
}
bootstrap->Unlock();
ClassLoader::UnlockLoadersTable();
*classes = NULL;
*classes_num = 0;
return JVMTI_ERROR_NONE;
}
/**
* Allocate memory to be filled with class pointers
*/
errorCode = _allocate( (sizeof(jclass) * count), (unsigned char**) classes );
if (errorCode != JVMTI_ERROR_NONE) {
for(index = 0; index < cl_count; index++)
{
classloader = (ClassLoader::GetClassLoaderTable())[index];
classloader->Unlock();
}
bootstrap->Unlock();
ClassLoader::UnlockLoadersTable();
return errorCode;
}
/**
* Set resulting class table
* First class loader is bootstrap class loader
*/
number = 0;
index = 0;
classloader = VM_Global_State::loader_env->bootstrap_class_loader;
do
{
/**
* Create jclass handle for classes and set in jclass table
*/
ClassTable::iterator it;
tbl = classloader->GetLoadedClasses();
for(it = tbl->begin(); it != tbl->end(); it++)
{
klass = &it->second;
if((*klass)->is_primitive())
continue;
if ((*klass)->get_class_loader() != classloader)
continue;
// create a new jclass handle for Class
ObjectHandle new_handle = struct_Class_to_jclass(*klass);
// set created handle into jclass handle table
(*classes)[number++] = (jclass)new_handle;
}
classloader->Unlock();
/**
* Get next class loader
*/
if( index < cl_count ) {
classloader = (ClassLoader::GetClassLoaderTable())[index++];
} else {
break;
}
} while( true );
assert( number == count );
ClassLoader::UnlockLoadersTable();
/**
* Set class number
*/
*classes_num = number;
return JVMTI_ERROR_NONE;
} // jvmtiGetLoadedClasses
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetClassLoaderClasses(jvmtiEnv* env,
jobject initiating_loader,
jint* class_count_ptr,
jclass** classes_ptr)
{
TRACE2("jvmti.class", "GetClassLoaderClasses called");
SuspendEnabledChecker sec;
unsigned index,
count;
Class **klass;
ClassTable *tbl;
ClassLoader* classloader;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (class_count_ptr == NULL || classes_ptr == NULL) {
return JVMTI_ERROR_NULL_POINTER;
}
/**
* Get class loader
*/
if( initiating_loader == NULL ) {
// get bootstrap class loader
classloader = VM_Global_State::loader_env->bootstrap_class_loader;
} else {
// get user defined class loader
classloader = ClassLoader::FindByObject((((ObjectHandle)initiating_loader)->object));
}
classloader->Lock();
/**
* Get the number of loaded classes
*/
tbl = classloader->GetInitiatedClasses();
if( !(count = tbl->GetItemCount()) ) {
classloader->Unlock();
// no loaded classes
*classes_ptr = NULL;
*class_count_ptr = 0;
return JVMTI_ERROR_NONE;
}
/**
* Allocate memory to be filled with class pointers
*/
errorCode = _allocate( (sizeof(jclass) * count), (unsigned char**)classes_ptr );
if (errorCode != JVMTI_ERROR_NONE) {
classloader->Unlock();
return errorCode;
}
/**
* Create jclass handle for classes and set in jclass table
*/
index = 0;
ClassTable::iterator it;
for(it = tbl->begin(); it != tbl->end(); it++)
{
klass = &it->second;
// create a new jclass handle for Class
ObjectHandle new_handle = struct_Class_to_jclass(*klass);
// set created handle into jclass handle table
(*classes_ptr)[index++] = (jclass)new_handle;
}
assert( index == count );
classloader->Unlock();
/**
* Set class number
*/
*class_count_ptr = count;
return JVMTI_ERROR_NONE;
} // jvmtiGetClassLoaderClasses
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetClassSignature( jvmtiEnv* env,
jclass handle,
char** sig,
char** gen_sig)
{
TRACE2("jvmti.class", "GetClassSignature called");
SuspendEnabledChecker sec;
int len;
size_t sig_len;
char *pointer,
*signature;
Class *klass;
jvmtiError result;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
/**
* Get class from handle, set error if need it
*/
klass = get_class_from_handle( env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE),
handle, &result );
if( klass == NULL ) {
// check getting class
return result;
}
if( sig ) {
// get class signature length
sig_len = GetClassSignatureLength( klass );
// allocate memory for class signature
result = _allocate( sig_len + 1, (unsigned char**)&signature );
if( result != JVMTI_ERROR_NONE ) {
return result;
}
// get class signature
GetClassSignature( klass, signature );
TRACE2("jvmti-class", "Class signature = " << signature);
// allocate memory for class UTF8 signature
len = get_utf8_length_of_8bit( (const U_8*)signature, sig_len);
result = _allocate( len + 1, (unsigned char**)&pointer );
if( result != JVMTI_ERROR_NONE ) {
return result;
}
// copy class UTF8 signature
utf8_from_8bit( pointer, (const U_8*)signature, sig_len );
// set class UTF8 signature
*sig = pointer;
// free memory for class signature
_deallocate( (unsigned char*)signature );
}
// set generic signature of the class
if( gen_sig ) *gen_sig = NULL;
return JVMTI_ERROR_NONE;
} // jvmtiGetClassSignature
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetClassStatus(jvmtiEnv* env, jclass handle, jint* status_ptr)
{
TRACE2("jvmti.class", "GetClassStatus called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, status_ptr,
&errorCode);
if (cl == NULL)
return errorCode;
*status_ptr = 0;
if(cl->is_primitive()) {
*status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE;
} else if(cl->is_array()) {
*status_ptr = JVMTI_CLASS_STATUS_ARRAY;
} else {
switch(cl->get_state())
{
case ST_Start:
case ST_LoadingAncestors:
case ST_Loaded:
case ST_BytecodesVerified:
case ST_InstanceSizeComputed:
break;
case ST_Prepared:
*status_ptr |= JVMTI_CLASS_STATUS_PREPARED;
break;
case ST_ConstraintsVerified:
case ST_Initializing:
*status_ptr |= JVMTI_CLASS_STATUS_PREPARED
| JVMTI_CLASS_STATUS_VERIFIED;
break;
case ST_Initialized:
*status_ptr |= JVMTI_CLASS_STATUS_INITIALIZED
| JVMTI_CLASS_STATUS_PREPARED
| JVMTI_CLASS_STATUS_VERIFIED;
break;
case ST_Error:
*status_ptr |= JVMTI_CLASS_STATUS_ERROR
| JVMTI_CLASS_STATUS_INITIALIZED
| JVMTI_CLASS_STATUS_PREPARED
| JVMTI_CLASS_STATUS_VERIFIED;
break;
default:
return JVMTI_ERROR_INTERNAL;
}
}
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetSourceFileName(jvmtiEnv* env, jclass handle, char** res)
{
TRACE2("jvmti.class", "GetSourceFileName called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
CHECK_CAPABILITY(can_get_source_file_name);
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, res,
&errorCode);
if( cl == NULL ) return errorCode;
if(cl->is_primitive() || cl->is_array())
{
TRACE2("jvmti.class", "GetSourceFileName called, name = "
<< cl->get_name()->bytes << " file name is absent");
return JVMTI_ERROR_ABSENT_INFORMATION;
}
if(!cl->has_source_information()) return JVMTI_ERROR_ABSENT_INFORMATION;
TRACE2("jvmti.class", "GetSourceFileName called, name = "
<< cl->get_name()->bytes << " file name = "
<< cl->get_source_file_name());
errorCode = _allocate(cl->get_source_file_name_length() + 1, (unsigned char**)res);
if( errorCode != JVMTI_ERROR_NONE ) return errorCode;
memcpy(*res, cl->get_source_file_name(), cl->get_source_file_name_length() + 1);
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetClassModifiers(jvmtiEnv* env, jclass handle, jint* modifiers_ptr)
{
TRACE2("jvmti.class", "GetClassModifiers called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, modifiers_ptr,
&errorCode);
if( cl == NULL ) return errorCode;
*modifiers_ptr = 0;
if(cl->is_public()) *modifiers_ptr |= ACC_PUBLIC;
if(cl->is_final()) *modifiers_ptr |= ACC_FINAL;
if(cl->is_super()) *modifiers_ptr |= ACC_SUPER;
if(cl->is_interface()) *modifiers_ptr |= ACC_INTERFACE;
if(cl->is_abstract()) *modifiers_ptr |= ACC_ABSTRACT;
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetClassMethods(jvmtiEnv* env, jclass handle, jint* method_count_ptr,
jmethodID** methods_ptr)
{
TRACE2("jvmti.class", "GetClassMethods called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle, method_count_ptr, methods_ptr,
&errorCode);
if( cl == NULL ) return errorCode;
/*
* Check class status. If class is not on PREPARED status, GetClassMethods(...)
* function returns JVMTI_ERROR_CLASS_NOT_PREPARED
*/
if(!cl->is_at_least_prepared())
return JVMTI_ERROR_CLASS_NOT_PREPARED;
errorCode = _allocate(cl->get_number_of_methods()*sizeof(jmethodID), (unsigned char**)methods_ptr );
if( errorCode != JVMTI_ERROR_NONE ) return errorCode;
*method_count_ptr = cl->get_number_of_methods();
for(short i = 0; i < cl->get_number_of_methods(); i++ )
(*methods_ptr)[i] = (jmethodID)cl->get_method(i);
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetClassFields(jvmtiEnv* env, jclass handle, jint* field_count_ptr,
jfieldID** fields_ptr)
{
TRACE2("jvmti.class", "GetClassFields called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), handle,
field_count_ptr, fields_ptr, &errorCode);
if( cl == NULL ) return errorCode;
/*
* Check class status. If class is not on PREPARED status, GetClassMethods(...)
* function returns JVMTI_ERROR_CLASS_NOT_PREPARED
*/
if(!cl->is_at_least_prepared())
return JVMTI_ERROR_CLASS_NOT_PREPARED;
errorCode = _allocate(cl->get_number_of_fields()*sizeof(jfieldID),
(unsigned char**)fields_ptr);
if( errorCode != JVMTI_ERROR_NONE ) return errorCode;
*field_count_ptr = cl->get_number_of_fields();
for(short i = 0; i < cl->get_number_of_fields(); i++ )
(*fields_ptr)[i] = (jfieldID)cl->get_field(i);
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetImplementedInterfaces(jvmtiEnv* env, jclass klass, jint* interface_count_ptr,
jclass** interfaces_ptr)
{
TRACE2("jvmti.class", "GetImplementedInterfaces called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(klass))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE), klass,
interface_count_ptr, interfaces_ptr, &errorCode);
if( cl == NULL ) return errorCode;
/*
* Check class status. If class is not on PREPARED status, GetClassMethods(...)
* function returns JVMTI_ERROR_CLASS_NOT_PREPARED
*/
if(!cl->is_at_least_prepared())
return JVMTI_ERROR_CLASS_NOT_PREPARED;
errorCode = _allocate( cl->get_number_of_superinterfaces()*sizeof(jclass),
reinterpret_cast<unsigned char**>(interfaces_ptr) );
if( errorCode != JVMTI_ERROR_NONE ) return errorCode;
ObjectHandle jclss;
for( int i = 0; i < cl->get_number_of_superinterfaces(); i++ )
{
jclss = struct_Class_to_jclass(cl->get_superinterface(i));
(*interfaces_ptr)[i] = (jclass)jclss;
}
*interface_count_ptr = cl->get_number_of_superinterfaces();
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiIsInterface(jvmtiEnv* env, jclass handle, jboolean* is_interface_ptr)
{
TRACE2("jvmti.class", "IsInterface called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE),
handle, is_interface_ptr, &errorCode);
if (cl == NULL)
return errorCode;
TRACE2("jvmti.class", "IsInterface: class = " << cl->get_name()->bytes);
*is_interface_ptr = (jboolean)(cl->is_interface() ? JNI_TRUE : JNI_FALSE);
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiIsArrayClass(jvmtiEnv* env, jclass handle, jboolean* is_array_class_ptr)
{
TRACE2("jvmti.class", "IsArrayClass called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* cl = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE),
handle, is_array_class_ptr, &errorCode);
if (cl == NULL)
return errorCode;
TRACE2("jvmti.class", "IsArrayClass: class = " << cl->get_name()->bytes);
*is_array_class_ptr = (jboolean)(cl->is_array() ? JNI_TRUE : JNI_FALSE);
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL jvmtiGetClassLoader(jvmtiEnv* env, jclass handle, jobject* classloader_ptr)
{
TRACE2("jvmti.class", "GetClassLoader called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* clss = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE),
handle, classloader_ptr, &errorCode);
if (clss == NULL)
return errorCode;
tmn_suspend_disable();
ManagedObject* cl = clss->get_class_loader()->GetLoader();
if( !cl ) {
*classloader_ptr = NULL;
} else {
ObjectHandle oh = oh_allocate_local_handle();
oh->object = cl;
*classloader_ptr = (jobject)oh;
}
tmn_suspend_enable();
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiGetSourceDebugExtension(jvmtiEnv* env, jclass handle, char** source_debug_extension_ptr)
{
TRACE2("jvmti.class", "GetSourceDebugExtension called");
SuspendEnabledChecker sec;
jvmtiError errorCode;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
if (! is_valid_class_object(handle))
return JVMTI_ERROR_INVALID_CLASS;
Class* clss = get_class_from_handle(env,
jvmtiPhase (JVMTI_PHASE_START | JVMTI_PHASE_LIVE),
handle, source_debug_extension_ptr, &errorCode);
if (clss == NULL)
return errorCode;
if(!clss->has_source_debug_extension()) return JVMTI_ERROR_ABSENT_INFORMATION;
errorCode = _allocate(clss->get_source_debug_extension_length() + 1,
reinterpret_cast<unsigned char**>(source_debug_extension_ptr));
if( errorCode != JVMTI_ERROR_NONE )
return errorCode;
memcpy(*source_debug_extension_ptr, clss->get_source_debug_extension(),
clss->get_source_debug_extension_length() + 1);
return JVMTI_ERROR_NONE;
}
/*
* @see official specification for details.
*/
jvmtiError JNICALL
jvmtiRedefineClasses(jvmtiEnv* env, jint UNREF class_count,
const jvmtiClassDefinition* UNREF class_definitions)
{
TRACE2("jvmti.class", "RedefineClasses called");
SuspendEnabledChecker sec;
/*
* Check given env & current phase.
*/
jvmtiPhase phases[] = {JVMTI_PHASE_LIVE};
CHECK_EVERYTHING();
//TBD
return JVMTI_NYI;
}