1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2003-2009 JNode.org
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful, but 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this library; If not, write to the Free Software Foundation, Inc., 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
package org.jnode.vm;
22
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.io.OutputStream;
26
import java.io.PrintStream;
27
import java.nio.ByteOrder;
28
import java.util.Locale;
29
import java.util.Properties;
30
31
import javax.naming.NameNotFoundException;
32
33
import org.apache.log4j.ConsoleAppender;
34
import org.apache.log4j.Logger;
35
import org.apache.log4j.PatternLayout;
36
import org.jnode.naming.InitialNaming;
37
import org.jnode.plugin.PluginManager;
38
import org.jnode.security.JNodePermission;
39
import org.jnode.system.BootLog;
40
import org.jnode.system.MemoryResource;
41
import org.jnode.system.ResourceManager;
42
import org.jnode.system.ResourceNotFreeException;
43
import org.jnode.system.ResourceOwner;
44
import org.jnode.system.SimpleResourceOwner;
45
import org.jnode.annotation.Internal;
46
import org.jnode.annotation.KernelSpace;
47
import org.jnode.annotation.MagicPermission;
48
import org.jnode.annotation.PrivilegedActionPragma;
49
import org.jnode.annotation.SharedStatics;
50
import org.jnode.annotation.Uninterruptible;
51
import org.jnode.vm.classmgr.AbstractExceptionHandler;
52
import org.jnode.vm.classmgr.VmArray;
53
import org.jnode.vm.classmgr.VmByteCode;
54
import org.jnode.vm.classmgr.VmClassLoader;
55
import org.jnode.vm.classmgr.VmCompiledCode;
56
import org.jnode.vm.classmgr.VmCompiledExceptionHandler;
57
import org.jnode.vm.classmgr.VmConstClass;
58
import org.jnode.vm.classmgr.VmConstantPool;
59
import org.jnode.vm.classmgr.VmMethod;
60
import org.jnode.vm.classmgr.VmStaticField;
61
import org.jnode.vm.classmgr.VmType;
62
import org.jnode.vm.isolate.VmIsolate;
63
import org.jnode.vm.memmgr.VmWriteBarrier;
64
import org.jnode.vm.scheduler.VmProcessor;
65
import org.jnode.vm.scheduler.VmThread;
66
import org.vmmagic.unboxed.Address;
67
import org.vmmagic.unboxed.Extent;
68
import org.vmmagic.unboxed.ObjectReference;
69
import org.vmmagic.unboxed.Offset;
70
71
import sun.nio.ch.Interruptible;
72
import sun.reflect.annotation.AnnotationType;
73
74
/**
75
 * System support for the Virtual Machine
76
 *
77
 * @author Ewout Prangsma (epr@users.sourceforge.net)
78
 */
79
@SharedStatics
80
@MagicPermission
81
public final class VmSystem {
82
83
    public static final int RC_HANDLER = 0xFFFFFFFB;
84
85
    public static final int RC_DEFHANDLER = 0xFFFFFFF1;
86
87
    private static boolean inited;
88
89
    private static VmSystemClassLoader systemLoader;
90
91
    private static String cmdLine;
92
93
    private static volatile long currentTimeMillis;
94
95
    private static long ghz = -1;
96
97
    private static long rtcIncrement;
98
99
    private static RTCService rtcService;
100
101
    private static SystemOutputStream bootOut;
102
103
    private static PrintStream bootOutStream;
104
105
    private static MemoryResource initJar;
106
107
    private static PrintStream out;
108
109
    private static final String LAYOUT = "%-5p [%c{1}]: %m%n";
110
111
    private static boolean inShutdown = false;
112
113
    private static int exitCode = 0;
114
115
    static int debug = 0;
116
117
    /**
118
     * Initialize the Virtual Machine
119
     */
120
    public static void initialize() {
121
        if (!inited) {
122
123
            // Initialize resource manager
124
            final ResourceManager rm = ResourceManagerImpl.initialize();
125
126
            /* Initialize the system classloader */
127
            VmSystemClassLoader loader = (VmSystemClassLoader) (getVmClass(VmProcessor.current()).getLoader());
128
            systemLoader = loader;
129
            loader.initialize();
130
131
            VmSystem.out = getSystemOut();
132
133
            // Initialize VmThread
134
            VmThread.initialize();
135
136
            final Vm vm = Vm.getVm();
137
138
            // Initialize the monitors for the heap manager
139
            Vm.getHeapManager().start();
140
141
            Locale.setDefault(Locale.ENGLISH);
142
143
            // Find & start all processors
144
            vm.initializeProcessors(rm);
145
146
            /* We're done initializing */
147
            inited = true;
148
            VmProcessor.current().systemReadyForThreadSwitch();
149
150
            // Load the command line
151
            final Properties props = System.getProperties();
152
            props.setProperty("jnode.cmdline", getCmdLine());
153
154
            // Make sure that we have the default locale,
155
            // otherwise String.toLowerCase fails because it needs itself
156
            // via Locale.getDefault.
157
            //Locale.getDefault();
158
            //Locale.setDefault(Locale.ENGLISH);
159
160
            // Calibrate the processors
161
            VmProcessor.current().calibrate();
162
163
            // Setup class loading & compilation service
164
            LoadCompileService.start();
165
166
            // Load the initial jarfile
167
            initJar = loadInitJar(rm);
168
169
            // Initialize log4j
170
            final Logger root = Logger.getRootLogger();
171
            final ConsoleAppender infoApp = new ConsoleAppender(new PatternLayout(LAYOUT));
172
            root.addAppender(infoApp);
173
174
            initOpenJDKSpecifics();
175
        }
176
    }
177
178
    private static void initOpenJDKSpecifics() {
179
        //todo this will be moved to java.lang.System during openjdk integration
180
        sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess() {
181
            public sun.reflect.ConstantPool getConstantPool(Class klass) {
182
                return new VmConstantPool(VmType.fromClass(klass));
183
            }
184
185
            public void setAnnotationType(Class klass, AnnotationType type) {
186
                klass.setAnnotationType(type);
187
            }
188
189
            public AnnotationType getAnnotationType(Class klass) {
190
                return klass.getAnnotationType();
191
            }
192
193
            public <E extends Enum<E>> E[] getEnumConstantsShared(Class<E> klass) {
194
                return klass.getEnumConstantsShared();
195
            }
196
197
            public void blockedOn(Thread t, Interruptible b) {
198
                //t.blockedOn(b);
199
                throw new UnsupportedOperationException();
200
            }
201
        });
202
        
203
        // Trigger initialization of the global environment variables.
204
        System.getenv();
205
    }
