/* * Copyright (c) 2013, 2018, 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. * * 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 #include #include #include "jvmti.h" #include "jni_tools.h" #include "jvmti_tools.h" #include "agent_common.h" #ifdef __cplusplus extern "C" { #endif #define STATIC_FIELD 0x0008 ///amount of objects to be tagged #define TEST_OBJECTS_COUNT 4 ///expected amount of times object will bre ported by callbacks #define PRIMITIVE_OCCURANCE_COUNT 1 #define STRING_OCCURANCE_COUNT 2 #define PRIMITIVE_ARRAY_OCCURANCE_COUNT 2 #define NONPRIMITIVE_OCCURANCE_COUNT 1 /** tag format 63 35 32 16 0 |1 |type|obj idx|field idx| */ #define TAG_TYPE_PRIMITIVE 0 #define TAG_TYPE_STRING 1 #define TAG_TYPE_ARRAY 2 #define TAG_TYPE_OBJECT 3 #define ENCODE_TAG(type,obj,fld) (0x8000000000000000ULL|(((jlong)type)<<32)|(((jlong)obj)<<16)|fld) #define DECODE_TYPE(tag) ((tag>>32)&0x0FFFF) #define DECODE_OBJECT(tag) ((tag>>16)&0x0FFFF) #define DECODE_FIELD(tag) (tag&0x0FFFF) ///expected values #define BOOLEAN JNI_FALSE #define BYTE 0xB #define CHAR 'z' #define SHORT 0xB00 #define INT ((int)0xDEADBEEF) #define LONG 0xDEADBEEFDEADLL #define FLOAT 3.1416f #define DOUBLE 3.14159265 #define ARRAY_LENGTH 5 static wchar_t *STRING = L"I hope you'll find me in the heap!"; static jboolean BOOLEAN_ARRAY[] = {JNI_TRUE, JNI_TRUE, JNI_FALSE, JNI_TRUE, JNI_FALSE}; static jbyte BYTE_ARRAY[] = {BYTE, BYTE+1, BYTE+2, BYTE+3, BYTE+4}; static jchar CHAR_ARRAY[] = {CHAR, CHAR+1, CHAR+2, CHAR+3, CHAR+4}; static jshort SHORT_ARRAY[] = {SHORT, SHORT+1, SHORT+2, SHORT+3, SHORT+4}; static jint INT_ARRAY[] = {INT, INT+1, INT+2, INT+3, INT+4}; static jlong LONG_ARRAY[] = {LONG, LONG+1, LONG+2, LONG+3, LONG+4}; static jfloat FLOAT_ARRAY[] = {FLOAT, FLOAT+1, FLOAT+2, FLOAT+3, FLOAT+4}; static jdouble DOUBLE_ARRAY[] = {DOUBLE, DOUBLE+1, DOUBLE+2, DOUBLE+3, DOUBLE+4}; static long timeout = 0; ///information about field typedef struct { char *name; char *signature; int found; int collected; int primitive; } field_info_t; ///information about object typedef struct { char *name; int fields_count; field_info_t *fields; int collected; } object_info_t; static object_info_t objects_info[TEST_OBJECTS_COUNT]; #define className "nsk/jvmti/IterateThroughHeap/callbacks/Callbacks" #define fieldName "testObjects" #define fieldSig "[Ljava/lang/Object;" // Check if the signature is signature of primitive type. jboolean is_primitive_type(const char *signature) { if(!strcmp(signature,"C") || !strcmp(signature, "B") || !strcmp(signature, "S") || !strcmp(signature, "I") || !strcmp(signature, "J") || !strcmp(signature, "F") || !strcmp(signature, "D") || !strcmp(signature, "Z")) return JNI_TRUE; return JNI_FALSE; } // For given signature find expected tag type int get_tag_type(const char *signature) { if(is_primitive_type(signature)) { return TAG_TYPE_PRIMITIVE; } else if(signature[0]=='[' && is_primitive_type(signature+1)) { return TAG_TYPE_ARRAY; } else if(!strcmp(signature, "Ljava/lang/String;")) { return TAG_TYPE_STRING; } else { return TAG_TYPE_OBJECT; } } /** * Check value corectness accordning to it's type. * Returns 0 if value matched with expected. */ jboolean verify_value(jvalue value, jvmtiPrimitiveType type) { switch(type) { case JVMTI_PRIMITIVE_TYPE_BOOLEAN: return value.z==BOOLEAN; case JVMTI_PRIMITIVE_TYPE_BYTE: return value.b==BYTE; case JVMTI_PRIMITIVE_TYPE_CHAR: return value.c==CHAR; case JVMTI_PRIMITIVE_TYPE_SHORT: return value.s==SHORT; case JVMTI_PRIMITIVE_TYPE_INT: return value.i==INT; case JVMTI_PRIMITIVE_TYPE_LONG: return value.j==LONG; case JVMTI_PRIMITIVE_TYPE_FLOAT: return value.f==FLOAT; case JVMTI_PRIMITIVE_TYPE_DOUBLE: return value.d==DOUBLE; default: NSK_COMPLAIN1("Unknown type: %X.",type); return JNI_FALSE; } } // Check that array values are correct depending on type of elements jboolean verify_array(const void *array, jvmtiPrimitiveType type, jint length) { void *expected_array; switch(type) { case JVMTI_PRIMITIVE_TYPE_BOOLEAN: expected_array = (void*)BOOLEAN_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_CHAR: expected_array = (void*)CHAR_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_BYTE: expected_array = (void*)BYTE_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_SHORT: expected_array = (void*)SHORT_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_INT: expected_array = (void*)INT_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_LONG: expected_array = (void*)LONG_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_FLOAT: expected_array = (void*)FLOAT_ARRAY; break; case JVMTI_PRIMITIVE_TYPE_DOUBLE: expected_array = (void*)DOUBLE_ARRAY; break; default: NSK_COMPLAIN0("Unexpected type of array's elements.\n"); return JNI_FALSE; } return memcmp(expected_array,array,length) == 0; } jint JNICALL field_callback(jvmtiHeapReferenceKind kind, const jvmtiHeapReferenceInfo* info, jlong object_class_tag, jlong* object_tag_ptr, jvalue value, jvmtiPrimitiveType value_type, void* user_data) { jlong tag; tag = *object_tag_ptr; // skip all non-tagged fields as well as fields of tagged objects if(tag == 0 || DECODE_TYPE(tag) == TAG_TYPE_OBJECT || DECODE_TYPE(tag) == TAG_TYPE_STRING) { return 0; } else if(DECODE_TYPE(tag) != TAG_TYPE_PRIMITIVE) { NSK_COMPLAIN3("jvmtiPrimitiveFieldCallback was invoked for an object with " "non-primitive field tag (0x%lX) corresponging to %s::%s.\n", DECODE_TYPE(tag), objects_info[DECODE_OBJECT(tag)].name, objects_info[DECODE_OBJECT(tag)].fields[DECODE_FIELD(tag)].name); nsk_jvmti_setFailStatus(); return 0; } objects_info[DECODE_OBJECT(tag)].fields[info->field.index].found++; if(!verify_value(value, value_type)) { NSK_COMPLAIN2("Field %s::%s has unexpected value.\n", objects_info[DECODE_OBJECT(tag)].name, objects_info[DECODE_OBJECT(tag)].fields[info->field.index].name); nsk_jvmti_setFailStatus(); } return 0; } jint JNICALL string_callback(jlong class_tag, jlong size, jlong* tag_ptr, const jchar* value, jint value_length, void* user_data) { int matched = 1; int i; //skip all untegged strings if(*tag_ptr==0) { return 0; } else if(DECODE_TYPE(*tag_ptr) != TAG_TYPE_STRING) { NSK_COMPLAIN2("jvmtiStringPrimitiveValueCallback was invoked for an object " "with non-string tag corresponding to %s::%s.\n", objects_info[DECODE_OBJECT(*tag_ptr)].name, objects_info[DECODE_OBJECT(*tag_ptr)].fields[DECODE_FIELD(*tag_ptr)].name); return 0; } objects_info[DECODE_OBJECT(*tag_ptr)].fields[DECODE_FIELD(*tag_ptr)].found++; //check that reported length is the same as expected if(value_length != (jint) wcslen(STRING)) { NSK_COMPLAIN4("Length of reported string %s::%s is %d while %d is expected.\n", objects_info[DECODE_OBJECT(*tag_ptr)].name, objects_info[DECODE_OBJECT(*tag_ptr)].fields[DECODE_FIELD(*tag_ptr)].name, value_length, wcslen(STRING)); nsk_jvmti_setFailStatus(); return 0; } //compare reported value with expected one for(i = 0; i