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.nio.ByteBuffer;
24
import java.nio.MemoryRawData;
25
26
import org.jnode.system.MemoryResource;
27
import org.jnode.system.MultiMediaMemoryResource;
28
import org.jnode.system.Resource;
29
import org.jnode.system.ResourceManager;
30
import org.jnode.system.ResourceNotFreeException;
31
import org.jnode.system.ResourceOwner;
32
import org.jnode.system.SimpleResourceOwner;
33
import org.jnode.annotation.MagicPermission;
34
import org.jnode.vm.scheduler.VmProcessor;
35
import org.vmmagic.unboxed.Address;
36
import org.vmmagic.unboxed.Extent;
37
import org.vmmagic.unboxed.ObjectReference;
38
import org.vmmagic.unboxed.Offset;
39
import org.vmmagic.unboxed.Word;
40
41
/**
42
 * Default implementation of MemoryResource.
43
 *
44
 * @author Ewout Prangsma (epr@users.sourceforge.net)
45
 */
46
@MagicPermission
47
class MemoryResourceImpl extends Region implements MemoryResource {
48
49
    /**
50
     * My parent
51
     */
52
    private final MemoryResourceImpl parent;
53
    /**
54
     * Start address
55
     */
56
    protected final Address start;
57
    /**
58
     * Exclusive end address
59
     */
60
    private final Address end;
61
    /**
62
     * Size in bytes
63
     */
64
    private final Extent size;
65
    /**
66
     * Has this resource been released?
67
     */
68
    private boolean released;
69
    /**
70
     * First active memory-resource
71
     */
72
    private static Region resources;
73
    /**
74
     * Data for mapping over byte arrays
75
     */
76
    private final Object data;
77
    /**
78
     * Resource owner for byte arrays
79
     */
80
    private static final ResourceOwner BYTE_ARRAY_OWNER = new SimpleResourceOwner("byte-array");
81
    /**
82
     * Size of an object reference
83
     */
84
    private final int slotSize;
85
    /**
86
     * My children
87
     */
88
    private MemoryResourceImpl children;
89
    /**
90
     * Offset relative to my parent
91
     */
92
    private final Offset offset;
93
94
    /**
95
     * Create a new instance
96
     *
97
     * @param owner
98
     * @param start
99
     * @param size
100
     */
101
    protected MemoryResourceImpl(MemoryResourceImpl parent, ResourceOwner owner, Address start, Extent size) {
102
        super(owner);
103
        this.parent = parent;
104
        this.start = start;
105
        if (parent != null) {
106
            this.offset = start.toWord().sub(parent.start.toWord()).toOffset();
107
        } else {
108
            this.offset = start.toWord().toOffset();
109
        }
110
        this.end = start.add(size);
111
        this.size = size;
112
        this.released = false;
113
        this.data = null;
114
        this.slotSize = VmProcessor.current().getArchitecture().getReferenceSize();
115
    }
116
117
    /**
118
     * Create a new instance
119
     *
120
     * @param arrayData
121
     * @param length
122
     * @param elementSize
123
     */
124
    public MemoryResourceImpl(Object arrayData, int length, int elementSize) {
125
        super(BYTE_ARRAY_OWNER);
126
        this.parent = null;
127
        this.data = arrayData;
128
        this.size = Extent.fromIntZeroExtend(length * elementSize);
129
        this.start = VmMagic.getArrayData(arrayData);
130
        this.offset = start.toWord().toOffset();
131
        this.end = start.add(length * elementSize);
132
        this.released = false;
133
        this.slotSize = VmProcessor.current().getArchitecture().getReferenceSize();
134
    }
135
136
    /**
137
     * Create a bytebuffer that has the same content as this resource.
138
     *
139
     * @return a bytebuffer that has the same content as this resource
140
     */
141
    public ByteBuffer asByteBuffer() {
142
        return MemoryRawData.wrap(this);
143
    }
144
145
    /**
146
     * Claim a memory region
147
     *
148
     * @param owner
149
     * @param start
150
     * @param size
151
     * @param mode
152
     * @return The claimed resource
153
     * @throws ResourceNotFreeException
154
     */
155
    protected static synchronized MemoryResource claimMemoryResource(ResourceOwner owner, Address start, Extent size,
156
                                                                     int mode) throws ResourceNotFreeException {
157
        if (start != null) {
158
            final MemoryResourceImpl res = new MemoryResourceImpl(null, owner, start, size);
159
            if (isFree(resources, res)) {
160
                resources = add(resources, res);
161
                return res;
162
            } else {
163
                throw new ResourceNotFreeException();
164
            }
165
        } else {
166
            // Find a range
167
            Address ptr;
168
            if (mode == ResourceManager.MEMMODE_ALLOC_DMA) {
169
                ptr = Unsafe.getMinAddress();
170
            } else {
171
                ptr = Unsafe.getMemoryEnd();
172
            }
173
            MemoryResourceImpl res = new MemoryResourceImpl(null, owner, ptr, size);
174
            while (!isFree(resources, res)) {
175
                ptr = ptr.add(64 * 1024);
176
                res = new MemoryResourceImpl(null, owner, ptr, size);
177
            }
178
            resources = add(resources, res);
179
            return res;
180
        }
181
    }
182
183
    /**
184
     * Gets a 8-bit signed byte at the given memory address
185
     *
186
     * @param memPtr
187
     * @return byte
188
     */
189
    public byte getByte(int memPtr) {
190
        testMemPtr(memPtr, 1);
191
        return start.loadByte(Offset.fromIntZeroExtend(memPtr));
192
    }
193
194
    /**
195
     * Gets multiple 8-bit signed bytes from the given memory address
196
     *
197
     * @param memPtr
198
     * @param dst
199
     * @param dstOfs
200
     * @param length
201
     */
202
    public void getBytes(int memPtr, byte[] dst, int dstOfs, int length) {
203
        if (dstOfs < 0) {
204
            throw new IndexOutOfBoundsException("dstOfs < 0");
205
        }
206
        if (length < 0) {
207
            throw new IndexOutOfBoundsException("length < 0");
208
        }
209
        if (dstOfs + length > dst.length) {
210
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
211
        }
212
        testMemPtr(memPtr, length);
213
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs);
214
        final Extent size = Extent.fromIntZeroExtend(length);
215
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
216
    }