206
207
    static boolean isInitialized() {
208
        return inited;
209
    }
210
211
    /**
212
     * Gets the system output stream.
213
     *
214
     * @return the system output stream
215
     */
216
    public static PrintStream getSystemOut() {
217
        SystemOutputStream sout = null;
218
        if (bootOut == null) {
219
            // initialization trick to avoid circularity and setting bootOut twice
220
            //todo review when migrating java.lang.System to OpenJDK
221
            sout = new SystemOutputStream();
222
        }
223
224
        if (bootOut == null) {
225
            bootOut = sout;
226
            bootOutStream = new PrintStream(bootOut, true);
227
            VmIOContext.setGlobalOutStream(bootOutStream);
228
            VmIOContext.setGlobalErrStream(bootOutStream);
229
            setOut(bootOutStream);
230
            setErr(bootOutStream);
231
            return bootOutStream;
232
        } else if (VmIsolate.isRoot()) {
233
            return bootOutStream;
234
        } else {
235
            return  VmIOContext.getGlobalOutStream();
236
        }
237
    }
238
239
    /**
240
     * Load the initial jarfile.
241
     *
242
     * @param rm the resource manager
243
     * @return The initial jarfile resource, or null if no initial jarfile is
244
     *         available.
245
     */
246
    private static MemoryResource loadInitJar(ResourceManager rm) {
247
        final Address start = Unsafe.getInitJarStart();
248
        final Address end = Unsafe.getInitJarEnd();
249
        final Extent size = end.toWord().sub(start.toWord()).toExtent();
250
        if (size.toWord().isZero()) {
251
            // No initial jarfile
252
            BootLog.info("No initial jarfile found");
253
            return null;
254
        } else {
255
            BootLog.info("Found initial jarfile of " + size.toInt() + "b");
256
            try {
257
                final ResourceOwner owner = new SimpleResourceOwner("System");
258
                return rm.claimMemoryResource(owner, start, size,
259
                    ResourceManager.MEMMODE_NORMAL);
260
            } catch (ResourceNotFreeException ex) {
261
                BootLog.error("Cannot claim initjar resource", ex);
262
                return null;
263
            }
264
        }
265
    }
266
267
    // ------------------------------------------
268
    // Information
269
    // ------------------------------------------
270
271
    /**
272
     * This method adds some default system properties
273
     *
274
     * @param res the system properties object
275
     */
