/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.nio.ByteOrder; import java.util.Locale; import java.util.Properties; import javax.naming.NameNotFoundException; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.jnode.annotation.Internal; import org.jnode.annotation.KernelSpace; import org.jnode.annotation.MagicPermission; import org.jnode.annotation.PrivilegedActionPragma; import org.jnode.annotation.SharedStatics; import org.jnode.annotation.Uninterruptible; import org.jnode.bootlog.BootLogInstance; import org.jnode.naming.InitialNaming; import org.jnode.permission.JNodePermission; import org.jnode.plugin.PluginManager; import org.jnode.system.resource.MemoryResource; import org.jnode.system.resource.ResourceManager; import org.jnode.system.resource.ResourceNotFreeException; import org.jnode.system.resource.ResourceOwner; import org.jnode.system.resource.SimpleResourceOwner; import org.jnode.vm.classmgr.AbstractExceptionHandler; import org.jnode.vm.classmgr.VmArray; import org.jnode.vm.classmgr.VmByteCode; import org.jnode.vm.classmgr.VmClassLoader; import org.jnode.vm.classmgr.VmCompiledCode; import org.jnode.vm.classmgr.VmCompiledExceptionHandler; import org.jnode.vm.classmgr.VmConstClass; import org.jnode.vm.classmgr.VmConstantPool; import org.jnode.vm.classmgr.VmMethod; import org.jnode.vm.classmgr.VmStaticField; import org.jnode.vm.classmgr.VmType; import org.jnode.vm.facade.VmArchitecture; import org.jnode.vm.facade.VmUtils; import org.jnode.vm.facade.VmWriteBarrier; import org.jnode.vm.isolate.VmIsolate; import org.jnode.vm.scheduler.VmProcessor; import org.jnode.vm.scheduler.VmThread; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Extent; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Offset; import sun.nio.ch.Interruptible; import sun.reflect.annotation.AnnotationType; /** * System support for the Virtual Machine * * @author Ewout Prangsma (epr@users.sourceforge.net) */ @SharedStatics @MagicPermission public final class VmSystem { public static final int RC_HANDLER = 0xFFFFFFFB; public static final int RC_DEFHANDLER = 0xFFFFFFF1; private static boolean inited; private static VmSystemClassLoader systemLoader; private static String cmdLine; private static volatile long currentTimeMillis; private static long ghz = -1; private static long rtcIncrement; private static RTCService rtcService; private static SystemOutputStream bootOut; private static PrintStream bootOutStream; private static MemoryResource initJar; private static PrintStream out; private static final String LAYOUT = "%-5p [%c{1}]: %m%n"; private static boolean inShutdown = false; private static int exitCode = 0; static int debug = 0; /** * Initialize the Virtual Machine */ public static void initialize() { if (!inited) { // Initialize Naming InitialNaming.setNameSpace(new DefaultNameSpace()); // Initialize BootLog BootLogImpl.initialize(); // Initialize resource manager final ResourceManager rm = ResourceManagerImpl.initialize(); /* Initialize the system classloader */ VmSystemClassLoader loader = (VmSystemClassLoader) (getVmClass(VmProcessor.current()).getLoader()); systemLoader = loader; loader.initialize(); VmSystem.out = getSystemOut(); // Initialize VmThread VmThread.initialize(); final org.jnode.vm.facade.Vm vm = VmUtils.getVm(); // Initialize the monitors for the heap manager vm.getHeapManager().start(); Locale.setDefault(Locale.ENGLISH); // Find & start all processors ((VmImpl) vm).initializeProcessors(rm); /* We're done initializing */ inited = true; VmProcessor.current().systemReadyForThreadSwitch(); // Load the command line final Properties props = System.getProperties(); props.setProperty("jnode.cmdline", getCmdLine()); // Make sure that we have the default locale, // otherwise String.toLowerCase fails because it needs itself // via Locale.getDefault. //Locale.getDefault(); //Locale.setDefault(Locale.ENGLISH); // Calibrate the processors VmProcessor.current().calibrate(); // Setup class loading & compilation service LoadCompileService.start(); // Load the initial jarfile initJar = loadInitJar(rm); // Initialize log4j final Logger root = Logger.getRootLogger(); final ConsoleAppender infoApp = new ConsoleAppender(new PatternLayout(LAYOUT)); root.addAppender(infoApp); initOpenJDKSpecifics(); } } private static void initOpenJDKSpecifics() { //todo this will be moved to java.lang.System during openjdk integration sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess() { public sun.reflect.ConstantPool getConstantPool(Class klass) { return new VmConstantPool(VmType.fromClass(klass)); } public void setAnnotationType(Class klass, AnnotationType type) { klass.setAnnotationType(type); } public AnnotationType getAnnotationType(Class klass) { return klass.getAnnotationType(); } public <E extends Enum<E>> E[] getEnumConstantsShared(Class<E> klass) { return klass.getEnumConstantsShared(); } public void blockedOn(Thread t, Interruptible b) { //t.blockedOn(b); throw new UnsupportedOperationException(); } }); // Trigger initialization of the global environment variables. System.getenv(); } static boolean isInitialized() { return inited; } /** * Gets the system output stream. * * @return the system output stream */ public static PrintStream getSystemOut() { SystemOutputStream sout = null; if (bootOut == null) { // initialization trick to avoid circularity and setting bootOut twice //todo review when migrating java.lang.System to OpenJDK sout = new SystemOutputStream(); } if (bootOut == null) { bootOut = sout; bootOutStream = new PrintStream(bootOut, true); VmIOContext.setGlobalOutStream(bootOutStream); VmIOContext.setGlobalErrStream(bootOutStream); setOut(bootOutStream); setErr(bootOutStream); return bootOutStream; } else if (VmIsolate.isRoot()) { return bootOutStream; } else { return VmIOContext.getGlobalOutStream(); } } /** * Load the initial jarfile. * * @param rm the resource manager * @return The initial jarfile resource, or null if no initial jarfile is * available. */ private static MemoryResource loadInitJar(ResourceManager rm) { final Address start = Unsafe.getInitJarStart(); final Address end = Unsafe.getInitJarEnd(); final Extent size = end.toWord().sub(start.toWord()).toExtent(); if (size.toWord().isZero()) { // No initial jarfile BootLogInstance.get().info("No initial jarfile found"); return null; } else { BootLogInstance.get().info("Found initial jarfile of " + size.toInt() + 'b'); try { final ResourceOwner owner = new SimpleResourceOwner("System"); return rm.claimMemoryResource(owner, start, size, ResourceManager.MEMMODE_NORMAL); } catch (ResourceNotFreeException ex) { BootLogInstance.get().error("Cannot claim initjar resource", ex); return null; } } } // ------------------------------------------ // Information // ------------------------------------------ /** * This method adds some default system properties * * @param res the system properties object */ public static void insertSystemProperties(Properties res) { final org.jnode.vm.facade.Vm vm = VmUtils.getVm(); final VmArchitecture arch = vm.getArch(); // Standard Java properties res.put("file.separator", "/"); // res.put("file.encoding", "ISO-8859-1"); res.put("java.awt.graphicsenv", "org.jnode.awt.JNodeGraphicsEnvironment"); //todo // res.put("java.awt.printerjob", ""); //todo res.put("java.class.path", ":"); res.put("java.class.version", "50.0"); res.put("java.compiler", "Internal"); //todo is this needed? res.put("java.endorsed.dirs", "/jifs/lib/"); res.put("java.ext.dirs", "/jifs/lib/"); res.put("java.home", "/jnode"); res.put("java.io.tmpdir", "/jnode/tmp"); res.put("java.library.path", "/jnode/tmp"); //dummy value but needed by Runtime.loadLibrary res.put("java.runtime.name", "JNode"); res.put("java.runtime.version", vm.getVersion()); res.put("java.specification.name", "Java Platform API Specification"); res.put("java.specification.vendor", "Sun Microsystems Inc."); res.put("java.specification.version", "1.6"); res.put("java.vendor", "JNode.org"); res.put("java.vendor.url", "http://jnode.org"); res.put("java.vendor.url.bug", "http://jnode.org"); res.put("java.version", "1.6"); res.put("java.vm.info", "JNode"); res.put("java.vm.name", "JNode"); res.put("java.vm.specification.name", "Java Virtual Machine Specification"); res.put("java.vm.specification.vendor", "Sun Microsystems Inc."); res.put("java.vm.specification.version", "1.0"); res.put("java.vm.vendor", "JNode.org"); res.put("java.vm.version", vm.getVersion()); res.put("line.separator", "\n"); res.put("os.arch", arch.getName()); res.put("os.name", "JNode"); res.put("os.version", vm.getVersion()); res.put("path.separator", ":"); //todo // res.put("user.country", ""); res.put("user.dir", "/"); res.put("user.home", "/jnode/home"); res.put("user.language", "en"); res.put("user.name", "admin"); //todo // res.put("user.timezone", ""); // GNU properties res.put("gnu.cpu.endian", (arch.getByteOrder() == ByteOrder.BIG_ENDIAN) ? "big" : "little"); res.put("gnu.classpath.home.url", "system://"); res.put("gnu.classpath.vm.shortname", "jnode"); res.put("gnu.javax.swing.noGraphics2D", "true"); //----------JNode related // Log4j properties res.put("log4j.defaultInitOverride", "true"); // keep this property until transparency support works fine with all drivers res.put("org.jnode.awt.transparency", "true"); //internal classpath for javac res.put("sun.boot.class.path", ":"); res.put("swing.handleTopLevelPaint", "false"); res.put("java.protocol.handler.pkgs", "org.jnode.protocol|gnu.java.net.protocol|gnu.inet"); res.put("java.content.handler.pkgs", "gnu.java.net.content"); //todo fix MethodAccessorGenerator issue with isolates //Setting it to max value to avoid the bugs with isolates & MethodAccessorGenerator, //see sun.reflect.ReflectionFactory for details res.put("sun.reflect.inflationThreshold", String.valueOf(Integer.MAX_VALUE)); VmSystemSettings.insertSystemProperties(res); } /** * Returns the commandline appended to the kernel by the bootloader (e.g. grub) * * @return the commandline appended to the kernel */ public static String getCmdLine() { if (cmdLine == null) { /* Load the command line */ final int cmdLineSize = Unsafe.getCmdLine(null); final byte[] cmdLineArr = new byte[cmdLineSize]; Unsafe.getCmdLine(cmdLineArr); //command line may contain 0, replace it with space for (int i = 0; i < cmdLineSize; i++) { if (cmdLineArr[i] == 0) { cmdLineArr[i] = (byte) ' '; } } cmdLine = new String(cmdLineArr).trim(); } return cmdLine; } /** * Gets the log of the bootstrap phase. * * @return String */ public static String getBootLog() { if (bootOut != null) { return bootOut.getData(); } else { return ""; } } // ------------------------------------------ // java.lang.Object support // ------------------------------------------ /** * Gets the class of the given object * * @param obj * @return The class */ public static Class<?> getClass(Object obj) { return getVmClass(obj).asClass(); } /** * Gets the VmClass of the given object. * * @param obj * @return VmClass */ public static VmType<?> getVmClass(Object obj) { if (obj == null) { throw new NullPointerException(); } else { return VmMagic.getObjectType(obj); } } /** * Clone the given object * * @param obj * @return Object */ public static Object clone(Cloneable obj) { return VmUtils.getVm().getHeapManager().clone(obj); } /** * Gets the hashcode of the given object * * @param obj * @return int */ public static int getHashCode(Object obj) { if (obj == null) { // According to spec, null has zero as hashcode. return 0; } else { return ObjectReference.fromObject(obj).toAddress().toInt(); } } // ------------------------------------------ // java.lang.Class support // ------------------------------------------ public static Class forName(String className) throws ClassNotFoundException { return getContextClassLoader().asClassLoader().loadClass(className); } /** * Gets the first non-system classloader out of the current stacktrace, or * the system classloader if no other classloader is found in the current * stacktrace. * * @return The classloader */ protected static VmClassLoader getContextClassLoader() { final VmStackReader reader = VmProcessor.current().getArchitecture() .getStackReader(); final VmSystemClassLoader systemLoader = VmSystem.systemLoader; Address f = VmMagic.getCurrentFrame(); while (reader.isValid(f)) { final VmMethod method = reader.getMethod(f); final VmClassLoader loader = method.getDeclaringClass().getLoader(); if ((loader != null) && (loader != systemLoader)) { return loader; } else { f = reader.getPrevious(f); } } return systemLoader; } // ------------------------------------------ // java.lang.SecurityManager support // ------------------------------------------ /** * Gets the current stacktrace as array of classes. * * @return Class[] */ public static Class[] getClassContext() { final VmStackReader reader = VmProcessor.current().getArchitecture() .getStackReader(); final VmStackFrame[] stack = reader.getVmStackTrace(VmMagic .getCurrentFrame(), null, VmThread.STACKTRACE_LIMIT); final int count = stack.length; final Class[] result = new Class[count]; for (int i = 0; i < count; i++) { result[i] = stack[i].getMethod().getDeclaringClass().asClass(); } return result; } /** * Gets the current stacktrace as array of classes excluding the calls to * java.lang.reflect.Method.invoke() and org.jnode.vm.VmReflection.invoke(). * * @return Class[] */ public static Class[] getRealClassContext() { final VmStackReader reader = VmProcessor.current().getArchitecture() .getStackReader(); final VmStackFrame[] stack = reader.getVmStackTrace(VmMagic .getCurrentFrame(), null, VmThread.STACKTRACE_LIMIT); final int count = stack.length; final Class[] result = new Class[count]; int real_count = 0; for (int i = 0; i < count; i++) { VmMethod method = stack[i].getMethod(); VmType<?> clazz = method.getDeclaringClass(); if ((method.getName().equals("invoke") && ( clazz.getName().equals("java.lang.reflect.Method") || clazz.getName().equals("org.jnode.vm.VmReflection")))) continue; result[real_count++] = clazz.asClass(); } Class[] real_result = new Class[real_count]; System.arraycopy(result, 0, real_result, 0, real_count); return real_result; } /** * Do nothing, until interrupted by an interrupts. */ public static void idle() { Unsafe.idle(); } @Internal public static final Object allocStack(int size) { try { return VmUtils.getVm().getHeapManager() .newInstance( systemLoader.loadClass( "org.jnode.vm.objects.VmSystemObject", true), size); } catch (ClassNotFoundException ex) { throw (NoClassDefFoundError) new NoClassDefFoundError() .initCause(ex); } } /** * Find an exception handler to handle the given exception in the given * frame at the given address. * * @param ex * @param frame * @param address * @return Object */ @PrivilegedActionPragma public static Address findThrowableHandler(Throwable ex, Address frame, Address address) { try { debug++; if (ex == null) { Unsafe.debug("NPE"); throw new NullPointerException(); } if (frame == null) { Unsafe.debug("frame==null"); return null; } final VmProcessor proc = VmProcessor.current(); final VmStackReader reader = proc.getArchitecture() .getStackReader(); final VmType exClass = VmMagic.getObjectType(ex); final VmMethod method = reader.getMethod(frame); if (method == null) { Unsafe.debug("Unknown method in class " + ex.getClass().getName()); return null; } // if (interpreted) { /* * Screen.debug("{ex at pc:"); Screen.debug(pc); Screen.debug(" of " + * method.getBytecodeSize()); Screen.debug(method.getName()); */ // } final int count; final VmByteCode bc = method.getBytecode(); final VmCompiledCode cc = reader.getCompiledCode(frame); if (bc != null) { count = bc.getNoExceptionHandlers(); } else { count = 0; } // Screen.debug("eCount=" + count); for (int i = 0; i < count; i++) { final AbstractExceptionHandler eh; final VmCompiledExceptionHandler ceh; ceh = cc.getExceptionHandler(i); eh = ceh; boolean match; match = ceh.isInScope(address); if (match) { final VmConstClass catchType = eh.getCatchType(); if (catchType == null) { /* Catch all exceptions */ return Address.fromAddress(ceh.getHandler()); } else { if (!catchType.isResolved()) { SoftByteCodes.resolveClass(catchType); } final VmType handlerClass = catchType .getResolvedVmClass(); if (handlerClass != null) { if (handlerClass.isAssignableFrom(exClass)) { return Address.fromAddress(ceh.getHandler()); } } else { System.err .println("Warning: handler class==null in " + method.getName()); } } } } if (cc.contains(address)) { return Address.fromAddress(cc.getDefaultExceptionHandler()); } else { return null; } } catch (Throwable ex2) { Unsafe.debug("Exception in findThrowableHandler"); try { ex2.printStackTrace(); } finally { Unsafe.die("findThrowableHandler"); } return null; } finally { debug--; } } // ------------------------------------------ // java.lang.System support // ------------------------------------------ /** * Copy one array to another. This is the implementation for System.arraycopy in JNode * * @param src * @param srcPos * @param dst * @param dstPos * @param length */ @PrivilegedActionPragma public static void arrayCopy(final Object src, final int srcPos, final Object dst, final int dstPos, final int length) { Class<?> src_class = src.getClass(); Class<?> dst_class = dst.getClass(); if (!src_class.isArray()) { // Unsafe.debug('!'); throw new ArrayStoreException("src is not an array"); } if (!dst_class.isArray()) { // Unsafe.debug("dst is not an array:"); // Unsafe.debug(dst_class.getName()); throw new ArrayStoreException("dst is not an array"); } String src_name = src_class.getName(); String dst_name = dst_class.getName(); char src_type = src_name.charAt(1); char dst_type = dst_name.charAt(1); if (src_type == '[') { src_type = 'L'; } if (dst_type == '[') { dst_type = 'L'; } if (src_type != dst_type) { // Unsafe.debug("invalid array types:"); // Unsafe.debug(src_class.getName()); // Unsafe.debug(dst_class.getName()); throw new ArrayStoreException( "Incompatible array types: " + src_class.getName() + ", " + dst_class.getName()); } if (srcPos < 0) { throw new IndexOutOfBoundsException("srcPos < 0"); } if (dstPos < 0) { throw new IndexOutOfBoundsException("dstPos < 0"); } if (length < 0) { throw new IndexOutOfBoundsException("length < 0"); } final int slotSize = VmProcessor.current().getArchitecture() .getReferenceSize(); final Offset lengthOffset = Offset .fromIntSignExtend(VmArray.LENGTH_OFFSET * slotSize); final int dataOffset = VmArray.DATA_OFFSET * slotSize; final Address srcAddr = ObjectReference.fromObject(src).toAddress(); final Address dstAddr = ObjectReference.fromObject(dst).toAddress(); final int srcLen = srcAddr.loadInt(lengthOffset); final int dstLen = dstAddr.loadInt(lengthOffset); // Calc end index (if overflow, then will be < 0 ) final int srcEnd = srcPos + length; final int dstEnd = dstPos + length; if ((srcEnd > srcLen) || (srcEnd < 0)) { throw new IndexOutOfBoundsException("srcPos+length > src.length (" + srcPos + '+' + length + " > " + srcLen + ')'); } if ((dstEnd > dstLen) || (dstEnd < 0)) { throw new IndexOutOfBoundsException("dstPos+length > dst.length"); } final int elemsize; final boolean isObjectArray; switch (src_type) { case 'Z': // Boolean case 'B': // Byte elemsize = 1; isObjectArray = false; break; case 'C': // Character case 'S': // Short elemsize = 2; isObjectArray = false; break; case 'I': // Integer case 'F': // Float elemsize = 4; isObjectArray = false; break; case 'L': // Object elemsize = slotSize; isObjectArray = true; break; case 'J': // Long case 'D': // Double elemsize = 8; isObjectArray = false; break; default: // Unsafe.debug("uat:"); // Unsafe.debug(src_type); // Unsafe.debug(src_name); throw new ArrayStoreException("Unknown array type"); } final Address srcPtr = srcAddr.add(dataOffset + (srcPos * elemsize)); final Address dstPtr = dstAddr.add(dataOffset + (dstPos * elemsize)); final Extent size = Extent.fromIntZeroExtend(length * elemsize); if (isObjectArray) { Class dst_comp_class = dst_class.getComponentType(); Class src_comp_class = src_class.getComponentType(); if (!dst_comp_class.isAssignableFrom(src_comp_class)) { //todo optimize for speed Object[] srca = (Object[]) src; Object[] dsta = (Object[]) dst; for (int i = 0; i < length; i++) { Object o = srca[srcPos + i]; if (o == null || dst_comp_class.isInstance(o)) { dsta[dstPos + i] = o; } else { throw new ArrayStoreException(); } } } else { Unsafe.copy(srcPtr, dstPtr, size); } } else { Unsafe.copy(srcPtr, dstPtr, size); } if (isObjectArray) { final VmWriteBarrier wb = VmUtils.getVm().getHeapManager().getWriteBarrier(); if (wb != null) { wb.arrayCopyWriteBarrier(src, srcPos, srcPos + length); } } } /** * Returns the current time in milliseconds. Note that while the unit of * time of the return value is a millisecond, the granularity of the value * depends on the underlying operating system and may be larger. For * example, many operating systems measure time in units of tens of * milliseconds. See the description of the class Date for a discussion of * slight discrepancies that may arise between "computer time" and * coordinated universal time (UTC). * <p/> * This method does call other methods and CANNOT be used in the low-level * system environment, where synchronization cannot be used. * * * @return the difference, measured in milliseconds, between the current * time and midnight, January 1, 1970 UTC */ public static long currentTimeMillis() { if (rtcIncrement == 0) { try { final RTCService rtcService = VmSystem.rtcService; if (rtcService != null) { final long rtcTime = rtcService.getTime(); if (rtcTime == 0L) { // We don't have an RTC service yet, return an invalid, // but for now good enough value return currentTimeMillis; } else { rtcIncrement = rtcTime - currentTimeMillis; } } } catch (Exception ex) { BootLogInstance.get().error("Error getting rtcIncrement ", ex); rtcIncrement = 1; } } return currentTimeMillis + rtcIncrement; } /** * <p> * Returns the current value of a nanosecond-precise system timer. * The value of the timer is an offset relative to some arbitrary fixed * time, which may be in the future (making the value negative). This * method is useful for timing events where nanosecond precision is * required. This is achieved by calling this method before and after the * event, and taking the difference between the two times: * </p> * <p> * <code>long startTime = System.nanoTime();</code><br /> * <code>... <emph>event code</emph> ...</code><br /> * <code>long endTime = System.nanoTime();</code><br /> * <code>long duration = endTime - startTime;</code><br /> * </p> * <p> * Note that the value is only nanosecond-precise, and not accurate; there * is no guarantee that the difference between two values is really a * nanosecond. Also, the value is prone to overflow if the offset * exceeds 2^63. * </p> * * @return the time of a system timer in nanoseconds. * @since 1.5 */ public static long nanoTime() { if (ghz == -1) { final long measureDuration = 1000; // in milliseconds long start = Unsafe.getCpuCycles(); long ms_start = currentTimeMillis(); long ms_end; try { Thread.sleep(measureDuration); } catch (InterruptedException e) { //ignore } finally { ms_end = currentTimeMillis(); } long end = Unsafe.getCpuCycles(); long ms = ms_end - ms_start; if (ms <= 0) { ms = measureDuration; } ghz = (end - start) / (ms * 1000000L); if (ghz <= 0) { ghz = 0; } } if (ghz == 0) { //todo these are CPUs under 1GHz, improve this case return currentTimeMillis() * 1000000L; } return Unsafe.getCpuCycles() / ghz; } /** * Returns the number of milliseconds since booting the kernel of JNode. * <p/> * This method does not call any other method and CAN be used in the * low-level system environment, where synchronization cannot be used. * * @return The current time of the kernel * @throws org.vmmagic.pragma.UninterruptiblePragma * */ @KernelSpace @Uninterruptible public static long currentKernelMillis() { return currentTimeMillis; } /** * @return VmClassLoader */ public static VmSystemClassLoader getSystemClassLoader() { return systemLoader; } /** * Returns the free memory in system ram * * @return free memory in system ram */ public static long freeMemory() { return VmUtils.getVm().getHeapManager().getFreeMemory(); } /** * Returns the total amount of system memory * * @return the total amount of system memory */ public static long totalMemory() { return VmUtils.getVm().getHeapManager().getTotalMemory(); } /** * Call the garbage collector */ public static void gc() { VmUtils.getVm().getHeapManager().gc(); } static class SystemOutputStream extends OutputStream { private StringBuffer data; /** * @see java.io.OutputStream#write(int) */ public void write(int b) throws IOException { final char ch = (char) (b & 0xFF); Unsafe.debug(ch); if (data == null) { synchronized (this) { data = new StringBuffer(); } } data.append(ch); } /** * Returns the data written to the system output stream * * @return data written to the system output stream */ public String getData() { return (data == null) ? "" : data.toString(); } } /** * @param rtcService The rtcService to set. */ public static final void setRtcService(RTCService rtcService) { if (VmSystem.rtcService == null) { VmSystem.rtcService = rtcService; } } /** * @param rtcService The rtcService previously set. */ public static final void resetRtcService(RTCService rtcService) { if (VmSystem.rtcService == rtcService) { VmSystem.rtcService = null; } } /** * @return Returns the initJar. */ public static final MemoryResource getInitJar() { return initJar; } /** * @return Returns the out. */ public static final PrintStream getOut() { return out; } /** * Calculate the speed of the current processor. * * @return the speed of the current processor in "JNodeMips" */ @Uninterruptible public static float calculateJNodeMips() { final long millis = currentTimeMillis % 1000; while (millis == (currentTimeMillis % 1000)) { // Wait } long count = 0; float dummy = 0.0f; while (millis != (currentTimeMillis % 1000)) { count++; dummy += 0.5f; } return count / 100000.0f; } /** * Is the system shutting down. * * @return if the system is shutting down */ public static boolean isShuttingDown() { return inShutdown; } /** * Gets the system exit code. * * @return the system exit code */ public static int getExitCode() { return exitCode; } /** * Halt the system. This method requires a JNodePermission("halt"). * * @param reset */ @PrivilegedActionPragma public static void halt(boolean reset) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new JNodePermission("halt")); } exitCode = (reset ? 1 : 0); inShutdown = true; try { final PluginManager pm = InitialNaming.lookup(PluginManager.NAME); pm.stopPlugins(); } catch (NameNotFoundException ex) { System.err.println("Cannot find ServiceManager"); } } /** * Set the effective System.in to a different InputStream. The actual behavior depends * on whether we're in proclet mode or not. If we are, we set the appropriate proxied stream, * to the new stream, depending on whether the current thread is a ProcletContext or not. * Otherwise, we update the System.in field. * * @param in the new InputStream * @see #setIn(InputStream) */ @PrivilegedActionPragma public static void setIn(InputStream in) { getIOContext().setSystemIn(in); } /** * Set the effective System.out to a different PrintStream. The actual behavior depends * on whether we're in proclet mode or not. If we are, we set the appropriate proxied stream, * to the new stream, depending on whether the current thread is a ProcletContext or not. * Otherwise, we update the System.out field. * * @param out the new PrintStream * @see java.lang.System#setOut(PrintStream) */ @PrivilegedActionPragma public static void setOut(PrintStream out) { getIOContext().setSystemOut(out); } /** * Set the effective System.err to a different PrintStream. The actual behavior depends * on whether we're in proclet mode or not. If we are, we set the appropriate proxied stream, * to the new stream, depending on whether the current thread is a ProcletContext or not. * Otherwise, we update the System.err field. * * @param err the new PrintStream * @see java.lang.System#setErr(PrintStream) */ @PrivilegedActionPragma public static void setErr(PrintStream err) { getIOContext().setSystemErr(err); } //todo protect this method from arbitrary access @PrivilegedActionPragma public static void setStaticField(Class<?> clazz, String fieldName, Object value) { final VmStaticField f = (VmStaticField) VmType.fromClass((Class<?>) clazz).getField( fieldName); final Object staticsTable; final Offset offset; if (f.isShared()) { staticsTable = VmMagic.currentProcessor().getSharedStaticsTable(); offset = Offset.fromIntZeroExtend(f.getSharedStaticsIndex() << 2); } else { staticsTable = VmMagic.currentProcessor().getIsolatedStaticsTable(); offset = Offset.fromIntZeroExtend(f.getIsolatedStaticsIndex() << 2); } final Address ptr = VmMagic.getArrayData(staticsTable); ptr.store(ObjectReference.fromObject(value), offset); } //io context related public static IOContext getIOContext() { return VmIsolate.currentIsolate().getIOContext(); } public static boolean hasVmIOContext() { return getIOContext() instanceof VmIOContext; } /** * Get the current global (i.e. non-ProcletContext) flavor of System.err. * * @return the global 'err' stream. */ public static PrintStream getGlobalErrStream() { return VmIOContext.getGlobalErrStream(); } /** * Get the current global (i.e. non-ProcletContext) flavor of System.in. * * @return the global 'in' stream. */ public static InputStream getGlobalInStream() { return VmIOContext.getGlobalInStream(); } /** * Get the current global (i.e. non-ProcletContext) flavor of System.out. * * @return the global 'out' stream. */ public static PrintStream getGlobalOutStream() { return VmIOContext.getGlobalOutStream(); } /** * Switch the current Isolate from the initial IOContext to an external one. * If the Isolate already has an external IOContext, this is a no-op. * * @param context */ public static synchronized void switchToExternalIOContext(IOContext context) { if (hasVmIOContext()) { getIOContext().exitContext(); VmIsolate.currentIsolate().setIOContext(context); context.enterContext(); } } /** * Reset to the current Isolate to its initial IOContext. */ public static synchronized void resetIOContext() { if (!hasVmIOContext()) { getIOContext().exitContext(); VmIsolate.currentIsolate().resetIOContext(); getIOContext().enterContext(); } else { throw new RuntimeException("IO Context cannot be reset"); } } /** * Wait for ms milliseconds in a busy waiting loop. * This method is very CPU intensive, so be carefull. * * @param ms */ public static void loop(long ms) { final long start = currentKernelMillis(); while (true) { if ((start + ms) <= currentKernelMillis()) { break; } } } }