2010-12-05 20:21:09 -07:00
|
|
|
/* Copyright (c) 2008-2010, Avian Contributors
|
2008-11-23 16:58:01 -07:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
#include "bootimage.h"
|
|
|
|
#include "heapwalk.h"
|
|
|
|
#include "common.h"
|
|
|
|
#include "machine.h"
|
|
|
|
#include "util.h"
|
2008-11-23 16:58:01 -07:00
|
|
|
#include "assembler.h"
|
|
|
|
|
|
|
|
// since we aren't linking against libstdc++, we must implement this
|
|
|
|
// ourselves:
|
|
|
|
extern "C" void __cxa_pure_virtual(void) { abort(); }
|
2008-11-21 16:20:35 -07:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
const unsigned HeapCapacity = 768 * 1024 * 1024;
|
|
|
|
|
|
|
|
// Notes on immutable references in the heap image:
|
|
|
|
//
|
|
|
|
// One of the advantages of a bootimage-based build is that reduces
|
|
|
|
// the overhead of major GCs at runtime since we can avoid scanning
|
|
|
|
// the pre-built heap image entirely. However, this only works if we
|
2010-12-19 15:23:19 -07:00
|
|
|
// can ensure that no part of the heap image (with exceptions noted
|
2010-11-26 12:41:31 -07:00
|
|
|
// below) ever points to runtime-allocated objects. Therefore (most)
|
|
|
|
// references in the heap image are considered immutable, and any
|
|
|
|
// attempt to update them at runtime will cause the process to abort.
|
|
|
|
//
|
|
|
|
// However, some references in the heap image really must be updated
|
|
|
|
// at runtime: e.g. the static field table for each class. Therefore,
|
|
|
|
// we allocate these as "fixed" objects, subject to mark-and-sweep
|
|
|
|
// collection, instead of as "copyable" objects subject to copying
|
|
|
|
// collection. This strategy avoids the necessity of maintaining
|
|
|
|
// "dirty reference" bitsets at runtime for the entire heap image;
|
|
|
|
// each fixed object has its own bitset specific to that object.
|
|
|
|
//
|
|
|
|
// In addition to the "fixed" object solution, there are other
|
|
|
|
// strategies available to avoid attempts to update immutable
|
|
|
|
// references at runtime:
|
|
|
|
//
|
|
|
|
// * Table-based: use a lazily-updated array or vector to associate
|
|
|
|
// runtime data with heap image objects (see
|
|
|
|
// e.g. getClassRuntimeData in machine.cpp).
|
|
|
|
//
|
|
|
|
// * Update references at build time: for example, we set the names
|
|
|
|
// of primitive classes before generating the heap image so that we
|
|
|
|
// need not populate them lazily at runtime.
|
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
bool
|
|
|
|
endsWith(const char* suffix, const char* s, unsigned length)
|
|
|
|
{
|
|
|
|
unsigned suffixLength = strlen(suffix);
|
|
|
|
return length >= suffixLength
|
|
|
|
and memcmp(suffix, s + (length - suffixLength), suffixLength) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2008-11-27 21:58:04 -07:00
|
|
|
makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
|
2009-05-31 21:16:58 -06:00
|
|
|
uintptr_t* codeMap, const char* className,
|
2009-02-14 13:23:31 -07:00
|
|
|
const char* methodName, const char* methodSpec)
|
2008-11-21 16:20:35 -07:00
|
|
|
{
|
2008-11-27 13:59:40 -07:00
|
|
|
object constants = 0;
|
|
|
|
PROTECT(t, constants);
|
|
|
|
|
|
|
|
object calls = 0;
|
|
|
|
PROTECT(t, calls);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-12-02 09:45:20 -07:00
|
|
|
DelayedPromise* addresses = 0;
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
for (Finder::Iterator it
|
|
|
|
(static_cast<Finder*>
|
|
|
|
(systemClassLoaderFinder(t, root(t, Machine::BootLoader))));
|
|
|
|
it.hasMore();)
|
|
|
|
{
|
2008-12-18 10:10:19 -07:00
|
|
|
unsigned nameSize = 0;
|
2008-11-21 16:20:35 -07:00
|
|
|
const char* name = it.next(&nameSize);
|
|
|
|
|
2009-02-14 13:23:31 -07:00
|
|
|
if (endsWith(".class", name, nameSize)
|
|
|
|
and (className == 0 or strncmp(name, className, nameSize - 6) == 0))
|
|
|
|
{
|
2009-03-06 17:10:31 -07:00
|
|
|
// fprintf(stderr, "%.*s\n", nameSize - 6, name);
|
2009-09-03 09:06:04 -06:00
|
|
|
object c = resolveSystemClass
|
2010-11-26 12:41:31 -07:00
|
|
|
(t, root(t, Machine::BootLoader),
|
|
|
|
makeByteArray(t, "%.*s", nameSize - 6, name), true);
|
2009-03-06 17:10:31 -07:00
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
PROTECT(t, c);
|
2008-11-27 21:44:04 -07:00
|
|
|
|
|
|
|
if (classMethodTable(t, c)) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
|
|
|
|
object method = arrayBody(t, classMethodTable(t, c), i);
|
2010-11-26 12:41:31 -07:00
|
|
|
if (((methodName == 0
|
|
|
|
or ::strcmp
|
|
|
|
(reinterpret_cast<char*>
|
|
|
|
(&byteArrayBody
|
|
|
|
(t, vm::methodName(t, method), 0)), methodName) == 0)
|
|
|
|
and (methodSpec == 0
|
2009-12-02 20:08:07 -07:00
|
|
|
or ::strcmp
|
2009-02-14 13:23:31 -07:00
|
|
|
(reinterpret_cast<char*>
|
|
|
|
(&byteArrayBody
|
2010-11-26 12:41:31 -07:00
|
|
|
(t, vm::methodSpec(t, method), 0)), methodSpec)
|
|
|
|
== 0)))
|
2009-02-14 13:23:31 -07:00
|
|
|
{
|
2010-11-26 12:41:31 -07:00
|
|
|
if (methodCode(t, method)
|
|
|
|
or (methodFlags(t, method) & ACC_NATIVE))
|
|
|
|
{
|
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
t->m->processor->compileMethod
|
|
|
|
(t, zone, &constants, &calls, &addresses, method);
|
|
|
|
}
|
|
|
|
|
|
|
|
object addendum = methodAddendum(t, method);
|
|
|
|
if (addendum and methodAddendumExceptionTable(t, addendum)) {
|
|
|
|
PROTECT(t, addendum);
|
|
|
|
|
|
|
|
// resolve exception types now to avoid trying to update
|
|
|
|
// immutable references at runtime
|
|
|
|
for (unsigned i = 0; i < shortArrayLength
|
|
|
|
(t, methodAddendumExceptionTable(t, addendum)); ++i)
|
|
|
|
{
|
|
|
|
uint16_t index = shortArrayBody
|
|
|
|
(t, methodAddendumExceptionTable(t, addendum), i) - 1;
|
|
|
|
|
|
|
|
object o = singletonObject
|
|
|
|
(t, addendumPool(t, addendum), index);
|
|
|
|
|
|
|
|
if (objectClass(t, o) == type(t, Machine::ReferenceType)) {
|
|
|
|
o = resolveClass
|
|
|
|
(t, root(t, Machine::BootLoader), referenceName(t, o));
|
|
|
|
|
|
|
|
set(t, addendumPool(t, addendum),
|
|
|
|
SingletonBody + (index * BytesPerWord), o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-27 21:44:04 -07:00
|
|
|
}
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-27 13:59:40 -07:00
|
|
|
for (; calls; calls = tripleThird(t, calls)) {
|
2008-12-01 19:38:00 -07:00
|
|
|
object method = tripleFirst(t, calls);
|
|
|
|
uintptr_t address;
|
|
|
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
2010-06-15 19:49:48 -06:00
|
|
|
address = reinterpret_cast<uintptr_t>(code + image->thunks.native.start);
|
2008-12-01 19:38:00 -07:00
|
|
|
} else {
|
2010-11-26 12:41:31 -07:00
|
|
|
address = codeCompiled(t, methodCode(t, method));
|
2008-12-01 19:38:00 -07:00
|
|
|
}
|
|
|
|
|
2008-11-27 13:59:40 -07:00
|
|
|
static_cast<ListenPromise*>(pointerValue(t, tripleSecond(t, calls)))
|
2009-03-10 19:08:16 -06:00
|
|
|
->listener->resolve(address, 0);
|
2008-11-27 13:59:40 -07:00
|
|
|
}
|
|
|
|
|
2008-12-02 09:45:20 -07:00
|
|
|
for (; addresses; addresses = addresses->next) {
|
|
|
|
uint8_t* value = reinterpret_cast<uint8_t*>(addresses->basis->value());
|
|
|
|
assert(t, value >= code);
|
|
|
|
|
2009-03-10 19:08:16 -06:00
|
|
|
void* location;
|
2010-12-09 21:09:48 -07:00
|
|
|
bool flat = addresses->listener->resolve
|
|
|
|
(reinterpret_cast<int64_t>(code), &location);
|
2009-03-10 19:08:16 -06:00
|
|
|
uintptr_t offset = value - code;
|
|
|
|
if (flat) {
|
|
|
|
offset |= BootFlatConstant;
|
|
|
|
}
|
|
|
|
memcpy(location, &offset, BytesPerWord);
|
|
|
|
|
|
|
|
assert(t, reinterpret_cast<intptr_t>(location)
|
2008-12-02 09:45:20 -07:00
|
|
|
>= reinterpret_cast<intptr_t>(code));
|
|
|
|
|
2009-03-10 19:08:16 -06:00
|
|
|
markBit(codeMap, reinterpret_cast<intptr_t>(location)
|
2008-12-02 09:45:20 -07:00
|
|
|
- reinterpret_cast<intptr_t>(code));
|
|
|
|
}
|
|
|
|
|
2008-11-27 13:59:40 -07:00
|
|
|
return constants;
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
objectSize(Thread* t, object o)
|
|
|
|
{
|
|
|
|
assert(t, not objectExtended(t, o));
|
2008-12-01 19:38:00 -07:00
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
return baseSize(t, o, objectClass(t, o));
|
|
|
|
}
|
|
|
|
|
2008-11-23 16:58:01 -07:00
|
|
|
void
|
2008-11-28 11:33:11 -07:00
|
|
|
visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants)
|
2008-11-23 16:58:01 -07:00
|
|
|
{
|
2008-11-28 11:33:11 -07:00
|
|
|
Machine* m = t->m;
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
for (HashMapIterator it(t, classLoaderMap(t, root(t, Machine::BootLoader)));
|
|
|
|
it.hasMore();)
|
|
|
|
{
|
2008-12-01 19:38:00 -07:00
|
|
|
w->visitRoot(tripleSecond(t, it.next()));
|
|
|
|
}
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
image->bootLoader = w->visitRoot(root(t, Machine::BootLoader));
|
|
|
|
image->appLoader = w->visitRoot(root(t, Machine::AppLoader));
|
2008-11-23 16:58:01 -07:00
|
|
|
image->types = w->visitRoot(m->types);
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
m->processor->visitRoots(t, w);
|
2008-11-28 11:33:11 -07:00
|
|
|
|
|
|
|
for (; constants; constants = tripleThird(t, constants)) {
|
|
|
|
w->visitRoot(tripleFirst(t, constants));
|
|
|
|
}
|
2008-11-23 16:58:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
HeapWalker*
|
2008-11-21 16:20:35 -07:00
|
|
|
makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map,
|
2008-11-28 11:33:11 -07:00
|
|
|
unsigned capacity, object constants)
|
2008-11-21 16:20:35 -07:00
|
|
|
{
|
2008-11-23 16:58:01 -07:00
|
|
|
class Visitor: public HeapVisitor {
|
2008-11-21 16:20:35 -07:00
|
|
|
public:
|
2008-11-23 16:58:01 -07:00
|
|
|
Visitor(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity):
|
2008-12-01 19:38:00 -07:00
|
|
|
t(t), currentObject(0), currentNumber(0), currentOffset(0), heap(heap),
|
|
|
|
map(map), position(0), capacity(capacity)
|
2008-11-21 16:20:35 -07:00
|
|
|
{ }
|
|
|
|
|
2008-11-27 21:44:04 -07:00
|
|
|
void visit(unsigned number) {
|
2008-12-01 19:38:00 -07:00
|
|
|
if (currentObject) {
|
|
|
|
unsigned offset = currentNumber - 1 + currentOffset;
|
|
|
|
unsigned mark = heap[offset] & (~PointerMask);
|
|
|
|
unsigned value = number | (mark << BootShift);
|
|
|
|
|
|
|
|
if (value) markBit(map, offset);
|
|
|
|
|
|
|
|
heap[offset] = value;
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void root() {
|
2008-12-01 19:38:00 -07:00
|
|
|
currentObject = 0;
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned visitNew(object p) {
|
|
|
|
if (p) {
|
|
|
|
unsigned size = objectSize(t, p);
|
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
unsigned number;
|
2010-11-26 12:41:31 -07:00
|
|
|
if ((currentObject
|
|
|
|
and (currentOffset * BytesPerWord) == ClassStaticTable)
|
|
|
|
or instanceOf(t, type(t, Machine::SystemClassLoaderType), p))
|
2008-12-01 19:38:00 -07:00
|
|
|
{
|
2010-11-26 12:41:31 -07:00
|
|
|
// Static tables and system classloaders must be allocated
|
|
|
|
// as fixed objects in the heap image so that they can be
|
|
|
|
// marked as dirty and visited during GC. Otherwise,
|
|
|
|
// attempts to update references in these objects to point
|
|
|
|
// to runtime-allocated memory would fail because we don't
|
|
|
|
// scan non-fixed objects in the heap image during GC.
|
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
FixedAllocator allocator
|
2009-05-31 21:16:58 -06:00
|
|
|
(t->m->system, reinterpret_cast<uint8_t*>(heap + position),
|
2008-12-01 19:38:00 -07:00
|
|
|
(capacity - position) * BytesPerWord);
|
|
|
|
|
|
|
|
unsigned totalInBytes;
|
|
|
|
uintptr_t* dst = static_cast<uintptr_t*>
|
|
|
|
(t->m->heap->allocateImmortalFixed
|
|
|
|
(&allocator, size, true, &totalInBytes));
|
|
|
|
|
|
|
|
memcpy(dst, p, size * BytesPerWord);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
dst[0] |= FixedMark;
|
|
|
|
|
|
|
|
number = (dst - heap) + 1;
|
|
|
|
position += ceiling(totalInBytes, BytesPerWord);
|
|
|
|
} else {
|
|
|
|
assert(t, position + size < capacity);
|
|
|
|
memcpy(heap + position, p, size * BytesPerWord);
|
|
|
|
|
|
|
|
number = position + 1;
|
|
|
|
position += size;
|
|
|
|
}
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-11-27 21:44:04 -07:00
|
|
|
visit(number);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
|
|
|
return number;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void visitOld(object, unsigned number) {
|
2008-11-27 21:44:04 -07:00
|
|
|
visit(number);
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
virtual void push(object object, unsigned number, unsigned offset) {
|
|
|
|
currentObject = object;
|
|
|
|
currentNumber = number;
|
|
|
|
currentOffset = offset;
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void pop() {
|
2008-12-01 19:38:00 -07:00
|
|
|
currentObject = 0;
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
2008-12-01 19:38:00 -07:00
|
|
|
object currentObject;
|
|
|
|
unsigned currentNumber;
|
|
|
|
unsigned currentOffset;
|
2008-11-21 16:20:35 -07:00
|
|
|
uintptr_t* heap;
|
|
|
|
uintptr_t* map;
|
|
|
|
unsigned position;
|
|
|
|
unsigned capacity;
|
2008-11-23 16:58:01 -07:00
|
|
|
} visitor(t, heap, map, capacity / BytesPerWord);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-11-23 16:58:01 -07:00
|
|
|
HeapWalker* w = makeHeapWalker(t, &visitor);
|
2008-11-28 11:33:11 -07:00
|
|
|
visitRoots(t, image, w, constants);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-11-23 16:58:01 -07:00
|
|
|
image->heapSize = visitor.position * BytesPerWord;
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-11-23 16:58:01 -07:00
|
|
|
return w;
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-11-27 13:59:40 -07:00
|
|
|
updateConstants(Thread* t, object constants, uint8_t* code, uintptr_t* codeMap,
|
2008-11-21 16:20:35 -07:00
|
|
|
HeapMap* heapTable)
|
|
|
|
{
|
2008-11-27 13:59:40 -07:00
|
|
|
for (; constants; constants = tripleThird(t, constants)) {
|
2008-11-29 16:08:14 -07:00
|
|
|
unsigned target = heapTable->find(tripleFirst(t, constants));
|
|
|
|
assert(t, target > 0);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
for (Promise::Listener* pl = static_cast<ListenPromise*>
|
|
|
|
(pointerValue(t, tripleSecond(t, constants)))->listener;
|
|
|
|
pl; pl = pl->next)
|
|
|
|
{
|
2009-03-10 19:08:16 -06:00
|
|
|
void* location;
|
|
|
|
bool flat = pl->resolve(0, &location);
|
|
|
|
uintptr_t offset = target | BootHeapOffset;
|
|
|
|
if (flat) {
|
|
|
|
offset |= BootFlatConstant;
|
|
|
|
}
|
|
|
|
memcpy(location, &offset, BytesPerWord);
|
2008-11-27 13:59:40 -07:00
|
|
|
|
2009-03-10 19:08:16 -06:00
|
|
|
assert(t, reinterpret_cast<intptr_t>(location)
|
2008-12-01 19:38:00 -07:00
|
|
|
>= reinterpret_cast<intptr_t>(code));
|
2008-11-27 13:59:40 -07:00
|
|
|
|
2009-03-10 19:08:16 -06:00
|
|
|
markBit(codeMap, reinterpret_cast<intptr_t>(location)
|
2008-12-01 19:38:00 -07:00
|
|
|
- reinterpret_cast<intptr_t>(code));
|
|
|
|
}
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
offset(object a, uintptr_t* b)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<uintptr_t>(b) - reinterpret_cast<uintptr_t>(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-12-27 15:55:23 -07:00
|
|
|
writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code,
|
|
|
|
unsigned codeCapacity, const char* className,
|
|
|
|
const char* methodName, const char* methodSpec)
|
2008-11-21 16:20:35 -07:00
|
|
|
{
|
2008-11-27 21:58:04 -07:00
|
|
|
Zone zone(t->m->system, t->m->heap, 64 * 1024);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
|
|
|
uintptr_t* codeMap = static_cast<uintptr_t*>
|
2009-05-31 21:16:58 -06:00
|
|
|
(t->m->heap->allocate(codeMapSize(codeCapacity)));
|
|
|
|
memset(codeMap, 0, codeMapSize(codeCapacity));
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-12-02 09:45:20 -07:00
|
|
|
object constants = makeCodeImage
|
2009-05-31 21:16:58 -06:00
|
|
|
(t, &zone, image, code, codeMap, className, methodName, methodSpec);
|
2009-03-06 17:10:31 -07:00
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
PROTECT(t, constants);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
// this map will not be used when the bootimage is loaded, so
|
|
|
|
// there's no need to preserve it:
|
|
|
|
setRoot(t, Machine::ByteArrayMap, makeWeakHashMap(t, 0, 0));
|
|
|
|
|
|
|
|
// name all primitive classes so we don't try to update immutable
|
|
|
|
// references at runtime:
|
|
|
|
{ object name = makeByteArray(t, "void");
|
|
|
|
set(t, type(t, Machine::JvoidType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "boolean");
|
|
|
|
set(t, type(t, Machine::JbooleanType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "byte");
|
|
|
|
set(t, type(t, Machine::JbyteType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "short");
|
|
|
|
set(t, type(t, Machine::JshortType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "char");
|
|
|
|
set(t, type(t, Machine::JcharType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "int");
|
|
|
|
set(t, type(t, Machine::JintType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "float");
|
|
|
|
set(t, type(t, Machine::JfloatType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "long");
|
|
|
|
set(t, type(t, Machine::JlongType), ClassName, name);
|
|
|
|
|
|
|
|
name = makeByteArray(t, "double");
|
|
|
|
set(t, type(t, Machine::JdoubleType), ClassName, name);
|
|
|
|
}
|
|
|
|
|
2011-01-18 08:35:52 -07:00
|
|
|
// resolve primitive array classes in case they are needed at
|
|
|
|
// runtime:
|
2011-01-27 21:03:39 -07:00
|
|
|
{ object name = makeByteArray(t, "[B");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[Z");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[S");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[C");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[I");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[J");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[F");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
|
2011-01-27 21:03:39 -07:00
|
|
|
name = makeByteArray(t, "[D");
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name, true);
|
2011-01-18 08:35:52 -07:00
|
|
|
}
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
collect(t, Heap::MajorCollection);
|
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
uintptr_t* heap = static_cast<uintptr_t*>
|
|
|
|
(t->m->heap->allocate(HeapCapacity));
|
|
|
|
uintptr_t* heapMap = static_cast<uintptr_t*>
|
|
|
|
(t->m->heap->allocate(heapMapSize(HeapCapacity)));
|
|
|
|
memset(heapMap, 0, heapMapSize(HeapCapacity));
|
|
|
|
|
2008-11-23 16:58:01 -07:00
|
|
|
HeapWalker* heapWalker = makeHeapImage
|
2009-05-31 21:16:58 -06:00
|
|
|
(t, image, heap, heapMap, HeapCapacity, constants);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-11-27 13:59:40 -07:00
|
|
|
updateConstants(t, constants, code, codeMap, heapWalker->map());
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
image->bootClassCount = hashMapSize
|
|
|
|
(t, classLoaderMap(t, root(t, Machine::BootLoader)));
|
|
|
|
|
|
|
|
unsigned* bootClassTable = static_cast<unsigned*>
|
|
|
|
(t->m->heap->allocate(image->bootClassCount * sizeof(unsigned)));
|
2008-12-01 19:38:00 -07:00
|
|
|
|
|
|
|
{ unsigned i = 0;
|
2010-11-26 12:41:31 -07:00
|
|
|
for (HashMapIterator it
|
|
|
|
(t, classLoaderMap(t, root(t, Machine::BootLoader)));
|
|
|
|
it.hasMore();)
|
|
|
|
{
|
|
|
|
bootClassTable[i++] = heapWalker->map()->find
|
|
|
|
(tripleSecond(t, it.next()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
image->appClassCount = hashMapSize
|
|
|
|
(t, classLoaderMap(t, root(t, Machine::AppLoader)));
|
|
|
|
|
|
|
|
unsigned* appClassTable = static_cast<unsigned*>
|
|
|
|
(t->m->heap->allocate(image->appClassCount * sizeof(unsigned)));
|
|
|
|
|
|
|
|
{ unsigned i = 0;
|
|
|
|
for (HashMapIterator it
|
|
|
|
(t, classLoaderMap(t, root(t, Machine::AppLoader)));
|
|
|
|
it.hasMore();)
|
|
|
|
{
|
|
|
|
appClassTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next()));
|
2008-12-01 19:38:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
image->stringCount = hashMapSize(t, root(t, Machine::StringMap));
|
2008-12-01 19:38:00 -07:00
|
|
|
unsigned* stringTable = static_cast<unsigned*>
|
2009-05-31 21:16:58 -06:00
|
|
|
(t->m->heap->allocate(image->stringCount * sizeof(unsigned)));
|
2008-12-01 19:38:00 -07:00
|
|
|
|
|
|
|
{ unsigned i = 0;
|
2010-11-26 12:41:31 -07:00
|
|
|
for (HashMapIterator it(t, root(t, Machine::StringMap)); it.hasMore();) {
|
2008-12-01 19:38:00 -07:00
|
|
|
stringTable[i++] = heapWalker->map()->find
|
|
|
|
(jreferenceTarget(t, tripleFirst(t, it.next())));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-31 21:16:58 -06:00
|
|
|
unsigned* callTable = t->m->processor->makeCallTable(t, heapWalker);
|
2008-12-01 19:38:00 -07:00
|
|
|
|
2008-11-23 16:58:01 -07:00
|
|
|
heapWalker->dispose();
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2009-05-31 21:16:58 -06:00
|
|
|
image->magic = BootImage::Magic;
|
|
|
|
image->codeBase = reinterpret_cast<uintptr_t>(code);
|
2008-11-29 18:39:42 -07:00
|
|
|
|
2008-12-01 19:38:00 -07:00
|
|
|
fprintf(stderr, "class count %d string count %d call count %d\n"
|
|
|
|
"heap size %d code size %d\n",
|
2010-11-26 12:41:31 -07:00
|
|
|
image->bootClassCount, image->stringCount, image->callCount,
|
2009-05-31 21:16:58 -06:00
|
|
|
image->heapSize, image->codeSize);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2008-11-29 18:39:42 -07:00
|
|
|
if (true) {
|
2009-05-31 21:16:58 -06:00
|
|
|
fwrite(image, sizeof(BootImage), 1, out);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1, out);
|
|
|
|
fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1, out);
|
2009-05-31 21:16:58 -06:00
|
|
|
fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, out);
|
|
|
|
fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, out);
|
2008-12-01 19:38:00 -07:00
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
unsigned offset = (image->bootClassCount * sizeof(unsigned))
|
|
|
|
+ (image->appClassCount * sizeof(unsigned))
|
2009-05-31 21:16:58 -06:00
|
|
|
+ (image->stringCount * sizeof(unsigned))
|
|
|
|
+ (image->callCount * sizeof(unsigned) * 2);
|
2008-12-01 19:38:00 -07:00
|
|
|
|
|
|
|
while (offset % BytesPerWord) {
|
|
|
|
uint8_t c = 0;
|
|
|
|
fwrite(&c, 1, 1, out);
|
|
|
|
++ offset;
|
|
|
|
}
|
|
|
|
|
2009-05-31 21:16:58 -06:00
|
|
|
fwrite(heapMap, pad(heapMapSize(image->heapSize)), 1, out);
|
|
|
|
fwrite(heap, pad(image->heapSize), 1, out);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2009-05-31 21:16:58 -06:00
|
|
|
fwrite(codeMap, pad(codeMapSize(image->codeSize)), 1, out);
|
|
|
|
fwrite(code, pad(image->codeSize), 1, out);
|
2008-11-28 15:02:45 -07:00
|
|
|
}
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
uint64_t
|
|
|
|
writeBootImage(Thread* t, uintptr_t* arguments)
|
|
|
|
{
|
|
|
|
FILE* out = reinterpret_cast<FILE*>(arguments[0]);
|
|
|
|
BootImage* image = reinterpret_cast<BootImage*>(arguments[1]);
|
|
|
|
uint8_t* code = reinterpret_cast<uint8_t*>(arguments[2]);
|
|
|
|
unsigned codeCapacity = arguments[3];
|
|
|
|
const char* className = reinterpret_cast<const char*>(arguments[4]);
|
|
|
|
const char* methodName = reinterpret_cast<const char*>(arguments[5]);
|
|
|
|
const char* methodSpec = reinterpret_cast<const char*>(arguments[6]);
|
|
|
|
|
|
|
|
writeBootImage2
|
|
|
|
(t, out, image, code, codeCapacity, className, methodName, methodSpec);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-11-21 16:20:35 -07:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int ac, const char** av)
|
|
|
|
{
|
2009-06-01 12:12:29 -06:00
|
|
|
if (ac < 3 or ac > 6) {
|
|
|
|
fprintf(stderr, "usage: %s <classpath> <output file> "
|
2009-02-14 13:23:31 -07:00
|
|
|
"[<class name> [<method name> [<method spec>]]]\n", av[0]);
|
2008-11-21 16:20:35 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s = makeSystem(0);
|
2010-11-26 12:41:31 -07:00
|
|
|
Heap* h = makeHeap(s, HeapCapacity * 2);
|
|
|
|
Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX);
|
|
|
|
Finder* f = makeFinder(s, h, av[1], 0);
|
2009-10-10 17:46:43 -06:00
|
|
|
Processor* p = makeProcessor(s, h, false);
|
2009-05-31 21:16:58 -06:00
|
|
|
|
|
|
|
BootImage image;
|
2010-11-26 12:41:31 -07:00
|
|
|
const unsigned CodeCapacity = 128 * 1024 * 1024;
|
2009-05-31 21:16:58 -06:00
|
|
|
uint8_t* code = static_cast<uint8_t*>(h->allocate(CodeCapacity));
|
|
|
|
p->initialize(&image, code, CodeCapacity);
|
|
|
|
|
2010-11-26 12:41:31 -07:00
|
|
|
Machine* m = new (h->allocate(sizeof(Machine))) Machine
|
|
|
|
(s, h, f, 0, p, c, 0, 0);
|
2008-11-21 16:20:35 -07:00
|
|
|
Thread* t = p->makeThread(m, 0, 0);
|
|
|
|
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
enter(t, Thread::IdleState);
|
|
|
|
|
2009-09-03 09:06:04 -06:00
|
|
|
FILE* output = vm::fopen(av[2], "wb");
|
2009-06-01 12:12:29 -06:00
|
|
|
if (output == 0) {
|
|
|
|
fprintf(stderr, "unable to open %s\n", av[2]);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-12-27 15:55:23 -07:00
|
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(output),
|
|
|
|
reinterpret_cast<uintptr_t>(&image),
|
|
|
|
reinterpret_cast<uintptr_t>(code),
|
|
|
|
CodeCapacity,
|
|
|
|
reinterpret_cast<uintptr_t>(ac > 3 ? av[3] : 0),
|
|
|
|
reinterpret_cast<uintptr_t>(ac > 4 ? av[4] : 0),
|
|
|
|
reinterpret_cast<uintptr_t>(ac > 5 ? av[5] : 0) };
|
|
|
|
|
|
|
|
run(t, writeBootImage, arguments);
|
2009-06-01 12:12:29 -06:00
|
|
|
|
|
|
|
fclose(output);
|
2008-11-21 16:20:35 -07:00
|
|
|
|
2009-03-06 17:10:31 -07:00
|
|
|
if (t->exception) {
|
|
|
|
printTrace(t, t->exception);
|
2010-12-27 15:55:23 -07:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
2009-03-06 17:10:31 -07:00
|
|
|
}
|
2008-11-21 16:20:35 -07:00
|
|
|
}
|