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.PrintWriter;
24
import java.lang.reflect.Constructor;
25
import java.lang.reflect.InvocationTargetException;
26
import java.util.List;
27
import java.util.Map;
28
import java.util.TreeMap;
29
30
import org.jnode.plugin.Extension;
31
import org.jnode.plugin.PluginDescriptor;
32
import org.jnode.plugin.PluginRegistry;
33
import org.jnode.system.ResourceManager;
34
import org.jnode.util.BootableArrayList;
35
import org.jnode.util.Counter;
36
import org.jnode.util.CounterGroup;
37
import org.jnode.util.Statistic;
38
import org.jnode.util.Statistics;
39
import org.jnode.annotation.Inline;
40
import org.jnode.annotation.Internal;
41
import org.jnode.annotation.KernelSpace;
42
import org.jnode.annotation.NoInline;
43
import org.jnode.annotation.SharedStatics;
44
import org.jnode.annotation.Uninterruptible;
45
import org.jnode.vm.classmgr.CompiledCodeList;
46
import org.jnode.vm.classmgr.VmClassLoader;
47
import org.jnode.vm.classmgr.VmSharedStatics;
48
import org.jnode.vm.classmgr.VmType;
49
import org.jnode.vm.memmgr.HeapHelper;
50
import org.jnode.vm.memmgr.VmHeapManager;
51
import org.jnode.vm.scheduler.VmProcessor;
52
import org.jnode.vm.scheduler.VmScheduler;
53
54
/**
55
 * @author Ewout Prangsma (epr@users.sourceforge.net)
56
 */
