mirror of
https://github.com/corda/corda.git
synced 2025-01-06 05:04:20 +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
|
private static final String FileSeparator
|
||||||
= System.getProperty("file.separator");
|
= System.getProperty("file.separator");
|
||||||
|
|
||||||
|
public static final String separator = FileSeparator;
|
||||||
|
|
||||||
// static {
|
// static {
|
||||||
// System.loadLibrary("natives");
|
// System.loadLibrary("natives");
|
||||||
// }
|
// }
|
||||||
@ -157,7 +159,7 @@ public class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String[] result = new String[count];
|
String[] result = new String[count];
|
||||||
for (int i = count; i >= 0; --i) {
|
for (int i = count - 1; i >= 0; --i) {
|
||||||
result[i] = list.value;
|
result[i] = list.value;
|
||||||
list = list.next;
|
list = list.next;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,6 @@ import java.net.URL;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
|
||||||
public class SystemClassLoader extends ClassLoader {
|
public class SystemClassLoader extends ClassLoader {
|
||||||
private Object map;
|
|
||||||
|
|
||||||
protected native Class findClass(String name) throws ClassNotFoundException;
|
protected native Class findClass(String name) throws ClassNotFoundException;
|
||||||
|
|
||||||
protected native Class findLoadedClass(String name);
|
protected native Class findLoadedClass(String name);
|
||||||
|
@ -22,7 +22,7 @@ public class Method<T> extends AccessibleObject implements Member {
|
|||||||
private byte[] spec;
|
private byte[] spec;
|
||||||
private Class<T> class_;
|
private Class<T> class_;
|
||||||
private Object code;
|
private Object code;
|
||||||
private Object compiled;
|
private long compiled;
|
||||||
|
|
||||||
private Method() { }
|
private Method() { }
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ public abstract class Calendar {
|
|||||||
int hour = remainder / MILLIS_PER_HOUR;
|
int hour = remainder / MILLIS_PER_HOUR;
|
||||||
remainder = remainder % MILLIS_PER_HOUR;
|
remainder = remainder % MILLIS_PER_HOUR;
|
||||||
int minute = remainder / MILLIS_PER_MINUTE;
|
int minute = remainder / MILLIS_PER_MINUTE;
|
||||||
remainder = remainder / MILLIS_PER_MINUTE;
|
remainder = remainder % MILLIS_PER_MINUTE;
|
||||||
int second = remainder / MILLIS_PER_SECOND;
|
int second = remainder / MILLIS_PER_SECOND;
|
||||||
fields[YEAR] = year;
|
fields[YEAR] = year;
|
||||||
fields[MONTH] = month;
|
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 \
|
common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \
|
||||||
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
"-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \
|
||||||
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
-D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \
|
||||||
-DBOOT_CLASSPATH=\"[classpathJar]\"
|
|
||||||
|
|
||||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \
|
||||||
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
|
"-I$(JAVA_HOME)/include/linux" -I$(src) -pthread
|
||||||
@ -104,6 +103,9 @@ endif
|
|||||||
ifeq ($(platform),darwin)
|
ifeq ($(platform),darwin)
|
||||||
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src)
|
||||||
lflags = $(common-lflags) -ldl -framework CoreFoundation
|
lflags = $(common-lflags) -ldl -framework CoreFoundation
|
||||||
|
ifeq ($(bootimage),true)
|
||||||
|
bootimage-lflags = -Wl,-segprot,__BOOT,rwx,rwx
|
||||||
|
endif
|
||||||
rdynamic =
|
rdynamic =
|
||||||
strip-all = -S -x
|
strip-all = -S -x
|
||||||
binaryToMacho = $(native-build)/binaryToMacho
|
binaryToMacho = $(native-build)/binaryToMacho
|
||||||
@ -132,6 +134,7 @@ ifeq ($(platform),windows)
|
|||||||
ar = i586-mingw32msvc-ar
|
ar = i586-mingw32msvc-ar
|
||||||
ranlib = i586-mingw32msvc-ranlib
|
ranlib = i586-mingw32msvc-ranlib
|
||||||
objcopy = i586-mingw32msvc-objcopy
|
objcopy = i586-mingw32msvc-objcopy
|
||||||
|
strip = i586-mingw32msvc-strip
|
||||||
else
|
else
|
||||||
build-cflags = $(common-cflags) \
|
build-cflags = $(common-cflags) \
|
||||||
"-I$(JAVA_HOME)/include/win32" -I$(src) -mthreads
|
"-I$(JAVA_HOME)/include/win32" -I$(src) -mthreads
|
||||||
@ -159,11 +162,9 @@ ifeq ($(mode),stress-major)
|
|||||||
endif
|
endif
|
||||||
ifeq ($(mode),fast)
|
ifeq ($(mode),fast)
|
||||||
cflags += -O3 -g3 -DNDEBUG
|
cflags += -O3 -g3 -DNDEBUG
|
||||||
strip = strip
|
|
||||||
endif
|
endif
|
||||||
ifeq ($(mode),small)
|
ifeq ($(mode),small)
|
||||||
cflags += -Os -g3 -DNDEBUG
|
cflags += -Os -g3 -DNDEBUG
|
||||||
strip = strip
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x)))
|
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x)))
|
||||||
@ -198,6 +199,8 @@ vm-depends = \
|
|||||||
$(src)/assembler.h \
|
$(src)/assembler.h \
|
||||||
$(src)/compiler.h \
|
$(src)/compiler.h \
|
||||||
$(src)/$(asm).h
|
$(src)/$(asm).h
|
||||||
|
$(src)/heapwalk.h \
|
||||||
|
$(src)/bootimage.h
|
||||||
|
|
||||||
vm-sources = \
|
vm-sources = \
|
||||||
$(src)/$(system).cpp \
|
$(src)/$(system).cpp \
|
||||||
@ -211,11 +214,6 @@ vm-sources = \
|
|||||||
$(src)/process.cpp \
|
$(src)/process.cpp \
|
||||||
$(src)/$(asm).cpp
|
$(src)/$(asm).cpp
|
||||||
|
|
||||||
ifeq ($(heapdump),true)
|
|
||||||
vm-sources += $(src)/heapdump.cpp
|
|
||||||
cflags += -DAVIAN_HEAPDUMP
|
|
||||||
endif
|
|
||||||
|
|
||||||
vm-asm-sources = $(src)/$(asm).S
|
vm-asm-sources = $(src)/$(asm).S
|
||||||
|
|
||||||
ifeq ($(process),compile)
|
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-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build))
|
||||||
vm-objects = $(vm-cpp-objects) $(vm-asm-objects)
|
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-source = $(src)/main.cpp
|
||||||
driver-object = $(native-build)/main.o
|
driver-object = $(native-build)/main.o
|
||||||
driver-dynamic-object = $(native-build)/main-dynamic.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
|
$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S
|
||||||
$(compile-asm-object)
|
$(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)
|
$(driver-object): $(driver-source)
|
||||||
$(compile-object)
|
$(compile-object)
|
||||||
|
|
||||||
@ -381,7 +416,7 @@ $(binaryToMacho): $(src)/binaryToMacho.cpp
|
|||||||
$(classpath-object): $(build)/classpath.jar $(binaryToMacho)
|
$(classpath-object): $(build)/classpath.jar $(binaryToMacho)
|
||||||
@echo "creating $(@)"
|
@echo "creating $(@)"
|
||||||
ifeq ($(platform),darwin)
|
ifeq ($(platform),darwin)
|
||||||
$(binaryToMacho) $(asm) $(build)/classpath.jar \
|
$(binaryToMacho) $(asm) $(build)/classpath.jar __TEXT __text \
|
||||||
__binary_classpath_jar_start __binary_classpath_jar_end > $(@)
|
__binary_classpath_jar_start __binary_classpath_jar_end > $(@)
|
||||||
else
|
else
|
||||||
(wd=$$(pwd); \
|
(wd=$$(pwd); \
|
||||||
@ -399,15 +434,54 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp
|
|||||||
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
|
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
|
||||||
$(compile-object)
|
$(compile-object)
|
||||||
|
|
||||||
$(static-library): $(vm-objects) $(jni-objects)
|
$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects)
|
||||||
@echo "creating $(@)"
|
@echo "creating $(@)"
|
||||||
rm -rf $(@)
|
rm -rf $(@)
|
||||||
$(ar) cru $(@) $(^)
|
$(ar) cru $(@) $(^)
|
||||||
$(ranlib) $(@)
|
$(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): \
|
$(executable): \
|
||||||
$(vm-objects) $(classpath-object) $(jni-objects) $(driver-object) \
|
$(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \
|
||||||
$(boot-object)
|
$(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 $(@)"
|
@echo "linking $(@)"
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
$(dlltool) -z $(@).def $(^)
|
$(dlltool) -z $(@).def $(^)
|
||||||
@ -416,13 +490,12 @@ ifeq ($(platform),windows)
|
|||||||
else
|
else
|
||||||
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
|
$(cc) $(^) $(rdynamic) $(lflags) -o $(@)
|
||||||
endif
|
endif
|
||||||
$(strip) $(strip-all) $(@)
|
|
||||||
|
|
||||||
$(dynamic-library): \
|
$(dynamic-library): \
|
||||||
$(vm-objects) $(classpath-object) $(dynamic-object) $(jni-objects) \
|
$(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \
|
||||||
$(boot-object)
|
$(boot-object) $(vm-classpath-object)
|
||||||
@echo "linking $(@)"
|
@echo "linking $(@)"
|
||||||
$(cc) $(^) $(shared) $(lflags) -o $(@)
|
$(cc) $(^) $(shared) $(lflags) $(bootimage-lflags) -o $(@)
|
||||||
$(strip) $(strip-all) $(@)
|
$(strip) $(strip-all) $(@)
|
||||||
|
|
||||||
$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library)
|
$(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)
|
so we use the binaryToMacho utility instead)
|
||||||
|
|
||||||
$ ../build/darwin-i386-compile-fast/binaryToMacho boot.jar \
|
$ ../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
|
Step 4: Write a driver which starts the VM and runs the desired main
|
||||||
|
@ -78,8 +78,16 @@ const int NoRegister = -1;
|
|||||||
|
|
||||||
class Promise {
|
class Promise {
|
||||||
public:
|
public:
|
||||||
|
class Listener {
|
||||||
|
public:
|
||||||
|
virtual void* resolve(int64_t value) = 0;
|
||||||
|
|
||||||
|
Listener* next;
|
||||||
|
};
|
||||||
|
|
||||||
virtual int64_t value() = 0;
|
virtual int64_t value() = 0;
|
||||||
virtual bool resolved() = 0;
|
virtual bool resolved() = 0;
|
||||||
|
virtual Listener* listen(unsigned) { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResolvedPromise: public Promise {
|
class ResolvedPromise: public Promise {
|
||||||
@ -134,6 +142,59 @@ class CombinedPromise: public Promise {
|
|||||||
Promise* high;
|
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 {
|
class TraceHandler {
|
||||||
public:
|
public:
|
||||||
virtual void handleTrace(Promise* address, unsigned padIndex,
|
virtual void handleTrace(Promise* address, unsigned padIndex,
|
||||||
@ -209,7 +270,8 @@ class Assembler {
|
|||||||
virtual unsigned argumentRegisterCount() = 0;
|
virtual unsigned argumentRegisterCount() = 0;
|
||||||
virtual int argumentRegister(unsigned index) = 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;
|
virtual unsigned alignFrameSize(unsigned sizeInWords) = 0;
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ pad(unsigned n)
|
|||||||
void
|
void
|
||||||
writeObject(const char* architecture,
|
writeObject(const char* architecture,
|
||||||
FILE* out, const uint8_t* data, unsigned size,
|
FILE* out, const uint8_t* data, unsigned size,
|
||||||
|
const char* segmentName, const char* sectionName,
|
||||||
const char* startName, const char* endName)
|
const char* startName, const char* endName)
|
||||||
{
|
{
|
||||||
unsigned startNameLength = strlen(startName) + 1;
|
unsigned startNameLength = strlen(startName) + 1;
|
||||||
@ -63,7 +64,7 @@ writeObject(const char* architecture,
|
|||||||
segment_command segment = {
|
segment_command segment = {
|
||||||
LC_SEGMENT, // cmd
|
LC_SEGMENT, // cmd
|
||||||
sizeof(segment_command) + sizeof(section), // cmdsize
|
sizeof(segment_command) + sizeof(section), // cmdsize
|
||||||
"__TEXT", // segname
|
"", // segname
|
||||||
0, // vmaddr
|
0, // vmaddr
|
||||||
pad(size), // vmsize
|
pad(size), // vmsize
|
||||||
sizeof(mach_header)
|
sizeof(mach_header)
|
||||||
@ -77,9 +78,11 @@ writeObject(const char* architecture,
|
|||||||
0 // flags
|
0 // flags
|
||||||
};
|
};
|
||||||
|
|
||||||
|
strncpy(segment.segname, segmentName, sizeof(segment.segname));
|
||||||
|
|
||||||
section sect = {
|
section sect = {
|
||||||
"__const", // sectname
|
"", // sectname
|
||||||
"__TEXT", // segname
|
"", // segname
|
||||||
0, // addr
|
0, // addr
|
||||||
pad(size), // size
|
pad(size), // size
|
||||||
sizeof(mach_header)
|
sizeof(mach_header)
|
||||||
@ -94,6 +97,9 @@ writeObject(const char* architecture,
|
|||||||
0, // reserved2
|
0, // reserved2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
strncpy(sect.segname, segmentName, sizeof(sect.segname));
|
||||||
|
strncpy(sect.sectname, sectionName, sizeof(sect.sectname));
|
||||||
|
|
||||||
symtab_command symbolTable = {
|
symtab_command symbolTable = {
|
||||||
LC_SYMTAB, // cmd
|
LC_SYMTAB, // cmd
|
||||||
sizeof(symtab_command), // cmdsize
|
sizeof(symtab_command), // cmdsize
|
||||||
@ -149,10 +155,10 @@ writeObject(const char* architecture,
|
|||||||
int
|
int
|
||||||
main(int argc, const char** argv)
|
main(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
if (argc != 5) {
|
if (argc != 7) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s <architecture> <input file> <start symbol name> "
|
"usage: %s <architecture> <input file> <segment name> "
|
||||||
"<end symbol name>\n",
|
"<section name> <start symbol name> <end symbol name>\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -172,8 +178,11 @@ main(int argc, const char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data) {
|
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);
|
munmap(data, size);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
perror(argv[0]);
|
perror(argv[0]);
|
||||||
|
30
src/boot.cpp
30
src/boot.cpp
@ -15,6 +15,34 @@
|
|||||||
// ourselves:
|
// ourselves:
|
||||||
extern "C" void __cxa_pure_virtual(void) { abort(); }
|
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__
|
#ifdef __MINGW32__
|
||||||
# define EXPORT __declspec(dllexport)
|
# define EXPORT __declspec(dllexport)
|
||||||
# define SYMBOL(x) binary_classpath_jar_##x
|
# 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);
|
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 Machine;
|
||||||
class Thread;
|
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;
|
int i = 0;
|
||||||
for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) {
|
for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) {
|
||||||
*reinterpret_cast<intptr_t*>(dst + pad(c.machineCodeSize) + i)
|
intptr_t* target = reinterpret_cast<intptr_t*>
|
||||||
= n->promise->value();
|
(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;
|
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 {
|
class Element {
|
||||||
public:
|
public:
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
virtual const char* next(unsigned* size) = 0;
|
||||||
|
virtual void dispose() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
Element(): next(0) { }
|
Element(): next(0) { }
|
||||||
|
|
||||||
|
virtual Iterator* iterator() = 0;
|
||||||
virtual System::Region* find(const char* name) = 0;
|
virtual System::Region* find(const char* name) = 0;
|
||||||
virtual bool exists(const char* name) = 0;
|
virtual bool exists(const char* name) = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
@ -62,10 +69,71 @@ class Element {
|
|||||||
|
|
||||||
class DirectoryElement: public Element {
|
class DirectoryElement: public Element {
|
||||||
public:
|
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):
|
DirectoryElement(System* s, const char* name):
|
||||||
s(s), name(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) {
|
virtual System::Region* find(const char* name) {
|
||||||
const char* file = append(s, this->name, "/", name);
|
const char* file = append(s, this->name, "/", name);
|
||||||
System::Region* region;
|
System::Region* region;
|
||||||
@ -83,7 +151,7 @@ class DirectoryElement: public Element {
|
|||||||
const char* file = append(s, this->name, "/", name);
|
const char* file = append(s, this->name, "/", name);
|
||||||
System::FileType type = s->identify(file);
|
System::FileType type = s->identify(file);
|
||||||
s->free(file);
|
s->free(file);
|
||||||
return type != System::DoesNotExist;
|
return type != System::TypeDoesNotExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
@ -371,10 +439,39 @@ class JarIndex {
|
|||||||
|
|
||||||
class JarElement: public Element {
|
class JarElement: public Element {
|
||||||
public:
|
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):
|
JarElement(System* s, const char* name):
|
||||||
s(s), name(name), region(0), index(0)
|
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() {
|
virtual void init() {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
System::Region* r;
|
System::Region* r;
|
||||||
@ -504,11 +601,11 @@ parsePath(System* s, const char* path, const char* bootLibrary)
|
|||||||
name[token.length] = 0;
|
name[token.length] = 0;
|
||||||
|
|
||||||
switch (s->identify(name)) {
|
switch (s->identify(name)) {
|
||||||
case System::File: {
|
case System::TypeFile: {
|
||||||
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name);
|
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case System::Directory: {
|
case System::TypeDirectory: {
|
||||||
e = new (allocate(s, sizeof(DirectoryElement)))
|
e = new (allocate(s, sizeof(DirectoryElement)))
|
||||||
DirectoryElement(s, name);
|
DirectoryElement(s, name);
|
||||||
} break;
|
} break;
|
||||||
@ -533,6 +630,40 @@ parsePath(System* s, const char* path, const char* bootLibrary)
|
|||||||
return first;
|
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 {
|
class MyFinder: public Finder {
|
||||||
public:
|
public:
|
||||||
MyFinder(System* system, const char* path, const char* bootLibrary):
|
MyFinder(System* system, const char* path, const char* bootLibrary):
|
||||||
@ -541,6 +672,11 @@ class MyFinder: public Finder {
|
|||||||
pathString(copy(system, path))
|
pathString(copy(system, path))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
virtual IteratorImp* iterator() {
|
||||||
|
return new (allocate(system, sizeof(MyIterator)))
|
||||||
|
MyIterator(system, path_);
|
||||||
|
}
|
||||||
|
|
||||||
virtual System::Region* find(const char* name) {
|
virtual System::Region* find(const char* name) {
|
||||||
for (Element* e = path_; e; e = e->next) {
|
for (Element* e = path_; e; e = e->next) {
|
||||||
System::Region* r = e->find(name);
|
System::Region* r = e->find(name);
|
||||||
|
40
src/finder.h
40
src/finder.h
@ -19,6 +19,46 @@ namespace vm {
|
|||||||
|
|
||||||
class Finder {
|
class Finder {
|
||||||
public:
|
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 System::Region* find(const char* name) = 0;
|
||||||
virtual bool exists(const char* name) = 0;
|
virtual bool exists(const char* name) = 0;
|
||||||
virtual const char* path() = 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);
|
for (; word <= wordLimit and (word < wordLimit or bit < bitLimit);
|
||||||
++word)
|
++word)
|
||||||
{
|
{
|
||||||
uintptr_t* p = map->data() + word;
|
uintptr_t w = map->data[word];
|
||||||
if (*p) {
|
if (2) {
|
||||||
for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit);
|
for (; bit < BitsPerWord and (word < wordLimit or bit < bitLimit);
|
||||||
++bit)
|
++bit)
|
||||||
{
|
{
|
||||||
if (map->data()[word] & (static_cast<uintptr_t>(1) << bit)) {
|
if (w & (static_cast<uintptr_t>(1) << bit)) {
|
||||||
index = ::indexOf(word, bit);
|
index = ::indexOf(word, bit);
|
||||||
// printf("hit at index %d\n", index);
|
// printf("hit at index %d\n", index);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} 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;
|
Segment* segment;
|
||||||
Map* child;
|
Map* child;
|
||||||
|
uintptr_t* data;
|
||||||
unsigned bitsPerRecord;
|
unsigned bitsPerRecord;
|
||||||
unsigned scale;
|
unsigned scale;
|
||||||
bool clearNewData;
|
bool clearNewData;
|
||||||
|
|
||||||
Map(Segment* segment, unsigned bitsPerRecord, unsigned scale,
|
Map(Segment* segment, uintptr_t* data, unsigned bitsPerRecord,
|
||||||
Map* child, bool clearNewData):
|
unsigned scale, Map* child, bool clearNewData):
|
||||||
segment(segment),
|
segment(segment),
|
||||||
child(child),
|
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),
|
bitsPerRecord(bitsPerRecord),
|
||||||
scale(scale),
|
scale(scale),
|
||||||
clearNewData(clearNewData)
|
clearNewData(clearNewData)
|
||||||
@ -171,8 +183,13 @@ class Segment {
|
|||||||
assert(segment->context, scale);
|
assert(segment->context, scale);
|
||||||
assert(segment->context, powerOfTwo(scale));
|
assert(segment->context, powerOfTwo(scale));
|
||||||
|
|
||||||
|
if (data == 0) {
|
||||||
|
data = segment->data + segment->capacity()
|
||||||
|
+ calculateOffset(segment->capacity());
|
||||||
|
}
|
||||||
|
|
||||||
if (clearNewData) {
|
if (clearNewData) {
|
||||||
memset(data(), 0, size() * BytesPerWord);
|
memset(data, 0, size() * BytesPerWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child) {
|
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) {
|
void replaceWith(Map* m) {
|
||||||
assert(segment->context, bitsPerRecord == m->bitsPerRecord);
|
assert(segment->context, bitsPerRecord == m->bitsPerRecord);
|
||||||
assert(segment->context, scale == m->scale);
|
assert(segment->context, scale == m->scale);
|
||||||
|
|
||||||
|
data = m->data;
|
||||||
|
|
||||||
m->segment = 0;
|
m->segment = 0;
|
||||||
|
m->data = 0;
|
||||||
|
|
||||||
if (child) child->replaceWith(m->child);
|
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) {
|
unsigned indexOf(unsigned segmentIndex) {
|
||||||
return (segmentIndex / scale) * bitsPerRecord;
|
return (segmentIndex / scale) * bitsPerRecord;
|
||||||
}
|
}
|
||||||
@ -224,33 +248,20 @@ class Segment {
|
|||||||
return indexOf(segment->indexOf(p));
|
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) {
|
void clearBit(unsigned i) {
|
||||||
assert(segment->context, wordOf(i) < size());
|
assert(segment->context, wordOf(i) < size());
|
||||||
|
|
||||||
vm::clearBit(data(), i);
|
vm::clearBit(data, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBit(unsigned i) {
|
void setBit(unsigned i) {
|
||||||
assert(segment->context, wordOf(i) < size());
|
assert(segment->context, wordOf(i) < size());
|
||||||
|
|
||||||
vm::markBit(data(), i);
|
vm::markBit(data, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearOnlyIndex(unsigned index) {
|
void clearOnlyIndex(unsigned index) {
|
||||||
clearBits(data(), bitsPerRecord, index);
|
clearBits(data, bitsPerRecord, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearOnly(unsigned segmentIndex) {
|
void clearOnly(unsigned segmentIndex) {
|
||||||
@ -267,7 +278,7 @@ class Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setOnlyIndex(unsigned index, unsigned v = 1) {
|
void setOnlyIndex(unsigned index, unsigned v = 1) {
|
||||||
setBits(data(), bitsPerRecord, index, v);
|
setBits(data, bitsPerRecord, index, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOnly(unsigned segmentIndex, unsigned v = 1) {
|
void setOnly(unsigned segmentIndex, unsigned v = 1) {
|
||||||
@ -285,13 +296,7 @@ class Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned get(void* p) {
|
unsigned get(void* p) {
|
||||||
return getBits(data(), bitsPerRecord, indexOf(p));
|
return getBits(data, bitsPerRecord, indexOf(p));
|
||||||
}
|
|
||||||
|
|
||||||
unsigned footprint(unsigned capacity) {
|
|
||||||
unsigned n = size(capacity);
|
|
||||||
if (child) n += child->footprint(capacity);
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -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) {
|
unsigned footprint(unsigned capacity) {
|
||||||
return capacity + (map and capacity ? map->footprint(capacity) : 0);
|
return capacity
|
||||||
|
+ (map and capacity ? map->calculateFootprint(capacity) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned capacity() {
|
unsigned capacity() {
|
||||||
@ -411,15 +430,18 @@ class Segment {
|
|||||||
|
|
||||||
class Fixie {
|
class Fixie {
|
||||||
public:
|
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),
|
age(immortal ? FixieTenureThreshold + 1 : 0),
|
||||||
hasMask(hasMask),
|
hasMask(hasMask),
|
||||||
marked(false),
|
marked(false),
|
||||||
dirty(false),
|
dirty(false),
|
||||||
size(size)
|
size(size),
|
||||||
|
next(0),
|
||||||
|
handle(0)
|
||||||
{
|
{
|
||||||
memset(mask(), 0, maskSize(size, hasMask));
|
memset(mask(), 0, maskSize(size, hasMask));
|
||||||
add(handle);
|
add(c, handle);
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "make fixie %p of size %d\n", this, totalSize());
|
fprintf(stderr, "make fixie %p of size %d\n", this, totalSize());
|
||||||
}
|
}
|
||||||
@ -429,7 +451,10 @@ class Fixie {
|
|||||||
return age == FixieTenureThreshold + 1;
|
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;
|
this->handle = handle;
|
||||||
if (handle) {
|
if (handle) {
|
||||||
next = *handle;
|
next = *handle;
|
||||||
@ -440,18 +465,25 @@ class Fixie {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove() {
|
void remove(Context* c UNUSED) {
|
||||||
if (handle) *handle = next;
|
if (handle) {
|
||||||
if (next) next->handle = 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) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "move fixie %p\n", this);
|
fprintf(stderr, "move fixie %p\n", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove();
|
remove(c);
|
||||||
add(handle);
|
add(c, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void** body() {
|
void** body() {
|
||||||
@ -502,6 +534,9 @@ class Context {
|
|||||||
limit(limit),
|
limit(limit),
|
||||||
lowMemoryThreshold(limit / 2),
|
lowMemoryThreshold(limit / 2),
|
||||||
lock(0),
|
lock(0),
|
||||||
|
|
||||||
|
immortalHeapStart(0),
|
||||||
|
immortalHeapEnd(0),
|
||||||
|
|
||||||
ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false),
|
ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false),
|
||||||
gen1(this, &ageMap, 0, 0),
|
gen1(this, &ageMap, 0, 0),
|
||||||
@ -571,7 +606,10 @@ class Context {
|
|||||||
unsigned lowMemoryThreshold;
|
unsigned lowMemoryThreshold;
|
||||||
|
|
||||||
System::Mutex* lock;
|
System::Mutex* lock;
|
||||||
|
|
||||||
|
uintptr_t* immortalHeapStart;
|
||||||
|
uintptr_t* immortalHeapEnd;
|
||||||
|
|
||||||
Segment::Map ageMap;
|
Segment::Map ageMap;
|
||||||
Segment gen1;
|
Segment gen1;
|
||||||
|
|
||||||
@ -690,7 +728,7 @@ inline void
|
|||||||
initNextGen1(Context* c)
|
initNextGen1(Context* c)
|
||||||
{
|
{
|
||||||
new (&(c->nextAgeMap)) Segment::Map
|
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 minimum = minimumNextGen1Capacity(c);
|
||||||
unsigned desired = minimum;
|
unsigned desired = minimum;
|
||||||
@ -775,6 +813,7 @@ free(Context* c, Fixie** fixies)
|
|||||||
{
|
{
|
||||||
for (Fixie** p = fixies; *p;) {
|
for (Fixie** p = fixies; *p;) {
|
||||||
Fixie* f = *p;
|
Fixie* f = *p;
|
||||||
|
|
||||||
if (f->immortal()) {
|
if (f->immortal()) {
|
||||||
p = &(f->next);
|
p = &(f->next);
|
||||||
} else {
|
} else {
|
||||||
@ -802,9 +841,9 @@ sweepFixies(Context* c)
|
|||||||
|
|
||||||
c->untenuredFixieFootprint = 0;
|
c->untenuredFixieFootprint = 0;
|
||||||
|
|
||||||
for (Fixie** p = &(c->visitedFixies); *p;) {
|
while (c->visitedFixies) {
|
||||||
Fixie* f = *p;
|
Fixie* f = c->visitedFixies;
|
||||||
*p = f->next;
|
f->remove(c);
|
||||||
|
|
||||||
if (not f->immortal()) {
|
if (not f->immortal()) {
|
||||||
++ f->age;
|
++ f->age;
|
||||||
@ -825,14 +864,14 @@ sweepFixies(Context* c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (f->dirty) {
|
if (f->dirty) {
|
||||||
f->move(&(c->dirtyTenuredFixies));
|
f->add(c, &(c->dirtyTenuredFixies));
|
||||||
} else {
|
} else {
|
||||||
f->move(&(c->tenuredFixies));
|
f->add(c, &(c->tenuredFixies));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c->untenuredFixieFootprint += f->totalSize();
|
c->untenuredFixieFootprint += f->totalSize();
|
||||||
|
|
||||||
f->move(&(c->fixies));
|
f->add(c, &(c->fixies));
|
||||||
}
|
}
|
||||||
|
|
||||||
f->marked = false;
|
f->marked = false;
|
||||||
@ -852,6 +891,12 @@ copyTo(Context* c, Segment* s, void* o, unsigned size)
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
immortalHeapContains(Context* c, void* p)
|
||||||
|
{
|
||||||
|
return p < c->immortalHeapEnd and p >= c->immortalHeapStart;
|
||||||
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
copy2(Context* c, void* o)
|
copy2(Context* c, void* o)
|
||||||
{
|
{
|
||||||
@ -888,6 +933,7 @@ copy2(Context* c, void* o)
|
|||||||
} else {
|
} else {
|
||||||
assert(c, not c->nextGen1.contains(o));
|
assert(c, not c->nextGen1.contains(o));
|
||||||
assert(c, not c->nextGen2.contains(o));
|
assert(c, not c->nextGen2.contains(o));
|
||||||
|
assert(c, not immortalHeapContains(c, o));
|
||||||
|
|
||||||
o = copyTo(c, &(c->nextGen1), o, size);
|
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);
|
fprintf(stderr, "mark fixie %p\n", f);
|
||||||
}
|
}
|
||||||
f->marked = true;
|
f->marked = true;
|
||||||
f->move(&(c->markedFixies));
|
f->move(c, &(c->markedFixies));
|
||||||
}
|
}
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return o;
|
return o;
|
||||||
|
} else if (immortalHeapContains(c, o)) {
|
||||||
|
*needsVisit = false;
|
||||||
|
return o;
|
||||||
} else if (wasCollected(c, o)) {
|
} else if (wasCollected(c, o)) {
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return follow(c, o);
|
return follow(c, o);
|
||||||
@ -950,23 +999,12 @@ update2(Context* c, void* o, bool* needsVisit)
|
|||||||
return update3(c, o, 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
|
void
|
||||||
markDirty(Context* c, Fixie* f)
|
markDirty(Context* c, Fixie* f)
|
||||||
{
|
{
|
||||||
if (not f->dirty) {
|
if (not f->dirty) {
|
||||||
f->dirty = true;
|
f->dirty = true;
|
||||||
f->move(&(c->dirtyTenuredFixies));
|
f->move(c, &(c->dirtyTenuredFixies));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,7 +1013,11 @@ markClean(Context* c, Fixie* f)
|
|||||||
{
|
{
|
||||||
if (f->dirty) {
|
if (f->dirty) {
|
||||||
f->dirty = false;
|
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);
|
map = &(c->nextHeapMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not (c->client->isFixed(result)
|
if (not (immortalHeapContains(c, result)
|
||||||
and fixie(result)->age >= FixieTenureThreshold)
|
or (c->client->isFixed(result)
|
||||||
and not seg->contains(result))
|
and fixie(result)->age >= FixieTenureThreshold)
|
||||||
|
or seg->contains(result)))
|
||||||
{
|
{
|
||||||
if (target and c->client->isFixed(target)) {
|
if (target and c->client->isFixed(target)) {
|
||||||
Fixie* f = fixie(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 (static_cast<unsigned>(f->age + 1) >= FixieTenureThreshold) {
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "dirty fixie %p at %d (%p)\n",
|
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
|
||||||
f, offset, f->body() + offset);
|
f, offset, f->body() + offset, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
markDirty(c, f);
|
f->dirty = true;
|
||||||
markBit(f->mask(), offset);
|
markBit(f->mask(), offset);
|
||||||
}
|
}
|
||||||
} else if (seg->contains(p)) {
|
} else if (seg->contains(p)) {
|
||||||
@ -1399,7 +1442,6 @@ visitDirtyFixies(Context* c, Fixie** p)
|
|||||||
assert(c, wasDirty);
|
assert(c, wasDirty);
|
||||||
|
|
||||||
if (clean) {
|
if (clean) {
|
||||||
*p = f->next;
|
|
||||||
markClean(c, f);
|
markClean(c, f);
|
||||||
} else {
|
} else {
|
||||||
p = &(f->next);
|
p = &(f->next);
|
||||||
@ -1410,9 +1452,9 @@ visitDirtyFixies(Context* c, Fixie** p)
|
|||||||
void
|
void
|
||||||
visitMarkedFixies(Context* c)
|
visitMarkedFixies(Context* c)
|
||||||
{
|
{
|
||||||
for (Fixie** p = &(c->markedFixies); *p;) {
|
while (c->markedFixies) {
|
||||||
Fixie* f = *p;
|
Fixie* f = c->markedFixies;
|
||||||
*p = f->next;
|
f->remove(c);
|
||||||
|
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "visit fixie %p\n", f);
|
fprintf(stderr, "visit fixie %p\n", f);
|
||||||
@ -1435,7 +1477,7 @@ visitMarkedFixies(Context* c)
|
|||||||
|
|
||||||
c->client->walk(f->body(), &w);
|
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;
|
c.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) {
|
||||||
|
c.immortalHeapStart = start;
|
||||||
|
c.immortalHeapEnd = start + sizeInWords;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(unsigned size) {
|
||||||
return ::tryAllocate(&c, size);
|
return ::tryAllocate(&c, size);
|
||||||
}
|
}
|
||||||
@ -1690,18 +1737,21 @@ class MyHeap: public Heap {
|
|||||||
{
|
{
|
||||||
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
return (new (allocator->allocate(*totalInBytes))
|
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,
|
virtual void* allocateImmortalFixed(Allocator* allocator,
|
||||||
bool objectMask, unsigned* totalInBytes)
|
unsigned sizeInWords, bool objectMask,
|
||||||
|
unsigned* totalInBytes)
|
||||||
{
|
{
|
||||||
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
return (new (allocator->allocate(*totalInBytes))
|
return (new (allocator->allocate(*totalInBytes))
|
||||||
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
|
Fixie(&c, sizeInWords, objectMask, 0, true))->body();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool needsMark(void* p) {
|
virtual bool needsMark(void* p) {
|
||||||
|
assert(&c, c.client->isFixed(p) or (not immortalHeapContains(&c, p)));
|
||||||
|
|
||||||
if (c.client->isFixed(p)) {
|
if (c.client->isFixed(p)) {
|
||||||
return fixie(p)->age >= FixieTenureThreshold;
|
return fixie(p)->age >= FixieTenureThreshold;
|
||||||
} else {
|
} else {
|
||||||
@ -1717,6 +1767,7 @@ class MyHeap: public Heap {
|
|||||||
bool targetNeedsMark(void* target) {
|
bool targetNeedsMark(void* target) {
|
||||||
return target
|
return target
|
||||||
and not c.gen2.contains(target)
|
and not c.gen2.contains(target)
|
||||||
|
and not immortalHeapContains(&c, target)
|
||||||
and not (c.client->isFixed(target)
|
and not (c.client->isFixed(target)
|
||||||
and fixie(target)->age >= FixieTenureThreshold);
|
and fixie(target)->age >= FixieTenureThreshold);
|
||||||
}
|
}
|
||||||
@ -1731,8 +1782,8 @@ class MyHeap: public Heap {
|
|||||||
void** target = static_cast<void**>(p) + offset + i;
|
void** target = static_cast<void**>(p) + offset + i;
|
||||||
if (targetNeedsMark(mask(*target))) {
|
if (targetNeedsMark(mask(*target))) {
|
||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "dirty fixie %p at %d (%p)\n",
|
fprintf(stderr, "dirty fixie %p at %d (%p): %p\n",
|
||||||
f, offset, f->body() + offset);
|
f, offset, f->body() + offset, mask(*target));
|
||||||
}
|
}
|
||||||
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
@ -1789,6 +1840,7 @@ class MyHeap: public Heap {
|
|||||||
} else if (c.nextGen1.contains(p)) {
|
} else if (c.nextGen1.contains(p)) {
|
||||||
return Reachable;
|
return Reachable;
|
||||||
} else if (c.nextGen2.contains(p)
|
} else if (c.nextGen2.contains(p)
|
||||||
|
or immortalHeapContains(&c, p)
|
||||||
or (c.gen2.contains(p)
|
or (c.gen2.contains(p)
|
||||||
and (c.mode == Heap::MinorCollection
|
and (c.mode == Heap::MinorCollection
|
||||||
or c.gen2.indexOf(p) >= c.gen2Base)))
|
or c.gen2.indexOf(p) >= c.gen2Base)))
|
||||||
|
@ -52,11 +52,13 @@ class Heap: public Allocator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual void setClient(Client* client) = 0;
|
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 collect(CollectionType type, unsigned footprint) = 0;
|
||||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
||||||
bool objectMask, unsigned* totalInBytes) = 0;
|
bool objectMask, unsigned* totalInBytes) = 0;
|
||||||
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateImmortalFixed(Allocator* allocator,
|
||||||
bool objectMask, unsigned* totalInBytes) = 0;
|
unsigned sizeInWords, bool objectMask,
|
||||||
|
unsigned* totalInBytes) = 0;
|
||||||
virtual bool needsMark(void* p) = 0;
|
virtual bool needsMark(void* p) = 0;
|
||||||
virtual bool needsMark(void* p, unsigned offset) = 0;
|
virtual bool needsMark(void* p, unsigned offset) = 0;
|
||||||
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
||||||
|
328
src/heapdump.cpp
328
src/heapdump.cpp
@ -9,194 +9,12 @@
|
|||||||
details. */
|
details. */
|
||||||
|
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
#include "heapwalk.h"
|
||||||
|
|
||||||
using namespace vm;
|
using namespace vm;
|
||||||
|
|
||||||
namespace {
|
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 {
|
enum {
|
||||||
Root,
|
Root,
|
||||||
Size,
|
Size,
|
||||||
@ -205,100 +23,30 @@ enum {
|
|||||||
Pop
|
Pop
|
||||||
};
|
};
|
||||||
|
|
||||||
inline object
|
void
|
||||||
get(object o, unsigned offsetInWords)
|
write1(FILE* out, uint8_t v)
|
||||||
{
|
{
|
||||||
return static_cast<object>
|
size_t n UNUSED = fwrite(&v, 1, 1, out);
|
||||||
(mask(cast<void*>(o, offsetInWords * BytesPerWord)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
write1(Context* c, uint8_t v)
|
write4(FILE* out, uint32_t v)
|
||||||
{
|
|
||||||
fwrite(&v, 1, 1, c->out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
write4(Context* c, uint32_t v)
|
|
||||||
{
|
{
|
||||||
uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF };
|
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
|
void
|
||||||
writeString(Context* c, int8_t* p, unsigned size)
|
writeString(FILE* out, int8_t* p, unsigned size)
|
||||||
{
|
{
|
||||||
write4(c, size);
|
write4(out, size);
|
||||||
fwrite(p, size, 1, c->out);
|
size_t n UNUSED = fwrite(p, size, 1, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
objectSize(Thread* t, object o)
|
objectSize(Thread* t, object o)
|
||||||
{
|
{
|
||||||
unsigned n = baseSize(t, o, objectClass(t, o));
|
return extendedSize(t, o, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -308,22 +56,58 @@ namespace vm {
|
|||||||
void
|
void
|
||||||
dumpHeap(Thread* t, FILE* out)
|
dumpHeap(Thread* t, FILE* out)
|
||||||
{
|
{
|
||||||
Context context(t, out);
|
class Visitor: public HeapVisitor {
|
||||||
|
|
||||||
class Visitor : public Heap::Visitor {
|
|
||||||
public:
|
public:
|
||||||
Visitor(Context* c): c(c) { }
|
Visitor(Thread* t, FILE* out): t(t), out(out), nextNumber(1) { }
|
||||||
|
|
||||||
virtual void visit(void* p) {
|
virtual void root() {
|
||||||
::visit(c, static_cast<object>(mask(*static_cast<void**>(p))));
|
write1(out, Root);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context* c;
|
virtual unsigned visitNew(object p) {
|
||||||
} v(&context);
|
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
|
} // 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);
|
object field = resolveField(t, codePool(t, code), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
if (UNLIKELY(exception)) goto throw_;
|
||||||
|
if (throwIfVolatileField(t, field)) goto throw_;
|
||||||
|
|
||||||
|
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
|
||||||
|
|
||||||
pushField(t, popObject(t), field);
|
pushField(t, popObject(t), field);
|
||||||
} else {
|
} else {
|
||||||
exception = makeNullPointerException(t);
|
exception = makeNullPointerException(t);
|
||||||
@ -1465,6 +1468,10 @@ interpret(Thread* t)
|
|||||||
|
|
||||||
object field = resolveField(t, codePool(t, code), index - 1);
|
object field = resolveField(t, codePool(t, code), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
if (UNLIKELY(exception)) goto throw_;
|
||||||
|
if (throwIfVolatileField(t, field)) goto throw_;
|
||||||
|
|
||||||
|
assert(t, fieldFlags(t, field) & ACC_STATIC);
|
||||||
|
|
||||||
PROTECT(t, field);
|
PROTECT(t, field);
|
||||||
|
|
||||||
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
|
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);
|
object field = resolveField(t, codePool(t, code), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
if (UNLIKELY(exception)) goto throw_;
|
||||||
|
if (throwIfVolatileField(t, field)) goto throw_;
|
||||||
|
|
||||||
|
assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0);
|
||||||
|
|
||||||
switch (fieldCode(t, field)) {
|
switch (fieldCode(t, field)) {
|
||||||
case ByteField:
|
case ByteField:
|
||||||
@ -2461,6 +2471,10 @@ interpret(Thread* t)
|
|||||||
|
|
||||||
object field = resolveField(t, codePool(t, code), index - 1);
|
object field = resolveField(t, codePool(t, code), index - 1);
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
if (UNLIKELY(exception)) goto throw_;
|
||||||
|
if (throwIfVolatileField(t, field)) goto throw_;
|
||||||
|
|
||||||
|
assert(t, fieldFlags(t, field) & ACC_STATIC);
|
||||||
|
|
||||||
PROTECT(t, field);
|
PROTECT(t, field);
|
||||||
|
|
||||||
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
|
if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke;
|
||||||
@ -2876,7 +2890,7 @@ class MyProcessor: public Processor {
|
|||||||
{
|
{
|
||||||
return vm::makeMethod
|
return vm::makeMethod
|
||||||
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
||||||
offset, name, spec, class_, code, 0);
|
offset, 0, name, spec, class_, code, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual object
|
virtual object
|
||||||
@ -3056,6 +3070,32 @@ class MyProcessor: public Processor {
|
|||||||
return 0;
|
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) {
|
virtual void dispose(vm::Thread* t) {
|
||||||
t->m->heap->free(t, sizeof(Thread));
|
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
|
void
|
||||||
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
||||||
{
|
{
|
||||||
@ -867,10 +835,6 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
|
|
||||||
staticTypes[staticCount++] = code;
|
staticTypes[staticCount++] = code;
|
||||||
} else {
|
} else {
|
||||||
if (value) {
|
|
||||||
abort(t); // todo: handle non-static field initializers
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord;
|
unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord;
|
||||||
if (excess) {
|
if (excess) {
|
||||||
memberOffset += BytesPerWord - 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);
|
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 {
|
class HeapClient: public Heap::Client {
|
||||||
public:
|
public:
|
||||||
HeapClient(Machine* m): m(m) { }
|
HeapClient(Machine* m): m(m) { }
|
||||||
@ -1648,6 +1694,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
|||||||
referenceLock(0),
|
referenceLock(0),
|
||||||
libraries(0),
|
libraries(0),
|
||||||
loader(0),
|
loader(0),
|
||||||
|
classMap(0),
|
||||||
bootstrapClassMap(0),
|
bootstrapClassMap(0),
|
||||||
monitorMap(0),
|
monitorMap(0),
|
||||||
stringMap(0),
|
stringMap(0),
|
||||||
@ -1748,86 +1795,32 @@ Thread::init()
|
|||||||
abort(this);
|
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);
|
unsigned size;
|
||||||
memset(t->m->loader, 0, sizeof(void*) * 2);
|
image = function(&size);
|
||||||
|
}
|
||||||
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);
|
|
||||||
|
|
||||||
m->unsafe = false;
|
m->unsafe = false;
|
||||||
|
|
||||||
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|
if (image) {
|
||||||
|= SingletonFlag;
|
m->processor->boot(this, image);
|
||||||
|
} else {
|
||||||
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|
boot(this);
|
||||||
|= 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m->monitorMap = makeWeakHashMap(this, 0, 0);
|
m->monitorMap = makeWeakHashMap(this, 0, 0);
|
||||||
m->stringMap = makeWeakHashMap(this, 0, 0);
|
|
||||||
|
|
||||||
m->jniMethodTable = makeVector(this, 0, 0, false);
|
m->jniMethodTable = makeVector(this, 0, 0, false);
|
||||||
|
|
||||||
m->localThread->set(this);
|
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 {
|
} else {
|
||||||
peer = parent->child;
|
peer = parent->child;
|
||||||
parent->child = this;
|
parent->child = this;
|
||||||
@ -2108,7 +2101,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
case Machine::ImmortalAllocation: {
|
case Machine::ImmortalAllocation: {
|
||||||
unsigned total;
|
unsigned total;
|
||||||
object o = static_cast<object>
|
object o = static_cast<object>
|
||||||
(t->m->heap->allocateImmortal
|
(t->m->heap->allocateImmortalFixed
|
||||||
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
||||||
|
|
||||||
cast<uintptr_t>(o, 0) = FixedMark;
|
cast<uintptr_t>(o, 0) = FixedMark;
|
||||||
@ -2329,8 +2322,7 @@ findLoadedClass(Thread* t, object spec)
|
|||||||
PROTECT(t, spec);
|
PROTECT(t, spec);
|
||||||
ACQUIRE(t, t->m->classLock);
|
ACQUIRE(t, t->m->classLock);
|
||||||
|
|
||||||
return hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
|
return hashMapFind(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual);
|
||||||
spec, byteArrayHash, byteArrayEqual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -2434,8 +2426,9 @@ resolveClass(Thread* t, object spec)
|
|||||||
PROTECT(t, spec);
|
PROTECT(t, spec);
|
||||||
ACQUIRE(t, t->m->classLock);
|
ACQUIRE(t, t->m->classLock);
|
||||||
|
|
||||||
object class_ = hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
|
object class_ = hashMapFind
|
||||||
spec, byteArrayHash, byteArrayEqual);
|
(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual);
|
||||||
|
|
||||||
if (class_ == 0) {
|
if (class_ == 0) {
|
||||||
if (byteArrayBody(t, spec, 0) == '[') {
|
if (byteArrayBody(t, spec, 0) == '[') {
|
||||||
class_ = hashMapFind
|
class_ = hashMapFind
|
||||||
@ -2487,8 +2480,7 @@ resolveClass(Thread* t, object spec)
|
|||||||
if (class_) {
|
if (class_) {
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
|
|
||||||
hashMapInsert(t, systemClassLoaderMap(t, t->m->loader),
|
hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash);
|
||||||
spec, class_, byteArrayHash);
|
|
||||||
} else if (t->exception == 0) {
|
} else if (t->exception == 0) {
|
||||||
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
||||||
t->exception = makeClassNotFoundException(t, message);
|
t->exception = makeClassNotFoundException(t, message);
|
||||||
@ -2770,6 +2762,38 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
#endif
|
#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
|
int
|
||||||
walkNext(Thread* t, object o, int previous)
|
walkNext(Thread* t, object o, int previous)
|
||||||
{
|
{
|
||||||
@ -2793,6 +2817,7 @@ void
|
|||||||
visitRoots(Machine* m, Heap::Visitor* v)
|
visitRoots(Machine* m, Heap::Visitor* v)
|
||||||
{
|
{
|
||||||
v->visit(&(m->loader));
|
v->visit(&(m->loader));
|
||||||
|
v->visit(&(m->classMap));
|
||||||
v->visit(&(m->bootstrapClassMap));
|
v->visit(&(m->bootstrapClassMap));
|
||||||
v->visit(&(m->monitorMap));
|
v->visit(&(m->monitorMap));
|
||||||
v->visit(&(m->stringMap));
|
v->visit(&(m->stringMap));
|
||||||
|
@ -1175,6 +1175,7 @@ class Machine {
|
|||||||
System::Monitor* referenceLock;
|
System::Monitor* referenceLock;
|
||||||
System::Library* libraries;
|
System::Library* libraries;
|
||||||
object loader;
|
object loader;
|
||||||
|
object classMap;
|
||||||
object bootstrapClassMap;
|
object bootstrapClassMap;
|
||||||
object monitorMap;
|
object monitorMap;
|
||||||
object stringMap;
|
object stringMap;
|
||||||
@ -1449,6 +1450,35 @@ expect(Thread* t, bool v)
|
|||||||
expect(t->m->system, 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
|
inline void
|
||||||
ensure(Thread* t, unsigned sizeInBytes)
|
ensure(Thread* t, unsigned sizeInBytes)
|
||||||
{
|
{
|
||||||
@ -2020,10 +2050,19 @@ resolveMethod(Thread* t, const char* className, const char* methodName,
|
|||||||
object
|
object
|
||||||
resolveObjectArrayClass(Thread* t, object elementSpec);
|
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
|
inline void
|
||||||
initClass(Thread* t, object c)
|
initClass(Thread* t, object c)
|
||||||
{
|
{
|
||||||
t->m->processor->initClass(t, c);
|
if (classNeedsInit(t, c)) {
|
||||||
|
t->m->processor->initClass(t, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -2225,6 +2264,9 @@ intern(Thread* t, object s);
|
|||||||
void
|
void
|
||||||
exit(Thread* t);
|
exit(Thread* t);
|
||||||
|
|
||||||
|
void
|
||||||
|
walk(Thread* t, Heap::Walker* w, object o, unsigned start);
|
||||||
|
|
||||||
int
|
int
|
||||||
walkNext(Thread* t, object o, int previous);
|
walkNext(Thread* t, object o, int previous);
|
||||||
|
|
||||||
|
@ -79,11 +79,20 @@ main(int ac, const char** av)
|
|||||||
++ vmArgs.nOptions;
|
++ vmArgs.nOptions;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOOT_IMAGE
|
||||||
|
++ vmArgs.nOptions;
|
||||||
|
#endif
|
||||||
|
|
||||||
JavaVMOption options[vmArgs.nOptions];
|
JavaVMOption options[vmArgs.nOptions];
|
||||||
vmArgs.options = options;
|
vmArgs.options = options;
|
||||||
|
|
||||||
unsigned optionIndex = 0;
|
unsigned optionIndex = 0;
|
||||||
|
|
||||||
|
#ifdef BOOT_IMAGE
|
||||||
|
options[optionIndex++].optionString
|
||||||
|
= const_cast<char*>("-Davian.bootimage=" BOOT_IMAGE);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BOOT_CLASSPATH
|
#ifdef BOOT_CLASSPATH
|
||||||
options[optionIndex++].optionString
|
options[optionIndex++].optionString
|
||||||
= const_cast<char*>("-Xbootclasspath:" BOOT_CLASSPATH);
|
= const_cast<char*>("-Xbootclasspath:" BOOT_CLASSPATH);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "ucontext.h"
|
#include "ucontext.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
#include "dirent.h"
|
||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
@ -428,6 +429,31 @@ class MySystem: public System {
|
|||||||
size_t length_;
|
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 {
|
class Library: public System::Library {
|
||||||
public:
|
public:
|
||||||
Library(System* s, void* p, const char* name, unsigned nameLength,
|
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) {
|
virtual Status map(System::Region** region, const char* name) {
|
||||||
Status status = 1;
|
Status status = 1;
|
||||||
|
|
||||||
int fd = open(name, O_RDONLY);
|
int fd = ::open(name, O_RDONLY);
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
int r = fstat(fd, &s);
|
int r = fstat(fd, &s);
|
||||||
@ -641,19 +667,31 @@ class MySystem: public System {
|
|||||||
return status;
|
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) {
|
virtual FileType identify(const char* name) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
int r = stat(name, &s);
|
int r = stat(name, &s);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (S_ISREG(s.st_mode)) {
|
if (S_ISREG(s.st_mode)) {
|
||||||
return File;
|
return TypeFile;
|
||||||
} else if (S_ISDIR(s.st_mode)) {
|
} else if (S_ISDIR(s.st_mode)) {
|
||||||
return Directory;
|
return TypeDirectory;
|
||||||
} else {
|
} else {
|
||||||
return Unknown;
|
return TypeUnknown;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return DoesNotExist;
|
return TypeDoesNotExist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +188,21 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
|
|||||||
int
|
int
|
||||||
findLineNumber(Thread* t, object method, unsigned ip);
|
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
|
} // namespace vm
|
||||||
|
|
||||||
#endif//PROCESS_H
|
#endif//PROCESS_H
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
#include "bootimage.h"
|
||||||
|
#include "heapwalk.h"
|
||||||
|
#include "zone.h"
|
||||||
|
#include "assembler.h"
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
@ -112,6 +116,24 @@ class Processor {
|
|||||||
virtual object
|
virtual object
|
||||||
getStackTrace(Thread* t, Thread* target) = 0;
|
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
|
object
|
||||||
invoke(Thread* t, object method, object this_, ...)
|
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;
|
typedef intptr_t Status;
|
||||||
|
|
||||||
enum FileType {
|
enum FileType {
|
||||||
Unknown,
|
TypeUnknown,
|
||||||
DoesNotExist,
|
TypeDoesNotExist,
|
||||||
File,
|
TypeFile,
|
||||||
Directory
|
TypeDirectory
|
||||||
};
|
};
|
||||||
|
|
||||||
class Thread {
|
class Thread {
|
||||||
@ -79,6 +79,12 @@ class System {
|
|||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Directory {
|
||||||
|
public:
|
||||||
|
virtual const char* next() = 0;
|
||||||
|
virtual void dispose() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Library {
|
class Library {
|
||||||
public:
|
public:
|
||||||
virtual void* resolve(const char* function) = 0;
|
virtual void* resolve(const char* function) = 0;
|
||||||
@ -128,6 +134,7 @@ class System {
|
|||||||
unsigned returnType) = 0;
|
unsigned returnType) = 0;
|
||||||
virtual Status map(Region**, const char* name) = 0;
|
virtual Status map(Region**, const char* name) = 0;
|
||||||
virtual FileType identify(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 Status load(Library**, const char* name, bool mapName) = 0;
|
||||||
virtual char pathSeparator() = 0;
|
virtual char pathSeparator() = 0;
|
||||||
virtual int64_t now() = 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;
|
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
|
void
|
||||||
treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node,
|
treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node,
|
||||||
object sentinal,
|
object sentinal,
|
||||||
@ -531,29 +550,20 @@ object
|
|||||||
treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
|
treeQuery(Thread* t, object tree, intptr_t key, object sentinal,
|
||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
||||||
{
|
{
|
||||||
object node = tree;
|
object node = treeFind(t, tree, key, sentinal, compare);
|
||||||
while (node != sentinal) {
|
return (node ? getTreeNodeValue(t, node) : 0);
|
||||||
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
|
object
|
||||||
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
|
treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value,
|
||||||
object sentinal,
|
object sentinal,
|
||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
intptr_t (*compare)(Thread* t, intptr_t key, object b))
|
||||||
{
|
{
|
||||||
PROTECT(t, tree);
|
PROTECT(t, tree);
|
||||||
PROTECT(t, sentinal);
|
PROTECT(t, sentinal);
|
||||||
|
|
||||||
|
object node = makeTreeNode(t, value, sentinal, sentinal);
|
||||||
|
|
||||||
TreeContext c(t, zone);
|
TreeContext c(t, zone);
|
||||||
treeFind(t, &c, tree, key, node, sentinal, compare);
|
treeFind(t, &c, tree, key, node, sentinal, compare);
|
||||||
expect(t, c.fresh);
|
expect(t, c.fresh);
|
||||||
@ -561,4 +571,11 @@ treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
|
|||||||
return treeAdd(t, &c);
|
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
|
} // 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));
|
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
||||||
|
|
||||||
object
|
object
|
||||||
treeInsertNode(Thread* t, Zone* zone, object tree, intptr_t key, object node,
|
treeInsert(Thread* t, Zone* zone, object tree, intptr_t key, object value,
|
||||||
object sentinal,
|
object sentinal,
|
||||||
intptr_t (*compare)(Thread* t, intptr_t key, object b));
|
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 {
|
class HashMapIterator: public Thread::Protector {
|
||||||
public:
|
public:
|
||||||
@ -103,11 +107,13 @@ class HashMapIterator: public Thread::Protector {
|
|||||||
|
|
||||||
void find() {
|
void find() {
|
||||||
object array = hashMapArray(t, map);
|
object array = hashMapArray(t, map);
|
||||||
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
if (array) {
|
||||||
if (arrayBody(t, array, i)) {
|
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
||||||
node = arrayBody(t, array, i);
|
if (arrayBody(t, array, i)) {
|
||||||
index = i + 1;
|
node = arrayBody(t, array, i);
|
||||||
return;
|
index = i + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node = 0;
|
node = 0;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "sys/stat.h"
|
#include "sys/stat.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "sys/timeb.h"
|
#include "sys/timeb.h"
|
||||||
|
#include "dirent.h"
|
||||||
|
|
||||||
#undef max
|
#undef max
|
||||||
#undef min
|
#undef min
|
||||||
@ -422,6 +423,31 @@ class MySystem: public System {
|
|||||||
HANDLE file;
|
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 {
|
class Library: public System::Library {
|
||||||
public:
|
public:
|
||||||
Library(System* s, HMODULE handle, const char* name, bool mapName):
|
Library(System* s, HMODULE handle, const char* name, bool mapName):
|
||||||
@ -630,19 +656,31 @@ class MySystem: public System {
|
|||||||
return status;
|
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) {
|
virtual FileType identify(const char* name) {
|
||||||
struct _stat s;
|
struct _stat s;
|
||||||
int r = _stat(name, &s);
|
int r = _stat(name, &s);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (S_ISREG(s.st_mode)) {
|
if (S_ISREG(s.st_mode)) {
|
||||||
return File;
|
return TypeFile;
|
||||||
} else if (S_ISDIR(s.st_mode)) {
|
} else if (S_ISDIR(s.st_mode)) {
|
||||||
return Directory;
|
return TypeDirectory;
|
||||||
} else {
|
} else {
|
||||||
return Unknown;
|
return TypeUnknown;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return DoesNotExist;
|
return TypeDoesNotExist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
368
src/x86.cpp
368
src/x86.cpp
@ -221,6 +221,38 @@ class Task {
|
|||||||
Task* next;
|
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 {
|
class OffsetTask: public Task {
|
||||||
public:
|
public:
|
||||||
OffsetTask(Task* next, Promise* promise, Promise* instructionOffset,
|
OffsetTask(Task* next, Promise* promise, Promise* instructionOffset,
|
||||||
@ -232,14 +264,15 @@ class OffsetTask: public Task {
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void run(Context* c) {
|
virtual void run(Context* c) {
|
||||||
uint8_t* instruction = c->result + instructionOffset->value();
|
if (promise->resolved()) {
|
||||||
intptr_t v = reinterpret_cast<uint8_t*>(promise->value())
|
resolveOffset
|
||||||
- instruction - instructionSize;
|
(c->s, c->result + instructionOffset->value(), instructionSize,
|
||||||
|
promise->value());
|
||||||
expect(c, isInt32(v));
|
} else {
|
||||||
|
new (promise->listen(sizeof(OffsetListener)))
|
||||||
int32_t v4 = v;
|
OffsetListener(c->s, c->result + instructionOffset->value(),
|
||||||
memcpy(instruction + instructionSize - 4, &v4, 4);
|
instructionSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise* promise;
|
Promise* promise;
|
||||||
@ -255,40 +288,70 @@ appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset,
|
|||||||
(c->tasks, promise, instructionOffset, instructionSize);
|
(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 {
|
class ImmediateTask: public Task {
|
||||||
public:
|
public:
|
||||||
ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size):
|
ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size,
|
||||||
|
unsigned promiseOffset):
|
||||||
Task(next),
|
Task(next),
|
||||||
promise(promise),
|
promise(promise),
|
||||||
offset(offset),
|
offset(offset),
|
||||||
size(size)
|
size(size),
|
||||||
|
promiseOffset(promiseOffset)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void run(Context* c) {
|
virtual void run(Context* c) {
|
||||||
switch (size) {
|
if (promise->resolved()) {
|
||||||
case 4: {
|
copy(c->s, c->result + offset->value(), promise->value(), size);
|
||||||
int32_t v = promise->value();
|
} else {
|
||||||
memcpy(c->result + offset->value(), &v, size);
|
new (promise->listen(sizeof(ImmediateListener))) ImmediateListener
|
||||||
} break;
|
(c->s, c->result + offset->value(), size, promiseOffset);
|
||||||
|
|
||||||
case 8: {
|
|
||||||
int64_t v = promise->value();
|
|
||||||
memcpy(c->result + offset->value(), &v, size);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
abort(c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise* promise;
|
Promise* promise;
|
||||||
Promise* offset;
|
Promise* offset;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
unsigned promiseOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
appendImmediateTask(Context* c, Promise* promise, Promise* offset,
|
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 = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask
|
||||||
(c->tasks, promise, offset, size);
|
(c->tasks, promise, offset, size);
|
||||||
@ -448,6 +511,39 @@ index(TernaryOperation operation,
|
|||||||
* OperandTypeCount * operand2);
|
* 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
|
void
|
||||||
jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a)
|
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);
|
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
|
void
|
||||||
jumpM(Context* c, unsigned size UNUSED, Assembler::Memory* a)
|
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);
|
moveCR(c, size, a, size, &r);
|
||||||
jumpR(c, size, &r);
|
jumpR(c, size, &r);
|
||||||
} else {
|
} 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);
|
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
|
void
|
||||||
swapRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a,
|
swapRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a,
|
||||||
unsigned bSize UNUSED, Assembler::Register* b)
|
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
|
void
|
||||||
moveAR(Context* c, unsigned aSize, Assembler::Address* a,
|
moveAR(Context* c, unsigned aSize, Assembler::Address* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
unsigned bSize, Assembler::Register* b)
|
||||||
@ -864,18 +1008,6 @@ moveAR(Context* c, unsigned aSize, Assembler::Address* a,
|
|||||||
moveMR(c, bSize, &memory, bSize, b);
|
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
|
void
|
||||||
moveCR(Context* c, unsigned, Assembler::Constant* a,
|
moveCR(Context* c, unsigned, Assembler::Constant* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
unsigned bSize, Assembler::Register* b)
|
||||||
@ -932,7 +1064,7 @@ moveCM(Context* c, unsigned aSize UNUSED, Assembler::Constant* a,
|
|||||||
if (a->value->resolved()) {
|
if (a->value->resolved()) {
|
||||||
c->code.append4(a->value->value());
|
c->code.append4(a->value->value());
|
||||||
} else {
|
} else {
|
||||||
appendImmediateTask(c, a->value, offset(c), 4);
|
appendImmediateTask(c, a->value, c->code.length(), 4);
|
||||||
c->code.append4(0);
|
c->code.append4(0);
|
||||||
}
|
}
|
||||||
break;
|
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
|
void
|
||||||
multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a,
|
multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a,
|
||||||
unsigned bSize, Assembler::Register* b)
|
unsigned bSize, Assembler::Register* b)
|
||||||
@ -1465,7 +1623,6 @@ multiplyCR(Context* c, unsigned aSize, Assembler::Constant* a,
|
|||||||
|
|
||||||
moveCR(c, aSize, a, aSize, &tmp);
|
moveCR(c, aSize, a, aSize, &tmp);
|
||||||
multiplyRR(c, aSize, &tmp, bSize, b);
|
multiplyRR(c, aSize, &tmp, bSize, b);
|
||||||
|
|
||||||
c->client->releaseTemporary(tmp.low);
|
c->client->releaseTemporary(tmp.low);
|
||||||
c->client->releaseTemporary(tmp.high);
|
c->client->releaseTemporary(tmp.high);
|
||||||
} else {
|
} 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
|
void
|
||||||
longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah,
|
longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah,
|
||||||
Assembler::Operand* bl, Assembler::Operand* bh,
|
Assembler::Operand* bl, Assembler::Operand* bh,
|
||||||
@ -1882,15 +2077,11 @@ populateTables(ArchitectureContext* c)
|
|||||||
bo[index(Move, M, R)] = CAST2(moveMR);
|
bo[index(Move, M, R)] = CAST2(moveMR);
|
||||||
bo[index(Move, R, M)] = CAST2(moveRM);
|
bo[index(Move, R, M)] = CAST2(moveRM);
|
||||||
bo[index(Move, C, M)] = CAST2(moveCM);
|
bo[index(Move, C, M)] = CAST2(moveCM);
|
||||||
// bo[index(Move, A, M)] = CAST2(moveAM);
|
|
||||||
bo[index(Move, A, R)] = CAST2(moveAR);
|
bo[index(Move, A, R)] = CAST2(moveAR);
|
||||||
// bo[index(Move, M, M)] = CAST2(moveMM);
|
|
||||||
|
|
||||||
bo[index(MoveZ, R, R)] = CAST2(moveZRR);
|
bo[index(MoveZ, R, R)] = CAST2(moveZRR);
|
||||||
bo[index(MoveZ, M, R)] = CAST2(moveZMR);
|
bo[index(MoveZ, M, R)] = CAST2(moveZMR);
|
||||||
|
|
||||||
bo[index(Swap, R, R)] = CAST2(swapRR);
|
|
||||||
|
|
||||||
bo[index(Compare, R, R)] = CAST2(compareRR);
|
bo[index(Compare, R, R)] = CAST2(compareRR);
|
||||||
bo[index(Compare, C, R)] = CAST2(compareCR);
|
bo[index(Compare, C, R)] = CAST2(compareCR);
|
||||||
bo[index(Compare, C, M)] = CAST2(compareCM);
|
bo[index(Compare, C, M)] = CAST2(compareCM);
|
||||||
@ -1998,14 +2189,35 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateCall(void* returnAddress, void* newTarget) {
|
virtual void updateCall(UnaryOperation op UNUSED,
|
||||||
uint8_t* instruction = static_cast<uint8_t*>(returnAddress) - 5;
|
bool assertAlignment UNUSED, void* returnAddress,
|
||||||
assert(&c, *instruction == 0xE8);
|
void* newTarget)
|
||||||
assert(&c, reinterpret_cast<uintptr_t>(instruction + 1) % 4 == 0);
|
{
|
||||||
|
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)
|
assert(&c, ((op == Call or op == LongCall) and *instruction == 0xE8)
|
||||||
- static_cast<uint8_t*>(returnAddress);
|
or ((op == Jump or op == LongJump) and *instruction == 0xE9));
|
||||||
memcpy(instruction + 1, &v, 4);
|
|
||||||
|
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) {
|
virtual unsigned alignFrameSize(unsigned sizeInWords) {
|
||||||
|
@ -3,6 +3,8 @@ public class Misc {
|
|||||||
private static int beta;
|
private static int beta;
|
||||||
private static byte byte1, byte2, byte3;
|
private static byte byte1, byte2, byte3;
|
||||||
|
|
||||||
|
private final int NonStaticConstant = 42;
|
||||||
|
|
||||||
private int gamma;
|
private int gamma;
|
||||||
private int pajama;
|
private int pajama;
|
||||||
private boolean boolean1;
|
private boolean boolean1;
|
||||||
@ -108,6 +110,8 @@ public class Misc {
|
|||||||
{ Misc m = new Misc();
|
{ Misc m = new Misc();
|
||||||
m.toString();
|
m.toString();
|
||||||
|
|
||||||
|
expect(m.NonStaticConstant == 42);
|
||||||
|
|
||||||
expect(m.time == 0xffffffffffffffffL);
|
expect(m.time == 0xffffffffffffffffL);
|
||||||
long t = m.time;
|
long t = m.time;
|
||||||
expect(t == 0xffffffffffffffffL);
|
expect(t == 0xffffffffffffffffL);
|
||||||
|
1
vm.pro
1
vm.pro
@ -50,6 +50,7 @@
|
|||||||
-keep public class java.lang.ExceptionInInitializerError
|
-keep public class java.lang.ExceptionInInitializerError
|
||||||
-keep public class java.lang.OutOfMemoryError
|
-keep public class java.lang.OutOfMemoryError
|
||||||
-keep public class java.lang.reflect.InvocationTargetException
|
-keep public class java.lang.reflect.InvocationTargetException
|
||||||
|
-keep public class java.io.IOException
|
||||||
|
|
||||||
# ClassLoader.getSystemClassloader() depends on the existence of this class:
|
# ClassLoader.getSystemClassloader() depends on the existence of this class:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user