276
    public static void insertSystemProperties(Properties res) {
277
278
        final Vm vm = Vm.getVm();
279
        final VmArchitecture arch = Vm.getArch();
280
281
        // Standard Java properties
282
        res.put("file.separator", "/");
283
//        res.put("file.encoding", "ISO-8859-1");
284
        res.put("java.awt.graphicsenv", "org.jnode.awt.JNodeGraphicsEnvironment");
285
        //todo
286
//        res.put("java.awt.printerjob", "");
287
        //todo
288
        res.put("java.class.path", ":");
289
        res.put("java.class.version", "50.0");
290
        res.put("java.compiler", "Internal"); //todo is this needed?
291
        res.put("java.endorsed.dirs", "/jifs/lib/");
292
        res.put("java.ext.dirs", "/jifs/lib/");
293
        res.put("java.home", "/jnode");
294
        res.put("java.io.tmpdir", "/jnode/tmp");
295
        res.put("java.library.path", "/jnode/tmp"); //dummy value but needed by Runtime.loadLibrary
296
        res.put("java.runtime.name", "JNode");
297
        res.put("java.runtime.version", vm.getVersion());
298
        res.put("java.specification.name", "Java Platform API Specification");
299
        res.put("java.specification.vendor", "Sun Microsystems Inc.");
300
        res.put("java.specification.version", "1.6");
301
        res.put("java.vendor", "JNode.org");
302
        res.put("java.vendor.url", "http://jnode.org");
303
        res.put("java.vendor.url.bug", "http://jnode.org");
304
        res.put("java.version", "1.6");
305
        res.put("java.vm.info", "JNode");
306
        res.put("java.vm.name", "JNode");
307
        res.put("java.vm.specification.name", "Java Virtual Machine Specification");
308
        res.put("java.vm.specification.vendor", "Sun Microsystems Inc.");
309
        res.put("java.vm.specification.version", "1.0");
310
        res.put("java.vm.vendor", "JNode.org");
311
        res.put("java.vm.version", vm.getVersion());
312
        res.put("line.separator", "\n");
313
        res.put("os.arch", arch.getName());
314
        res.put("os.name", "JNode");
315
        res.put("os.version", vm.getVersion());
316
        res.put("path.separator", ":");
317
        //todo
318
//        res.put("user.country", "");
319
        res.put("user.dir", "/");
320
        res.put("user.home", "/jnode/home");
321
        res.put("user.language", "en");
322
        res.put("user.name", "admin");
323
        //todo
324
//        res.put("user.timezone", "");
325
326
        // GNU properties
327
        res.put("gnu.cpu.endian", (arch.getByteOrder() == ByteOrder.BIG_ENDIAN) ? "big" : "little");
328
        res.put("gnu.classpath.home.url", "system://");
329
        res.put("gnu.classpath.vm.shortname", "jnode");
330
        res.put("gnu.javax.swing.noGraphics2D", "true");
331
332
        //----------JNode related
333
        // Log4j properties
334
        res.put("log4j.defaultInitOverride", "true");
335
336
        // keep this property until transparency support works fine with all drivers
337
        res.put("org.jnode.awt.transparency", "true");
338
339
        //internal classpath for javac
340
        res.put("sun.boot.class.path", ":");
341
342
        res.put("swing.handleTopLevelPaint", "false");
343
        res.put("java.protocol.handler.pkgs", "org.jnode.protocol|gnu.java.net.protocol|gnu.inet");
344
        res.put("java.content.handler.pkgs", "gnu.java.net.content");
345
346
        VmSystemSettings.insertSystemProperties(res);
347
    }
348
349
    /**
350
     * Returns the commandline appended to the kernel by the bootloader (e.g. grub)
351
     *
352
     * @return the commandline appended to the kernel
353
     */
354
    public static String getCmdLine() {
355
        if (cmdLine == null) {
356
            /* Load the command line */
357
            final int cmdLineSize = Unsafe.getCmdLine(null);
358
            final byte[] cmdLineArr = new byte[cmdLineSize];
359
            Unsafe.getCmdLine(cmdLineArr);
360
            cmdLine = new String(cmdLineArr).trim();
361
        }
362
        return cmdLine;
363
    }
364
365
    /**
366
     * Gets the log of the bootstrap phase.
367
     *
368
     * @return String
369
     */
370
    public static String getBootLog() {
371
        if (bootOut != null) {
372
            return bootOut.getData();
373
        } else {
374
            return "";
375
        }
376
    }
377
378
    // ------------------------------------------
379
    // java.lang.Object support
380
    // ------------------------------------------
381
382
    /**
383
     * Gets the class of the given object
384
     *
385
     * @param obj
386
     * @return The class
387
     */
388
    public static Class<?> getClass(Object obj) {
389
        return getVmClass(obj).asClass();
390
    }
391
392
    /**
393
     * Gets the VmClass of the given object.
394
     *
395
     * @param obj
396
     * @return VmClass
397
     */
398
    public static VmType<?> getVmClass(Object obj) {
399
        if (obj == null) {
400
            throw new NullPointerException();
401
        } else {
402
            return VmMagic.getObjectType(obj);
403
        }
404
    }
405
406
    /**
407
     * Clone the given object
408
     *
409
     * @param obj
410
     * @return Object
411
     */
412
    public static Object clone(Cloneable obj) {
413
        return Vm.getHeapManager().clone(obj);
414
    }
415
416
    /**
417
     * Gets the hashcode of the given object
418
     *
419
     * @param obj
420
     * @return int
421
     */
422
    public static int getHashCode(Object obj) {
423
        if (obj == null) {
424
            // According to spec, null has zero as hashcode.
425
            return 0;
426
        } else {
427
            return ObjectReference.fromObject(obj).toAddress().toInt();
428
        }
429
    }
430
431
    // ------------------------------------------
432
    // java.lang.Class support
433
    // ------------------------------------------
434
435
    public static Class forName(String className) throws ClassNotFoundException {
436
        return getContextClassLoader().asClassLoader().loadClass(className);
437
    }
438
439
    /**
440
     * Gets the first non-system classloader out of the current stacktrace, or
441
     * the system classloader if no other classloader is found in the current
442
     * stacktrace.
443
     *
444
     * @return The classloader
445
     */