217
218
    /**
219
     * Gets a 16-bit signed short at the given memory address
220
     *
221
     * @param memPtr
222
     * @return short
223
     */
224
    public short getShort(int memPtr) {
225
        testMemPtr(memPtr, 2);
226
        return start.loadShort(Offset.fromIntZeroExtend(memPtr));
227
    }
228
229
    /**
230
     * Gets multiple 16-bit signed bytes from the given memory address
231
     *
232
     * @param memPtr
233
     * @param dst
234
     * @param dstOfs
235
     * @param length
236
     */
237
    public void getShorts(int memPtr, short[] dst, int dstOfs, int length) {
238
        if (dstOfs < 0) {
239
            throw new IndexOutOfBoundsException("dstOfs < 0");
240
        }
241
        if (length < 0) {
242
            throw new IndexOutOfBoundsException("length < 0");
243
        }
244
        if (dstOfs + length > dst.length) {
245
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
246
        }
247
        testMemPtr(memPtr, length * 2);
248
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs * 2);
249
        final Extent size = Extent.fromIntZeroExtend(length * 2);
250
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
251
    }
252
253
    /**
254
     * Gets a 16-bit unsigned char at the given memory address
255
     *
256
     * @param memPtr
257
     * @return char
258
     */
259
    public char getChar(int memPtr) {
260
        testMemPtr(memPtr, 2);
261
        return start.loadChar(Offset.fromIntZeroExtend(memPtr));
262
    }
263
264
    /**
265
     * Gets multiple 16-bit unsigned chars from the given memory address
266
     *
267
     * @param memPtr
268
     * @param dst
269
     * @param dstOfs
270
     * @param length
271
     */
272
    public void getChars(int memPtr, char[] dst, int dstOfs, int length) {
273
        if (dstOfs < 0) {
274
            throw new IndexOutOfBoundsException("dstOfs < 0");
275
        }
276
        if (length < 0) {
277
            throw new IndexOutOfBoundsException("length < 0");
278
        }
279
        if (dstOfs + length > dst.length) {
280
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
281
        }
282
        testMemPtr(memPtr, length * 2);
283
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs * 2);
284
        final Extent size = Extent.fromIntZeroExtend(length * 2);
285
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
286
    }
287
288
    /**
289
     * Gets a 32-bit signed int at the given memory address
290
     *
291
     * @param memPtr
292
     * @return int
293
     */
294
    public int getInt(int memPtr) {
295
        testMemPtr(memPtr, 4);
296
        return start.loadInt(Offset.fromIntZeroExtend(memPtr));
297
    }
298
299
    /**
300
     * Gets multiple 32-bit signed ints from the given memory address
301
     *
302
     * @param memPtr
303
     * @param dst
304
     * @param dstOfs
305
     * @param length
306
     */
307
    public void getInts(int memPtr, int[] dst, int dstOfs, int length) {
308
        if (dstOfs < 0) {
309
            throw new IndexOutOfBoundsException("dstOfs < 0");
310
        }
311
        if (length < 0) {
312
            throw new IndexOutOfBoundsException("length < 0");
313
        }
314
        if (dstOfs + length > dst.length) {
315
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
316
        }
317
        testMemPtr(memPtr, length * 4);
318
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs * 4);
319
        final Extent size = Extent.fromIntZeroExtend(length * 4);
320
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
321
    }
322
323
    /**
324
     * Gets a 64-bit signed long at the given memory address
325
     *
326
     * @param memPtr
327
     * @return long
328
     */
329
    public long getLong(int memPtr) {
330
        testMemPtr(memPtr, 8);
331
        return start.loadLong(Offset.fromIntZeroExtend(memPtr));
332
    }
333
334
    /**
335
     * Gets multiple 64-bit signed longs from the given memory address
336
     *
337
     * @param memPtr
338
     * @param dst
339
     * @param dstOfs
340
     * @param length
341
     */
342
    public void getLongs(int memPtr, long[] dst, int dstOfs, int length) {
343
        if (dstOfs < 0) {
344
            throw new IndexOutOfBoundsException("dstOfs < 0");
345
        }
346
        if (length < 0) {
347
            throw new IndexOutOfBoundsException("length < 0");
348
        }
349
        if (dstOfs + length > dst.length) {
350
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
351
        }
352
        testMemPtr(memPtr, length * 8);
353
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs * 8);
354
        final Extent size = Extent.fromIntZeroExtend(length * 8);
