mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
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:
commit
a1ec71423e
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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() { }
|
||||
|
||||
|
@ -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
105
makefile
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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]);
|
||||
|
30
src/boot.cpp
30
src/boot.cpp
@ -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
369
src/bootimage.cpp
Normal 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
82
src/bootimage.h
Normal 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
|
@ -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;
|
||||
|
||||
|
1384
src/compile.cpp
1384
src/compile.cpp
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
}
|
||||
|
142
src/finder.cpp
142
src/finder.cpp
@ -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);
|
||||
|
40
src/finder.h
40
src/finder.h
@ -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(¤tSize))
|
||||
{ }
|
||||
|
||||
~Iterator() {
|
||||
it->dispose();
|
||||
}
|
||||
|
||||
bool hasMore() {
|
||||
if (current) return true;
|
||||
current = it->next(¤tSize);
|
||||
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;
|
||||
|
266
src/heap.cpp
266
src/heap.cpp
@ -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)))
|
||||
|
@ -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;
|
||||
|
328
src/heapdump.cpp
328
src/heapdump.cpp
@ -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
341
src/heapwalk.cpp
Normal 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
49
src/heapwalk.h
Normal 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
|
@ -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));
|
||||
}
|
||||
|
249
src/machine.cpp
249
src/machine.cpp
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_, ...)
|
||||
{
|
||||
|
15
src/system.h
15
src/system.h
@ -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;
|
||||
|
49
src/util.cpp
49
src/util.cpp
@ -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
|
||||
|
22
src/util.h
22
src/util.h
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
368
src/x86.cpp
368
src/x86.cpp
@ -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) {
|
||||
|
@ -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
1
vm.pro
@ -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:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user