446
    protected static VmClassLoader getContextClassLoader() {
447
        final VmStackReader reader = VmProcessor.current().getArchitecture()
448
            .getStackReader();
449
        final VmSystemClassLoader systemLoader = VmSystem.systemLoader;
450
        Address f = VmMagic.getCurrentFrame();
451
        while (reader.isValid(f)) {
452
            final VmMethod method = reader.getMethod(f);
453
            final VmClassLoader loader = method.getDeclaringClass().getLoader();
454
            if ((loader != null) && (loader != systemLoader)) {
455
                return loader;
456
            } else {
457
                f = reader.getPrevious(f);
458
            }
459
        }
460
        return systemLoader;
461
    }
462
463
    // ------------------------------------------
464
    // java.lang.SecurityManager support
465
    // ------------------------------------------
466
467
    /**
468
     * Gets the current stacktrace as array of classes.
469
     *
470
     * @return Class[]
471
     */
472
    public static Class[] getClassContext() {
473
        final VmStackReader reader = VmProcessor.current().getArchitecture()
474
            .getStackReader();
475
        final VmStackFrame[] stack = reader.getVmStackTrace(VmMagic
476
            .getCurrentFrame(), null, VmThread.STACKTRACE_LIMIT);
477
        final int count = stack.length;
478
        final Class[] result = new Class[count];
479
480
        for (int i = 0; i < count; i++) {
481
            result[i] = stack[i].getMethod().getDeclaringClass().asClass();
482
        }
483
484
        return result;
485
    }
486
487
    /**
488
     * Gets the current stacktrace as array of classes excluding the calls to
489
     * java.lang.reflect.Method.invoke() and org.jnode.vm.VmReflection.invoke().
490
     *
491
     * @return Class[]
492
     */
493
    public static Class[] getRealClassContext() {
494
        final VmStackReader reader = VmProcessor.current().getArchitecture()
495
            .getStackReader();
496
        final VmStackFrame[] stack = reader.getVmStackTrace(VmMagic
497
            .getCurrentFrame(), null, VmThread.STACKTRACE_LIMIT);
498
        final int count = stack.length;
499
        final Class[] result = new Class[count];
500
        int real_count = 0;
501
        for (int i = 0; i < count; i++) {
502
            VmMethod method = stack[i].getMethod();
503
            VmType<?> clazz = method.getDeclaringClass();
504
            if ((method.getName().equals("invoke") && (
505
                clazz.getName().equals("java.lang.reflect.Method") ||
506
                    clazz.getName().equals("org.jnode.vm.VmReflection"))))
507
                continue;
508
509
            result[real_count++] = clazz.asClass();
510
        }
511
512
        Class[] real_result = new Class[real_count];
513
        System.arraycopy(result, 0, real_result, 0, real_count);
514
515
        return real_result;
516
    }
517
518
    /**
519
     * Do nothing, until interrupted by an interrupts.
520
     */
521
    public static void idle() {
522
        Unsafe.idle();
523
    }
524
525
    @Internal
526
    public static final Object allocStack(int size) {
527
        try {
528
            return Vm.getHeapManager()
529
                .newInstance(
530
                    systemLoader.loadClass(
531
                        "org.jnode.vm.VmSystemObject", true), size);
532
        } catch (ClassNotFoundException ex) {
533
            throw (NoClassDefFoundError) new NoClassDefFoundError()
534
                .initCause(ex);
535
        }
536
    }
537
538
    /**
539
     * Find an exception handler to handle the given exception in the given
540
     * frame at the given address.
541
     *
542
     * @param ex
543
     * @param frame
544
     * @param address
545
     * @return Object
546
     */
547
    @PrivilegedActionPragma
548
    public static Address findThrowableHandler(Throwable ex, Address frame,
549
                                               Address address) {
550
551
        try {
552
            debug++;
553
554
            if (ex == null) {
555
                Unsafe.debug("NPE");
556
                throw new NullPointerException();
557
            }
558
            if (frame == null) {
559
                Unsafe.debug("frame==null");
560
                return null;
561
            }
562
            final VmProcessor proc = VmProcessor.current();
563
            final VmStackReader reader = proc.getArchitecture()
564
                .getStackReader();
565
566
            final VmType exClass = VmMagic.getObjectType(ex);
567
            final VmMethod method = reader.getMethod(frame);
568
            if (method == null) {
569
                Unsafe.debug("Unknown method");
570
                return null;
571
            }
572
573
            // if (interpreted) {
574
            /*
575
             * Screen.debug("{ex at pc:"); Screen.debug(pc); Screen.debug(" of " +
576
             * method.getBytecodeSize()); Screen.debug(method.getName());
577
             */
578
            // }
579
            final int count;
580
            final VmByteCode bc = method.getBytecode();
581
            final VmCompiledCode cc = reader.getCompiledCode(frame);
582
            if (bc != null) {
583
                count = bc.getNoExceptionHandlers();
584
            } else {
585
                count = 0;
586
            }
587
            // Screen.debug("eCount=" + count);
588
            for (int i = 0; i < count; i++) {
589
                final AbstractExceptionHandler eh;
590
                final VmCompiledExceptionHandler ceh;
591
                ceh = cc.getExceptionHandler(i);
592
                eh = ceh;
593
                boolean match;
594
595
                match = ceh.isInScope(address);
596
597
                if (match) {
598
                    final VmConstClass catchType = eh.getCatchType();
599
600
                    if (catchType == null) {
601
                        /* Catch all exceptions */
602
                        return Address.fromAddress(ceh.getHandler());
603
                    } else {
604
                        if (!catchType.isResolved()) {
605
                            SoftByteCodes.resolveClass(catchType);
606
                        }
607
                        final VmType handlerClass = catchType
608
                            .getResolvedVmClass();
609
                        if (handlerClass != null) {
610
                            if (handlerClass.isAssignableFrom(exClass)) {
611
                                return Address.fromAddress(ceh.getHandler());
612
                            }
613
                        } else {
614
                            System.err
615
                                .println("Warning: handler class==null in "
616
                                    + method.getName());
617
                        }
618
                    }
619
                }
620
            }
621
622
            if (cc.contains(address)) {
623
                return Address.fromAddress(cc.getDefaultExceptionHandler());
624
            } else {
625
                return null;
626
            }
627
        } catch (Throwable ex2) {
628
            Unsafe.debug("Exception in findThrowableHandler");
629
            try {
630
                ex2.printStackTrace();
631
            } finally {
632
                Unsafe.die("findThrowableHandler");
633
            }
634
            return null;
635
        } finally {
636
            debug--;
637
        }
638
    }