355
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
356
    }
357
358
    /**
359
     * Gets a float at the given memory address
360
     *
361
     * @param memPtr
362
     * @return float
363
     */
364
    public float getFloat(int memPtr) {
365
        testMemPtr(memPtr, 4);
366
        return start.loadFloat(Offset.fromIntZeroExtend(memPtr));
367
    }
368
369
    /**
370
     * Gets multiple 32-bit floats from the given memory address
371
     *
372
     * @param memPtr
373
     * @param dst
374
     * @param dstOfs
375
     * @param length
376
     */
377
    public void getFloats(int memPtr, float[] dst, int dstOfs, int length) {
378
        if (dstOfs < 0) {
379
            throw new IndexOutOfBoundsException("dstOfs < 0");
380
        }
381
        if (length < 0) {
382
            throw new IndexOutOfBoundsException("length < 0");
383
        }
384
        if (dstOfs + length > dst.length) {
385
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
386
        }
387
        testMemPtr(memPtr, length * 4);
388
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs * 4);
389
        final Extent size = Extent.fromIntZeroExtend(length * 4);
390
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
391
    }
392
393
    /**
394
     * Gets a double at the given memory address
395
     *
396
     * @param memPtr
397
     * @return double
398
     */
399
    public double getDouble(int memPtr) {
400
        testMemPtr(memPtr, 8);
401
        return start.loadDouble(Offset.fromIntZeroExtend(memPtr));
402
    }
403
404
    /**
405
     * Gets multiple 64-bit doubles from the given memory address
406
     *
407
     * @param memPtr
408
     * @param dst
409
     * @param dstOfs
410
     * @param length
411
     */
412
    public void getDoubles(int memPtr, double[] dst, int dstOfs, int length) {
413
        if (dstOfs < 0) {
414
            throw new IndexOutOfBoundsException("dstOfs < 0");
415
        }
416
        if (length < 0) {
417
            throw new IndexOutOfBoundsException("length < 0");
418
        }
419
        if (dstOfs + length > dst.length) {
420
            throw new IndexOutOfBoundsException("dstOfs + length > dst.length");
421
        }
422
        testMemPtr(memPtr, length * 8);
423
        final Address dstPtr = VmMagic.getArrayData(dst).add(dstOfs * 8);
424
        final Extent size = Extent.fromIntZeroExtend(length * 8);
425
        Unsafe.copy(start.add(Offset.fromIntZeroExtend(memPtr)), dstPtr, size);
426
    }
427
428
    /**
429
     * Gets a object reference at the given memory address
430
     *
431
     * @param memPtr
432
     * @return Object
433
     */
434
    public Object getObject(int memPtr) {
435
        if (this.data != null) {
436
            throw new SecurityException("Cannot get an Object from a byte-array");
437
        }
438
        testMemPtr(memPtr, 4);
439
        return start.loadObjectReference(Offset.fromIntSignExtend(memPtr));
440
    }
441
442
    /**
443
     * Sets a byte at a given memory address
444
     *
445
     * @param memPtr
446
     * @param value
447
     */
448
    public void setByte(int memPtr, byte value) {
449
        testMemPtr(memPtr, 1);
450
        start.store(value, Offset.fromIntSignExtend(memPtr));
451
    }
452
453
    /**
454
     * Sets multiple 8-bit signed bytes at the given memory address
455
     *
456
     * @param src
457
     * @param srcOfs
458
     * @param dstPtr
459
     * @param length
460
     */
461
    public void setBytes(byte[] src, int srcOfs, int dstPtr, int length) {
462
        if (srcOfs < 0) {
463
            throw new IndexOutOfBoundsException("srcOfs < 0");
464
        }
465
        if (length < 0) {
466
            throw new IndexOutOfBoundsException("length < 0");
467
        }
468
        if (srcOfs + length > src.length) {
469
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
470
        }
471
        testMemPtr(dstPtr, length);
472
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs);
473
        final Extent size = Extent.fromIntZeroExtend(length);
474
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
475
    }
476
477
    /**
478
     * Sets a char at a given memory address
479
     *
480
     * @param memPtr
481
     * @param value
482
     */
483
    public void setChar(int memPtr, char value) {
484
        testMemPtr(memPtr, 2);
485
        start.store(value, Offset.fromIntSignExtend(memPtr));
486
    }
487
488
    /**
489
     * Sets multiple 16-bit unsigned chars at the given memory address
490
     *
491
     * @param src
492
     * @param srcOfs
493
     * @param dstPtr
494
     * @param length
495
     */
496
    public void setChars(char[] src, int srcOfs, int dstPtr, int length) {
497
        if (srcOfs < 0) {
498
            throw new IndexOutOfBoundsException("srcOfs < 0");
499
        }
500
        if (length < 0) {
501
            throw new IndexOutOfBoundsException("length < 0");
502
        }
503
        if (srcOfs + length > src.length) {
504
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
505
        }
506
        testMemPtr(dstPtr, length * 2);
507
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs * 2);
508
        final Extent size = Extent.fromIntZeroExtend(length * 2);
509
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
510
    }
511
512
    /**
513
     * Sets a short at a given memory address
514
     *
515
     * @param memPtr
516
     * @param value
517
     */
518
    public void setShort(int memPtr, short value) {
519
        testMemPtr(memPtr, 2);
520
        start.store(value, Offset.fromIntSignExtend(memPtr));
521
    }
522
523
    /**
524
     * Sets multiple 16-bit signed shorts at the given memory address
525
     *
526
     * @param src
527
     * @param srcOfs
528
     * @param dstPtr
529
     * @param length
530
     */
531
    public void setShorts(short[] src, int srcOfs, int dstPtr, int length) {
532
        if (srcOfs < 0) {
533
            throw new IndexOutOfBoundsException("srcOfs < 0");
534
        }
535
        if (length < 0) {
536
            throw new IndexOutOfBoundsException("length < 0");
537
        }
538
        if (srcOfs + length > src.length) {
539
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
540
        }
541
        testMemPtr(dstPtr, length * 2);
542
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs * 2);
543
        final Extent size = Extent.fromIntZeroExtend(length * 2);
544
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
545
    }
546
547
    /**
548
     * Sets an int at a given memory address
549
     *
550
     * @param memPtr
551
     * @param value
552
     */
553
    public void setInt(int memPtr, int value) {
554
        testMemPtr(memPtr, 4);
555
        start.store(value, Offset.fromIntSignExtend(memPtr));
556
    }
557
558
    /**
559
     * Sets multiple 32-bit signed ints at the given memory address
560
     *
561
     * @param src
562
     * @param srcOfs
563
     * @param dstPtr
564
     * @param length
565
     */
566
    public void setInts(int[] src, int srcOfs, int dstPtr, int length) {
567
        if (srcOfs < 0) {
568
            throw new IndexOutOfBoundsException("srcOfs < 0");
569
        }
570
        if (length < 0) {
571
            throw new IndexOutOfBoundsException("length < 0");
572
        }
573
        if (srcOfs + length > src.length) {
574
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
575
        }
576
        testMemPtr(dstPtr, length * 4);
577
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs * 4);
578
        final Extent size = Extent.fromIntZeroExtend(length * 4);
579
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
580
    }
581
582
    /**
583
     * Sets a float at a given memory address
584
     *
585
     * @param memPtr
586
     * @param value
587
     */
588
    public void setFloat(int memPtr, float value) {
589
        testMemPtr(memPtr, 4);
590
        start.store(value, Offset.fromIntSignExtend(memPtr));
591
    }
592
593
    /**
594
     * Sets multiple 32-bit floats at the given memory address
595
     *
596
     * @param src
597
     * @param srcOfs
598
     * @param dstPtr
599
     * @param length
600
     */
601
    public void setFloats(float[] src, int srcOfs, int dstPtr, int length) {
602
        if (srcOfs < 0) {
603
            throw new IndexOutOfBoundsException("srcOfs < 0");
604
        }
605
        if (length < 0) {
606
            throw new IndexOutOfBoundsException("length < 0");
607
        }
608
        if (srcOfs + length > src.length) {
609
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
610
        }
611
        testMemPtr(dstPtr, length * 4);
612
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs * 4);
613
        final Extent size = Extent.fromIntZeroExtend(length * 4);
614
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
615
    }
616
617
    /**
618
     * Sets a long at a given memory address
619
     *
620
     * @param memPtr
621
     * @param value
622
     */
623
    public void setLong(int memPtr, long value) {
624
        testMemPtr(memPtr, 8);
625
        start.store(value, Offset.fromIntSignExtend(memPtr));
626
    }
627
628
    /**
629
     * Sets multiple 64-bit signed longs at the given memory address
630
     *
631
     * @param src
632
     * @param srcOfs
633
     * @param dstPtr
634
     * @param length
635
     */
636
    public void setLongs(long[] src, int srcOfs, int dstPtr, int length) {
637
        if (srcOfs < 0) {
638
            throw new IndexOutOfBoundsException("srcOfs < 0");
639
        }
640
        if (length < 0) {
641
            throw new IndexOutOfBoundsException("length < 0");
642
        }
643
        if (srcOfs + length > src.length) {
644
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
645
        }
646
        testMemPtr(dstPtr, length * 8);
647
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs * 8);
648
        final Extent size = Extent.fromIntZeroExtend(length * 8);
649
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
650
    }
651
652
    /**
653
     * Sets a double at a given memory address
654
     *
655
     * @param memPtr
656
     * @param value
657
     */
658
    public void setDouble(int memPtr, double value) {
659
        testMemPtr(memPtr, 8);
660
        start.store(value, Offset.fromIntSignExtend(memPtr));
661
    }
662
663
    /**
664
     * Sets multiple 64-bit doubles at the given memory address
665
     *
666
     * @param src
667
     * @param srcOfs
668
     * @param dstPtr
669
     * @param length
670
     */
671
    public void setDoubles(double[] src, int srcOfs, int dstPtr, int length) {
672
        if (srcOfs < 0) {
673
            throw new IndexOutOfBoundsException("srcOfs < 0");
674
        }
675
        if (length < 0) {
676
            throw new IndexOutOfBoundsException("length < 0");
677
        }
678
        if (srcOfs + length > src.length) {
679
            throw new IndexOutOfBoundsException("srcOfs + length > src.length");
680
        }
681
        testMemPtr(dstPtr, length * 8);
682
        final Address srcPtr = VmMagic.getArrayData(src).add(srcOfs * 8);
683
        final Extent size = Extent.fromIntZeroExtend(length * 8);
684
        Unsafe.copy(srcPtr, start.add(dstPtr), size);
685
    }
