/*
* Copyright (c) 2012, 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.
*/
package com.sun.max.vm;
import static com.sun.max.vm.MaxineVM.*;
import com.sun.max.unsafe.*;
import com.sun.max.util.*;
import com.sun.max.vm.reference.*;
import com.sun.max.vm.runtime.*;
/**
* The set of "VM" properties, defined and used by the VM. This is a subset of the standard set of properties defined by
* {@link java.lang.System#getProperties(), and is used by {@code JVMTI}. The set below is the same as reported by
* HotSpot.
*
* Several properties are defined to be immutable, and all of those except {@code java.vm.info}, have values that are
* computed once, at image build time. Values set as {@code null} here are filled in by the VM at startup, (but not early
* enough to be strictly compliant with JVMTI). Access to the property names and values must be possible in primordial
* mode. In addition a JVMTI agent can set a property in primordial mode and that value has to take effect in the VM
* startup.
*
* JVMTI specifically does <b>not</b> require that the values initially set here track changes subsequently made by
* {@link System#setProperty(String, String)}.
*
* We consistently use "Oracle" for vendor even though Hotspot still reports "Sun" for JDK 6.
*/
public enum VMProperty {
// These are the "strongly recommended" properties
JAVA_VM_VENDOR("java.vm.vendor", "Oracle Corporation", false),
JAVA_VM_VERSION("java.vm.version", MaxineVM.VERSION_STRING, false),
JAVA_VM_NAME("java.vm.name", MaxineVM.name(), false),
JAVA_VM_INFO("java.vm.info", vm().compilationBroker.mode(), false), // updated by VM at runtime, immutable otherwise
JAVA_LIBRARY_PATH("java.library.path", null, true),
JAVA_CLASS_PATH("java.class.path", null, true),
// These are the remainder supported by Hotspot
JAVA_VM_SPECIFICATION_NAME("java.vm.specification.name", "Java Virtual Machine Specification", false),
JAVA_VM_SPECIFICATION_VENDOR("java.vm.specification.vendor", "Oracle Corporation", false),
JAVA_VM_SPECIFICATION_VERSION("java.vm.specification.version", "1.0", false),
JAVA_EXT_DIRS("java.ext.dirs", null, true),
JAVA_ENDORSED_DIRS("java.endorsed.dirs", null, true),
JAVA_HOME("java.home", null, true),
SUN_BOOT_LIBRARY_PATH("sun.boot.library.path", null, true),
SUN_BOOT_CLASS_PATH("sun.boot.class.path", null, true),
SUN_JAVA_COMMAND("sun.java.command", null, false),
SUN_JAVA_LAUNCHER("sun.java.launcher", "SUN_STANDARD", false);
private static final Offset BYTE_DATA_OFFSET = VMConfiguration.vmConfig().layoutScheme().byteArrayLayout.getElementOffsetFromOrigin(0);
public final String property;
private String value;
public final boolean mutable;
/**
* Computed at boot image time to avoid the allocation that occurs in {@link String#getBytes}.
* The cached values evidently depend on the boot heap not being relocated.
*/
private byte[] propertyBytes;
private byte[] valueBytes;
/**
* This value, if set, indicates that a JVMTI agent has set the value in primordial mode.
* Evidently the property must be mutable.
*/
private Pointer valueCString;
private VMProperty(String property, String value, boolean mutable) {
this.property = property;
this.propertyBytes = property.getBytes();
this.value = value;
if (value != null) {
valueBytes = value.getBytes();
}
this.mutable = mutable;
}
public static final VMProperty[] VALUES = values();
/**
* Set the value of this property, provided it is writeable.
* @param value
*/
public void setValue(String value) {
if (mutable) {
this.value = value;
if (value != null) {
valueBytes = value.getBytes();
}
}
}
/**
* Update this property's value, even if not writable.
* Used by the VM to update values that are not writeable by VMTI agents.
* Only applicable to {@java.vm.info} currently.
* @param value
*/
public void updateImmutableValue(String value) {
assert value != null;
this.value = value;
valueBytes = value.getBytes();
}
/**
* A way for a JVMTI agent to set the value before the VM is initialized.
* This will override any calls to {@link setValue}.
* @param value
*/
public void setValue(Pointer value) {
valueCString = value;
}
/**
* Check if {@code} name is a {@linkplain VMProperty}.
* @param name
* @return the associated {@linkplain VMProperty} or {@code null} if no match.
*/
public static VMProperty isVMProperty(String name) {
for (int i = 0; i < VALUES.length; i++) {
VMProperty vmProperty = VALUES[i];
if (name.equals(vmProperty.property)) {
return vmProperty;
}
}
return null;
}
/**
* Check if {@code} cstring is a {@linkplain VMProperty}.
* @param name
* @return the associated {@linkplain VMProperty} or {@code null} if no match.
*/
public static VMProperty isVMProperty(Pointer cstring) {
for (int i = 0; i < VALUES.length; i++) {
VMProperty vmProperty = VALUES[i];
if (CString.equals(cstring, vmProperty.property)) {
return vmProperty;
}
}
return null;
}
private static Pointer getByteArrayStart(byte[] data) {
return Reference.fromJava(data).toOrigin().plus(BYTE_DATA_OFFSET);
}
/**
* Return the property name as a C string.
* @return
*/
public Pointer propertyAsCString() {
return getByteArrayStart(propertyBytes);
}
/**
* Get the value of the property as a {@link String}.
* @return
*/
public String value() {
if (valueCString.isNotZero()) {
try {
return CString.utf8ToJava(valueCString);
} catch (Utf8Exception ex) {
FatalError.unexpected("VMProperty.value", ex);
return null;
}
} else {
return value;
}
}
/**
* Get the value of the property as a C string.
* @return
*/
public Pointer valueAsCString() {
if (valueCString.isNotZero()) {
return valueCString;
}
if (value == null) {
return Pointer.zero();
} else {
return getByteArrayStart(valueBytes);
}
}
}