639
640
    // ------------------------------------------
641
    // java.lang.System support
642
    // ------------------------------------------
643
644
    /**
645
     * Copy one array to another. This is the implementation for System.arraycopy in JNode
646
     *
647
     * @param src
648
     * @param srcPos
649
     * @param dst
650
     * @param dstPos
651
     * @param length
652
     */
653
    @PrivilegedActionPragma
654
    public static void arrayCopy(final Object src, final int srcPos,
655
                                 final Object dst, final int dstPos, final int length) {
656
        Class<?> src_class = src.getClass();
657
        Class<?> dst_class = dst.getClass();
658
659
        if (!src_class.isArray()) {
660
            // Unsafe.debug('!');
661
            throw new ArrayStoreException("src is not an array");
662
        }
663
664
        if (!dst_class.isArray()) {
665
            // Unsafe.debug("dst is not an array:");
666
            // Unsafe.debug(dst_class.getName());
667
            throw new ArrayStoreException("dst is not an array");
668
        }
669
670
        String src_name = src_class.getName();
671
        String dst_name = dst_class.getName();
672
673
        char src_type = src_name.charAt(1);
674
        char dst_type = dst_name.charAt(1);
675
676
        if (src_type == '[') {
677
            src_type = 'L';
678
        }
679
        if (dst_type == '[') {
680
            dst_type = 'L';
681
        }
682
683
        if (src_type != dst_type) {
684
            // Unsafe.debug("invalid array types:");
685
            // Unsafe.debug(src_class.getName());
686
            // Unsafe.debug(dst_class.getName());
687
            throw new ArrayStoreException(
688
                "Incompatible array types: " + src_class.getName() + ", " + dst_class.getName());
689
        }
690
691
        if (srcPos < 0) {
692
            throw new IndexOutOfBoundsException("srcPos < 0");
693
        }
694
        if (dstPos < 0) {
695
            throw new IndexOutOfBoundsException("dstPos < 0");
696
        }
697
        if (length < 0) {
698
            throw new IndexOutOfBoundsException("length < 0");
699
        }
700
701
        final int slotSize = VmProcessor.current().getArchitecture()
702
            .getReferenceSize();
703
        final Offset lengthOffset = Offset
704
            .fromIntSignExtend(VmArray.LENGTH_OFFSET * slotSize);
705
        final int dataOffset = VmArray.DATA_OFFSET * slotSize;
706
707
        final Address srcAddr = ObjectReference.fromObject(src).toAddress();
708
        final Address dstAddr = ObjectReference.fromObject(dst).toAddress();
709
710
        final int srcLen = srcAddr.loadInt(lengthOffset);
711
        final int dstLen = dstAddr.loadInt(lengthOffset);
712
713
        // Calc end index (if overflow, then will be < 0 )
714
        final int srcEnd = srcPos + length;
715
        final int dstEnd = dstPos + length;
716
717
        if ((srcEnd > srcLen) || (srcEnd < 0)) {
718
            throw new IndexOutOfBoundsException("srcPos+length > src.length ("
719
                + srcPos + "+" + length + " > " + srcLen + ")");
720
        }
721
        if ((dstEnd > dstLen) || (dstEnd < 0)) {
722
            throw new IndexOutOfBoundsException("dstPos+length > dst.length");
723
        }
724
725
        final int elemsize;
726
        final boolean isObjectArray;
727
        switch (src_type) {
728
            case 'Z':
729
                // Boolean
730
            case 'B':
731
                // Byte
732
                elemsize = 1;
733
                isObjectArray = false;
734
                break;
735
            case 'C':
736
                // Character
737
            case 'S':
738
                // Short
739
                elemsize = 2;
740
                isObjectArray = false;
741
                break;
742
            case 'I':
743
                // Integer
744
            case 'F':
745
                // Float
746
                elemsize = 4;
747
                isObjectArray = false;
748
                break;
749
            case 'L':
750
                // Object
751
                elemsize = slotSize;
752
                isObjectArray = true;
753
                break;
754
            case 'J':
755
                // Long
756
            case 'D':
757
                // Double
758
                elemsize = 8;
759
                isObjectArray = false;
760
                break;
761
            default:
762
                // Unsafe.debug("uat:");
763
                // Unsafe.debug(src_type);
764
                // Unsafe.debug(src_name);
765
                throw new ArrayStoreException("Unknown array type");
766
        }
767
768
        final Address srcPtr = srcAddr.add(dataOffset + (srcPos * elemsize));
769
        final Address dstPtr = dstAddr.add(dataOffset + (dstPos * elemsize));
770
        final Extent size = Extent.fromIntZeroExtend(length * elemsize);
771
772
773
        if (isObjectArray) {
774
            Class dst_comp_class = dst_class.getComponentType();
775
            Class src_comp_class = src_class.getComponentType();
776
            if (!dst_comp_class.isAssignableFrom(src_comp_class)) {
777
                //todo optimize for speed
778
                Object[] srca = (Object[]) src;
779
                Object[] dsta = (Object[]) dst;
780
                for (int i = 0; i < length; i++) {
781
                    Object o = srca[srcPos + i];
782
                    if (o == null || dst_comp_class.isInstance(o)) {
783
                        dsta[dstPos + i] = o;
784
                    } else {
785
                        throw new ArrayStoreException();
786
                    }
787
                }
788
            } else {
789
                Unsafe.copy(srcPtr, dstPtr, size);
790
            }
791
        } else {
792
            Unsafe.copy(srcPtr, dstPtr, size);
793
        }
794
795
        if (isObjectArray) {
796
            final VmWriteBarrier wb = Vm.getHeapManager().getWriteBarrier();
797
            if (wb != null) {
798
                wb.arrayCopyWriteBarrier(src, srcPos, srcPos + length);
799
            }
800
        }
801
    }
802
803
    /**
804
     * Returns the current time in milliseconds. Note that while the unit of
805
     * time of the return value is a millisecond, the granularity of the value
806
     * depends on the underlying operating system and may be larger. For
807
     * example, many operating systems measure time in units of tens of
808
     * milliseconds. See the description of the class Date for a discussion of
809
     * slight discrepancies that may arise between "computer time" and
810
     * coordinated universal time (UTC).
811
     * <p/>
812
     * This method does call other methods and CANNOT be used in the low-level
813
     * system environment, where synchronization cannot be used. *
814
     *
815
     * @return the difference, measured in milliseconds, between the current
816
     *         time and midnight, January 1, 1970 UTC
817
     */
818
    public static long currentTimeMillis() {
819
820
        if (rtcIncrement == 0) {
821
            try {
822
                final RTCService rtcService = VmSystem.rtcService;
823
                if (rtcService != null) {
824
                    final long rtcTime = rtcService.getTime();
825
                    if (rtcTime == 0L) {
826
                        // We don't have an RTC service yet, return an invalid,
827
                        // but for now good enough value
828
                        return currentTimeMillis;
829
                    } else {
830
                        rtcIncrement = rtcTime - currentTimeMillis;
831
                    }
832
                }
833
            } catch (Exception ex) {
834
                BootLog.error("Error getting rtcIncrement ", ex);
835
                rtcIncrement = 1;
836
            }
837
        }
838
        return currentTimeMillis + rtcIncrement;
839
    }
840
841
    /**
842
     * <p>
843
     * Returns the current value of a nanosecond-precise system timer.
844
     * The value of the timer is an offset relative to some arbitrary fixed
845
     * time, which may be in the future (making the value negative).  This
846
     * method is useful for timing events where nanosecond precision is
847
     * required.  This is achieved by calling this method before and after the
848
     * event, and taking the difference between the two times:
849
     * </p>
850
     * <p>
851
     * <code>long startTime = System.nanoTime();</code><br />
852
     * <code>... <emph>event code</emph> ...</code><br />
853
     * <code>long endTime = System.nanoTime();</code><br />
854
     * <code>long duration = endTime - startTime;</code><br />
855
     * </p>
856
     * <p>
857
     * Note that the value is only nanosecond-precise, and not accurate; there
858
     * is no guarantee that the difference between two values is really a
859
     * nanosecond.  Also, the value is prone to overflow if the offset
860
     * exceeds 2^63.
861
     * </p>
862
     *
863
     * @return the time of a system timer in nanoseconds.
864
     * @since 1.5
865
     */
866
    public static long nanoTime() {        
867
        if (ghz == -1) {
868
            final long measureDuration = 1000; // in milliseconds
869
            
870
            long start = Unsafe.getCpuCycles();
871
            long ms_start = currentTimeMillis();
872
            long ms_end;
873
            try {
874
                Thread.sleep(measureDuration);
875
            } catch (InterruptedException e) {
876
                //ignore
877
            } finally {
878
                ms_end = currentTimeMillis();
879
            }
880
            long end = Unsafe.getCpuCycles();
881
            long ms = ms_end - ms_start;
882
            if (ms <= 0) {
883
                ms = measureDuration;
884
            }
885
886
            ghz = (end - start) / (ms * 1000000L);
887
            if (ghz <= 0) {
888
                ghz = 0;   
889
            }         
890
        }
891
        
892
        if (ghz == 0) {
893
            //todo these are CPUs under 1GHz, improve this case
894
            return currentTimeMillis() * 1000000L;
895
        }
896
        
897
        return Unsafe.getCpuCycles() / ghz;
898
    }
899
900
    /**
901
     * Returns the number of milliseconds since booting the kernel of JNode.
902
     * <p/>
903
     * This method does not call any other method and CAN be used in the
904
     * low-level system environment, where synchronization cannot be used.
905
     *
906
     * @return The current time of the kernel
907
     * @throws org.vmmagic.pragma.UninterruptiblePragma
908
     *
909
     */
910
    @KernelSpace
911
    @Uninterruptible
912
    public static long currentKernelMillis() {
913
        return currentTimeMillis;
914
    }
915
916
    /**
917
     * @return VmClassLoader
918
     */
919
    public static VmSystemClassLoader getSystemClassLoader() {
920
        return systemLoader;
921
    }
922
923
    /**
924
     * Returns the free memory in system ram
925
     *
926
     * @return free memory in system ram
927
     */
928
    public static long freeMemory() {
929
        return Vm.getHeapManager().getFreeMemory();
930
    }
931
932
    /**
933
     * Returns the total amount of system memory
934
     *
935
     * @return the total amount of system memory
936
     */
937
    public static long totalMemory() {
938
        return Vm.getHeapManager().getTotalMemory();
939
    }
940
941
    /**
942
     * Call the garbage collector
943
     */
944
    public static void gc() {
945
        Vm.getHeapManager().gc();
946
    }
947
948
    static class SystemOutputStream extends OutputStream {
949
950
        private StringBuffer data;
951
952
        /**
953
         * @see java.io.OutputStream#write(int)
954
         */
955
        public void write(int b) throws IOException {
956
            final char ch = (char) (b & 0xFF);
957
            Unsafe.debug(ch);
958
            if (data == null) {
959
                synchronized (this) {
960
                    data = new StringBuffer();
961
                }
962
            }
963
            data.append(ch);
964
        }
965
966
        /**
967
         * Returns the data written to the system output stream
968
         *
969
         * @return data written to the system output stream
970
         */
971
        public String getData() {
972
            return (data == null) ? "" : data.toString();
973
        }
974
    }
975
976
    /**
977
     * @param rtcService The rtcService to set.
978
     */
979
    public static final void setRtcService(RTCService rtcService) {
980
        if (VmSystem.rtcService == null) {
981
            VmSystem.rtcService = rtcService;
982
        }
983
    }
984
985
    /**
986
     * @param rtcService The rtcService previously set.
987
     */
988
    public static final void resetRtcService(RTCService rtcService) {
989
        if (VmSystem.rtcService == rtcService) {
990
            VmSystem.rtcService = null;
991
        }
992
    }
993
994
    /**
995
     * @return Returns the initJar.
996
     */
997
    public static final MemoryResource getInitJar() {
998
        return initJar;
999
    }
1000
1001
    /**
1002
     * @return Returns the out.
1003
     */
1004
    public static final PrintStream getOut() {
1005
        return out;
1006
    }
1007
1008
    /**
1009
     * Calculate the speed of the current processor.
1010
     *
1011
     * @return the speed of the current processor in "JNodeMips"
1012
     */
1013
    @Uninterruptible
1014
    public static float calculateJNodeMips() {
1015
        final long millis = currentTimeMillis % 1000;
1016
        while (millis == (currentTimeMillis % 1000)) {
1017
            // Wait
1018
        }
1019
        long count = 0;
1020
        float dummy = 0.0f;
1021
        while (millis != (currentTimeMillis % 1000)) {
1022
            count++;
1023
            dummy += 0.5f;
1024
        }
1025
        return count / 100000.0f;
1026
    }
1027
1028
    /**
1029
     * Is the system shutting down.
1030
     *
1031
     * @return if the system is shutting down
1032
     */
1033
    public static boolean isShuttingDown() {
1034
        return inShutdown;
1035
    }
1036
1037
    /**
1038
     * Gets the system exit code.
1039
     *
1040
     * @return the system exit code
1041
     */
1042
    public static int getExitCode() {
1043
        return exitCode;
1044
    }
1045
1046
    /**
1047
     * Halt the system. This method requires a JNodePermission("halt").
1048
     *
1049
     * @param reset
1050
     */
1051
    @PrivilegedActionPragma
1052
    public static void halt(boolean reset) {
1053
        final SecurityManager sm = System.getSecurityManager();
1054
        if (sm != null) {
1055
            sm.checkPermission(new JNodePermission("halt"));
1056
        }
1057
        exitCode = (reset ? 1 : 0);
1058
        inShutdown = true;
1059
        try {
1060
            final PluginManager pm = InitialNaming.lookup(PluginManager.NAME);
1061
            pm.stopPlugins();
1062
        } catch (NameNotFoundException ex) {
1063
            System.err.println("Cannot find ServiceManager");
1064
        }
1065
    }
