Merge branch 'master' into powerpc

Conflicts:

	makefile
	src/assembler.h
	src/binaryToMacho.cpp
	src/compile.cpp
	src/compiler.cpp
	src/x86.cpp
This commit is contained in:
Joel Dice 2009-02-09 16:22:01 -07:00
commit a1ec71423e
35 changed files with 3103 additions and 1105 deletions

View File

@ -14,6 +14,8 @@ public class File {
private static final String FileSeparator
= System.getProperty("file.separator");
public static final String separator = FileSeparator;
// static {
// System.loadLibrary("natives");
// }
@ -157,7 +159,7 @@ public class File {
}
String[] result = new String[count];
for (int i = count; i >= 0; --i) {
for (int i = count - 1; i >= 0; --i) {
result[i] = list.value;
list = list.next;
}

View File

@ -14,8 +14,6 @@ import java.net.URL;
import java.net.MalformedURLException;
public class SystemClassLoader extends ClassLoader {
private Object map;
protected native Class findClass(String name) throws ClassNotFoundException;
protected native Class findLoadedClass(String name);

View File

@ -22,7 +22,7 @@ public class Method<T> extends AccessibleObject implements Member {
private byte[] spec;
private Class<T> class_;
private Object code;
private Object compiled;
private long compiled;
private Method() { }

View File

@ -126,7 +126,7 @@ public abstract class Calendar {
int hour = remainder / MILLIS_PER_HOUR;
remainder = remainder % MILLIS_PER_HOUR;
int minute = remainder / MILLIS_PER_MINUTE;
remainder = remainder / MILLIS_PER_MINUTE;
remainder = remainder % MILLIS_PER_MINUTE;
int second = remainder / MILLIS_PER_SECOND;
fields[YEAR] = year;
fields[MONTH] = month;

105
makefile
View File

@ -62,7 +62,6 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
-DBOOT_CLASSPATH=\"[classpathJar]\"
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
@ -104,6 +103,9 @@ endif
ifeq ($(platform),darwin)
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
lflags = $(common-lflags) -ldl -framework CoreFoundation
ifeq ($(bootimage),true)
bootimage-lflags = -Wl,-segprot,__BOOT,rwx,rwx
endif
rdynamic =
strip-all = -S -x
binaryToMacho = $(native-build)/binaryToMacho
@ -132,6 +134,7 @@ ifeq ($(platform),windows)
ar = i586-mingw32msvc-ar
ranlib = i586-mingw32msvc-ranlib
objcopy = i586-mingw32msvc-objcopy
strip = i586-mingw32msvc-strip
else
build-cflags = $(common-cflags) \
"-I$(JAVA_HOME)/include/win32" -I$(src) -mthreads
@ -159,11 +162,9 @@ ifeq ($(mode),stress-major)
endif
ifeq ($(mode),fast)
cflags += -O3 -g3 -DNDEBUG
strip = strip
endif
ifeq ($(mode),small)
cflags += -Os -g3 -DNDEBUG
strip = strip
endif
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x)))
@ -198,6 +199,8 @@ vm-depends = \
$(src)/assembler.h \
$(src)/compiler.h \
$(src)/$(asm).h
$(src)/heapwalk.h \
$(src)/bootimage.h
vm-sources = \
$(src)/$(system).cpp \
@ -211,11 +214,6 @@ vm-sources = \
$(src)/process.cpp \
$(src)/$(asm).cpp
ifeq ($(heapdump),true)
vm-sources += $(src)/heapdump.cpp
cflags += -DAVIAN_HEAPDUMP
endif
vm-asm-sources = $(src)/$(asm).S
ifeq ($(process),compile)
@ -232,6 +230,37 @@ vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(native-build))
vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build))
vm-objects = $(vm-cpp-objects) $(vm-asm-objects)
heapwalk-sources = $(src)/heapwalk.cpp
heapwalk-objects = \
$(call cpp-objects,$(heapwalk-sources),$(src),$(native-build))
ifeq ($(heapdump),true)
vm-sources += $(src)/heapdump.cpp
vm-heapwalk-objects = $(heapwalk-objects)
cflags += -DAVIAN_HEAPDUMP
endif
bootimage-generator-sources = $(src)/bootimage.cpp
bootimage-generator-objects = \
$(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build))
bootimage-generator = \
$(build)/$(build-platform)-$(build-arch)-compile-fast/bootimage-generator
bootimage-bin = $(native-build)/bootimage.bin
bootimage-object = $(native-build)/bootimage-bin.o
ifeq ($(bootimage),true)
ifneq ($(build-arch),$(arch))
error "can't cross-build a bootimage"
endif
vm-classpath-object = $(bootimage-object)
cflags += -DBOOT_IMAGE=\"bootimageBin\"
else
vm-classpath-object = $(classpath-object)
cflags += -DBOOT_CLASSPATH=\"[classpathJar]\"
endif
driver-source = $(src)/main.cpp
driver-object = $(native-build)/main.o
driver-dynamic-object = $(native-build)/main-dynamic.o
@ -358,6 +387,12 @@ $(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
$(compile-asm-object)
$(bootimage-generator-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(compile-object)
$(heapwalk-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends)
$(compile-object)
$(driver-object): $(driver-source)
$(compile-object)
@ -381,7 +416,7 @@ $(binaryToMacho): $(src)/binaryToMacho.cpp
$(classpath-object): $(build)/classpath.jar $(binaryToMacho)
@echo "creating $(@)"
ifeq ($(platform),darwin)
$(binaryToMacho) $(asm) $(build)/classpath.jar \
$(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \
__binary_classpath_jar_start __binary_classpath_jar_end > $(@)
else
(wd=$$(pwd); \
@ -399,15 +434,54 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
$(compile-object)
$(static-library): $(vm-objects) $(jni-objects)
$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects)
@echo "creating $(@)"
rm -rf $(@)
$(ar) cru $(@) $(^)
$(ranlib) $(@)
$(bootimage-bin): $(bootimage-generator)
$(<) $(classpath-build) > $(@)
$(bootimage-object): $(bootimage-bin) $(binaryToMacho)
@echo "creating $(@)"
ifeq ($(platform),darwin)
$(binaryToMacho) $(<) __BOOT __boot \
__binary_bootimage_bin_start __binary_bootimage_bin_end > $(@)
else
(wd=$$(pwd); \
cd $(native-build); \
$(objcopy) --rename-section=.data=.boot -I binary bootimage.bin \
-O $(object-format) -B $(object-arch) "$${wd}/$(@).tmp"; \
$(objcopy) --set-section-flags .boot=alloc,load,code "$${wd}/$(@).tmp" \
"$${wd}/$(@)")
endif
$(executable): \
$(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \
$(boot-object)
$(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
$(dlltool) -d $(@).def -e $(@).exp
$(cc) $(@).exp $(^) $(lflags) -o $(@)
else
$(cc) $(^) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@)
endif
$(strip) $(strip-all) $(@)
$(bootimage-generator):
(unset MAKEFLAGS && \
make mode=fast process=compile \
arch=$(build-arch) \
platform=$(build-platform) \
bootimage-generator= \
build-bootimage-generator=$(bootimage-generator) \
$(bootimage-generator))
$(build-bootimage-generator): \
$(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \
$(bootimage-generator-objects)
@echo "linking $(@)"
ifeq ($(platform),windows)
$(dlltool) -z $(@).def $(^)
@ -416,13 +490,12 @@ ifeq ($(platform),windows)
else
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
endif
$(strip) $(strip-all) $(@)
$(dynamic-library): \
$(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \
$(boot-object)
$(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \
$(boot-object) $(vm-classpath-object)
@echo "linking $(@)"
$(cc) $(^) $(shared) $(lflags) -o $(@)
$(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@)
$(strip) $(strip-all) $(@)
$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)

View File

@ -174,7 +174,7 @@ for darwin-i386: (objcopy is not currently supported on this platform,
so we use the binaryToMacho utility instead)
$ ../build/darwin-i386-compile-fast/binaryToMacho boot.jar \
__binary_boot_jar_start __binary_boot_jar_end > boot-jar.o
__TEXT __text __binary_boot_jar_start __binary_boot_jar_end > boot-jar.o
Step 4: Write a driver which starts the VM and runs the desired main

View File

@ -78,8 +78,16 @@ const int NoRegister = -1;
class Promise {
public:
class Listener {
public:
virtual void* resolve(int64_t value) = 0;
Listener* next;
};
virtual int64_t value() = 0;
virtual bool resolved() = 0;
virtual Listener* listen(unsigned) { return 0; }
};
class ResolvedPromise: public Promise {
@ -134,6 +142,59 @@ class CombinedPromise: public Promise {
Promise* high;
};
class ListenPromise: public Promise {
public:
ListenPromise(System* s, Allocator* allocator):
s(s), allocator(allocator), listener(0)
{ }
virtual int64_t value() {
abort(s);
}
virtual bool resolved() {
return false;
}
virtual Listener* listen(unsigned sizeInBytes) {
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
l->next = listener;
listener = l;
return l;
}
System* s;
Allocator* allocator;
Listener* listener;
Promise* promise;
};
class DelayedPromise: public ListenPromise {
public:
DelayedPromise(System* s, Allocator* allocator, Promise* basis,
DelayedPromise* next):
ListenPromise(s, allocator), basis(basis), next(next)
{ }
virtual int64_t value() {
abort(s);
}
virtual bool resolved() {
return false;
}
virtual Listener* listen(unsigned sizeInBytes) {
Listener* l = static_cast<Listener*>(allocator->allocate(sizeInBytes));
l->next = listener;
listener = l;
return l;
}
Promise* basis;
DelayedPromise* next;
};
class TraceHandler {
public:
virtual void handleTrace(Promise* address, unsigned padIndex,
@ -209,7 +270,8 @@ class Assembler {
virtual unsigned argumentRegisterCount() = 0;
virtual int argumentRegister(unsigned index) = 0;
virtual void updateCall(void* returnAddress, void* newTarget) = 0;
virtual void updateCall(UnaryOperation op, bool assertAlignment,
void* returnAddress, void* newTarget) = 0;
virtual unsigned alignFrameSize(unsigned sizeInWords) = 0;

View File

@ -33,6 +33,7 @@ pad(unsigned n)
void
writeObject(const char* architecture,
FILE* out, const uint8_t* data, unsigned size,
const char* segmentName, const char* sectionName,
const char* startName, const char* endName)
{
unsigned startNameLength = strlen(startName) + 1;
@ -63,7 +64,7 @@ writeObject(const char* architecture,
segment_command segment = {
LC_SEGMENT, // cmd
sizeof(segment_command) + sizeof(section), // cmdsize
"__TEXT", // segname
"", // segname
0, // vmaddr
pad(size), // vmsize
sizeof(mach_header)
@ -77,9 +78,11 @@ writeObject(const char* architecture,
0 // flags
};
strncpy(segment.segname, segmentName, sizeof(segment.segname));
section sect = {
"__const", // sectname
"__TEXT", // segname
"", // sectname
"", // segname
0, // addr
pad(size), // size
sizeof(mach_header)
@ -94,6 +97,9 @@ writeObject(const char* architecture,
0, // reserved2
};
strncpy(sect.segname, segmentName, sizeof(sect.segname));
strncpy(sect.sectname, sectionName, sizeof(sect.sectname));
symtab_command symbolTable = {
LC_SYMTAB, // cmd
sizeof(symtab_command), // cmdsize
@ -149,10 +155,10 @@ writeObject(const char* architecture,
int
main(int argc, const char** argv)
{
if (argc != 5) {
if (argc != 7) {
fprintf(stderr,
"usage: %s <architecture> <input file> <start symbol name> "
"<end symbol name>\n",
"usage: %s <architecture> <input file> <segment name> "
"<section name> <start symbol name> <end symbol name>\n",
argv[0]);
return -1;
}
@ -172,8 +178,11 @@ main(int argc, const char** argv)
}
if (data) {
writeObject(argv[1], stdout, data, size, argv[3], argv[4]);
writeObject
(argv[1], stdout, data, size, argv[3], argv[4], argv[5], argv[6]);
munmap(data, size);
return 0;
} else {
perror(argv[0]);

View File

@ -15,6 +15,34 @@
// ourselves:
extern "C" void __cxa_pure_virtual(void) { abort(); }
#ifdef BOOT_IMAGE
#ifdef __MINGW32__
# define EXPORT __declspec(dllexport)
# define SYMBOL(x) binary_bootimage_bin_##x
#else
# define EXPORT __attribute__ ((visibility("default")))
# define SYMBOL(x) _binary_bootimage_bin_##x
#endif
extern "C" {
extern const uint8_t SYMBOL(start)[];
extern const uint8_t SYMBOL(end)[];
EXPORT const uint8_t*
bootimageBin(unsigned* size)
{
*size = SYMBOL(end) - SYMBOL(start);
return SYMBOL(start);
}
}
#endif//BOOT_IMAGE
#ifdef BOOT_CLASSPATH
#ifdef __MINGW32__
# define EXPORT __declspec(dllexport)
# define SYMBOL(x) binary_classpath_jar_##x
@ -36,3 +64,5 @@ extern "C" {
}
}
#endif//BOOT_CLASSPATH

369
src/bootimage.cpp Normal file
View File

@ -0,0 +1,369 @@
/* Copyright (c) 2008, Avian Contributors
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. */
#include "bootimage.h"
#include "heapwalk.h"
#include "common.h"
#include "machine.h"
#include "util.h"
#include "assembler.h"
// since we aren't linking against libstdc++, we must implement this
// ourselves:
extern "C" void __cxa_pure_virtual(void) { abort(); }
using namespace vm;
namespace {
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
makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code,
unsigned capacity, uintptr_t* codeMap)
{
unsigned size = 0;
t->m->processor->compileThunks(t, image, code, &size, capacity);
object constants = 0;
PROTECT(t, constants);
object calls = 0;
PROTECT(t, calls);
DelayedPromise* addresses = 0;
for (Finder::Iterator it(t->m->finder); it.hasMore();) {
unsigned nameSize = 0;
const char* name = it.next(&nameSize);
if (endsWith(".class", name, nameSize)) {
//fprintf(stderr, "%.*s\n", nameSize - 6, name);
object c = resolveClass
(t, makeByteArray(t, "%.*s", nameSize - 6, name));
PROTECT(t, c);
if (classMethodTable(t, c)) {
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
object method = arrayBody(t, classMethodTable(t, c), i);
if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) {
t->m->processor->compileMethod
(t, zone, code, &size, capacity, &constants, &calls, &addresses,
method);
}
}
}
}
}
for (; calls; calls = tripleThird(t, calls)) {
object method = tripleFirst(t, calls);
uintptr_t address;
if (methodFlags(t, method) & ACC_NATIVE) {
address = reinterpret_cast<uintptr_t>(code + image->nativeThunk);
} else {
address = methodCompiled(t, method);
}
static_cast<ListenPromise*>(pointerValue(t, tripleSecond(t, calls)))
->listener->resolve(address);
}
for (; addresses; addresses = addresses->next) {
uint8_t* value = reinterpret_cast<uint8_t*>(addresses->basis->value());
assert(t, value >= code);
void* dst = addresses->listener->resolve
((value - code) | (1 << BootShift));
assert(t, reinterpret_cast<intptr_t>(dst)
>= reinterpret_cast<intptr_t>(code));
markBit(codeMap, reinterpret_cast<intptr_t>(dst)
- reinterpret_cast<intptr_t>(code));
}
image->codeSize = size;
return constants;
}
unsigned
objectSize(Thread* t, object o)
{
assert(t, not objectExtended(t, o));
return baseSize(t, o, objectClass(t, o));
}
void
visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants)
{
Machine* m = t->m;
for (HashMapIterator it(t, m->classMap); it.hasMore();) {
w->visitRoot(tripleSecond(t, it.next()));
}
image->loader = w->visitRoot(m->loader);
image->types = w->visitRoot(m->types);
m->processor->visitRoots(image, w);
for (; constants; constants = tripleThird(t, constants)) {
w->visitRoot(tripleFirst(t, constants));
}
}
HeapWalker*
makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map,
unsigned capacity, object constants)
{
class Visitor: public HeapVisitor {
public:
Visitor(Thread* t, uintptr_t* heap, uintptr_t* map, unsigned capacity):
t(t), currentObject(0), currentNumber(0), currentOffset(0), heap(heap),
map(map), position(0), capacity(capacity)
{ }
void visit(unsigned number) {
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;
}
}
virtual void root() {
currentObject = 0;
}
virtual unsigned visitNew(object p) {
if (p) {
unsigned size = objectSize(t, p);
unsigned number;
if (currentObject
and (currentOffset * BytesPerWord) == ClassStaticTable)
{
FixedAllocator allocator
(t, reinterpret_cast<uint8_t*>(heap + position),
(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);
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;
}
visit(number);
return number;
} else {
return 0;
}
}
virtual void visitOld(object, unsigned number) {
visit(number);
}
virtual void push(object object, unsigned number, unsigned offset) {
currentObject = object;
currentNumber = number;
currentOffset = offset;
}
virtual void pop() {
currentObject = 0;
}
Thread* t;
object currentObject;
unsigned currentNumber;
unsigned currentOffset;
uintptr_t* heap;
uintptr_t* map;
unsigned position;
unsigned capacity;
} visitor(t, heap, map, capacity / BytesPerWord);
HeapWalker* w = makeHeapWalker(t, &visitor);
visitRoots(t, image, w, constants);
image->heapSize = visitor.position * BytesPerWord;
return w;
}
void
updateConstants(Thread* t, object constants, uint8_t* code, uintptr_t* codeMap,
HeapMap* heapTable)
{
for (; constants; constants = tripleThird(t, constants)) {
unsigned target = heapTable->find(tripleFirst(t, constants));
assert(t, target > 0);
for (Promise::Listener* pl = static_cast<ListenPromise*>
(pointerValue(t, tripleSecond(t, constants)))->listener;
pl; pl = pl->next)
{
void* dst = pl->resolve(target);
assert(t, reinterpret_cast<intptr_t>(dst)
>= reinterpret_cast<intptr_t>(code));
markBit(codeMap, reinterpret_cast<intptr_t>(dst)
- reinterpret_cast<intptr_t>(code));
}
}
}
unsigned
offset(object a, uintptr_t* b)
{
return reinterpret_cast<uintptr_t>(b) - reinterpret_cast<uintptr_t>(a);
}
void
writeBootImage(Thread* t, FILE* out)
{
Zone zone(t->m->system, t->m->heap, 64 * 1024);
BootImage image;
const unsigned CodeCapacity = 32 * 1024 * 1024;
uint8_t* code = static_cast<uint8_t*>(t->m->heap->allocate(CodeCapacity));
uintptr_t* codeMap = static_cast<uintptr_t*>
(t->m->heap->allocate(codeMapSize(CodeCapacity)));
memset(codeMap, 0, codeMapSize(CodeCapacity));
object constants = makeCodeImage
(t, &zone, &image, code, CodeCapacity, codeMap);
PROTECT(t, constants);
const unsigned HeapCapacity = 32 * 1024 * 1024;
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));
collect(t, Heap::MajorCollection);
HeapWalker* heapWalker = makeHeapImage
(t, &image, heap, heapMap, HeapCapacity, constants);
updateConstants(t, constants, code, codeMap, heapWalker->map());
image.classCount = hashMapSize(t, t->m->classMap);
unsigned* classTable = static_cast<unsigned*>
(t->m->heap->allocate(image.classCount * sizeof(unsigned)));
{ unsigned i = 0;
for (HashMapIterator it(t, t->m->classMap); it.hasMore();) {
classTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next()));
}
}
image.stringCount = hashMapSize(t, t->m->stringMap);
unsigned* stringTable = static_cast<unsigned*>
(t->m->heap->allocate(image.stringCount * sizeof(unsigned)));
{ unsigned i = 0;
for (HashMapIterator it(t, t->m->stringMap); it.hasMore();) {
stringTable[i++] = heapWalker->map()->find
(jreferenceTarget(t, tripleFirst(t, it.next())));
}
}
unsigned* callTable = t->m->processor->makeCallTable
(t, &image, heapWalker, code);
heapWalker->dispose();
image.magic = BootImage::Magic;
image.codeBase = reinterpret_cast<uintptr_t>(code);
fprintf(stderr, "class count %d string count %d call count %d\n"
"heap size %d code size %d\n",
image.classCount, image.stringCount, image.callCount, image.heapSize,
image.codeSize);
if (true) {
fwrite(&image, sizeof(BootImage), 1, out);
fwrite(classTable, image.classCount * sizeof(unsigned), 1, out);
fwrite(stringTable, image.stringCount * sizeof(unsigned), 1, out);
fwrite(callTable, image.callCount * sizeof(unsigned) * 2, 1, out);
unsigned offset = (image.classCount * sizeof(unsigned))
+ (image.stringCount * sizeof(unsigned))
+ (image.callCount * sizeof(unsigned) * 2);
while (offset % BytesPerWord) {
uint8_t c = 0;
fwrite(&c, 1, 1, out);
++ offset;
}
fwrite(heapMap, pad(heapMapSize(image.heapSize)), 1, out);
fwrite(heap, pad(image.heapSize), 1, out);
fwrite(codeMap, pad(codeMapSize(image.codeSize)), 1, out);
fwrite(code, pad(image.codeSize), 1, out);
}
}
} // namespace
int
main(int ac, const char** av)
{
if (ac != 2) {
fprintf(stderr, "usage: %s <classpath>\n", av[0]);
return -1;
}
System* s = makeSystem(0);
Heap* h = makeHeap(s, 128 * 1024 * 1024);
Finder* f = makeFinder(s, av[1], 0);
Processor* p = makeProcessor(s, h);
Machine* m = new (h->allocate(sizeof(Machine))) Machine(s, h, f, p, 0, 0);
Thread* t = p->makeThread(m, 0, 0);
enter(t, Thread::ActiveState);
enter(t, Thread::IdleState);
writeBootImage(t, stdout);
return 0;
}

82
src/bootimage.h Normal file
View File

@ -0,0 +1,82 @@
/* Copyright (c) 2008, Avian Contributors
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. */
#ifndef BOOTIMAGE_H
#define BOOTIMAGE_H
#include "common.h"
namespace vm {
const unsigned BootMask = (~static_cast<unsigned>(0)) / BytesPerWord;
const unsigned BootShift = 32 - log(BytesPerWord);
class BootImage {
public:
static const unsigned Magic = 0x22377322;
unsigned magic;
unsigned heapSize;
unsigned codeSize;
unsigned classCount;
unsigned stringCount;
unsigned callCount;
unsigned loader;
unsigned types;
unsigned methodTree;
unsigned methodTreeSentinal;
uintptr_t codeBase;
unsigned defaultThunk;
unsigned nativeThunk;
unsigned aioobThunk;
unsigned thunkTable;
unsigned thunkSize;
unsigned compileMethodCall;
unsigned invokeNativeCall;
unsigned throwArrayIndexOutOfBoundsCall;
#define THUNK(s) unsigned s##Call;
#include "thunks.cpp"
#undef THUNK
};
inline unsigned
codeMapSize(unsigned codeSize)
{
return ceiling(codeSize, BitsPerWord) * BytesPerWord;
}
inline unsigned
heapMapSize(unsigned heapSize)
{
return ceiling(heapSize, BitsPerWord * BytesPerWord) * BytesPerWord;
}
inline object
bootObject(uintptr_t* heap, unsigned offset)
{
if (offset) {
return reinterpret_cast<object>(heap + offset - 1);
} else {
return 0;
}
}
} // namespace vm
#endif//BOOTIMAGE_H

View File

@ -287,6 +287,15 @@ difference(void* a, void* b)
return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b);
}
template <class T>
inline void*
voidPointer(T function)
{
void* p;
memcpy(&p, &function, sizeof(void*));
return p;
}
class Machine;
class Thread;

File diff suppressed because it is too large Load Diff

View File

@ -5044,8 +5044,26 @@ class MyCompiler: public Compiler {
int i = 0;
for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) {
*reinterpret_cast<intptr_t*>(dst + pad(c.machineCodeSize) + i)
= n->promise->value();
intptr_t* target = reinterpret_cast<intptr_t*>
(dst + pad(c.assembler->length()) + i);
if (n->promise->resolved()) {
*target = n->promise->value();
} else {
class Listener: public Promise::Listener {
public:
Listener(intptr_t* target): target(target){ }
virtual void* resolve(int64_t value) {
*target = value;
return target;
}
intptr_t* target;
};
new (n->promise->listen(sizeof(Listener))) Listener(target);
}
i += BytesPerWord;
}
}

View File

@ -51,8 +51,15 @@ equal(const void* a, unsigned al, const void* b, unsigned bl)
class Element {
public:
class Iterator {
public:
virtual const char* next(unsigned* size) = 0;
virtual void dispose() = 0;
};
Element(): next(0) { }
virtual Iterator* iterator() = 0;
virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0;
virtual void dispose() = 0;
@ -62,10 +69,71 @@ class Element {
class DirectoryElement: public Element {
public:
class Iterator: public Element::Iterator {
public:
Iterator(System* s, const char* name, unsigned skip):
s(s), name(name), skip(skip), directory(0), last(0), it(0)
{
if (not s->success(s->open(&directory, name))) {
directory = 0;
}
}
virtual const char* next(unsigned* size) {
if (it) {
const char* v = it->next(size);
if (v) {
return v;
} else {
it->dispose();
it = 0;
}
}
if (last) {
s->free(last);
}
if (directory) {
for (const char* v = directory->next(); v; v = directory->next()) {
if (v[0] != '.') {
last = append(s, name, "/", v);
if (s->identify(last) == System::TypeDirectory) {
it = new (allocate(s, sizeof(Iterator))) Iterator(s, last, skip);
it->name = last;
}
const char* result = last + skip;
*size = strlen(result);
return result;
}
}
}
return 0;
}
virtual void dispose() {
directory->dispose();
s->free(this);
}
System* s;
const char* name;
unsigned skip;
System::Directory* directory;
const char* last;
Iterator* it;
};
DirectoryElement(System* s, const char* name):
s(s), name(name)
{ }
virtual Element::Iterator* iterator() {
return new (allocate(s, sizeof(Iterator)))
Iterator(s, name, strlen(name) + 1);
}
virtual System::Region* find(const char* name) {
const char* file = append(s, this->name, "/", name);
System::Region* region;
@ -83,7 +151,7 @@ class DirectoryElement: public Element {
const char* file = append(s, this->name, "/", name);
System::FileType type = s->identify(file);
s->free(file);
return type != System::DoesNotExist;
return type != System::TypeDoesNotExist;
}
virtual void dispose() {
@ -371,10 +439,39 @@ class JarIndex {
class JarElement: public Element {
public:
class Iterator: public Element::Iterator {
public:
Iterator(System* s, JarIndex* index): s(s), index(index), position(0) { }
virtual const char* next(unsigned* size) {
if (position < index->position) {
JarIndex::Node* n = index->nodes + (position++);
*size = JarIndex::fileNameLength(n->entry);
return reinterpret_cast<const char*>(JarIndex::fileName(n->entry));
} else {
return 0;
}
}
virtual void dispose() {
s->free(this);
}
System* s;
JarIndex* index;
unsigned position;
};
JarElement(System* s, const char* name):
s(s), name(name), region(0), index(0)
{ }
virtual Element::Iterator* iterator() {
init();
return new (allocate(s, sizeof(Iterator))) Iterator(s, index);
}
virtual void init() {
if (index == 0) {
System::Region* r;
@ -504,11 +601,11 @@ parsePath(System* s, const char* path, const char* bootLibrary)
name[token.length] = 0;
switch (s->identify(name)) {
case System::File: {
case System::TypeFile: {
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name);
} break;
case System::Directory: {
case System::TypeDirectory: {
e = new (allocate(s, sizeof(DirectoryElement)))
DirectoryElement(s, name);
} break;
@ -533,6 +630,40 @@ parsePath(System* s, const char* path, const char* bootLibrary)
return first;
}
class MyIterator: public Finder::IteratorImp {
public:
MyIterator(System* s, Element* path):
s(s), e(path ? path->next : 0), it(path ? path->iterator() : 0)
{ }
virtual const char* next(unsigned* size) {
while (it) {
const char* v = it->next(size);
if (v) {
return v;
} else {
it->dispose();
if (e) {
it = e->iterator();
e = e->next;
} else {
it = 0;
}
}
}
return 0;
}
virtual void dispose() {
if (it) it->dispose();
s->free(this);
}
System* s;
Element* e;
Element::Iterator* it;
};
class MyFinder: public Finder {
public:
MyFinder(System* system, const char* path, const char* bootLibrary):
@ -541,6 +672,11 @@ class MyFinder: public Finder {
pathString(copy(system, path))
{ }
virtual IteratorImp* iterator() {
return new (allocate(system, sizeof(MyIterator)))
MyIterator(system, path_);
}
virtual System::Region* find(const char* name) {
for (Element* e = path_; e; e = e->next) {
System::Region* r = e->find(name);

View File

@ -19,6 +19,46 @@ namespace vm {
class Finder {
public:
class IteratorImp {
public:
virtual const char* next(unsigned* size) = 0;
virtual void dispose() = 0;
};
class Iterator {
public:
Iterator(Finder* finder):
it(finder->iterator()),
current(it->next(&currentSize))
{ }
~Iterator() {
it->dispose();
}
bool hasMore() {
if (current) return true;
current = it->next(&currentSize);
return current != 0;
}
const char* next(unsigned* size) {
if (hasMore()) {
*size = currentSize;
const char* v = current;
current = 0;
return v;
} else {
return 0;
}
}
IteratorImp* it;
const char* current;
unsigned currentSize;
};
virtual IteratorImp* iterator() = 0;
virtual System::Region* find(const char* name) = 0;
virtual bool exists(const char* name) = 0;
virtual const char* path() = 0;

View File

@ -121,17 +121,17 @@ class Segment {
for (; word <= wordLimit and (word < wordLimit or bit < bitLimit);
++word)
{
uintptr_t* p = map->data() + word;
if (*p) {
uintptr_t w = map->data[word];
if (2) {
for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit);
++bit)
{
if (map->data()[word] & (static_cast<uintptr_t>(1) << bit)) {
if (w & (static_cast<uintptr_t>(1) << bit)) {
index = ::indexOf(word, bit);
// printf("hit at index %d\n", index);
// printf("hit at index %d\n", index);
return true;
} else {
// printf("miss at index %d\n", indexOf(word, bit));
// printf("miss at index %d\n", indexOf(word, bit));
}
}
}
@ -153,14 +153,26 @@ class Segment {
Segment* segment;
Map* child;
uintptr_t* data;
unsigned bitsPerRecord;
unsigned scale;
bool clearNewData;
Map(Segment* segment, unsigned bitsPerRecord, unsigned scale,
Map* child, bool clearNewData):
Map(Segment* segment, uintptr_t* data, unsigned bitsPerRecord,
unsigned scale, Map* child, bool clearNewData):
segment(segment),
child(child),
data(data),
bitsPerRecord(bitsPerRecord),
scale(scale),
clearNewData(clearNewData)
{ }
Map(Segment* segment, unsigned bitsPerRecord, unsigned scale, Map* child,
bool clearNewData):
segment(segment),
child(child),
data(0),
bitsPerRecord(bitsPerRecord),
scale(scale),
clearNewData(clearNewData)
@ -171,8 +183,13 @@ class Segment {
assert(segment->context, scale);
assert(segment->context, powerOfTwo(scale));
if (data == 0) {
data = segment->data + segment->capacity()
+ calculateOffset(segment->capacity());
}
if (clearNewData) {
memset(data(), 0, size() * BytesPerWord);
memset(data, 0, size() * BytesPerWord);
}
if (child) {
@ -180,40 +197,47 @@ class Segment {
}
}
unsigned calculateOffset(unsigned capacity) {
unsigned n = 0;
if (child) n += child->calculateFootprint(capacity);
return n;
}
static unsigned calculateSize(Context* c UNUSED, unsigned capacity,
unsigned scale, unsigned bitsPerRecord)
{
unsigned result
= ceiling(ceiling(capacity, scale) * bitsPerRecord, BitsPerWord);
assert(c, result);
return result;
}
unsigned calculateSize(unsigned capacity) {
return calculateSize(segment->context, capacity, scale, bitsPerRecord);
}
unsigned size() {
return calculateSize(segment->capacity());
}
unsigned calculateFootprint(unsigned capacity) {
unsigned n = calculateSize(capacity);
if (child) n += child->calculateFootprint(capacity);
return n;
}
void replaceWith(Map* m) {
assert(segment->context, bitsPerRecord == m->bitsPerRecord);
assert(segment->context, scale == m->scale);
data = m->data;
m->segment = 0;
m->data = 0;
if (child) child->replaceWith(m->child);
}
unsigned offset(unsigned capacity) {
unsigned n = 0;
if (child) n += child->footprint(capacity);
return n;
}
unsigned offset() {
return offset(segment->capacity());
}
uintptr_t* data() {
return segment->data + segment->capacity() + offset();
}
unsigned size(unsigned capacity) {
unsigned result
= ceiling(ceiling(capacity, scale) * bitsPerRecord, BitsPerWord);
assert(segment->context, result);
return result;
}
unsigned size() {
return size(max(segment->capacity(), 1));
}
unsigned indexOf(unsigned segmentIndex) {
return (segmentIndex / scale) * bitsPerRecord;
}
@ -224,33 +248,20 @@ class Segment {
return indexOf(segment->indexOf(p));
}
void update(uintptr_t* newData, unsigned capacity) {
assert(segment->context, capacity >= segment->capacity());
uintptr_t* p = newData + offset(capacity);
if (segment->position()) {
memcpy(p, data(), size(segment->position()) * BytesPerWord);
}
if (child) {
child->update(newData, capacity);
}
}
void clearBit(unsigned i) {
assert(segment->context, wordOf(i) < size());
vm::clearBit(data(), i);
vm::clearBit(data, i);
}
void setBit(unsigned i) {
assert(segment->context, wordOf(i) < size());
vm::markBit(data(), i);
vm::markBit(data, i);
}
void clearOnlyIndex(unsigned index) {
clearBits(data(), bitsPerRecord, index);
clearBits(data, bitsPerRecord, index);
}
void clearOnly(unsigned segmentIndex) {
@ -267,7 +278,7 @@ class Segment {
}
void setOnlyIndex(unsigned index, unsigned v = 1) {
setBits(data(), bitsPerRecord, index, v);
setBits(data, bitsPerRecord, index, v);
}
void setOnly(unsigned segmentIndex, unsigned v = 1) {
@ -285,13 +296,7 @@ class Segment {
}
unsigned get(void* p) {
return getBits(data(), bitsPerRecord, indexOf(p));
}
unsigned footprint(unsigned capacity) {
unsigned n = size(capacity);
if (child) n += child->footprint(capacity);
return n;
return getBits(data, bitsPerRecord, indexOf(p));
}
};
@ -334,8 +339,22 @@ class Segment {
}
}
Segment(Context* context, Map* map, uintptr_t* data, unsigned position,
unsigned capacity):
context(context),
data(data),
position_(position),
capacity_(capacity),
map(map)
{
if (map) {
map->init();
}
}
unsigned footprint(unsigned capacity) {
return capacity + (map and capacity ? map->footprint(capacity) : 0);
return capacity
+ (map and capacity ? map->calculateFootprint(capacity) : 0);
}
unsigned capacity() {
@ -411,15 +430,18 @@ class Segment {
class Fixie {
public:
Fixie(unsigned size, bool hasMask, Fixie** handle, bool immortal):
Fixie(Context* c, unsigned size, bool hasMask, Fixie** handle,
bool immortal):
age(immortal ? FixieTenureThreshold + 1 : 0),
hasMask(hasMask),
marked(false),
dirty(false),
size(size)
size(size),
next(0),
handle(0)
{
memset(mask(), 0, maskSize(size, hasMask));
add(handle);
add(c, handle);
if (DebugFixies) {
fprintf(stderr, "make fixie %p of size %d\n", this, totalSize());
}
@ -429,7 +451,10 @@ class Fixie {
return age == FixieTenureThreshold + 1;
}
void add(Fixie** handle) {
void add(Context* c UNUSED, Fixie** handle) {
assert(c, this->handle == 0);
assert(c, next == 0);
this->handle = handle;
if (handle) {
next = *handle;
@ -440,18 +465,25 @@ class Fixie {
}
}
void remove() {
if (handle) *handle = next;
if (next) next->handle = handle;
void remove(Context* c UNUSED) {
if (handle) {
assert(c, *handle == this);
*handle = next;
}
if (next) {
next->handle = handle;
}
next = 0;
handle = 0;
}
void move(Fixie** handle) {
void move(Context* c, Fixie** handle) {
if (DebugFixies) {
fprintf(stderr, "move fixie %p\n", this);
}
remove();
add(handle);
remove(c);
add(c, handle);
}
void** body() {
@ -502,6 +534,9 @@ class Context {
limit(limit),
lowMemoryThreshold(limit / 2),
lock(0),
immortalHeapStart(0),
immortalHeapEnd(0),
ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false),
gen1(this, &ageMap, 0, 0),
@ -571,7 +606,10 @@ class Context {
unsigned lowMemoryThreshold;
System::Mutex* lock;
uintptr_t* immortalHeapStart;
uintptr_t* immortalHeapEnd;
Segment::Map ageMap;
Segment gen1;
@ -690,7 +728,7 @@ inline void
initNextGen1(Context* c)
{
new (&(c->nextAgeMap)) Segment::Map
(&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false);
(&(c->nextGen1), max(1, log(TenureThreshold)), 1, 0, false);
unsigned minimum = minimumNextGen1Capacity(c);
unsigned desired = minimum;
@ -775,6 +813,7 @@ free(Context* c, Fixie** fixies)
{
for (Fixie** p = fixies; *p;) {
Fixie* f = *p;
if (f->immortal()) {
p = &(f->next);
} else {
@ -802,9 +841,9 @@ sweepFixies(Context* c)
c->untenuredFixieFootprint = 0;
for (Fixie** p = &(c->visitedFixies); *p;) {
Fixie* f = *p;
*p = f->next;
while (c->visitedFixies) {
Fixie* f = c->visitedFixies;
f->remove(c);
if (not f->immortal()) {
++ f->age;
@ -825,14 +864,14 @@ sweepFixies(Context* c)
}
if (f->dirty) {
f->move(&(c->dirtyTenuredFixies));
f->add(c, &(c->dirtyTenuredFixies));
} else {
f->move(&(c->tenuredFixies));
f->add(c, &(c->tenuredFixies));
}
} else {
c->untenuredFixieFootprint += f->totalSize();
f->move(&(c->fixies));
f->add(c, &(c->fixies));
}
f->marked = false;
@ -852,6 +891,12 @@ copyTo(Context* c, Segment* s, void* o, unsigned size)
return dst;
}
bool
immortalHeapContains(Context* c, void* p)
{
return p < c->immortalHeapEnd and p >= c->immortalHeapStart;
}
void*
copy2(Context* c, void* o)
{
@ -888,6 +933,7 @@ copy2(Context* c, void* o)
} else {
assert(c, not c->nextGen1.contains(o));
assert(c, not c->nextGen2.contains(o));
assert(c, not immortalHeapContains(c, o));
o = copyTo(c, &(c->nextGen1), o, size);
@ -926,10 +972,13 @@ update3(Context* c, void* o, bool* needsVisit)
fprintf(stderr, "mark fixie %p\n", f);
}
f->marked = true;
f->move(&(c->markedFixies));
f->move(c, &(c->markedFixies));
}
*needsVisit = false;
return o;
} else if (immortalHeapContains(c, o)) {
*needsVisit = false;
return o;
} else if (wasCollected(c, o)) {
*needsVisit = false;
return follow(c, o);
@ -950,23 +999,12 @@ update2(Context* c, void* o, bool* needsVisit)
return update3(c, o, needsVisit);
}
void*
update(Context* c, void** p, bool* needsVisit)
{
if (mask(*p) == 0) {
*needsVisit = false;
return 0;
}
return update2(c, mask(*p), needsVisit);
}
void
markDirty(Context* c, Fixie* f)
{
if (not f->dirty) {
f->dirty = true;
f->move(&(c->dirtyTenuredFixies));
f->move(c, &(c->dirtyTenuredFixies));
}
}
@ -975,7 +1013,11 @@ markClean(Context* c, Fixie* f)
{
if (f->dirty) {
f->dirty = false;
f->move(&(c->tenuredFixies));
if (f->immortal()) {
f->remove(c);
} else {
f->move(c, &(c->tenuredFixies));
}
}
}
@ -993,9 +1035,10 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
map = &(c->nextHeapMap);
}
if (not (c->client->isFixed(result)
and fixie(result)->age >= FixieTenureThreshold)
and not seg->contains(result))
if (not (immortalHeapContains(c, result)
or (c->client->isFixed(result)
and fixie(result)->age >= FixieTenureThreshold)
or seg->contains(result)))
{
if (target and c->client->isFixed(target)) {
Fixie* f = fixie(target);
@ -1003,11 +1046,11 @@ updateHeapMap(Context* c, void* p, void* target, unsigned offset, void* result)
if (static_cast<unsigned>(f->age + 1) >= FixieTenureThreshold) {
if (DebugFixies) {
fprintf(stderr, "dirty fixie %p at %d (%p)\n",
f, offset, f->body() + offset);
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
f, offset, f->body() + offset, result);
}
markDirty(c, f);
f->dirty = true;
markBit(f->mask(), offset);
}
} else if (seg->contains(p)) {
@ -1399,7 +1442,6 @@ visitDirtyFixies(Context* c, Fixie** p)
assert(c, wasDirty);
if (clean) {
*p = f->next;
markClean(c, f);
} else {
p = &(f->next);
@ -1410,9 +1452,9 @@ visitDirtyFixies(Context* c, Fixie** p)
void
visitMarkedFixies(Context* c)
{
for (Fixie** p = &(c->markedFixies); *p;) {
Fixie* f = *p;
*p = f->next;
while (c->markedFixies) {
Fixie* f = c->markedFixies;
f->remove(c);
if (DebugFixies) {
fprintf(stderr, "visit fixie %p\n", f);
@ -1435,7 +1477,7 @@ visitMarkedFixies(Context* c)
c->client->walk(f->body(), &w);
f->move(&(c->visitedFixies));
f->move(c, &(c->visitedFixies));
}
}
@ -1664,6 +1706,11 @@ class MyHeap: public Heap {
c.client = client;
}
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) {
c.immortalHeapStart = start;
c.immortalHeapEnd = start + sizeInWords;
}
virtual void* tryAllocate(unsigned size) {
return ::tryAllocate(&c, size);
}
@ -1690,18 +1737,21 @@ class MyHeap: public Heap {
{
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
return (new (allocator->allocate(*totalInBytes))
Fixie(sizeInWords, objectMask, &(c.fixies), false))->body();
Fixie(&c, sizeInWords, objectMask, &(c.fixies), false))->body();
}
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes)
virtual void* allocateImmortalFixed(Allocator* allocator,
unsigned sizeInWords, bool objectMask,
unsigned* totalInBytes)
{
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
return (new (allocator->allocate(*totalInBytes))
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
Fixie(&c, sizeInWords, objectMask, 0, true))->body();
}
virtual bool needsMark(void* p) {
assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p)));
if (c.client->isFixed(p)) {
return fixie(p)->age >= FixieTenureThreshold;
} else {
@ -1717,6 +1767,7 @@ class MyHeap: public Heap {
bool targetNeedsMark(void* target) {
return target
and not c.gen2.contains(target)
and not immortalHeapContains(&c, target)
and not (c.client->isFixed(target)
and fixie(target)->age >= FixieTenureThreshold);
}
@ -1731,8 +1782,8 @@ class MyHeap: public Heap {
void** target = static_cast<void**>(p) + offset + i;
if (targetNeedsMark(mask(*target))) {
if (DebugFixies) {
fprintf(stderr, "dirty fixie %p at %d (%p)\n",
f, offset, f->body() + offset);
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
f, offset, f->body() + offset, mask(*target));
}
dirty = true;
@ -1789,6 +1840,7 @@ class MyHeap: public Heap {
} else if (c.nextGen1.contains(p)) {
return Reachable;
} else if (c.nextGen2.contains(p)
or immortalHeapContains(&c, p)
or (c.gen2.contains(p)
and (c.mode == Heap::MinorCollection
or c.gen2.indexOf(p) >= c.gen2Base)))

View File

@ -52,11 +52,13 @@ class Heap: public Allocator {
};
virtual void setClient(Client* client) = 0;
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0;
virtual void collect(CollectionType type, unsigned footprint) = 0;
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes) = 0;
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
bool objectMask, unsigned* totalInBytes) = 0;
virtual void* allocateImmortalFixed(Allocator* allocator,
unsigned sizeInWords, bool objectMask,
unsigned* totalInBytes) = 0;
virtual bool needsMark(void* p) = 0;
virtual bool needsMark(void* p, unsigned offset) = 0;
virtual void mark(void* p, unsigned offset, unsigned count) = 0;

View File

@ -9,194 +9,12 @@
details. */
#include "machine.h"
#include "heapwalk.h"
using namespace vm;
namespace {
const uintptr_t PointerShift = log(BytesPerWord);
class Set {
public:
class Entry {
public:
object value;
uint32_t number;
int next;
};
static unsigned footprint(unsigned capacity) {
return sizeof(Set)
+ pad(sizeof(int) * capacity)
+ pad(sizeof(Set::Entry) * capacity);
}
Set(unsigned capacity):
size(0),
capacity(capacity),
index(reinterpret_cast<int*>
(reinterpret_cast<uint8_t*>(this)
+ sizeof(Set))),
entries(reinterpret_cast<Entry*>
(reinterpret_cast<uint8_t*>(index)
+ pad(sizeof(int) * capacity)))
{ }
unsigned size;
unsigned capacity;
int* index;
Entry* entries;
};
class Stack {
public:
class Entry {
public:
object value;
int offset;
};
static const unsigned Capacity = 4096;
Stack(Stack* next): next(next), entryCount(0) { }
Stack* next;
unsigned entryCount;
Entry entries[Capacity];
};
class Context {
public:
Context(Thread* thread, FILE* out):
thread(thread), out(out), objects(0), stack(0), nextNumber(1)
{ }
~Context() {
if (objects) {
thread->m->heap->free(objects, Set::footprint(objects->capacity));
}
while (stack) {
Stack* dead = stack;
stack = dead->next;
thread->m->heap->free(stack, sizeof(Stack));
}
}
Thread* thread;
FILE* out;
Set* objects;
Stack* stack;
uint32_t nextNumber;
};
void
push(Context* c, object p, int offset)
{
if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
Stack(c->stack);
}
Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
e->value = p;
e->offset = offset;
}
bool
pop(Context* c, object* p, int* offset)
{
if (c->stack) {
if (c->stack->entryCount == 0) {
if (c->stack->next) {
Stack* dead = c->stack;
c->stack = dead->next;
c->thread->m->heap->free(dead, sizeof(Stack));
} else {
return false;
}
}
Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
*p = e->value;
*offset = e->offset;
return true;
} else {
return false;
}
}
unsigned
hash(object p, unsigned capacity)
{
return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
& (capacity - 1);
}
Set::Entry*
find(Context* c, object p)
{
if (c->objects == 0) return 0;
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
Set::Entry* e = c->objects->entries + i;
if (e->value == p) {
return e;
}
i = e->next;
}
return 0;
}
Set::Entry*
add(Context* c UNUSED, Set* set, object p, uint32_t number)
{
assert(c->thread, set->size < set->capacity);
unsigned index = hash(p, set->capacity);
int offset = set->size++;
Set::Entry* e = set->entries + offset;
e->value = p;
e->number = number;
e->next = set->index[index];
set->index[index] = offset;
return e;
}
Set::Entry*
add(Context* c, object p)
{
if (c->objects == 0 or c->objects->size == c->objects->capacity) {
unsigned capacity;
if (c->objects) {
capacity = c->objects->capacity * 2;
} else {
capacity = 4096; // must be power of two
}
Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
Set(capacity);
memset(set->index, 0xFF, sizeof(int) * capacity);
if (c->objects) {
for (unsigned i = 0; i < c->objects->capacity; ++i) {
for (int j = c->objects->index[i]; j >= 0;) {
Set::Entry* e = c->objects->entries + j;
add(c, set, e->value, e->number);
j = e->next;
}
}
c->thread->m->heap->free
(c->objects, Set::footprint(c->objects->capacity));
}
c->objects = set;
}
return add(c, c->objects, p, 0);
}
enum {
Root,
Size,
@ -205,100 +23,30 @@ enum {
Pop
};
inline object
get(object o, unsigned offsetInWords)
void
write1(FILE* out, uint8_t v)
{
return static_cast<object>
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
size_t n UNUSED = fwrite(&v, 1, 1, out);
}
void
write1(Context* c, uint8_t v)
{
fwrite(&v, 1, 1, c->out);
}
void
write4(Context* c, uint32_t v)
write4(FILE* out, uint32_t v)
{
uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF };
fwrite(b, 4, 1, c->out);
size_t n UNUSED = fwrite(b, 4, 1, out);
}
void
writeString(Context* c, int8_t* p, unsigned size)
writeString(FILE* out, int8_t* p, unsigned size)
{
write4(c, size);
fwrite(p, size, 1, c->out);
write4(out, size);
size_t n UNUSED = fwrite(p, size, 1, out);
}
unsigned
objectSize(Thread* t, object o)
{
unsigned n = baseSize(t, o, objectClass(t, o));
if (objectExtended(t, o)) {
++ n;
}
return n;
}
void
visit(Context* c, object p)
{
Thread* t = c->thread;
int nextChildOffset;
write1(c, Root);
visit: {
Set::Entry* e = find(c, p);
if (e) {
write4(c, e->number);
} else {
e = add(c, p);
e->number = c->nextNumber++;
write4(c, e->number);
write1(c, Size);
write4(c, objectSize(t, p));
if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) {
object name = className(t, p);
if (name) {
write1(c, ClassName);
writeString(c, &byteArrayBody(t, name, 0),
byteArrayLength(t, name) - 1);
}
}
nextChildOffset = walkNext(t, p, -1);
if (nextChildOffset != -1) {
goto children;
}
}
}
goto pop;
children: {
write1(c, Push);
push(c, p, nextChildOffset);
p = get(p, nextChildOffset);
goto visit;
}
pop: {
if (pop(c, &p, &nextChildOffset)) {
write1(c, Pop);
nextChildOffset = walkNext(t, p, nextChildOffset);
if (nextChildOffset >= 0) {
goto children;
} else {
goto pop;
}
}
}
return extendedSize(t, o, baseSize(t, o, objectClass(t, o)));
}
} // namespace
@ -308,22 +56,58 @@ namespace vm {
void
dumpHeap(Thread* t, FILE* out)
{
Context context(t, out);
class Visitor : public Heap::Visitor {
class Visitor: public HeapVisitor {
public:
Visitor(Context* c): c(c) { }
Visitor(Thread* t, FILE* out): t(t), out(out), nextNumber(1) { }
virtual void visit(void* p) {
::visit(c, static_cast<object>(mask(*static_cast<void**>(p))));
virtual void root() {
write1(out, Root);
}
Context* c;
} v(&context);
virtual unsigned visitNew(object p) {
if (p) {
unsigned number = nextNumber++;
write4(out, number);
add(&context, 0)->number = 0;
write1(out, Size);
write4(out, objectSize(t, p));
visitRoots(t->m, &v);
if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType))
{
object name = className(t, p);
if (name) {
write1(out, ClassName);
writeString(out, &byteArrayBody(t, name, 0),
byteArrayLength(t, name) - 1);
}
}
return number;
} else {
return 0;
}
}
virtual void visitOld(object, unsigned number) {
write4(out, number);
}
virtual void push(object, unsigned, unsigned) {
write1(out, Push);
}
virtual void pop() {
write1(out, Pop);
}
Thread* t;
FILE* out;
unsigned nextNumber;
} visitor(t, out);
HeapWalker* w = makeHeapWalker(t, &visitor);
w->visitAllRoots();
w->dispose();
}
} // namespace vm

341
src/heapwalk.cpp Normal file
View File

@ -0,0 +1,341 @@
/* Copyright (c) 2008, Avian Contributors
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. */
#include "machine.h"
#include "heapwalk.h"
using namespace vm;
namespace {
const uintptr_t PointerShift = log(BytesPerWord);
class Context;
class Set: public HeapMap {
public:
class Entry {
public:
object value;
uint32_t number;
int next;
};
static unsigned footprint(unsigned capacity) {
return sizeof(Set)
+ pad(sizeof(int) * capacity)
+ pad(sizeof(Set::Entry) * capacity);
}
Set(Context* context, unsigned capacity):
context(context),
index(reinterpret_cast<int*>
(reinterpret_cast<uint8_t*>(this)
+ sizeof(Set))),
entries(reinterpret_cast<Entry*>
(reinterpret_cast<uint8_t*>(index)
+ pad(sizeof(int) * capacity))),
size(0),
capacity(capacity)
{ }
virtual int find(object value);
virtual void dispose();
Context* context;
int* index;
Entry* entries;
unsigned size;
unsigned capacity;
};
class Stack {
public:
class Entry {
public:
object value;
int offset;
};
static const unsigned Capacity = 4096;
Stack(Stack* next): next(next), entryCount(0) { }
Stack* next;
unsigned entryCount;
Entry entries[Capacity];
};
class Context {
public:
Context(Thread* thread):
thread(thread), objects(0), stack(0)
{ }
void dispose() {
if (objects) {
objects->dispose();
}
while (stack) {
Stack* dead = stack;
stack = dead->next;
thread->m->heap->free(stack, sizeof(Stack));
}
}
Thread* thread;
Set* objects;
Stack* stack;
};
void
push(Context* c, object p, int offset)
{
if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
Stack(c->stack);
}
Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
e->value = p;
e->offset = offset;
}
bool
pop(Context* c, object* p, int* offset)
{
if (c->stack) {
if (c->stack->entryCount == 0) {
if (c->stack->next) {
Stack* dead = c->stack;
c->stack = dead->next;
c->thread->m->heap->free(dead, sizeof(Stack));
} else {
return false;
}
}
Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
*p = e->value;
*offset = e->offset;
return true;
} else {
return false;
}
}
unsigned
hash(object p, unsigned capacity)
{
return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
& (capacity - 1);
}
Set::Entry*
find(Context* c, object p)
{
if (c->objects == 0) return 0;
for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
Set::Entry* e = c->objects->entries + i;
if (e->value == p) {
return e;
}
i = e->next;
}
return 0;
}
int
Set::find(object value)
{
Set::Entry* e = ::find(context, value);
if (e) {
return e->number;
} else {
return -1;
}
}
void
Set::dispose()
{
context->thread->m->heap->free(this, footprint(capacity));
}
Set::Entry*
add(Context* c UNUSED, Set* set, object p, uint32_t number)
{
assert(c->thread, set->size < set->capacity);
unsigned index = hash(p, set->capacity);
int offset = set->size++;
Set::Entry* e = set->entries + offset;
e->value = p;
e->number = number;
e->next = set->index[index];
set->index[index] = offset;
return e;
}
Set::Entry*
add(Context* c, object p)
{
if (c->objects == 0 or c->objects->size == c->objects->capacity) {
unsigned capacity;
if (c->objects) {
capacity = c->objects->capacity * 2;
} else {
capacity = 4096; // must be power of two
}
Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
Set(c, capacity);
memset(set->index, 0xFF, sizeof(int) * capacity);
if (c->objects) {
for (unsigned i = 0; i < c->objects->capacity; ++i) {
for (int j = c->objects->index[i]; j >= 0;) {
Set::Entry* e = c->objects->entries + j;
add(c, set, e->value, e->number);
j = e->next;
}
}
c->thread->m->heap->free
(c->objects, Set::footprint(c->objects->capacity));
}
c->objects = set;
}
return add(c, c->objects, p, 0);
}
inline object
get(object o, unsigned offsetInWords)
{
return static_cast<object>
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
}
unsigned
objectSize(Thread* t, object o)
{
unsigned n = baseSize(t, o, objectClass(t, o));
if (objectExtended(t, o)) {
++ n;
}
return n;
}
unsigned
walk(Context* c, HeapVisitor* v, object p)
{
Thread* t = c->thread;
object root = p;
int nextChildOffset;
v->root();
visit: {
Set::Entry* e = find(c, p);
if (e) {
v->visitOld(p, e->number);
} else {
e = add(c, p);
e->number = v->visitNew(p);
nextChildOffset = walkNext(t, p, -1);
if (nextChildOffset != -1) {
goto children;
}
}
}
goto pop;
children: {
v->push(p, find(c, p)->number, nextChildOffset);
push(c, p, nextChildOffset);
p = get(p, nextChildOffset);
goto visit;
}
pop: {
if (pop(c, &p, &nextChildOffset)) {
v->pop();
nextChildOffset = walkNext(t, p, nextChildOffset);
if (nextChildOffset >= 0) {
goto children;
} else {
goto pop;
}
}
}
return find(c, root)->number;
}
class MyHeapWalker: public HeapWalker {
public:
MyHeapWalker(Thread* t, HeapVisitor* v):
context(t), visitor(v)
{
add(&context, 0)->number = v->visitNew(0);
}
virtual unsigned visitRoot(object root) {
return walk(&context, visitor, root);
}
virtual void visitAllRoots() {
class Visitor: public Heap::Visitor {
public:
Visitor(Context* c, HeapVisitor* v): c(c), v(v) { }
virtual void visit(void* p) {
walk(c, v, static_cast<object>(mask(*static_cast<void**>(p))));
}
Context* c;
HeapVisitor* v;
} v(&context, visitor);
visitRoots(context.thread->m, &v);
}
virtual HeapMap* map() {
return context.objects;
}
virtual void dispose() {
context.dispose();
context.thread->m->heap->free(this, sizeof(MyHeapWalker));
}
Context context;
HeapVisitor* visitor;
};
} // namespace
namespace vm {
HeapWalker*
makeHeapWalker(Thread* t, HeapVisitor* v)
{
return new (t->m->heap->allocate(sizeof(MyHeapWalker))) MyHeapWalker(t, v);
}
} // namespace vm

49
src/heapwalk.h Normal file
View File

@ -0,0 +1,49 @@
/* Copyright (c) 2008, Avian Contributors
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. */
#ifndef HEAPWALK_H
#define HEAPWALK_H
#include "common.h"
namespace vm {
class Thread;
class HeapMap {
public:
virtual int find(object value) = 0;
virtual void dispose() = 0;
};
class HeapVisitor {
public:
virtual void root() = 0;
virtual unsigned visitNew(object value) = 0;
virtual void visitOld(object value, unsigned number) = 0;
virtual void push(object parent, unsigned parentNumber,
unsigned childOffset) = 0;
virtual void pop() = 0;
};
class HeapWalker {
public:
virtual unsigned visitRoot(object root) = 0;
virtual void visitAllRoots() = 0;
virtual HeapMap* map() = 0;
virtual void dispose() = 0;
};
HeapWalker*
makeHeapWalker(Thread* t, HeapVisitor* v);
} // namespace vm
#endif//HEAPWALK_H

View File

@ -1452,7 +1452,10 @@ interpret(Thread* t)
object field = resolveField(t, codePool(t, code), index - 1);
if (UNLIKELY(exception)) goto throw_;
if (throwIfVolatileField(t, field)) goto throw_;
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
pushField(t, popObject(t), field);
} else {
exception = makeNullPointerException(t);
@ -1465,6 +1468,10 @@ interpret(Thread* t)
object field = resolveField(t, codePool(t, code), index - 1);
if (UNLIKELY(exception)) goto throw_;
if (throwIfVolatileField(t, field)) goto throw_;
assert(t, fieldFlags(t, field) & ACC_STATIC);
PROTECT(t, field);
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
@ -2396,6 +2403,9 @@ interpret(Thread* t)
object field = resolveField(t, codePool(t, code), index - 1);
if (UNLIKELY(exception)) goto throw_;
if (throwIfVolatileField(t, field)) goto throw_;
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
switch (fieldCode(t, field)) {
case ByteField:
@ -2461,6 +2471,10 @@ interpret(Thread* t)
object field = resolveField(t, codePool(t, code), index - 1);
if (UNLIKELY(exception)) goto throw_;
if (throwIfVolatileField(t, field)) goto throw_;
assert(t, fieldFlags(t, field) & ACC_STATIC);
PROTECT(t, field);
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
@ -2876,7 +2890,7 @@ class MyProcessor: public Processor {
{
return vm::makeMethod
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
offset, name, spec, class_, code, 0);
offset, 0, name, spec, class_, code, 0);
}
virtual object
@ -3056,6 +3070,32 @@ class MyProcessor: public Processor {
return 0;
}
virtual void compileThunks(vm::Thread*, BootImage*, uint8_t*, unsigned*,
unsigned)
{
abort(s);
}
virtual void compileMethod(vm::Thread*, Zone*, uint8_t*, unsigned*, unsigned,
object*, object*, DelayedPromise**, object)
{
abort(s);
}
virtual void visitRoots(BootImage*, HeapWalker*) {
abort(s);
}
virtual unsigned* makeCallTable(vm::Thread*, BootImage*, HeapWalker*,
uint8_t*)
{
abort(s);
}
virtual void boot(vm::Thread*, BootImage* image) {
expect(s, image == 0);
}
virtual void dispose(vm::Thread* t) {
t->m->heap->free(t, sizeof(Thread));
}

View File

@ -248,38 +248,6 @@ walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
}
}
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start)
{
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
object objectMask = static_cast<object>
(t->m->heap->follow(classObjectMask(t, class_)));
if (objectMask) {
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
uint32_t mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
} else if (classVmFlags(t, class_) & SingletonFlag) {
unsigned length = singletonLength(t, o);
if (length) {
walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
} else if (start == 0) {
w->visit(0);
}
} else if (start == 0) {
w->visit(0);
}
}
void
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
{
@ -867,10 +835,6 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
staticTypes[staticCount++] = code;
} else {
if (value) {
abort(t); // todo: handle non-static field initializers
}
unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord;
if (excess) {
memberOffset += BytesPerWord - excess;
@ -1534,6 +1498,88 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name,
hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash);
}
void
boot(Thread* t)
{
Machine* m = t->m;
m->unsafe = true;
m->loader = allocate(t, sizeof(void*) * 3, true);
memset(m->loader, 0, sizeof(void*) * 2);
m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
arrayLength(t, m->types) = TypeCount;
memset(&arrayBody(t, m->types, 0), 0, TypeCount * BytesPerWord);
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, m->types, Machine::ArrayType);
set(t, m->types, 0, arrayClass);
object loaderClass = arrayBody
(t, m->types, Machine::SystemClassLoaderType);
set(t, m->loader, 0, loaderClass);
object objectClass = arrayBody(t, m->types, Machine::JobjectType);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, classClass, 0, classClass);
set(t, classClass, ClassSuper, objectClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, intArrayClass, 0, classClass);
set(t, intArrayClass, ClassSuper, objectClass);
m->unsafe = false;
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|= SingletonFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|= ReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JcharType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JshortType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JintType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JlongType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType))
|= PrimitiveFlag;
m->bootstrapClassMap = makeHashMap(t, 0, 0);
m->classMap = makeHashMap(t, 0, 0);
m->stringMap = makeWeakHashMap(t, 0, 0);
m->processor->boot(t, 0);
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1, false);
codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
PROTECT(t, bootMethod);
#include "type-java-initializations.cpp"
}
}
class HeapClient: public Heap::Client {
public:
HeapClient(Machine* m): m(m) { }
@ -1648,6 +1694,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
referenceLock(0),
libraries(0),
loader(0),
classMap(0),
bootstrapClassMap(0),
monitorMap(0),
stringMap(0),
@ -1748,86 +1795,32 @@ Thread::init()
abort(this);
}
Thread* t = this;
BootImage* image = 0;
const char* imageFunctionName = findProperty(m, "avian.bootimage");
if (imageFunctionName) {
void* p = m->libraries->resolve(imageFunctionName);
if (p) {
BootImage* (*function)(unsigned*);
memcpy(&function, &p, BytesPerWord);
t->m->loader = allocate(t, sizeof(void*) * 3, true);
memset(t->m->loader, 0, sizeof(void*) * 2);
t->m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
arrayLength(t, t->m->types) = TypeCount;
memset(&arrayBody(t, t->m->types, 0), 0, TypeCount * BytesPerWord);
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, t->m->types, Machine::ArrayType);
set(t, t->m->types, 0, arrayClass);
object loaderClass = arrayBody
(t, t->m->types, Machine::SystemClassLoaderType);
set(t, t->m->loader, 0, loaderClass);
object objectClass = arrayBody(t, m->types, Machine::JobjectType);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, classClass, 0, classClass);
set(t, classClass, ClassSuper, objectClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, intArrayClass, 0, classClass);
set(t, intArrayClass, ClassSuper, objectClass);
unsigned size;
image = function(&size);
}
}
m->unsafe = false;
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|= SingletonFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|= ReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JcharType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JshortType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JintType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JlongType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType))
|= PrimitiveFlag;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
{ object loaderMap = makeHashMap(this, 0, 0);
set(t, m->loader, SystemClassLoaderMap, loaderMap);
if (image) {
m->processor->boot(this, image);
} else {
boot(this);
}
m->monitorMap = makeWeakHashMap(this, 0, 0);
m->stringMap = makeWeakHashMap(this, 0, 0);
m->jniMethodTable = makeVector(this, 0, 0, false);
m->localThread->set(this);
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1, false);
codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
PROTECT(t, bootMethod);
#include "type-java-initializations.cpp"
}
} else {
peer = parent->child;
parent->child = this;
@ -2108,7 +2101,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
case Machine::ImmortalAllocation: {
unsigned total;
object o = static_cast<object>
(t->m->heap->allocateImmortal
(t->m->heap->allocateImmortalFixed
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
cast<uintptr_t>(o, 0) = FixedMark;
@ -2329,8 +2322,7 @@ findLoadedClass(Thread* t, object spec)
PROTECT(t, spec);
ACQUIRE(t, t->m->classLock);
return hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
spec, byteArrayHash, byteArrayEqual);
return hashMapFind(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual);
}
object
@ -2434,8 +2426,9 @@ resolveClass(Thread* t, object spec)
PROTECT(t, spec);
ACQUIRE(t, t->m->classLock);
object class_ = hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
spec, byteArrayHash, byteArrayEqual);
object class_ = hashMapFind
(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual);
if (class_ == 0) {
if (byteArrayBody(t, spec, 0) == '[') {
class_ = hashMapFind
@ -2487,8 +2480,7 @@ resolveClass(Thread* t, object spec)
if (class_) {
PROTECT(t, class_);
hashMapInsert(t, systemClassLoaderMap(t, t->m->loader),
spec, class_, byteArrayHash);
hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash);
} else if (t->exception == 0) {
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
t->exception = makeClassNotFoundException(t, message);
@ -2770,6 +2762,38 @@ collect(Thread* t, Heap::CollectionType type)
#endif
}
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start)
{
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
object objectMask = static_cast<object>
(t->m->heap->follow(classObjectMask(t, class_)));
if (objectMask) {
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
uint32_t mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
::walk(t, w, mask, fixedSize, arrayElementSize, arrayLength, start);
} else if (classVmFlags(t, class_) & SingletonFlag) {
unsigned length = singletonLength(t, o);
if (length) {
::walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
} else if (start == 0) {
w->visit(0);
}
} else if (start == 0) {
w->visit(0);
}
}
int
walkNext(Thread* t, object o, int previous)
{
@ -2793,6 +2817,7 @@ void
visitRoots(Machine* m, Heap::Visitor* v)
{
v->visit(&(m->loader));
v->visit(&(m->classMap));
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->monitorMap));
v->visit(&(m->stringMap));

View File

@ -1175,6 +1175,7 @@ class Machine {
System::Monitor* referenceLock;
System::Library* libraries;
object loader;
object classMap;
object bootstrapClassMap;
object monitorMap;
object stringMap;
@ -1449,6 +1450,35 @@ expect(Thread* t, bool v)
expect(t->m->system, v);
}
class FixedAllocator: public Allocator {
public:
FixedAllocator(Thread* t, uint8_t* base, unsigned capacity):
t(t), base(base), offset(0), capacity(capacity)
{ }
virtual void* tryAllocate(unsigned) {
abort(t);
}
virtual void* allocate(unsigned size) {
unsigned paddedSize = pad(size);
expect(t, offset + paddedSize < capacity);
void* p = base + offset;
offset += paddedSize;
return p;
}
virtual void free(const void*, unsigned) {
abort(t);
}
Thread* t;
uint8_t* base;
unsigned offset;
unsigned capacity;
};
inline void
ensure(Thread* t, unsigned sizeInBytes)
{
@ -2020,10 +2050,19 @@ resolveMethod(Thread* t, const char* className, const char* methodName,
object
resolveObjectArrayClass(Thread* t, object elementSpec);
inline bool
classNeedsInit(Thread* t, object c)
{
return classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0;
}
inline void
initClass(Thread* t, object c)
{
t->m->processor->initClass(t, c);
if (classNeedsInit(t, c)) {
t->m->processor->initClass(t, c);
}
}
object
@ -2225,6 +2264,9 @@ intern(Thread* t, object s);
void
exit(Thread* t);
void
walk(Thread* t, Heap::Walker* w, object o, unsigned start);
int
walkNext(Thread* t, object o, int previous);

View File

@ -79,11 +79,20 @@ main(int ac, const char** av)
++ vmArgs.nOptions;
#endif
#ifdef BOOT_IMAGE
++ vmArgs.nOptions;
#endif
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
unsigned optionIndex = 0;
#ifdef BOOT_IMAGE
options[optionIndex++].optionString
= const_cast<char*>("-Davian.bootimage=" BOOT_IMAGE);
#endif
#ifdef BOOT_CLASSPATH
options[optionIndex++].optionString
= const_cast<char*>("-Xbootclasspath:" BOOT_CLASSPATH);

View File

@ -26,6 +26,7 @@
#include "signal.h"
#include "ucontext.h"
#include "stdint.h"
#include "dirent.h"
#include "arch.h"
#include "system.h"
@ -428,6 +429,31 @@ class MySystem: public System {
size_t length_;
};
class Directory: public System::Directory {
public:
Directory(System* s, DIR* directory): s(s), directory(directory) { }
virtual const char* next() {
if (directory) {
dirent* e = readdir(directory);
if (e) {
return e->d_name;
}
}
return 0;
}
virtual void dispose() {
if (directory) {
closedir(directory);
}
s->free(this);
}
System* s;
DIR* directory;
};
class Library: public System::Library {
public:
Library(System* s, void* p, const char* name, unsigned nameLength,
@ -623,7 +649,7 @@ class MySystem: public System {
virtual Status map(System::Region** region, const char* name) {
Status status = 1;
int fd = open(name, O_RDONLY);
int fd = ::open(name, O_RDONLY);
if (fd != -1) {
struct stat s;
int r = fstat(fd, &s);
@ -641,19 +667,31 @@ class MySystem: public System {
return status;
}
virtual Status open(System::Directory** directory, const char* name) {
Status status = 1;
DIR* d = opendir(name);
if (d) {
*directory = new (allocate(this, sizeof(Directory))) Directory(this, d);
status = 0;
}
return status;
}
virtual FileType identify(const char* name) {
struct stat s;
int r = stat(name, &s);
if (r == 0) {
if (S_ISREG(s.st_mode)) {
return File;
return TypeFile;
} else if (S_ISDIR(s.st_mode)) {
return Directory;
return TypeDirectory;
} else {
return Unknown;
return TypeUnknown;
}
} else {
return DoesNotExist;
return TypeDoesNotExist;
}
}

View File

@ -188,6 +188,21 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
int
findLineNumber(Thread* t, object method, unsigned ip);
inline bool
throwIfVolatileField(Thread* t, object field)
{
if (fieldFlags(t, field) & ACC_VOLATILE) {
object message = makeString
(t, "volatile fields are not yet supported: %s.%s",
&byteArrayBody(t, className(t, fieldClass(t, field)), 0),
&byteArrayBody(t, fieldName(t, field), 0));
t->exception = makeNoSuchFieldError(t, message);
return true;
} else {
return false;
}
}
} // namespace vm
#endif//PROCESS_H

View File

@ -14,6 +14,10 @@
#include "common.h"
#include "system.h"
#include "heap.h"
#include "bootimage.h"
#include "heapwalk.h"
#include "zone.h"
#include "assembler.h"
namespace vm {
@ -112,6 +116,24 @@ class Processor {
virtual object
getStackTrace(Thread* t, Thread* target) = 0;
virtual void
compileThunks(Thread* t, BootImage* image, uint8_t* code, unsigned* size,
unsigned capacity) = 0;
virtual void
compileMethod(Thread* t, Zone* zone, uint8_t* code, unsigned* offset,
unsigned capacity, object* constants, object* calls,
DelayedPromise** addresses, object method) = 0;
virtual void
visitRoots(BootImage* image, HeapWalker* w) = 0;
virtual unsigned*
makeCallTable(Thread* t, BootImage* image, HeapWalker* w, uint8_t* code) = 0;
virtual void
boot(Thread* t, BootImage* image) = 0;
object
invoke(Thread* t, object method, object this_, ...)
{

View File

@ -20,10 +20,10 @@ class System {
typedef intptr_t Status;
enum FileType {
Unknown,
DoesNotExist,
File,
Directory
TypeUnknown,
TypeDoesNotExist,
TypeFile,
TypeDirectory
};
class Thread {
@ -79,6 +79,12 @@ class System {
virtual void dispose() = 0;
};
class Directory {
public:
virtual const char* next() = 0;
virtual void dispose() = 0;
};
class Library {
public:
virtual void* resolve(const char* function) = 0;
@ -128,6 +134,7 @@ class System {
unsigned returnType) = 0;
virtual Status map(Region**, const char* name) = 0;
virtual FileType identify(const char* name) = 0;
virtual Status open(Directory**, const char* name) = 0;
virtual Status load(Library**, const char* name, bool mapName) = 0;
virtual char pathSeparator() = 0;
virtual int64_t now() = 0;

View File

@ -106,6 +106,25 @@ cloneTreeNode(Thread* t, object n)
return newNode;
}
object
treeFind(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
object node = tree;
while (node != sentinal) {
intptr_t difference = compare(t, key, getTreeNodeValue(t, node));
if (difference < 0) {
node = treeNodeLeft(t, node);
} else if (difference > 0) {
node = treeNodeRight(t, node);
} else {
return node;
}
}
return 0;
}
void
treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node,
object sentinal,
@ -531,29 +550,20 @@ object
treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
object node = tree;
while (node != sentinal) {
intptr_t difference = compare(t, key, getTreeNodeValue(t, node));
if (difference < 0) {
node = treeNodeLeft(t, node);
} else if (difference > 0) {
node = treeNodeRight(t, node);
} else {
return getTreeNodeValue(t, node);
}
}
return 0;
object node = treeFind(t, tree, key, sentinal, compare);
return (node ? getTreeNodeValue(t, node) : 0);
}
object
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
PROTECT(t, tree);
PROTECT(t, sentinal);
object node = makeTreeNode(t, value, sentinal, sentinal);
TreeContext c(t, zone);
treeFind(t, &c, tree, key, node, sentinal, compare);
expect(t, c.fresh);
@ -561,4 +571,11 @@ treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
return treeAdd(t, &c);
}
void
treeUpdate(Thread* t, object tree, intptr_t key, object value, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b))
{
setTreeNodeValue(t, treeFind(t, tree, key, sentinal, compare), value);
}
} // namespace vm

View File

@ -89,9 +89,13 @@ treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
object
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value,
object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
void
treeUpdate(Thread* t, object tree, intptr_t key, object value, object sentinal,
intptr_t (*compare)(Thread* t, intptr_t key, object b));
class HashMapIterator: public Thread::Protector {
public:
@ -103,11 +107,13 @@ class HashMapIterator: public Thread::Protector {
void find() {
object array = hashMapArray(t, map);
for (unsigned i = index; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
node = arrayBody(t, array, i);
index = i + 1;
return;
if (array) {
for (unsigned i = index; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
node = arrayBody(t, array, i);
index = i + 1;
return;
}
}
}
node = 0;

View File

@ -11,6 +11,7 @@
#include "sys/stat.h"
#include "windows.h"
#include "sys/timeb.h"
#include "dirent.h"
#undef max
#undef min
@ -422,6 +423,31 @@ class MySystem: public System {
HANDLE file;
};
class Directory: public System::Directory {
public:
Directory(System* s, DIR* directory): s(s), directory(directory) { }
virtual const char* next() {
if (directory) {
dirent* e = readdir(directory);
if (e) {
return e->d_name;
}
}
return 0;
}
virtual void dispose() {
if (directory) {
closedir(directory);
}
s->free(this);
}
System* s;
DIR* directory;
};
class Library: public System::Library {
public:
Library(System* s, HMODULE handle, const char* name, bool mapName):
@ -630,19 +656,31 @@ class MySystem: public System {
return status;
}
virtual Status open(System::Directory** directory, const char* name) {
Status status = 1;
DIR* d = opendir(name);
if (d) {
*directory = new (allocate(this, sizeof(Directory))) Directory(this, d);
status = 0;
}
return status;
}
virtual FileType identify(const char* name) {
struct _stat s;
int r = _stat(name, &s);
if (r == 0) {
if (S_ISREG(s.st_mode)) {
return File;
return TypeFile;
} else if (S_ISDIR(s.st_mode)) {
return Directory;
return TypeDirectory;
} else {
return Unknown;
return TypeUnknown;
}
} else {
return DoesNotExist;
return TypeDoesNotExist;
}
}

View File

@ -221,6 +221,38 @@ class Task {
Task* next;
};
void*
resolveOffset(System* s, uint8_t* instruction, unsigned instructionSize,
int64_t value)
{
intptr_t v = reinterpret_cast<uint8_t*>(value)
- instruction - instructionSize;
expect(s, isInt32(v));
int32_t v4 = v;
memcpy(instruction + instructionSize - 4, &v4, 4);
return instruction + instructionSize;
}
class OffsetListener: public Promise::Listener {
public:
OffsetListener(System* s, uint8_t* instruction,
unsigned instructionSize):
s(s),
instruction(instruction),
instructionSize(instructionSize)
{ }
virtual void* resolve(int64_t value) {
return resolveOffset(s, instruction, instructionSize, value);
}
System* s;
uint8_t* instruction;
unsigned instructionSize;
};
class OffsetTask: public Task {
public:
OffsetTask(Task* next, Promise* promise, Promise* instructionOffset,
@ -232,14 +264,15 @@ class OffsetTask: public Task {
{ }
virtual void run(Context* c) {
uint8_t* instruction = c->result + instructionOffset->value();
intptr_t v = reinterpret_cast<uint8_t*>(promise->value())
- instruction - instructionSize;
expect(c, isInt32(v));
int32_t v4 = v;
memcpy(instruction + instructionSize - 4, &v4, 4);
if (promise->resolved()) {
resolveOffset
(c->s, c->result + instructionOffset->value(), instructionSize,
promise->value());
} else {
new (promise->listen(sizeof(OffsetListener)))
OffsetListener(c->s, c->result + instructionOffset->value(),
instructionSize);
}
}
Promise* promise;
@ -255,40 +288,70 @@ appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset,
(c->tasks, promise, instructionOffset, instructionSize);
}
void
copy(System* s, void* dst, int64_t src, unsigned size)
{
switch (size) {
case 4: {
int32_t v = src;
memcpy(dst, &v, 4);
} break;
case 8: {
int64_t v = src;
memcpy(dst, &v, 8);
} break;
default: abort(s);
}
}
class ImmediateListener: public Promise::Listener {
public:
ImmediateListener(System* s, void* dst, unsigned size, unsigned offset):
s(s), dst(dst), size(size), offset(offset)
{ }
virtual void* resolve(int64_t value) {
copy(s, dst, value, size);
return static_cast<uint8_t*>(dst) + offset;
}
System* s;
void* dst;
unsigned size;
unsigned offset;
};
class ImmediateTask: public Task {
public:
ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size):
ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size,
unsigned promiseOffset):
Task(next),
promise(promise),
offset(offset),
size(size)
size(size),
promiseOffset(promiseOffset)
{ }
virtual void run(Context* c) {
switch (size) {
case 4: {
int32_t v = promise->value();
memcpy(c->result + offset->value(), &v, size);
} break;
case 8: {
int64_t v = promise->value();
memcpy(c->result + offset->value(), &v, size);
} break;
default:
abort(c);
if (promise->resolved()) {
copy(c->s, c->result + offset->value(), promise->value(), size);
} else {
new (promise->listen(sizeof(ImmediateListener))) ImmediateListener
(c->s, c->result + offset->value(), size, promiseOffset);
}
}
Promise* promise;
Promise* offset;
unsigned size;
unsigned promiseOffset;
};
void
appendImmediateTask(Context* c, Promise* promise, Promise* offset,
unsigned size)
unsigned size, unsigned promiseOffset = 0)
{
c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask
(c->tasks, promise, offset, size);
@ -448,6 +511,39 @@ index(TernaryOperation operation,
* OperandTypeCount * operand2);
}
void
moveCR(Context* c, unsigned aSize, Assembler::Constant* a,
unsigned bSize, Assembler::Register* b);
void
moveCR2(Context*, unsigned, Assembler::Constant*, unsigned,
Assembler::Register*, unsigned);
void
callR(Context*, unsigned, Assembler::Register*);
void
callC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
{
assert(c, size == BytesPerWord);
unconditional(c, 0xe8, a);
}
void
longCallC(Context* c, unsigned size, Assembler::Constant* a)
{
assert(c, size == BytesPerWord);
if (BytesPerWord == 8) {
Assembler::Register r(r10);
moveCR2(c, size, a, size, &r, 11);
callR(c, size, &r);
} else {
callC(c, size, a);
}
}
void
jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a)
{
@ -466,6 +562,20 @@ jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
unconditional(c, 0xe9, a);
}
void
longJumpC(Context* c, unsigned size, Assembler::Constant* a)
{
assert(c, size == BytesPerWord);
if (BytesPerWord == 8) {
Assembler::Register r(r10);
moveCR2(c, size, a, &r, 11);
jumpR(c, size, &r);
} else {
jumpC(c, size, a);
}
}
void
jumpM(Context* c, unsigned size UNUSED, Assembler::Memory* a)
{
@ -536,7 +646,32 @@ longJumpC(Context* c, unsigned size, Assembler::Constant* a)
moveCR(c, size, a, size, &r);
jumpR(c, size, &r);
} else {
jumpC(c, size, a);
if (a->value->resolved()) {
int64_t v = a->value->value();
if (isInt8(v)) {
c->code.append(0x6a);
c->code.append(v);
} else if (isInt32(v)) {
c->code.append(0x68);
c->code.append4(v);
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, size, a, size, &tmp);
pushR(c, size, &tmp);
c->client->releaseTemporary(tmp.low);
}
} else {
if (BytesPerWord == 4) {
c->code.append(0x68);
appendImmediateTask(c, a->value, c->code.length(), BytesPerWord);
c->code.appendAddress(static_cast<uintptr_t>(0));
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, size, a, size, &tmp);
pushR(c, size, &tmp);
c->client->releaseTemporary(tmp.low);
}
}
}
}
@ -654,6 +789,43 @@ negateRR(Context* c, unsigned aSize, Assembler::Register* a,
negateR(c, aSize, a);
}
void
moveCR2(Context* c, unsigned, Assembler::Constant* a,
unsigned bSize, Assembler::Register* b, unsigned promiseOffset)
{
if (BytesPerWord == 4 and bSize == 8) {
int64_t v = a->value->value();
ResolvedPromise high((v >> 32) & 0xFFFFFFFF);
Assembler::Constant ah(&high);
ResolvedPromise low(v & 0xFFFFFFFF);
Assembler::Constant al(&low);
Assembler::Register bh(b->high);
moveCR(c, 4, &al, 4, b);
moveCR(c, 4, &ah, 4, &bh);
} else {
rex(c, 0x48, b->low);
c->code.append(0xb8 | b->low);
if (a->value->resolved()) {
c->code.appendAddress(a->value->value());
} else {
appendImmediateTask
(c, a->value, c->code.length(), BytesPerWord, promiseOffset);
c->code.appendAddress(static_cast<uintptr_t>(0));
}
}
}
void
moveCR(Context* c, unsigned aSize, Assembler::Constant* a,
unsigned bSize, Assembler::Register* b)
{
moveCR2(c, aSize, a, bSize, b, 0);
}
void
swapRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a,
unsigned bSize UNUSED, Assembler::Register* b)
@ -823,34 +995,6 @@ moveRM(Context* c, unsigned aSize, Assembler::Register* a,
}
}
// void
// moveMM(Context* c, unsigned aSize, Assembler::Memory* a,
// unsigned bSize, Assembler::Memory* b)
// {
// assert(c, aSize == bSize);
// if (BytesPerWord == 8 or aSize <= 4) {
// uint32_t mask;
// if (BytesPerWord == 4 and aSize == 1) {
// mask = (1 << rax) | (1 << rcx) | (1 << rdx) | (1 << rbx);
// } else {
// mask = ~static_cast<uint32_t>(0);
// }
// Assembler::Register tmp(c->client->acquireTemporary(mask));
// moveMR(c, aSize, a, aSize, &tmp);
// moveRM(c, aSize, &tmp, bSize, b);
// c->client->releaseTemporary(tmp.low);
// } else {
// Assembler::Register tmp(c->client->acquireTemporary(),
// c->client->acquireTemporary());
// moveMR(c, aSize, a, aSize, &tmp);
// moveRM(c, aSize, &tmp, bSize, b);
// c->client->releaseTemporary(tmp.low);
// c->client->releaseTemporary(tmp.high);
// }
// }
void
moveAR(Context* c, unsigned aSize, Assembler::Address* a,
unsigned bSize, Assembler::Register* b)
@ -864,18 +1008,6 @@ moveAR(Context* c, unsigned aSize, Assembler::Address* a,
moveMR(c, bSize, &memory, bSize, b);
}
// void
// moveAM(Context* c, unsigned aSize, Assembler::Address* a,
// unsigned bSize, Assembler::Memory* b)
// {
// assert(c, BytesPerWord == 8 or (aSize == 4 and bSize == 4));
// Assembler::Register tmp(c->client->acquireTemporary());
// moveAR(c, aSize, a, aSize, &tmp);
// moveRM(c, aSize, &tmp, bSize, b);
// c->client->releaseTemporary(tmp.low);
// }
void
moveCR(Context* c, unsigned, Assembler::Constant* a,
unsigned bSize, Assembler::Register* b)
@ -932,7 +1064,7 @@ moveCM(Context* c, unsigned aSize UNUSED, Assembler::Constant* a,
if (a->value->resolved()) {
c->code.append4(a->value->value());
} else {
appendImmediateTask(c, a->value, offset(c), 4);
appendImmediateTask(c, a->value, c->code.length(), 4);
c->code.append4(0);
}
break;
@ -1452,6 +1584,32 @@ multiplyRR(Context* c, unsigned aSize, Assembler::Register* a,
}
}
void
compareCR(Context* c, unsigned size, Assembler::Constant* a,
Assembler::Register* b)
{
assert(c, BytesPerWord == 8 or size == 4);
if (a->value->resolved() and isInt32(a->value->value())) {
int64_t v = a->value->value();
if (size == 8) rex(c);
if (isInt8(v)) {
c->code.append(0x83);
c->code.append(0xf8 | b->low);
c->code.append(v);
} else {
c->code.append(0x81);
c->code.append(0xf8 | b->low);
c->code.append4(v);
}
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, size, a, &tmp);
compareRR(c, size, &tmp, b);
c->client->releaseTemporary(tmp.high);
}
}
void
multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a,
unsigned bSize, Assembler::Register* b)
@ -1465,7 +1623,6 @@ multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a,
moveCR(c, aSize, a, aSize, &tmp);
multiplyRR(c, aSize, &tmp, bSize, b);
c->client->releaseTemporary(tmp.low);
c->client->releaseTemporary(tmp.high);
} else {
@ -1492,6 +1649,44 @@ multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a,
}
}
void
compareRM(Context* c, unsigned aSize, Assembler::Register* a,
unsigned bSize UNUSED, Assembler::Memory* b)
{
assert(c, aSize == bSize);
assert(c, BytesPerWord == 8 or aSize == 4);
if (BytesPerWord == 8 and aSize == 4) {
moveRR(c, 4, a, 8, a);
}
encode(c, 0x39, a->low, b, true);
}
void
compareCM(Context* c, unsigned aSize, Assembler::Constant* a,
unsigned bSize, Assembler::Memory* b)
{
assert(c, aSize == bSize);
assert(c, BytesPerWord == 8 or aSize == 4);
if (a->value->resolved()) {
encode(c, isInt8(v) ? 0x83 : 0x81, 7, b, true);
if (isInt8(v)) {
c->code.append(v);
} else if (isInt32(v)) {
c->code.append4(v);
} else {
abort(c);
}
} else {
Assembler::Register tmp(c->client->acquireTemporary());
moveCR(c, aSize, a, bSize, &tmp);
compareRM(c, bSize, &tmp, bSize, b);
c->client->releaseTemporary(tmp.low);
}
}
void
longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah,
Assembler::Operand* bl, Assembler::Operand* bh,
@ -1882,15 +2077,11 @@ populateTables(ArchitectureContext* c)
bo[index(Move, M, R)] = CAST2(moveMR);
bo[index(Move, R, M)] = CAST2(moveRM);
bo[index(Move, C, M)] = CAST2(moveCM);
// bo[index(Move, A, M)] = CAST2(moveAM);
bo[index(Move, A, R)] = CAST2(moveAR);
// bo[index(Move, M, M)] = CAST2(moveMM);
bo[index(MoveZ, R, R)] = CAST2(moveZRR);
bo[index(MoveZ, M, R)] = CAST2(moveZMR);
bo[index(Swap, R, R)] = CAST2(swapRR);
bo[index(Compare, R, R)] = CAST2(compareRR);
bo[index(Compare, C, R)] = CAST2(compareCR);
bo[index(Compare, C, M)] = CAST2(compareCM);
@ -1998,14 +2189,35 @@ class MyArchitecture: public Assembler::Architecture {
}
}
virtual void updateCall(void* returnAddress, void* newTarget) {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
assert(&c, *instruction == 0xE8);
assert(&c, reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
virtual void updateCall(UnaryOperation op UNUSED,
bool assertAlignment UNUSED, void* returnAddress,
void* newTarget)
{
if (BytesPerWord == 4 or op == Call or op == Jump) {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
int32_t v = static_cast<uint8_t*>(newTarget)
- static_cast<uint8_t*>(returnAddress);
memcpy(instruction + 1, &v, 4);
assert(&c, ((op == Call or op == LongCall) and *instruction == 0xE8)
or ((op == Jump or op == LongJump) and *instruction == 0xE9));
assert(&c, (not assertAlignment)
or reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
int32_t v = static_cast<uint8_t*>(newTarget)
- static_cast<uint8_t*>(returnAddress);
memcpy(instruction + 1, &v, 4);
} else {
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 13;
assert(&c, instruction[0] == 0x49 and instruction[1] == 0xBA);
assert(&c, instruction[10] == 0x41 and instruction[11] == 0xFF);
assert(&c, (op == LongCall and instruction[12] == 0xD2)
or (op == LongJump and instruction[12] == 0xE2));
assert(&c, (not assertAlignment)
or reinterpret_cast<uintptr_t>(instruction + 2) % 8 == 0);
memcpy(instruction + 2, &newTarget, 8);
}
}
virtual unsigned alignFrameSize(unsigned sizeInWords) {

View File

@ -3,6 +3,8 @@ public class Misc {
private static int beta;
private static byte byte1, byte2, byte3;
private final int NonStaticConstant = 42;
private int gamma;
private int pajama;
private boolean boolean1;
@ -108,6 +110,8 @@ public class Misc {
{ Misc m = new Misc();
m.toString();
expect(m.NonStaticConstant == 42);
expect(m.time == 0xffffffffffffffffL);
long t = m.time;
expect(t == 0xffffffffffffffffL);

1
vm.pro
View File

@ -50,6 +50,7 @@
-keep public class java.lang.ExceptionInInitializerError
-keep public class java.lang.OutOfMemoryError
-keep public class java.lang.reflect.InvocationTargetException
-keep public class java.io.IOException
# ClassLoader.getSystemClassloader() depends on the existence of this class: