From: <jik...@li...> - 2011-08-10 06:37:37
|
details: http://jikesrvm.hg.sourceforge.net/hgweb/jikesrvm/soc2011/rev/6d531a495a01 changeset: 10467:6d531a495a01 user: James Bornholt <u48...@an...> date: Wed Aug 10 16:37:22 2011 +1000 description: System property methods diffstat: rvm/src/org/jikesrvm/runtime/jvmti/JVMTIFunctions.java | 154 ++++++++++++++++- rvm/src/org/jikesrvm/runtime/jvmti/JVMTIHelpers.java | 14 + test-agents/systemproperties/Makefile | 26 ++ test-agents/systemproperties/systemproperties.c | 67 +++++++ 4 files changed, 253 insertions(+), 8 deletions(-) diffs (truncated from 324 to 300 lines): diff -r 39dee0a15818 -r 6d531a495a01 rvm/src/org/jikesrvm/runtime/jvmti/JVMTIFunctions.java --- a/rvm/src/org/jikesrvm/runtime/jvmti/JVMTIFunctions.java Fri Aug 05 00:34:49 2011 +1000 +++ b/rvm/src/org/jikesrvm/runtime/jvmti/JVMTIFunctions.java Wed Aug 10 16:37:22 2011 +1000 @@ -13,6 +13,8 @@ package org.jikesrvm.runtime.jvmti; +import java.util.Properties; + import org.jikesrvm.SizeConstants; import org.jikesrvm.VM; import org.jikesrvm.classloader.Atom; @@ -1475,9 +1477,36 @@ return JVMTI_ERROR_NOT_AVAILABLE; } + /** + * For the object indicated by objectJREF, return via hash_code_ptr a hash + * code. + * @param agent The JVMTI agent making the call + * @param objectJREF The JREF index of the object + * @param hash_code_ptr On return, points to the object's hash code + * @return a jvmtiError + */ private static int GetObjectHashCode(JVMTIAgent agent, int objectJREF, Address hash_code_ptr) { - VM.sysWriteln("JVMTI ERROR: Function GetObjectHashCode not implemented"); - return JVMTI_ERROR_NOT_AVAILABLE; + try { + if ( hash_code_ptr.isZero() ) { + return JVMTI_ERROR_NULL_POINTER; + } + Object obj; + try { + obj = (Object) RVMThread.getCurrentThread().getJNIEnv().getJNIRef(objectJREF); + } catch (ClassCastException e) { + return JVMTI_ERROR_INVALID_OBJECT; + } + if ( obj == null ) { + return JVMTI_ERROR_INVALID_OBJECT; + } + + hash_code_ptr.store(obj.hashCode()); + + return JVMTI_ERROR_NONE; + } catch (Throwable unexpected) { + unexpected.printStackTrace(System.err); + return JVMTI_ERROR_INTERNAL; + } } private static int GetObjectMonitorUsage(JVMTIAgent agent, int objectJREF, Address info_ptr) { @@ -2658,19 +2687,128 @@ * System Properties */ + /** + * The list of VM system property keys which may be used with + * GetSystemProperty is returned. + * @param agent The JVMTI agent making the call + * @param count_ptr A pointer to an int in which we will store the number of + * property keys being returned + * @param property_ptr On return, points to an array of property key strings + * @return a jvmtiError + */ private static int GetSystemProperties(JVMTIAgent agent, Address count_ptr, Address property_ptr) { - VM.sysWriteln("JVMTI ERROR: Function GetSystemProperties not implemented"); - return JVMTI_ERROR_NOT_AVAILABLE; + try { + if ( count_ptr.isZero() || property_ptr.isZero() ) { + return JVMTI_ERROR_NULL_POINTER; + } + + Properties props = java.lang.System.getProperties(); + + // Build an array + Address key_array = JVMTIHelpers.alloc(props.size() << LOG_BYTES_IN_ADDRESS); + if ( key_array.isZero() ) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } + Address loc = key_array; + for ( Object key : props.keySet() ) { + String key_str = (String) key; + Address key_buffer = JVMTIHelpers.alloc(key_str.length() + 1); + if ( key_buffer.isZero() ) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } + JVMTIHelpers.writeModifiedUTF8FromString(key_str, key_buffer); + loc.store(key_buffer); + loc = loc.plus(BYTES_IN_ADDRESS); + } + + // Store the array and count + count_ptr.store(props.size()); + property_ptr.store(key_array); + + return JVMTI_ERROR_NONE; + } catch (Throwable unexpected) { + unexpected.printStackTrace(System.err); + return JVMTI_ERROR_INTERNAL; + } } + /** + * Return a VM system property value given the property key. + * @param agent The JVMTI agent making the call + * @param property A pointer to a modified UTF8 string containing the key of + * the property to retreive + * @param value_ptr On return, points to the property value string + * @return a jvmtiError + */ private static int GetSystemProperty(JVMTIAgent agent, Address property, Address value_ptr) { - VM.sysWriteln("JVMTI ERROR: Function GetSystemProperty not implemented"); - return JVMTI_ERROR_NOT_AVAILABLE; + try { + if ( property.isZero() || value_ptr.isZero() ) { + return JVMTI_ERROR_NULL_POINTER; + } + + // Get the value + String key = JVMTIHelpers.readStringFromModifiedUTF8(property); + String val = java.lang.System.getProperty(key); + if ( val == null ) { + return JVMTI_ERROR_NOT_AVAILABLE; + } + + // Write a string with the value + Address val_buffer = JVMTIHelpers.alloc(val.length() + 1); + if ( val_buffer.isZero() ) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } + JVMTIHelpers.writeModifiedUTF8FromString(val, val_buffer); + + // Store the result + value_ptr.store(val_buffer); + + return JVMTI_ERROR_NONE; + } catch (Throwable unexpected) { + unexpected.printStackTrace(System.err); + return JVMTI_ERROR_INTERNAL; + } } + /** + * Set a VM system property value. + * XXX TODO we do not protect any of our system properties. Should we? e.g. + * properties like java.vm.name are writable with this configuration. + * @param agent The JVMTI agent making the call + * @param property The key of the property to set, as a modified UTF8 string + * @param value_ptr The value to set, as a modified UTF8 string + * @return a jvmtiError + */ private static int SetSystemProperty(JVMTIAgent agent, Address property, Address value_ptr) { - VM.sysWriteln("JVMTI ERROR: Function SetSystemProperty not implemented"); - return JVMTI_ERROR_NOT_AVAILABLE; + try { + if ( property.isZero() ) { + return JVMTI_ERROR_NULL_POINTER; + } + + // Get the key + String key = JVMTIHelpers.readStringFromModifiedUTF8(property); + + // If value_ptr is null, we just need to check if the specified property + // is writable. Since we don't implement any restrictions, this is just + // true if the property exists. + if ( value_ptr.isZero() ) { + if ( java.lang.System.getProperty(key) == null ) { + return JVMTI_ERROR_NOT_AVAILABLE; + } + else { + return JVMTI_ERROR_NONE; + } + } + String value = JVMTIHelpers.readStringFromModifiedUTF8(value_ptr); + + // Set the value + java.lang.System.setProperty(key, value); + + return JVMTI_ERROR_NONE; + } catch (Throwable unexpected) { + unexpected.printStackTrace(System.err); + return JVMTI_ERROR_INTERNAL; + } } /* diff -r 39dee0a15818 -r 6d531a495a01 rvm/src/org/jikesrvm/runtime/jvmti/JVMTIHelpers.java --- a/rvm/src/org/jikesrvm/runtime/jvmti/JVMTIHelpers.java Fri Aug 05 00:34:49 2011 +1000 +++ b/rvm/src/org/jikesrvm/runtime/jvmti/JVMTIHelpers.java Wed Aug 10 16:37:22 2011 +1000 @@ -12,11 +12,13 @@ */ package org.jikesrvm.runtime.jvmti; +import java.io.UTFDataFormatException; import java.nio.ByteBuffer; import org.jikesrvm.SizeConstants; import org.jikesrvm.VM; import org.jikesrvm.classloader.UTF8Convert; +import org.jikesrvm.jni.JNIGenericHelpers; import org.jikesrvm.runtime.SysCall; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; @@ -72,6 +74,18 @@ } /** + * Read a modified UTF8 null-terminated string from native code into a Java + * string. + * @param str The address of the C string + * @return A Java string + * @throws UTFDataFormatException + */ + public static String readStringFromModifiedUTF8(Address str) throws UTFDataFormatException { + byte[] strBytes = JNIGenericHelpers.createByteArrayFromC(str); + return UTF8Convert.fromUTF8(strBytes); + } + + /** * Set a bit in a multi-word bitfield either on or off. This is pretty * inefficient but lets us deal with bitfields whose length we don't know * a priori diff -r 39dee0a15818 -r 6d531a495a01 test-agents/systemproperties/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-agents/systemproperties/Makefile Wed Aug 10 16:37:22 2011 +1000 @@ -0,0 +1,26 @@ +# Simple makefile for x86_64-osx testing + +LIBNAME=systemproperties +SOURCES=systemproperties.c +ARCH=-arch i386 -m32 -mstackrealign +#ARCH=-arch x86_64 +#JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home +JAVA_HOME=../../ + +CFLAGS= -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer +CFLAGS+= $(ARCH) -W -Wall -Wno-unused -Wno-parentheses +CFLAGS+= -I. -I$(JAVA_HOME)/include + +OBJECTS=$(SOURCES:%.c=%.o) +LIBRARY=lib$(LIBNAME).jnilib +LDFLAGS=-Wl -soname=$(LIBRARY) -static-libgcc -mimpure-text +LIBRARIES=-lc +LINK_SHARED=$(LINK.c) -shared -o $@ + +all: $(LIBRARY) + +$(LIBRARY): $(OBJECTS) + $(LINK_SHARED) $(OBJECTS) $(LIBRARIES) + +clean: + rm -f $(LIBRARY) $(OBJECTS) diff -r 39dee0a15818 -r 6d531a495a01 test-agents/systemproperties/systemproperties.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-agents/systemproperties/systemproperties.c Wed Aug 10 16:37:22 2011 +1000 @@ -0,0 +1,67 @@ +/* + * Tests the General section functions + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "jni.h" +#include "jvmti.h" + +// Called when the agent is first loaded. +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + jint ret; + jvmtiError error; + jvmtiEnv *jvmti; + + ret = (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION); + if ( ret != JNI_OK ) { + fprintf(stderr, "Systemproperties agent: ERROR: couldn't create JVMTI environment (%d)\n", ret); + return -1; + } + + int count; + char **array; + error = (*jvmti)->GetSystemProperties(jvmti, &count, &array); + if ( error != JVMTI_ERROR_NONE ) { + fprintf(stderr, "Systemproperties agent: ERROR: couldn't get system properties (%d)\n", error); + } + else { + int i; + fprintf(stdout, "Systemproperties agent: got %d properties:\n", count); + for ( i = 0; i < count; i++ ) { + fprintf(stdout, "* %s\n", array[i]); + } + } + + char *key = "java.vm.name"; + char *val; + error = (*jvmti)->GetSystemProperty(jvmti, key, &val); + if ( error != JVMTI_ERROR_NONE ) { + fprintf(stderr, "Systemproperties agent: ERROR: couldn't get system property %s (%d)\n", key, error); + } |