1066
1067
    /**
1068
     * Set the effective System.in to a different InputStream.  The actual behavior depends
1069
     * on whether we're in proclet mode or not.  If we are, we set the appropriate proxied stream,
1070
     * to the new stream, depending on whether the current thread is a ProcletContext or not.
1071
     * Otherwise, we update the System.in field.
1072
     *
1073
     * @param in the new InputStream
1074
     * @see #setIn(InputStream)
1075
     */
1076
    @PrivilegedActionPragma
1077
    public static void setIn(InputStream in) {
1078
        getIOContext().setSystemIn(in);
1079
    }
1080
1081
    /**
1082
     * Set the effective System.out to a different PrintStream.  The actual behavior depends
1083
     * on whether we're in proclet mode or not.  If we are, we set the appropriate proxied stream,
1084
     * to the new stream, depending on whether the current thread is a ProcletContext or not.
1085
     * Otherwise, we update the System.out field.
1086
     *
1087
     * @param out the new PrintStream
1088
     * @see java.lang.System#setOut(PrintStream)
1089
     */
1090
    @PrivilegedActionPragma
1091
    public static void setOut(PrintStream out) {
1092
        getIOContext().setSystemOut(out);
1093
    }
1094
1095
    /**
1096
     * Set the effective System.err to a different PrintStream.  The actual behavior depends
1097
     * on whether we're in proclet mode or not.  If we are, we set the appropriate proxied stream,
1098
     * to the new stream, depending on whether the current thread is a ProcletContext or not.
1099
     * Otherwise, we update the System.err field.
1100
     *
1101
     * @param err the new PrintStream
1102
     * @see java.lang.System#setErr(PrintStream)
1103
     */
1104
    @PrivilegedActionPragma
1105
    public static void setErr(PrintStream err) {
1106
        getIOContext().setSystemErr(err);
1107
    }
1108
1109
    //todo protect this method from arbitrary access
1110
    @PrivilegedActionPragma
1111
    public static void setStaticField(Class<?> clazz, String fieldName,
1112
                                      Object value) {
1113
        final VmStaticField f = (VmStaticField) VmType.fromClass((Class<?>) clazz).getField(
1114
            fieldName);
1115
        final Object staticsTable;
1116
        final Offset offset;
1117
        if (f.isShared()) {
1118
            staticsTable = VmMagic.currentProcessor().getSharedStaticsTable();
1119
            offset = Offset.fromIntZeroExtend(f.getSharedStaticsIndex() << 2);
1120
        } else {
1121
            staticsTable = VmMagic.currentProcessor().getIsolatedStaticsTable();
1122
            offset = Offset.fromIntZeroExtend(f.getIsolatedStaticsIndex() << 2);
1123
        }
1124
        final Address ptr = VmMagic.getArrayData(staticsTable);
1125
        ptr.store(ObjectReference.fromObject(value), offset);
1126
    }
1127
1128
    //io context related
1129
1130
    public static IOContext getIOContext() {
1131
        return VmIsolate.currentIsolate().getIOContext();
1132
    }
1133
1134
    public static boolean hasVmIOContext() {
1135
        return getIOContext() instanceof VmIOContext;
1136
    }
1137
1138
1139
    /**
1140
     * Get the current global (i.e. non-ProcletContext) flavor of System.err.
1141
     *
1142
     * @return the global 'err' stream.
1143
     */
1144
    public static PrintStream getGlobalErrStream() {
1145
        return VmIOContext.getGlobalErrStream();
1146
    }
1147
1148
    /**
1149
     * Get the current global (i.e. non-ProcletContext) flavor of System.in.
1150
     *
1151
     * @return the global 'in' stream.
1152
     */
1153
    public static InputStream getGlobalInStream() {
1154
        return VmIOContext.getGlobalInStream();
1155
    }
1156
1157
    /**
1158
     * Get the current global (i.e. non-ProcletContext) flavor of System.out.
1159
     *
1160
     * @return the global 'out' stream.
1161
     */
1162
    public static PrintStream getGlobalOutStream() {
1163
        return VmIOContext.getGlobalOutStream();
1164
    }
1165
1166
    /**
1167
     * Switch the current Isolate from the initial IOContext to an external one.
1168
     * If the Isolate already has an external IOContext, this is a no-op.
1169
     *
1170
     * @param context
1171
     */
1172
    public static synchronized void switchToExternalIOContext(IOContext context) {
1173
        if (hasVmIOContext()) {
1174
            getIOContext().exitContext();
1175
            VmIsolate.currentIsolate().setIOContext(context);
1176
            context.enterContext();
1177
        }
1178
    }
1179
1180
    /**
1181
     * Reset to the current Isolate to its initial IOContext.
1182
     */
1183
    public static synchronized void resetIOContext() {
1184
        if (!hasVmIOContext()) {
1185
            getIOContext().exitContext();
1186
            VmIsolate.currentIsolate().resetIOContext();
1187
            getIOContext().enterContext();
1188
        } else {
1189
            throw new RuntimeException("IO Context cannot be reset");
1190
        }
1191
    }
1192
}