686
687
    /**
688
     * Sets a Object at a given memory address
689
     *
690
     * @param memPtr
691
     * @param value
692
     */
693
    public void setObject(int memPtr, Object value) {
694
        if (this.data != null) {
695
            throw new SecurityException("Cannot set an Object in a byte-array");
696
        }
697
        testMemPtr(memPtr, 4);
698
        start.store(ObjectReference.fromObject(value), Offset.fromIntSignExtend(memPtr));
699
    }
700
701
    /**
702
     * Fill the memory at the given memory address with size times 0 bytes.
703
     * <p/>
704
     * memPtr must be VmObject.SLOT_SIZE aligned
705
     * <p/>
706
     * size % VmObject.SLOT_SIZE must be 0
707
     *
708
     * @param memPtr
709
     * @param size
710
     */
711
    public void clear(int memPtr, int size) {
712
        testMemPtr(memPtr, size);
713
        Unsafe.clear(start.add(Offset.fromIntZeroExtend(memPtr)), Extent.fromIntSignExtend(size));
714
    }
715
716
    /**
717
     * (non-Javadoc)
718
     *
719
     * @see org.jnode.system.MemoryResource#copy(int, int, int)
720
     */
721
    public void copy(int srcMemPtr, int destMemPtr, int length) {
722
        testMemPtr(srcMemPtr, length);
723
        testMemPtr(destMemPtr, length);
724
        final Extent size = Extent.fromIntZeroExtend(length);
725
        Unsafe.copy(start.add(srcMemPtr), start.add(destMemPtr), size);
726
    }
727
728
    /**
729
     * Remove a child from my list of children.
730
     *
731
     * @param child
732
     */
733
    private synchronized void removeChild(MemoryResourceImpl child) {
734
        this.children = (MemoryResourceImpl) remove(this.children, child);
735
    }
736
737
    /**
738
     * Give up this resource. After this method has been called, the resource cannot be used
739
     * anymore.
740
     */
741
    public final void release() {
742
        if (!this.released) {
743
            // Mark released as true
744
            this.released = true;
745
746
            // Release all children
747
            synchronized (this) {
748
                while (this.children != null) {
749
                    this.children.release();
750
                }
751
            }
752
753
            if (parent != null) {
754
                // Remove me from parent.
755
                parent.removeChild(this);
756
            } else if (data == null) {
757
                // Remove me from global memory resource list
758
                synchronized (getClass()) {
759
                    resources = remove(resources, this);
760
                }
761
            }
762
        }
763
    }
764
765
    protected final void testMemPtr(int memPtr, int size) {
766
        if (released) {
767
            throw new IndexOutOfBoundsException("MemoryResource is released");
768
        }
769
        final Word end = Word.fromIntZeroExtend(memPtr + size);
770
        if ((memPtr < 0) || end.GT(this.size.toWord())) {
771
            throw new IndexOutOfBoundsException("At " + memPtr + ", this.size=" + this.size.toLong());
772
        }
773
    }
774
775
    /**
776
     * Returns the size of this buffer in bytes.
777
     *
778
     * @return int
779
     */
780
    public Extent getSize() {
781
        return size;
782
    }
783
784
    /**
785
     * Gets the address of the first byte of this buffer
786
     *
787
     * @return Address of first byte in buffer
788
     */
789
    public Address getAddress() {
790
        return start;
791
    }
792
793
    /**
794
     * Compare to regions.
795
     *
796
     * @param otherRegion
797
     * @return a negative integer, zero, or a positive integer as this object is less than, equal
798
     *         to, or greater than the specified region. If the regions overlap, 0 is returned.
799
     */
800
    public int compareTo(Region otherRegion) {
801
        final MemoryResourceImpl other = (MemoryResourceImpl) otherRegion;
802
        if (this.end.LE(other.start)) {
803
            // this < other
804
            return -1;
805
        }
806
        if (this.start.GE(other.end)) {
807
            // this > other
808
            return 1;
809
        }
810
        // this overlaps other
811
        return 0;
812
    }
813
814
    /**
815
     * Compare this region with a given address.
816
     *
817
     * @param address
818
     * @return a negative integer, zero, or a positive integer as this region is less than,
819
     *         overlapping, or greater than the address.
820
     */
821
    public int compareTo(VmAddress address) {
822
        final Address addr = Address.fromAddress(address);
823
        if (this.end.LE(addr)) {
824
            // this < address
825
            return -1;
826
        }
827
        if (this.start.GE(addr)) {
828
            // this > other
829
            return 1;
830
        }
831
        // this overlaps address
832
        return 0;
833
    }
834
835
    /**
836
     * @param memPtr
837
     * @param value
838
     * @param count
839
     * @see org.jnode.system.MemoryResource#setByte(int, byte, int)
840
     */
841
    public void setByte(int memPtr, byte value, int count) {
842
        testMemPtr(memPtr, count);
843
        Unsafe.setBytes(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
844
    }
845
846
    /**
847
     * @param memPtr
848
     * @param value
849
     * @param count
850
     * @see org.jnode.system.MemoryResource#setChar(int, char, int)
851
     */
852
    public void setChar(int memPtr, char value, int count) {
853
        testMemPtr(memPtr, count * 2);
854
        Unsafe.setChars(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
855
    }
856
857
    /**
858
     * @param memPtr
859
     * @param value
860
     * @param count
861
     * @see org.jnode.system.MemoryResource#setDouble(int, double, int)
862
     */
863
    public void setDouble(int memPtr, double value, int count) {
864
        testMemPtr(memPtr, count * 8);
865
        Unsafe.setDoubles(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
866
    }
867
868
    /**
869
     * @param memPtr
870
     * @param value
871
     * @param count
872
     * @see org.jnode.system.MemoryResource#setFloat(int, float, int)
873
     */
874
    public void setFloat(int memPtr, float value, int count) {
875
        testMemPtr(memPtr, count * 4);
876
        Unsafe.setFloats(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
877
    }
878
879
    /**
880
     * @param memPtr
881
     * @param value
882
     * @param count
883
     * @see org.jnode.system.MemoryResource#setInt24(int, int, int)
884
     */
885
    public void setInt24(int memPtr, int value, int count) {
886
        testMemPtr(memPtr, count * 3);
887
        Unsafe.setInts24(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
888
    }
889
890
    /**
891
     * @param memPtr
892
     * @param value
893
     * @param count
894
     * @see org.jnode.system.MemoryResource#setInt(int, int, int)
895
     */
896
    public void setInt(int memPtr, int value, int count) {
897
        testMemPtr(memPtr, count * 4);
898
        Unsafe.setInts(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
899
    }
900
901
    /**
902
     * @param memPtr
903
     * @param value
904
     * @param count
905
     * @see org.jnode.system.MemoryResource#setLong(int, long, int)
906
     */
907
    public void setLong(int memPtr, long value, int count) {
908
        testMemPtr(memPtr, count * 8);
909
        Unsafe.setLongs(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
910
    }
911
912
    /**
913
     * @param memPtr
914
     * @param value
915
     * @param count
916
     * @see org.jnode.system.MemoryResource#setObject(int, java.lang.Object, int)
917
     */
918
    public void setObject(int memPtr, Object value, int count) {
919
        testMemPtr(memPtr, count * slotSize);
920
        Unsafe.setObjects(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
921
    }
922
923
    /**
924
     * @param memPtr
925
     * @param value
926
     * @param count
927
     * @see org.jnode.system.MemoryResource#setShort(int, short, int)
928
     */
929
    public void setShort(int memPtr, short value, int count) {
930
        testMemPtr(memPtr, count * 2);
931
        Unsafe.setShorts(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
932
    }
933
934
    /**
935
     * @param memPtr
936
     * @param value
937
     * @param count
938
     * @see org.jnode.system.MemoryResource#andByte(int, byte, int)
939
     */
940
    public void andByte(int memPtr, byte value, int count) {
941
        testMemPtr(memPtr, count);
942
        Unsafe.andByte(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
943
    }
944
945
    /**
946
     * @param memPtr
947
     * @param value
948
     * @param count
949
     * @see org.jnode.system.MemoryResource#andChar(int, char, int)
950
     */
951
    public void andChar(int memPtr, char value, int count) {
952
        testMemPtr(memPtr, count * 2);
953
        Unsafe.andChar(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
954
    }
955
956
    /**
957
     * @param memPtr
958
     * @param value
959
     * @param count
960
     */
961
    public void andInt24(int memPtr, int value, int count) {
962
        testMemPtr(memPtr, count * 3);
963
        Unsafe.andInt24(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
964
    }
965
966
    /**
967
     * @param memPtr
968
     * @param value
969
     * @param count
970
     * @see org.jnode.system.MemoryResource#andInt(int, int, int)
971
     */
972
    public void andInt(int memPtr, int value, int count) {
973
        testMemPtr(memPtr, count * 4);
974
        Unsafe.andInt(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
975
    }
976
977
    /**
978
     * @param memPtr
979
     * @param value
980
     * @param count
981
     * @see org.jnode.system.MemoryResource#andLong(int, long, int)
982
     */
983
    public void andLong(int memPtr, long value, int count) {
984
        testMemPtr(memPtr, count * 8);
985
        Unsafe.andLong(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
986
    }
987
988
    /**
989
     * @param memPtr
990
     * @param value
991
     * @param count
992
     * @see org.jnode.system.MemoryResource#andShort(int, short, int)
993
     */
994
    public void andShort(int memPtr, short value, int count) {
995
        testMemPtr(memPtr, count * 2);
996
        Unsafe.andShort(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
997
    }
998
999
    /**
1000
     * @param memPtr
1001
     * @param value
1002
     * @param count
1003
     * @see org.jnode.system.MemoryResource#orByte(int, byte, int)
1004
     */
1005
    public void orByte(int memPtr, byte value, int count) {
1006
        testMemPtr(memPtr, count);
1007
        Unsafe.orByte(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1008
    }
1009
1010
    /**
1011
     * @param memPtr
1012
     * @param value
1013
     * @param count
1014
     * @see org.jnode.system.MemoryResource#orChar(int, char, int)
1015
     */
1016
    public void orChar(int memPtr, char value, int count) {
1017
        testMemPtr(memPtr, count * 2);
1018
        Unsafe.orChar(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1019
    }
1020
1021
    /**
1022
     * @param memPtr
1023
     * @param value
1024
     * @param count
1025
     */
1026
    public void orInt24(int memPtr, int value, int count) {
1027
        testMemPtr(memPtr, count * 3);
1028
        Unsafe.orInt24(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1029
    }
1030
1031
    /**
1032
     * @param memPtr
1033
     * @param value
1034
     * @param count
1035
     * @see org.jnode.system.MemoryResource#orInt(int, int, int)
1036
     */
1037
    public void orInt(int memPtr, int value, int count) {
1038
        testMemPtr(memPtr, count * 4);
1039
        Unsafe.orInt(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1040
    }
1041
1042
    /**
1043
     * @param memPtr
1044
     * @param value
1045
     * @param count
1046
     * @see org.jnode.system.MemoryResource#orLong(int, long, int)
1047
     */
1048
    public void orLong(int memPtr, long value, int count) {
1049
        testMemPtr(memPtr, count * 8);
1050
        Unsafe.orLong(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1051
    }
1052
1053
    /**
1054
     * @param memPtr
1055
     * @param value
1056
     * @param count
1057
     * @see org.jnode.system.MemoryResource#orShort(int, short, int)
1058
     */
1059
    public void orShort(int memPtr, short value, int count) {
1060
        testMemPtr(memPtr, count * 2);
1061
        Unsafe.orShort(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1062
    }
1063
1064
    /**
1065
     * @param memPtr
1066
     * @param value
1067
     * @param count
1068
     * @see org.jnode.system.MemoryResource#xorByte(int, byte, int)
1069
     */
1070
    public void xorByte(int memPtr, byte value, int count) {
1071
        testMemPtr(memPtr, count);
1072
        Unsafe.xorByte(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1073
    }
1074
1075
    /**
1076
     * @param memPtr
1077
     * @param value
1078
     * @param count
1079
     * @see org.jnode.system.MemoryResource#xorChar(int, char, int)
1080
     */
1081
    public void xorChar(int memPtr, char value, int count) {
1082
        testMemPtr(memPtr, count * 2);
1083
        Unsafe.xorChar(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1084
    }
1085
1086
    /**
1087
     * @param memPtr
1088
     * @param value
1089
     * @param count
1090
     * @see org.jnode.system.MemoryResource#xorInt(int, int, int)
1091
     */
1092
    public void xorInt24(int memPtr, int value, int count) {
1093
        testMemPtr(memPtr, count * 3);
1094
        Unsafe.xorInt24(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1095
    }
1096
1097
    /**
1098
     * @param memPtr
1099
     * @param value
1100
     * @param count
1101
     * @see org.jnode.system.MemoryResource#xorInt(int, int, int)
1102
     */
1103
    public void xorInt(int memPtr, int value, int count) {
1104
        testMemPtr(memPtr, count * 4);
1105
        Unsafe.xorInt(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1106
    }
1107
1108
    /**
1109
     * @param memPtr
1110
     * @param value
1111
     * @param count
1112
     * @see org.jnode.system.MemoryResource#xorLong(int, long, int)
1113
     */
1114
    public void xorLong(int memPtr, long value, int count) {
1115
        testMemPtr(memPtr, count * 8);
1116
        Unsafe.xorLong(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1117
    }
1118
1119
    /**
1120
     * @param memPtr
1121
     * @param value
1122
     * @param count
1123
     * @see org.jnode.system.MemoryResource#xorShort(int, short, int)
1124
     */
1125
    public void xorShort(int memPtr, short value, int count) {
1126
        testMemPtr(memPtr, count * 2);
1127
        Unsafe.xorShort(start.add(Offset.fromIntZeroExtend(memPtr)), value, count);
1128
    }
1129
1130
    /**
1131
     * Get a memory resource for a portion of this memory resources.
1132
     * The first area of this memory resource that fits the given size
1133
     * and it not claimed by any child resource is returned.
1134
     * If not large enought area if found, a ResourceNotFreeException is thrown.
1135
     * A child resource is always releases when the parent is released.
1136
     * A child resource can be released without releasing the parent.
1137
     *
1138
     * @param size  Length of the returned resource in bytes.
1139
     * @param align
1140
     * @return a memory resource for a portion of this memory resources
1141
     * @throws IndexOutOfBoundsException
1142
     * @throws ResourceNotFreeException
1143
     */
1144
    public MemoryResource claimChildResource(Extent size, int align)
1145
        throws IndexOutOfBoundsException, ResourceNotFreeException {
1146
        if (released) {
1147
            throw new IndexOutOfBoundsException("MemoryResource is released");
1148
        }
1149
        if (align <= 0) {
1150
            throw new IllegalArgumentException("Align must be >= 1");
1151
        }
1152
1153
        Offset offset = Offset.zero();
1154
        final Word alignMask = Word.fromIntZeroExtend(align - 1);
1155
        while (true) {
1156
            final Address addr = this.start.add(offset);
1157
            final MemoryResourceImpl child = new MemoryResourceImpl(this, getOwner(), addr, size);
1158
            final MemoryResourceImpl existingChild = (MemoryResourceImpl) get(this.children, child);
1159
            if (existingChild == null) {
1160
                // We found a free region
1161
                this.children = (MemoryResourceImpl) add(this.children, child);
1162
                return child;
1163
            }
1164
            // We found an existing child, skip over that.
1165
            offset = existingChild.getOffset().add(existingChild.getSize());
1166
1167
            // Align the new offset
1168
            if (!offset.toWord().and(alignMask).isZero()) {
1169
                offset = offset.toWord().add(alignMask).and(alignMask.not()).toOffset();
1170
            }
1171
1172
            // Do we have space left?
1173
            if (offset.toWord().add(size).GT(this.size.toWord())) {
1174
                throw new ResourceNotFreeException();
1175
            }
1176
        }
1177
    }
1178
1179
    /**
1180
     * Get a memory resource for a portion of this memory resources.
1181
     * The first area of this memory resource that fits the given size
1182
     * and it not claimed by any child resource is returned.
1183
     * If not large enought area if found, a ResourceNotFreeException is thrown.
1184
     * A child resource is always releases when the parent is released.
1185
     * A child resource can be released without releasing the parent.
1186
     *
1187
     * @param size  Length of the returned resource in bytes.
1188
     * @param align Align of this boundary. Align must be a multiple of 2.
1189
     * @return a memory resource for a portion of this memory resources
1190
     * @throws IndexOutOfBoundsException
1191
     * @throws ResourceNotFreeException
1192
     */
1193
    public MemoryResource claimChildResource(int size, int align)
1194
        throws IndexOutOfBoundsException, ResourceNotFreeException {
1195
        return claimChildResource(Extent.fromIntZeroExtend(size), align);
1196
    }
1197
1198
    /**
1199
     * Get a memory resource for a portion of this memory resources.
1200
     * A child resource is always releases when the parent is released.
1201
     * A child resource can be released without releasing the parent.
1202
     *
1203
     * @param offset        Offset relative to the start of this resource.
1204
     * @param size          Length of the returned resource in bytes.
1205
     * @param allowOverlaps If true, overlapping child resources will be allowed,
1206
     * otherwise overlapping child resources will resulut in a ResourceNotFreeException.
1207
     * @return a memory resource for a portion of this memory resources
1208
     * @throws IndexOutOfBoundsException
1209
     * @throws ResourceNotFreeException
1210
     */
1211
    public MemoryResource claimChildResource(Offset offset, Extent size, boolean allowOverlaps)
1212
        throws IndexOutOfBoundsException, ResourceNotFreeException {
1213
        if (released) {
1214
            throw new IndexOutOfBoundsException("MemoryResource is released");
1215
        }
1216
        if (offset.toWord().add(size).GT(this.size.toWord())) {
1217
            throw new IndexOutOfBoundsException("Offset + size > this.size");
1218
        }
1219
        final Address addr = this.start.add(offset);
1220
        final MemoryResourceImpl child = new MemoryResourceImpl(this, getOwner(), addr, size);
1221
        synchronized (this) {
1222
            // Re-test released flag
1223
            if (released) {
1224
                throw new IndexOutOfBoundsException("MemoryResource is released");
1225
            }
1226
            if (!allowOverlaps) {
1227
                if (!isFree(this.children, child)) {
1228
                    throw new ResourceNotFreeException();
1229
                }
1230
            }
1231
            this.children = (MemoryResourceImpl) add(this.children, child);
1232
        }
1233
        return child;
1234
    }
1235
1236
    /**
1237
     * Get a memory resource for a portion of this memory resources.
1238
     * A child resource is always releases when the parent is released.
1239
     * A child resource can be released without releasing the parent.
1240
     *
1241
     * @param offset        Offset relative to the start of this resource.
1242
     * @param size          Length of the returned resource in bytes.
1243
     * @param allowOverlaps If true, overlapping child resources will be allowed,
1244
     * otherwise overlapping child resources will resulut in a ResourceNotFreeException.
1245
     * @return a memory resource for a portion of this memory resource
1246
     * @throws IndexOutOfBoundsException
1247
     * @throws ResourceNotFreeException
1248
     */
1249
    public MemoryResource claimChildResource(int offset, int size, boolean allowOverlaps)
1250
        throws IndexOutOfBoundsException, ResourceNotFreeException {
1251
        return claimChildResource(Offset.fromIntZeroExtend(offset), Extent.fromIntZeroExtend(size), allowOverlaps);
1252
    }
1253
1254
    /**
1255
     * Creates a multi media memory resource wrapping this given memory resource.
1256
     *
1257
     * @return The created instance. This will never be null.
1258
     */
1259
    public final MultiMediaMemoryResource asMultiMediaMemoryResource() {
1260
        final MultiMediaMemoryResourceImpl child;
1261
        child = Vm.getArch().createMultiMediaMemoryResource(this);
1262
        this.children = (MemoryResourceImpl) add(this.children, child);
1263
        return child;
1264
    }
1265
1266
    /**
1267
     * Gets the parent resource if any.
1268
     *
1269
     * @return The parent resource, or null if this resource has no parent.
1270
     */
1271
    public final Resource getParent() {
1272
        return parent;
1273
    }
1274
1275
    /**
1276
     * Gets the offset relative to my parent.
1277
     * If this resource has no parent, the address of this buffer is returned.
1278
     *
1279
     * @return the offset relative to my parent or address of this buffer
1280
     */
1281
    public final Offset getOffset() {
1282
        return this.offset;
1283
    }
1284
}