57
@SharedStatics
58
public final class Vm extends VmSystemObject implements Statistics {
59
60
    /**
61
     * The single instance
62
     */
63
    private static Vm instance;
64
65
    /**
66
     * Are will in bootimage building phase?
67
     */
68
    private transient boolean bootstrap;
69
70
    /**
71
     * The current architecture
72
     */
73
    private final VmArchitecture arch;
74
75
    /**
76
     * The heap manager
77
     */
78
    private final VmHeapManager heapManager;
79
80
    /** Set this boolean to turn the hot method manager on/off */
81
    // private final boolean runHotMethodManager = false;
82
    /**
83
     * Should this VM run in debug mode?
84
     */
85
    private final boolean debugMode;
86
87
    /**
88
     * Version of the OS and VM
89
     */
90
    private final String version;
91
92
    /**
93
     * The statics table
94
     */
95
    private final VmSharedStatics statics;
96
97
    /**
98
     * The list of all system processors
99
     */
100
    private final List<VmProcessor> processors;
101
102
    /**
103
     * All statistics
104
     */
105
    private transient Map<String, Statistic> statistics;
106
107
    /**
108
     * List of all compiled methods
109
     */
110
    private final CompiledCodeList compiledMethods;
111
112
    /**
113
     * Should assertions be verified?
114
     */
115
    public static final boolean VerifyAssertions = true;
116
117
    /**
118
     * For assertion checking things that should never happen.
119
     */
120
    public static final boolean NOT_REACHED = false;
121
122
    private VmScheduler scheduler;
123
124
    /**
125
     * Initialize a new instance
126
     *
127
     * @param arch
128
     * @throws InstantiationException
129
     */
130
    public Vm(String version, VmArchitecture arch, VmSharedStatics statics,
131
              boolean debugMode, VmClassLoader loader, PluginRegistry pluginReg)
132
        throws InstantiationException {
133
        this.version = version;
134
        this.debugMode = debugMode;
135
        this.bootstrap = true;
136
        this.arch = arch;
137
        final HeapHelper helper = new HeapHelperImpl(arch);
138
        instance = this;
139
        this.heapManager = createHeapManager(helper, arch, loader, pluginReg);
140
        this.statics = statics;
141
        this.processors = new BootableArrayList<VmProcessor>();
142
        this.compiledMethods = new CompiledCodeList();
143
    }
144
145
    /**
146
     * Find and instantiate the heap manager.
147
     *
148
     * @param arch
149
     * @param loader
150
     * @param pluginReg
151
     * @return
152
     * @throws InstantiationException
153
     */
154
    private static VmHeapManager createHeapManager(HeapHelper helper,
155
                                                   VmArchitecture arch, VmClassLoader loader, PluginRegistry pluginReg)
156
        throws InstantiationException {
157
        if (pluginReg == null) {
158
            // Use in tests and asm constant construction
159
            return null;
160
        }
161
162
        // Find and instantiate the heap manager.
163
        PluginDescriptor core = pluginReg
164
            .getPluginDescriptor("org.jnode.vm.core");
165
        Extension[] memMgrs = core.getExtensionPoint("memmgr").getExtensions();
166
        if (memMgrs.length != 1) {
167
            throw new InstantiationException(
168
                "memmgr extension point must have 1 extension");
169
        }
170
        Extension memMgr = memMgrs[0];
171
        if (memMgr.getConfigurationElements().length != 1) {
172
            throw new InstantiationException(
173
                "Expected 1 element in memmgr extension");
174
        }
175
        String memMgrClassName = memMgr.getConfigurationElements()[0]
176
            .getAttribute("class");
177
        Class[] consArgTypes = {VmClassLoader.class, HeapHelper.class};
178
        try {
179
            Class cls = Class.forName(memMgrClassName);
180
            Constructor cons = cls.getConstructor(consArgTypes);
181
            return (VmHeapManager) cons.newInstance(new Object[]{loader,
182
                helper});
183
        } catch (ClassNotFoundException ex) {
184
            throw new InstantiationException("Cannot find heap manager class "
185
                + memMgrClassName);
186
        } catch (IllegalAccessException ex) {
187
            throw new InstantiationException(
188
                "Cannot access heap manager class " + memMgrClassName);
189
        } catch (InvocationTargetException ex) {
190
            throw (InstantiationException) new InstantiationException(
191
                "Exception in creating heap manager" + ex.getMessage())
192
                .initCause(ex);
193
        } catch (NoSuchMethodException ex) {
194
            throw new InstantiationException(
195
                "Cannot find heap manager constructor");
196
        }
197
    }
198
199
    /**
200
     * @return Returns the bootstrap.
201
     */
202
    public final boolean isBootstrap() {
203
        return this.bootstrap;
204
    }
205
206
    /**
207
     * Is JNode currently running.
208
     *
209
     * @return true or false
210
     */
211
    public static final boolean isRunningVm() {
212
        return ((instance != null) && !instance.bootstrap);
213
    }
214
215
    /**
216
     * Is the bootimage being written?
217
     *
218
     * @return true or false.
219
     */
220
    public static final boolean isWritingImage() {
221
        return ((instance == null) || instance.bootstrap);
222
    }
223
224
    /**
225
     * Causes JNode to stop working with a given message.
226
     *
227
     * @param msg
228
     */
229
    public static final void sysFail(String msg) {
230
        if (isRunningVm()) {
231
            Unsafe.die(msg);
232
        }
233
    }
234
235
    /**
236
     * @return Returns the arch.
237
     */
238
    public static final VmArchitecture getArch() {
239
        return instance.arch;
240
    }
241
242
    /**
243
     * @return Returns the instance.
244
     */
245
    @KernelSpace
246
    @Uninterruptible
247
    public static final Vm getVm() {
248
        return instance;
249
    }
250
251
    /**
252
     * @return Returns the heapManager.
253
     */
254
    public static final VmHeapManager getHeapManager() {
255
        return instance.heapManager;
256
    }
257
258
    /**
259
     * Returns the number of available processors currently available to the
260
     * virtual machine. This number may change over time; so a multi-processor
261
     * program want to poll this to determine maximal resource usage.
262
     *
263
     * @return the number of processors available, at least 1
264
     */
265
    public final int availableProcessors() {
266
        return processors.size();
267
    }
268
269
    // The following code has been moved to org.jnode.shell.command.system.VmInfoCommand
270
//    /**
271
//     * Show VM info.
272
//     * 
273
//     * @param args
274
//     */
275
//    public static void main(String[] args) {
276
//        final Vm vm = getVm();
277
//        if ((vm != null) && !vm.isBootstrap()) {
278
//            final PrintStream out = System.out;
279
//            out.println("JNode VM " + vm.getVersion());
280
//            vm.dumpStatistics(out);
281
//            vm.getSharedStatics().dumpStatistics(out);
282
//            vm.heapManager.dumpStatistics(out);
283
//            final SecurityManager sm = System.getSecurityManager();
284
//            out.println("Security manager: " + sm);
285
//            for (VmProcessor cpu : vm.processors) {
286
//                out.println("Processor " + vm.processors.indexOf(cpu) + " (" + cpu.getIdString() + ")");
287
//                cpu.dumpStatistics(out);
288
//            }
289
//            if ((args.length > 0) && args[0].equals("reset")) {
290
//                vm.resetCounters();
291
//            }
292
//        }
293
//    }
294
295
    /**
296
     * Does this VM run in debug mode.
297
     *
298
     * @return Returns the debugMode.
299
     */
300
    public final boolean isDebugMode() {
301
        return this.debugMode;
302
    }
303
304
    /**
305
     * @return Returns the statics.
306
     */
307
    public final VmSharedStatics getSharedStatics() {
308
        return this.statics;
309
    }
310
311
    /**
312
     * Gets the version of the current VM.
313
     *
314
     * @return Returns the version.
315
     */
316
    public final String getVersion() {
317
        return this.version;
318
    }
319
320
    /**
321
     * Find all processors in the system and start them.
322
     */
323
    final void initializeProcessors(ResourceManager rm) {
324
        // Add the current (bootstrap) processor
325
        addProcessor(VmProcessor.current());
326
        // Let the architecture find the processors
327
        arch.initializeProcessors(rm);
328
        // Show some info
329
        final int cnt = processors.size();
330
        if (cnt == 1) {
331
            System.out.println("Detected 1 processor");
332
        } else {
333
            System.out.println("Detected " + cnt + " processors");
334
        }
335
    }
336
337
    /**
338
     * Add a discovered CPU.
339
     *
340
     * @param cpu
341
     */
342
    final void addProcessor(VmProcessor cpu) {
343
        processors.add(cpu);
344
    }
345
346
    /**
347
     * Gets or creates a counter with a given name.
348
     *
349
     * @param name
350
     * @return The counter
351
     */
352
    public final Counter getCounter(String name) {
353
        Counter cnt = (Counter) getStatistic(name);
354
        if (cnt == null) {
355
            synchronized (this) {
356
                cnt = (Counter) getStatistic(name);
357
                if (cnt == null) {
358
                    cnt = new Counter(name, name);
359
                    addStatistic(name, cnt);
360
                }
361
            }
362
        }
363
        return cnt;
364
    }
365
366
    /**
367
     * Gets or creates a counter group with a given name.
368
     *
369
     * @param name
370
     * @return The counter group
371
     */
372
    public final CounterGroup getCounterGroup(String name) {
373
        CounterGroup cnt = (CounterGroup) getStatistic(name);
374
        if (cnt == null) {
375
            synchronized (this) {
376
                cnt = (CounterGroup) getStatistic(name);
377
                if (cnt == null) {
378
                    cnt = new CounterGroup(name, name);
379
                    addStatistic(name, cnt);
380
                }
381
            }
382
        }
383
        return cnt;
384
    }
385
386
    private Statistic getStatistic(String name) {
387
        if (statistics != null) {
388
            return statistics.get(name);
389
        } else {
390
            return null;
391
        }
392
    }
393
394
    private void addStatistic(String name, Statistic stat) {
395
        if (statistics == null) {
396
            statistics = new TreeMap<String, Statistic>();
397
        }
398
        statistics.put(name, stat);
399
    }
400
401
    /**
402
     * @see org.jnode.util.Statistics#getStatistics()
403
     */
404
    public synchronized Statistic[] getStatistics() {
405
        if (statistics != null) {
406
            return statistics.values().toArray(
407
                new Statistic[statistics.size()]);
408
        } else {
409
            return new Statistic[0];
410
        }
411
    }
412
413
    public void dumpStatistics(PrintWriter out) {
414
        if (statistics != null) {
415
            final Statistic[] stats = getStatistics();
416
            for (int i = 0; i < stats.length; i++) {
417
                out.println(stats[i]);
418
            }
419
        }
420
    }
421
422
    public final void resetCounters() {
423
        if (statistics != null) {
424
            final Statistic[] stats = getStatistics();
425
            for (int i = 0; i < stats.length; i++) {
426
                final Statistic s = stats[i];
427
                if (s instanceof Counter) {
428
                    ((Counter) s).reset();
429
                }
430
            }
431
        }
432
    }
433
434
    /**
435
     * Assert the given value to be true.
436
     *
437
     * @param value
438
     */
439
    public static void _assert(boolean value) {
440
        if (!value) {
441
            assertionFailed(null, null);
442
        }
443
    }
444
445
    /**
446
     * Assert the given value to be true.
447
     *
448
     * @param value
449
     */
450
    public static void _assert(boolean value, String msg) {
451
        if (!value) {
452
            assertionFailed(msg, null);
453
        }
454
    }
455
456
    /**
457
     * Assert the given value to be true.
458
     *
459
     * @param value
460
     */
461
    public static void _assert(boolean value, String msg, String msg2) {
462
        if (!value) {
463
            assertionFailed(msg, msg2);
464
        }
465
    }
466
467
    /**
468
     * Throw an AssertionError with the given messages.
469
     *
470
     * @param msg
471
     * @param msg2
472
     * @throws NoInlinePragma
473
     */
474
    @NoInline
475
    private static void assertionFailed(String msg, String msg2) {
476
        if ((msg == null) && (msg2 == null)) {
477
            msg = "Assertion failed";
478
        } else if (msg2 != null) {
479
            msg = msg + ": " + msg2;
480
        }
481
        throw new AssertionError(msg);
482
    }
483
484
    /**
485
     * Gets the list of compiled methods.
486
     *
487
     * @return Returns the compiledMethods.
488
     */
489
    @KernelSpace
490
    public static final CompiledCodeList getCompiledMethods() {
491
        return instance.compiledMethods;
492
    }
493
494
    /**
495
     * A new type has been resolved by the VM. Create a new MM type to reflect
496
     * the VM type, and associate the MM type with the VM type.
497
     *
498
     * @param vmType The newly resolved type
499
     */
500
    @Inline
501
    public static void notifyClassResolved(VmType<?> vmType) {
502
        final Vm instance = Vm.instance;
503
        if (instance != null) {
504
            final VmHeapManager hm = instance.heapManager;
505
            if (hm != null) {
506
                hm.notifyClassResolved(vmType);
507
            }
508
        }
509
    }
510
511
    /**
512
     * @return the scheduler
513
     */
514
    @Internal
515
    public final VmScheduler getScheduler() {
516
        return scheduler;
517
    }
518
519
    /**
520
     * @param scheduler the scheduler to set
521
     */
522
    @Internal
523
    public final void setScheduler(VmScheduler scheduler) {
524
        if (this.scheduler == null) {
525
            this.scheduler = scheduler;
526
        }
527
    }
528
529
    /**
530
     * @return a copy of the processors list
531
     */
532
    public final List<VmProcessor> getProcessors() {
533
        return new BootableArrayList<VmProcessor>(processors);
534
    }
535
}