mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
implement fixed object support
This commit is contained in:
parent
6710ca85d7
commit
60072b9fdc
33
makefile
33
makefile
@ -28,7 +28,7 @@ src = src
|
||||
classpath = classpath
|
||||
test = test
|
||||
|
||||
input = $(test-build)/Hello.class
|
||||
input = $(test-build)/Enums.class
|
||||
|
||||
build-cxx = g++
|
||||
build-cc = gcc
|
||||
@ -192,11 +192,11 @@ ifeq ($(platform),darwin)
|
||||
classpath-object =
|
||||
endif
|
||||
|
||||
test-sources = $(shell find $(test) -name '*.java')
|
||||
test-sources = $(wildcard $(test)/*.java)
|
||||
test-classes = $(call java-classes,$(test-sources),$(test),$(test-build))
|
||||
|
||||
class-name = $(patsubst $(1)/%.class,%,$(2))
|
||||
class-names = $(foreach x,$(1),$(call class-name,$(x)))
|
||||
class-names = $(foreach x,$(2),$(call class-name,$(1),$(x)))
|
||||
|
||||
flags = -cp $(test-build)
|
||||
args = $(flags) $(call class-name,$(test-build),$(input))
|
||||
@ -204,7 +204,15 @@ args = $(flags) $(call class-name,$(test-build),$(input))
|
||||
.PHONY: build
|
||||
build: $(interpreter) $(archive) $(classpath-classes) $(test-classes)
|
||||
|
||||
$(input): $(classpath-classes)
|
||||
.PHONY: classes
|
||||
classes:
|
||||
@mkdir -p $(classpath-build)
|
||||
$(javac) -d $(classpath-build) -bootclasspath $(classpath) \
|
||||
$(classpath-sources)
|
||||
@mkdir -p $(test-build)
|
||||
$(javac) -d $(test-build) -bootclasspath $(classpath-build) $(test-sources)
|
||||
|
||||
$(test-classes): $(classpath-classes)
|
||||
|
||||
.PHONY: run
|
||||
run: build
|
||||
@ -221,7 +229,8 @@ vg: build
|
||||
.PHONY: test
|
||||
test: build
|
||||
/bin/bash $(test)/test.sh 2>/dev/null \
|
||||
$(interpreter) $(mode) "$(flags)" $(call class-names,$(test-classes))
|
||||
$(interpreter) $(mode) "$(flags)" \
|
||||
$(call class-names,$(test-build),$(test-classes))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ -236,7 +245,7 @@ clean-native:
|
||||
gen-arg = $(shell echo $(1) | sed -e 's:$(native-build)/type-\(.*\)\.cpp:\1:')
|
||||
$(generated-code): %.cpp: $(src)/types.def $(generator)
|
||||
@echo "generating $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(generator) $(call gen-arg,$(@)) < $(<) > $(@)
|
||||
|
||||
$(native-build)/type-generator.o: \
|
||||
@ -244,7 +253,7 @@ $(native-build)/type-generator.o: \
|
||||
|
||||
define compile-class
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(javac) -bootclasspath $(classpath) -classpath $(classpath) \
|
||||
-d $(1) $(<)
|
||||
@touch $(@)
|
||||
@ -252,21 +261,21 @@ endef
|
||||
|
||||
$(classpath-build)/%.class: $(classpath)/%.java
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(javac) -bootclasspath $(classpath) -classpath $(classpath) \
|
||||
-d $(classpath-build) $(<)
|
||||
@touch $(@)
|
||||
|
||||
$(test-build)/%.class: $(test)/%.java
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(javac) -bootclasspath $(classpath) -classpath $(classpath) \
|
||||
-d $(test-build) $(<)
|
||||
@touch $(@)
|
||||
|
||||
define compile-object
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cxx) $(cflags) -c $(<) -o $(@)
|
||||
endef
|
||||
|
||||
@ -293,12 +302,12 @@ $(classpath-object): $(build)/classpath.jar
|
||||
|
||||
$(generator-objects): $(native-build)/%.o: $(src)/%.cpp
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(build-cxx) -DPOINTER_SIZE=$(pointer-size) $(build-cflags) -c $(<) -o $(@)
|
||||
|
||||
$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p -m 1777 $(dir $(@))
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cxx) $(jni-cflags) -c $(<) -o $(@)
|
||||
|
||||
$(archive): $(interpreter-objects) $(jni-objects) $(classpath-object)
|
||||
|
@ -109,10 +109,10 @@ Java_java_lang_Object_clone(Thread* t, jclass, jobject o)
|
||||
object clone;
|
||||
|
||||
if (classArrayElementSize(t, class_)) {
|
||||
clone = static_cast<object>(allocate(t, size));
|
||||
clone = static_cast<object>(allocate(t, size, classObjectMask(t, class_)));
|
||||
memcpy(clone, *o, size);
|
||||
// clear any object header flags:
|
||||
cast<object>(*o, 0) = objectClass(t, *o);
|
||||
setObjectClass(t, *o, objectClass(t, *o));
|
||||
} else {
|
||||
clone = make(t, objectClass(t, *o));
|
||||
memcpy(reinterpret_cast<void**>(clone) + 1,
|
||||
|
@ -232,6 +232,10 @@ bitsToFloat(uint32_t bits)
|
||||
return f;
|
||||
}
|
||||
|
||||
// an object must survive TenureThreshold + 2 garbage collections
|
||||
// before being copied to gen2 (muat be at least 1):
|
||||
const unsigned TenureThreshold = 3;
|
||||
|
||||
class Machine;
|
||||
class Thread;
|
||||
|
||||
|
@ -674,7 +674,7 @@ class StackMapper {
|
||||
MyProtector(StackMapper* mapper): Protector(mapper->t), mapper(mapper) { }
|
||||
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
v->visit(&(mapper->method));
|
||||
vm::visit(t, v, &(mapper->method));
|
||||
}
|
||||
|
||||
StackMapper* mapper;
|
||||
@ -1073,14 +1073,14 @@ visitParameters(MyThread* t, Heap::Visitor* v, void* frame)
|
||||
|
||||
unsigned index = 0;
|
||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||
v->visit(frameLocalObject(t, frame, index++));
|
||||
visit(t, v, frameLocalObject(t, frame, index++));
|
||||
}
|
||||
|
||||
for (MethodSpecIterator it(t, spec); it.hasNext();) {
|
||||
switch (*it.next()) {
|
||||
case 'L':
|
||||
case '[':
|
||||
v->visit(frameLocalObject(t, frame, index++));
|
||||
visit(t, v, frameLocalObject(t, frame, index++));
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
@ -1122,7 +1122,7 @@ visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* frame)
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
if (getBit(stackMap, i)) {
|
||||
v->visit(frameLocalObject(t, frame, i + parameterFootprint));
|
||||
visit(t, v, frameLocalObject(t, frame, i + parameterFootprint));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1134,7 +1134,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
||||
void* frame = frameStart(t);
|
||||
|
||||
if (frameValid(frame)) {
|
||||
v->visit(&frameMethod(frame));
|
||||
visit(t, v, &frameMethod(frame));
|
||||
}
|
||||
|
||||
for (; frameValid(frame); frame = frameNext(frame)) {
|
||||
@ -1142,7 +1142,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
||||
// caller is native. Otherwise, the caller owns them.
|
||||
void* next = frameNext(frame);
|
||||
if (frameValid(next)) {
|
||||
v->visit(&frameMethod(next));
|
||||
visit(t, v, &frameMethod(next));
|
||||
|
||||
if (methodFlags(t, frameMethod(next)) & ACC_NATIVE) {
|
||||
visitParameters(t, v, frame);
|
||||
@ -4573,10 +4573,10 @@ class JavaCompiler: public Compiler {
|
||||
MyProtector(JavaCompiler* c): Protector(c->t), c(c) { }
|
||||
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
v->visit(&(c->method));
|
||||
vm::visit(t, v, &(c->method));
|
||||
|
||||
for (unsigned i = 0; i < c->pool.length(); i += BytesPerWord) {
|
||||
v->visit(reinterpret_cast<object*>(&(c->pool.getAddress(i))));
|
||||
vm::visit(t, v, reinterpret_cast<object*>(&(c->pool.getAddress(i))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4799,7 +4799,7 @@ class ArgumentList {
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
for (unsigned i = 0; i < list->position; ++i) {
|
||||
if (list->objectMask[i]) {
|
||||
v->visit(reinterpret_cast<object*>(list->array + i));
|
||||
vm::visit(t, v, reinterpret_cast<object*>(list->array + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4984,7 +4984,7 @@ class MyProcessor: public Processor {
|
||||
|
||||
if (t->m->active) {
|
||||
for (Reference* r = t->reference; r; r = r->next) {
|
||||
v->visit(&(r->target));
|
||||
visit(t, v, &(r->target));
|
||||
}
|
||||
|
||||
visitStack(t, v);
|
||||
|
@ -6,10 +6,6 @@ using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
// an object must survive TenureThreshold + 2 garbage collections
|
||||
// before being copied to gen2 (muat be at least 1):
|
||||
const unsigned TenureThreshold = 3;
|
||||
|
||||
const unsigned Top = ~static_cast<unsigned>(0);
|
||||
|
||||
const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024;
|
||||
@ -648,6 +644,9 @@ update3(Context* c, void* o, bool* needsVisit)
|
||||
if (wasCollected(c, o)) {
|
||||
*needsVisit = false;
|
||||
return follow(c, o);
|
||||
} else if (c->client->checkFixed(o)) {
|
||||
*needsVisit = false;
|
||||
return o;
|
||||
} else {
|
||||
*needsVisit = true;
|
||||
return copy(c, o);
|
||||
|
@ -35,7 +35,7 @@ class Heap {
|
||||
public:
|
||||
virtual ~Client() { }
|
||||
virtual void visitRoots(Visitor*) = 0;
|
||||
virtual unsigned sizeInWords(void*) = 0;
|
||||
virtual bool checkFixed(void*) = 0;
|
||||
virtual unsigned copiedSizeInWords(void*) = 0;
|
||||
virtual void copy(void*, void*) = 0;
|
||||
virtual void walk(void*, Walker*) = 0;
|
||||
|
@ -2955,11 +2955,11 @@ class MyProcessor: public Processor {
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(vmt);
|
||||
|
||||
v->visit(&(t->code));
|
||||
visit(t, v, &(t->code));
|
||||
|
||||
for (unsigned i = 0; i < t->sp; ++i) {
|
||||
if (t->stack[i * 2] == ObjectTag) {
|
||||
v->visit(t->stack + (i * 2) + 1);
|
||||
visit(t, v, reinterpret_cast<object*>(t->stack + (i * 2) + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,11 @@ DestroyJavaVM(Machine* m)
|
||||
Processor* p = m->processor;
|
||||
Heap* h = m->heap;
|
||||
Finder* f = m->finder;
|
||||
Thread* t = m->rootThread;
|
||||
|
||||
int exitCode = (m->rootThread->exception ? -1 : 0);
|
||||
int exitCode = (t->exception ? -1 : 0);
|
||||
enter(t, Thread::ActiveState);
|
||||
t->exit();
|
||||
|
||||
m->dispose();
|
||||
p->dispose();
|
||||
@ -1859,7 +1862,7 @@ extern "C" JNIEXPORT jint JNICALL
|
||||
JNI_GetDefaultJavaVMInitArgs(void* args)
|
||||
{
|
||||
JDK1_1InitArgs* a = static_cast<JDK1_1InitArgs*>(args);
|
||||
a->maxHeapSize = 128 * 1024 * 1024;
|
||||
a->maxHeapSize = 64 * 1024 * 1024;
|
||||
a->classpath = ".";
|
||||
a->properties = 0;
|
||||
return 0;
|
||||
|
480
src/machine.cpp
480
src/machine.cpp
@ -115,11 +115,6 @@ footprint(Thread* t)
|
||||
{
|
||||
unsigned n = t->heapOffset + t->heapIndex;
|
||||
|
||||
if (t->large) {
|
||||
n += extendedSize
|
||||
(t, t->large, baseSize(t, t->large, objectClass(t, t->large)));
|
||||
}
|
||||
|
||||
for (Thread* c = t->child; c; c = c->peer) {
|
||||
n += footprint(c);
|
||||
}
|
||||
@ -131,8 +126,8 @@ void
|
||||
visitRoots(Thread* t, Heap::Visitor* v)
|
||||
{
|
||||
if (t->state != Thread::ZombieState) {
|
||||
v->visit(&(t->javaThread));
|
||||
v->visit(&(t->exception));
|
||||
visit(t, v, &(t->javaThread));
|
||||
visit(t, v, &(t->exception));
|
||||
|
||||
t->m->processor->visitObjects(t, v);
|
||||
|
||||
@ -147,9 +142,75 @@ visitRoots(Thread* t, Heap::Visitor* v)
|
||||
}
|
||||
|
||||
void
|
||||
finalizerTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
walk(Thread* t, object o, Heap::Walker* w)
|
||||
{
|
||||
v->visit(&finalizerTarget(t, *p));
|
||||
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) {
|
||||
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
|
||||
// p, class_, objectMask, intArrayLength(t, objectMask));
|
||||
|
||||
unsigned fixedSize = classFixedSize(t, class_);
|
||||
unsigned arrayElementSize = classArrayElementSize(t, class_);
|
||||
unsigned arrayLength
|
||||
= (arrayElementSize ?
|
||||
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
|
||||
|
||||
int mask[intArrayLength(t, objectMask)];
|
||||
memcpy(mask, &intArrayBody(t, objectMask, 0),
|
||||
intArrayLength(t, objectMask) * 4);
|
||||
|
||||
// fprintf
|
||||
// (stderr,
|
||||
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
|
||||
// fixedSize, arrayLength, arrayElementSize, mask[0]);
|
||||
|
||||
unsigned fixedSizeInWords = ceiling(fixedSize, BytesPerWord);
|
||||
unsigned arrayElementSizeInWords
|
||||
= ceiling(arrayElementSize, BytesPerWord);
|
||||
|
||||
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
|
||||
if (mask[i / 32] & (static_cast<uintptr_t>(1) << (i % 32))) {
|
||||
if (not w->visit(i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool arrayObjectElements = false;
|
||||
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
||||
unsigned k = fixedSizeInWords + j;
|
||||
if (mask[k / 32] & (static_cast<uintptr_t>(1) << (k % 32))) {
|
||||
arrayObjectElements = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (arrayObjectElements) {
|
||||
for (unsigned i = 0; i < arrayLength; ++i) {
|
||||
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
||||
unsigned k = fixedSizeInWords + j;
|
||||
if (mask[k / 32] & (static_cast<uintptr_t>(1) << (k % 32))) {
|
||||
if (not w->visit
|
||||
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w->visit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
||||
{
|
||||
visit(t, v, &finalizerTarget(t, *p));
|
||||
|
||||
object finalizer = *p;
|
||||
*p = finalizerNext(t, finalizer);
|
||||
@ -158,14 +219,14 @@ finalizerTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
}
|
||||
|
||||
void
|
||||
referenceTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
||||
{
|
||||
if (DebugReferences) {
|
||||
fprintf(stderr, "target %p unreachable for reference %p\n",
|
||||
jreferenceTarget(t, *p), *p);
|
||||
}
|
||||
|
||||
v->visit(p);
|
||||
visit(t, v, p);
|
||||
jreferenceTarget(t, *p) = 0;
|
||||
|
||||
if (jreferenceQueue(t, *p)
|
||||
@ -173,7 +234,7 @@ referenceTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
{
|
||||
// queue is reachable - add the reference
|
||||
|
||||
v->visit(&jreferenceQueue(t, *p));
|
||||
visit(t, v, &jreferenceQueue(t, *p));
|
||||
|
||||
object q = jreferenceQueue(t, *p);
|
||||
|
||||
@ -192,7 +253,7 @@ referenceTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
}
|
||||
|
||||
void
|
||||
referenceUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
referenceUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
||||
{
|
||||
if (DebugReferences) {
|
||||
fprintf(stderr, "reference %p unreachable (target %p)\n",
|
||||
@ -203,27 +264,103 @@ referenceUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
|
||||
{
|
||||
// queue is reachable - add the reference
|
||||
referenceTargetUnreachable(t, p, v);
|
||||
referenceTargetUnreachable(t, v, p);
|
||||
} else {
|
||||
*p = jreferenceNext(t, *p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
referenceTargetReachable(Thread* t, object* p, Heap::Visitor* v)
|
||||
referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p)
|
||||
{
|
||||
if (DebugReferences) {
|
||||
fprintf(stderr, "target %p reachable for reference %p\n",
|
||||
jreferenceTarget(t, *p), *p);
|
||||
}
|
||||
|
||||
v->visit(p);
|
||||
v->visit(&jreferenceTarget(t, *p));
|
||||
visit(t, v, p);
|
||||
visit(t, v, &jreferenceTarget(t, *p));
|
||||
|
||||
if (t->m->heap->status(jreferenceQueue(t, *p)) == Heap::Unreachable) {
|
||||
jreferenceQueue(t, *p) = 0;
|
||||
} else {
|
||||
v->visit(&jreferenceQueue(t, *p));
|
||||
visit(t, v, &jreferenceQueue(t, *p));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
freeFixies(Thread* t, object* fixies)
|
||||
{
|
||||
for (object* p = fixies; *p;) {
|
||||
object o = *p;
|
||||
*p = fixedNext(t, o);
|
||||
|
||||
t->m->system->free(fixedStart(t, o));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sweepFixies(Thread* t)
|
||||
{
|
||||
Machine* m = t->m;
|
||||
|
||||
assert(t, m->markedFixies == 0);
|
||||
|
||||
if (m->heap->collectionType() == Heap::MajorCollection) {
|
||||
freeFixies(t, &(m->tenuredFixies));
|
||||
freeFixies(t, &(m->dirtyFixies));
|
||||
}
|
||||
freeFixies(t, &(m->fixies));
|
||||
|
||||
for (object* p = &(m->visitedFixies); *p;) {
|
||||
object o = *p;
|
||||
*p = fixedNext(t, o);
|
||||
|
||||
fixedAge(t, o) = (fixedAge(t, o) + 1);
|
||||
if (fixedAge(t, o) > TenureThreshold) {
|
||||
fixedAge(t, o) = TenureThreshold;
|
||||
}
|
||||
|
||||
if (fixedAge(t, o) == TenureThreshold) {
|
||||
fixedMove(t, o, &(m->tenuredFixies));
|
||||
|
||||
if (fixedDirty(t, o)) {
|
||||
unsigned size = baseSize(t, o, objectClass(t, o));
|
||||
uintptr_t* mask = fixedMask(t, o, size);
|
||||
memset(mask, 0, ceiling(size, BytesPerWord) * BytesPerWord);
|
||||
fixedDirty(t, o) = 0;
|
||||
}
|
||||
} else {
|
||||
fixedMove(t, o, &(m->fixies));
|
||||
}
|
||||
|
||||
fixedMarked(t, o) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visitDirtyFixies(Thread* t, Heap::Visitor* v)
|
||||
{
|
||||
for (object* p = &(t->m->dirtyFixies); *p;) {
|
||||
object o = *p;
|
||||
*p = fixedNext(t, o);
|
||||
|
||||
unsigned size = baseSize(t, o, objectClass(t, o));
|
||||
uintptr_t* mask = fixedMask(t, o, size);
|
||||
for (unsigned word = 0; word < wordOf(size); ++ word) {
|
||||
if (mask[word]) {
|
||||
for (unsigned bit = 0; bit < bitOf(size); ++ bit) {
|
||||
unsigned index = indexOf(word, bit);
|
||||
if (getBit(mask, index)) {
|
||||
visit(t, v, &cast<object>(o, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(mask, 0, ceiling(size, BytesPerWord) * BytesPerWord);
|
||||
fixedDirty(t, o) = 0;
|
||||
fixedMove(t, o, &(t->m->tenuredFixies));
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,29 +368,30 @@ void
|
||||
postVisit(Thread* t, Heap::Visitor* v)
|
||||
{
|
||||
Machine* m = t->m;
|
||||
bool major = m->heap->collectionType() == Heap::MajorCollection;
|
||||
|
||||
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
|
||||
v->visit(p);
|
||||
v->visit(&finalizerTarget(t, *p));
|
||||
visit(t, v, p);
|
||||
visit(t, v, &finalizerTarget(t, *p));
|
||||
}
|
||||
|
||||
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
|
||||
v->visit(p);
|
||||
v->visit(&finalizerTarget(t, *p));
|
||||
visit(t, v, p);
|
||||
visit(t, v, &finalizerTarget(t, *p));
|
||||
}
|
||||
|
||||
object firstNewTenuredFinalizer = 0;
|
||||
object lastNewTenuredFinalizer = 0;
|
||||
|
||||
for (object* p = &(m->finalizers); *p;) {
|
||||
v->visit(p);
|
||||
visit(t, v, p);
|
||||
|
||||
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
||||
// target is unreachable - queue it up for finalization
|
||||
finalizerTargetUnreachable(t, p, v);
|
||||
finalizerTargetUnreachable(t, v, p);
|
||||
} else {
|
||||
// target is reachable
|
||||
v->visit(&finalizerTarget(t, *p));
|
||||
visit(t, v, &finalizerTarget(t, *p));
|
||||
|
||||
if (m->heap->status(*p) == Heap::Tenured) {
|
||||
// the finalizer is tenured, so we remove it from
|
||||
@ -279,15 +417,15 @@ postVisit(Thread* t, Heap::Visitor* v)
|
||||
for (object* p = &(m->weakReferences); *p;) {
|
||||
if (m->heap->status(*p) == Heap::Unreachable) {
|
||||
// reference is unreachable
|
||||
referenceUnreachable(t, p, v);
|
||||
referenceUnreachable(t, v, p);
|
||||
} else if (m->heap->status(jreferenceTarget(t, *p))
|
||||
== Heap::Unreachable)
|
||||
{
|
||||
// target is unreachable
|
||||
referenceTargetUnreachable(t, p, v);
|
||||
referenceTargetUnreachable(t, v, p);
|
||||
} else {
|
||||
// both reference and target are reachable
|
||||
referenceTargetReachable(t, p, v);
|
||||
referenceTargetReachable(t, v, p);
|
||||
|
||||
if (m->heap->status(*p) == Heap::Tenured) {
|
||||
// the reference is tenured, so we remove it from
|
||||
@ -308,16 +446,16 @@ postVisit(Thread* t, Heap::Visitor* v)
|
||||
}
|
||||
}
|
||||
|
||||
if (m->heap->collectionType() == Heap::MajorCollection) {
|
||||
if (major) {
|
||||
for (object* p = &(m->tenuredFinalizers); *p;) {
|
||||
v->visit(p);
|
||||
visit(t, v, p);
|
||||
|
||||
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
||||
// target is unreachable - queue it up for finalization
|
||||
finalizerTargetUnreachable(t, p, v);
|
||||
finalizerTargetUnreachable(t, v, p);
|
||||
} else {
|
||||
// target is reachable
|
||||
v->visit(&finalizerTarget(t, *p));
|
||||
visit(t, v, &finalizerTarget(t, *p));
|
||||
p = &finalizerNext(t, *p);
|
||||
}
|
||||
}
|
||||
@ -325,15 +463,15 @@ postVisit(Thread* t, Heap::Visitor* v)
|
||||
for (object* p = &(m->tenuredWeakReferences); *p;) {
|
||||
if (m->heap->status(*p) == Heap::Unreachable) {
|
||||
// reference is unreachable
|
||||
referenceUnreachable(t, p, v);
|
||||
referenceUnreachable(t, v, p);
|
||||
} else if (m->heap->status(jreferenceTarget(t, *p))
|
||||
== Heap::Unreachable)
|
||||
{
|
||||
// target is unreachable
|
||||
referenceTargetUnreachable(t, p, v);
|
||||
referenceTargetUnreachable(t, v, p);
|
||||
} else {
|
||||
// both reference and target are reachable
|
||||
referenceTargetReachable(t, p, v);
|
||||
referenceTargetReachable(t, v, p);
|
||||
p = &jreferenceNext(t, *p);
|
||||
}
|
||||
}
|
||||
@ -362,11 +500,7 @@ postCollect(Thread* t)
|
||||
t->heap = t->defaultHeap;
|
||||
t->heapOffset = 0;
|
||||
t->heapIndex = 0;
|
||||
|
||||
if (t->large) {
|
||||
t->m->system->free(t->large);
|
||||
t->large = 0;
|
||||
}
|
||||
t->allocatedLarge = false;
|
||||
|
||||
for (Thread* c = t->child; c; c = c->peer) {
|
||||
postCollect(c);
|
||||
@ -1234,7 +1368,8 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
||||
ENTER(t, Thread::ExclusiveState);
|
||||
|
||||
classFlags(t, bootstrapClass) = classFlags(t, class_);
|
||||
classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_);
|
||||
classVmFlags(t, bootstrapClass)
|
||||
|= (classVmFlags(t, class_) & ~BootstrapFlag);
|
||||
|
||||
set(t, bootstrapClass, ClassSuper, classSuper(t, class_));
|
||||
set(t, bootstrapClass, ClassInterfaceTable, classInterfaceTable(t, class_));
|
||||
@ -1404,6 +1539,11 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
finalizeQueue(0),
|
||||
weakReferences(0),
|
||||
tenuredWeakReferences(0),
|
||||
fixies(0),
|
||||
tenuredFixies(0),
|
||||
dirtyFixies(0),
|
||||
markedFixies(0),
|
||||
visitedFixies(0),
|
||||
unsafe(false),
|
||||
heapPoolIndex(0)
|
||||
{
|
||||
@ -1438,6 +1578,12 @@ Machine::dispose()
|
||||
r = r->next;
|
||||
system->free(t);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
||||
system->free(heapPool[i]);
|
||||
}
|
||||
|
||||
system->free(this);
|
||||
}
|
||||
|
||||
Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||
@ -1447,11 +1593,11 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||
peer((parent ? parent->child : 0)),
|
||||
child(0),
|
||||
state(NoState),
|
||||
allocatedLarge(false),
|
||||
criticalLevel(0),
|
||||
systemThread(0),
|
||||
javaThread(javaThread),
|
||||
exception(0),
|
||||
large(0),
|
||||
heapIndex(0),
|
||||
heapOffset(0),
|
||||
protector(0),
|
||||
@ -1479,7 +1625,7 @@ Thread::init()
|
||||
|
||||
Thread* t = this;
|
||||
|
||||
t->m->loader = allocate(t, sizeof(void*) * 3);
|
||||
t->m->loader = allocate(t, sizeof(void*) * 3, true);
|
||||
memset(t->m->loader, 0, sizeof(void*) * 2);
|
||||
|
||||
#include "type-initializations.cpp"
|
||||
@ -1589,20 +1735,11 @@ Thread::exit()
|
||||
void
|
||||
Thread::dispose()
|
||||
{
|
||||
if (large) {
|
||||
m->system->free(large);
|
||||
large = 0;
|
||||
}
|
||||
|
||||
if (systemThread) {
|
||||
systemThread->dispose();
|
||||
systemThread = 0;
|
||||
}
|
||||
|
||||
#ifdef VM_STRESS
|
||||
m->system->free(heap);
|
||||
heap = 0;
|
||||
#endif // VM_STRESS
|
||||
m->system->free(defaultHeap);
|
||||
|
||||
m->system->free(this);
|
||||
}
|
||||
@ -1632,6 +1769,10 @@ exit(Thread* t)
|
||||
function(t, finalizerTarget(t, f));
|
||||
}
|
||||
|
||||
freeFixies(t, &(t->m->tenuredFixies));
|
||||
freeFixies(t, &(t->m->dirtyFixies));
|
||||
freeFixies(t, &(t->m->fixies));
|
||||
|
||||
disposeAll(t, t->m->rootThread);
|
||||
}
|
||||
|
||||
@ -1746,12 +1887,45 @@ enter(Thread* t, Thread::State s)
|
||||
}
|
||||
|
||||
object
|
||||
allocate2(Thread* t, unsigned sizeInBytes)
|
||||
allocateFixed(Thread* t, unsigned sizeInBytes, bool objectMask)
|
||||
{
|
||||
if (sizeInBytes > Thread::HeapSizeInBytes and t->large == 0) {
|
||||
return allocateLarge(t, sizeInBytes);
|
||||
ENTER(t, Thread::ExclusiveState);
|
||||
|
||||
unsigned mask = objectMask
|
||||
* ceiling(sizeInBytes / BytesPerWord, BytesPerWord)
|
||||
* BytesPerWord;
|
||||
unsigned total = sizeInBytes + FixedFootprint + mask;
|
||||
|
||||
uint8_t* p = static_cast<uint8_t*>(t->m->system->tryAllocate(total));
|
||||
if (p == 0) {
|
||||
collect(t, Heap::MajorCollection);
|
||||
|
||||
p = static_cast<uint8_t*>(t->m->system->allocate(total));
|
||||
}
|
||||
|
||||
memset(p + FixedFootprint + sizeInBytes, 0, mask);
|
||||
|
||||
object o = reinterpret_cast<object>(p + FixedFootprint);
|
||||
|
||||
cast<uintptr_t>(o, 0) = FixedMark;
|
||||
fixedAge(t, o) = 0;
|
||||
fixedMarked(t, o) = 0;
|
||||
fixedDirty(t, o) = 0;
|
||||
fixedAdd(t, o, &(t->m->fixies));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
object
|
||||
allocateLarge(Thread* t, unsigned sizeInBytes, bool objectMask)
|
||||
{
|
||||
t->allocatedLarge = true;
|
||||
return allocateFixed(t, sizeInBytes, objectMask);
|
||||
}
|
||||
|
||||
object
|
||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
||||
{
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
while (t->m->exclusive and t->m->exclusive != t) {
|
||||
@ -1760,11 +1934,14 @@ allocate2(Thread* t, unsigned sizeInBytes)
|
||||
ENTER(t, Thread::IdleState);
|
||||
}
|
||||
|
||||
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||
if (sizeInBytes <= Thread::HeapSizeInBytes
|
||||
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||
>= Thread::HeapSizeInWords)
|
||||
{
|
||||
t->heap = 0;
|
||||
if (t->large == 0 and t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
||||
if ((not t->allocatedLarge)
|
||||
and t->m->heapPoolIndex < Machine::HeapPoolSize)
|
||||
{
|
||||
t->heap = static_cast<uintptr_t*>
|
||||
(t->m->system->tryAllocate(Thread::HeapSizeInBytes));
|
||||
if (t->heap) {
|
||||
@ -1781,7 +1958,7 @@ allocate2(Thread* t, unsigned sizeInBytes)
|
||||
}
|
||||
|
||||
if (sizeInBytes > Thread::HeapSizeInBytes) {
|
||||
return allocateLarge(t, sizeInBytes);
|
||||
return allocateLarge(t, sizeInBytes, objectMask);
|
||||
} else {
|
||||
return allocateSmall(t, sizeInBytes);
|
||||
}
|
||||
@ -2533,38 +2710,53 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
Client(Machine* m): m(m) { }
|
||||
|
||||
virtual void visitRoots(Heap::Visitor* v) {
|
||||
v->visit(&(m->loader));
|
||||
v->visit(&(m->bootstrapClassMap));
|
||||
v->visit(&(m->monitorMap));
|
||||
v->visit(&(m->stringMap));
|
||||
v->visit(&(m->types));
|
||||
v->visit(&(m->jniInterfaceTable));
|
||||
Thread* t = m->rootThread;
|
||||
|
||||
visit(t, v, &(m->loader));
|
||||
visit(t, v, &(m->bootstrapClassMap));
|
||||
visit(t, v, &(m->monitorMap));
|
||||
visit(t, v, &(m->stringMap));
|
||||
visit(t, v, &(m->types));
|
||||
visit(t, v, &(m->jniInterfaceTable));
|
||||
|
||||
for (Reference* r = m->jniReferences; r; r = r->next) {
|
||||
v->visit(&(r->target));
|
||||
visit(t, v, &(r->target));
|
||||
}
|
||||
|
||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||
::visitRoots(t, v);
|
||||
}
|
||||
|
||||
if (m->heap->collectionType() == Heap::MinorCollection) {
|
||||
visitDirtyFixies(t, v);
|
||||
}
|
||||
|
||||
postVisit(m->rootThread, v);
|
||||
}
|
||||
|
||||
virtual unsigned sizeInWords(void* p) {
|
||||
virtual bool checkFixed(void* p) {
|
||||
Thread* t = m->rootThread;
|
||||
object o = static_cast<object>(p);
|
||||
|
||||
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||
|
||||
return extendedSize
|
||||
(t, o, baseSize(t, o, static_cast<object>
|
||||
(m->heap->follow(objectClass(t, o)))));
|
||||
if (objectFixed(t, o)) {
|
||||
if ((not fixedMarked(t, o))
|
||||
and m->heap->collectionType() == Heap::MajorCollection
|
||||
or fixedAge(t, o) < TenureThreshold)
|
||||
{
|
||||
fixedMarked(t, o) = 1;
|
||||
fixedMove(t, o, &(m->markedFixies));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned copiedSizeInWords(void* p) {
|
||||
Thread* t = m->rootThread;
|
||||
|
||||
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||
assert(t, not objectFixed(t, o));
|
||||
|
||||
unsigned n = baseSize(t, o, static_cast<object>
|
||||
(m->heap->follow(objectClass(t, o))));
|
||||
@ -2580,6 +2772,8 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
Thread* t = m->rootThread;
|
||||
|
||||
object src = static_cast<object>(m->heap->follow(mask(srcp)));
|
||||
assert(t, not objectFixed(t, src));
|
||||
|
||||
object class_ = static_cast<object>
|
||||
(m->heap->follow(objectClass(t, src)));
|
||||
|
||||
@ -2601,67 +2795,9 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
Thread* t = m->rootThread;
|
||||
|
||||
object o = static_cast<object>(m->heap->follow(mask(p)));
|
||||
object class_ = static_cast<object>(m->heap->follow(objectClass(t, o)));
|
||||
object objectMask = static_cast<object>
|
||||
(m->heap->follow(classObjectMask(t, class_)));
|
||||
assert(t, not objectFixed(t, o));
|
||||
|
||||
if (objectMask) {
|
||||
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
|
||||
// p, class_, objectMask, intArrayLength(t, objectMask));
|
||||
|
||||
unsigned fixedSize = classFixedSize(t, class_);
|
||||
unsigned arrayElementSize = classArrayElementSize(t, class_);
|
||||
unsigned arrayLength
|
||||
= (arrayElementSize ?
|
||||
cast<uintptr_t>(p, fixedSize - BytesPerWord) : 0);
|
||||
|
||||
int mask[intArrayLength(t, objectMask)];
|
||||
memcpy(mask, &intArrayBody(t, objectMask, 0),
|
||||
intArrayLength(t, objectMask) * 4);
|
||||
|
||||
// fprintf
|
||||
// (stderr,
|
||||
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
|
||||
// fixedSize, arrayLength, arrayElementSize, mask[0]);
|
||||
|
||||
unsigned fixedSizeInWords = ceiling(fixedSize, BytesPerWord);
|
||||
unsigned arrayElementSizeInWords
|
||||
= ceiling(arrayElementSize, BytesPerWord);
|
||||
|
||||
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
|
||||
if (mask[i / 32] & (static_cast<uintptr_t>(1) << (i % 32))) {
|
||||
if (not w->visit(i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool arrayObjectElements = false;
|
||||
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
||||
unsigned k = fixedSizeInWords + j;
|
||||
if (mask[k / 32] & (static_cast<uintptr_t>(1) << (k % 32))) {
|
||||
arrayObjectElements = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (arrayObjectElements) {
|
||||
for (unsigned i = 0; i < arrayLength; ++i) {
|
||||
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
||||
unsigned k = fixedSizeInWords + j;
|
||||
if (mask[k / 32] & (static_cast<uintptr_t>(1) << (k % 32))) {
|
||||
if (not w->visit
|
||||
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w->visit(0);
|
||||
}
|
||||
::walk(m->rootThread, o, w);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -2687,6 +2823,8 @@ collect(Thread* t, Heap::CollectionType type)
|
||||
m->system->free(m->heapPool[i]);
|
||||
}
|
||||
m->heapPoolIndex = 0;
|
||||
|
||||
sweepFixies(t);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2769,6 +2907,84 @@ makeTrace(Thread* t, uintptr_t start)
|
||||
return trace;
|
||||
}
|
||||
|
||||
void
|
||||
mark(Thread* t, object o, unsigned offset)
|
||||
{
|
||||
if (objectFixed(t, o)) {
|
||||
if (fixedAge(t, o) == TenureThreshold) {
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
|
||||
markBit(fixedMask(t, o), offset / BytesPerWord);
|
||||
|
||||
fixedDirty(t, o) = 1;
|
||||
fixedMove(t, o, &(t->m->dirtyFixies));
|
||||
}
|
||||
} else if (t->m->heap->needsMark(&cast<void*>(o, offset))) {
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
|
||||
t->m->heap->mark(&cast<void*>(o, offset));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mark(Thread* t, object o, unsigned offset, unsigned count)
|
||||
{
|
||||
if (objectFixed(t, o)) {
|
||||
if (fixedAge(t, o) == TenureThreshold) {
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
|
||||
uintptr_t* mask = fixedMask(t, o);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
markBit(mask, (offset / BytesPerWord) + i);
|
||||
}
|
||||
|
||||
fixedDirty(t, o) = 1;
|
||||
fixedMove(t, o, &(t->m->dirtyFixies));
|
||||
}
|
||||
} else {
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
unsigned j = offset + (i * BytesPerWord);
|
||||
if (t->m->heap->needsMark(&cast<void*>(o, j))) {
|
||||
t->m->heap->mark(&cast<void*>(o, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visit(Thread* t, Heap::Visitor* v, object* p)
|
||||
{
|
||||
v->visit(p);
|
||||
|
||||
for (object* p = &(t->m->markedFixies); *p;) {
|
||||
object o = *p;
|
||||
*p = fixedNext(t, o);
|
||||
|
||||
class Walker: public Heap::Walker {
|
||||
public:
|
||||
Walker(Thread* t, Heap::Visitor* v, object o):
|
||||
t(t), v(v), o(o)
|
||||
{ }
|
||||
|
||||
virtual bool visit(unsigned offset) {
|
||||
::visit(t, v, &cast<object>(o, offset * BytesPerWord));
|
||||
return true;
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
Heap::Visitor* v;
|
||||
object o;
|
||||
} w(t, v, o);
|
||||
|
||||
walk(t, o, &w);
|
||||
|
||||
fixedMove(t, o, &(t->m->visitedFixies));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
noop()
|
||||
{ }
|
||||
|
158
src/machine.h
158
src/machine.h
@ -34,6 +34,13 @@ const uintptr_t HashTakenMark = 1;
|
||||
const uintptr_t ExtendedMark = 2;
|
||||
const uintptr_t FixedMark = 3;
|
||||
|
||||
const unsigned FixedAge = 0;
|
||||
const unsigned FixedMarked = 1;
|
||||
const unsigned FixedDirty = 2;
|
||||
const unsigned FixedHandle = BytesPerWord;
|
||||
const unsigned FixedNext = BytesPerWord * 2;
|
||||
const unsigned FixedFootprint = BytesPerWord * 3;
|
||||
|
||||
enum FieldCode {
|
||||
VoidField,
|
||||
ByteField,
|
||||
@ -1147,6 +1154,11 @@ class Machine {
|
||||
object finalizeQueue;
|
||||
object weakReferences;
|
||||
object tenuredWeakReferences;
|
||||
object fixies;
|
||||
object tenuredFixies;
|
||||
object dirtyFixies;
|
||||
object markedFixies;
|
||||
object visitedFixies;
|
||||
bool unsafe;
|
||||
JavaVMVTable javaVMVTable;
|
||||
JNIEnvVTable jniEnvVTable;
|
||||
@ -1163,6 +1175,9 @@ threadInterrupted(Thread* t, object thread);
|
||||
void
|
||||
enterActiveState(Thread* t);
|
||||
|
||||
void
|
||||
visit(Thread* t, Heap::Visitor* v, object* p);
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
enum State {
|
||||
@ -1196,7 +1211,7 @@ class Thread {
|
||||
SingleProtector(Thread* t, object* p): Protector(t), p(p) { }
|
||||
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
v->visit(p);
|
||||
vm::visit(t, v, p);
|
||||
}
|
||||
|
||||
object* p;
|
||||
@ -1251,11 +1266,11 @@ class Thread {
|
||||
Thread* peer;
|
||||
Thread* child;
|
||||
State state;
|
||||
bool allocatedLarge;
|
||||
unsigned criticalLevel;
|
||||
System::Thread* systemThread;
|
||||
object javaThread;
|
||||
object exception;
|
||||
object large;
|
||||
unsigned heapIndex;
|
||||
unsigned heapOffset;
|
||||
Protector* protector;
|
||||
@ -1406,25 +1421,23 @@ expect(Thread* t, bool v)
|
||||
expect(t->m->system, v);
|
||||
}
|
||||
|
||||
inline object
|
||||
allocateLarge(Thread* t, unsigned sizeInBytes)
|
||||
{
|
||||
return t->large = static_cast<object>(t->m->system->allocate(sizeInBytes));
|
||||
}
|
||||
object
|
||||
allocateFixed(Thread* t, unsigned sizeInBytes, bool objectMask);
|
||||
|
||||
object
|
||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
||||
|
||||
inline object
|
||||
allocateSmall(Thread* t, unsigned sizeInBytes)
|
||||
{
|
||||
object o = reinterpret_cast<object>(t->heap + t->heapIndex);
|
||||
t->heapIndex += ceiling(sizeInBytes, BytesPerWord);
|
||||
cast<object>(o, 0) = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
object
|
||||
allocate2(Thread* t, unsigned sizeInBytes);
|
||||
|
||||
inline object
|
||||
allocate(Thread* t, unsigned sizeInBytes)
|
||||
allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
||||
{
|
||||
stress(t);
|
||||
|
||||
@ -1432,7 +1445,7 @@ allocate(Thread* t, unsigned sizeInBytes)
|
||||
>= Thread::HeapSizeInWords
|
||||
or t->m->exclusive))
|
||||
{
|
||||
return allocate2(t, sizeInBytes);
|
||||
return allocate2(t, sizeInBytes, objectMask);
|
||||
} else {
|
||||
return allocateSmall(t, sizeInBytes);
|
||||
}
|
||||
@ -1441,6 +1454,9 @@ allocate(Thread* t, unsigned sizeInBytes)
|
||||
void
|
||||
mark(Thread* t, object target, unsigned offset);
|
||||
|
||||
void
|
||||
mark(Thread* t, object target, unsigned offset, unsigned count);
|
||||
|
||||
inline void
|
||||
set(Thread* t, object target, unsigned offset, object value)
|
||||
{
|
||||
@ -1489,41 +1505,93 @@ baseSize(Thread* t, object o, object class_)
|
||||
BytesPerWord);
|
||||
}
|
||||
|
||||
inline void
|
||||
mark(Thread* t, object target, unsigned offset, unsigned count)
|
||||
inline void*
|
||||
fixedStart(Thread* t UNUSED, object o)
|
||||
{
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
if (objectFixed(t, target)) {
|
||||
unsigned size = baseSize(t, target, objectClass(t, target))
|
||||
* BytesPerWord;
|
||||
assert(t, objectFixed(t, o));
|
||||
return &cast<object>(o, - FixedFootprint);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
markBit(&cast<uintptr_t>(target, size), offset + (i * BytesPerWord));
|
||||
}
|
||||
} else {
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
unsigned j = offset + (i * BytesPerWord);
|
||||
if (t->m->heap->needsMark(&cast<void*>(target, j))) {
|
||||
t->m->heap->mark(&cast<void*>(target, j));
|
||||
}
|
||||
}
|
||||
inline uint8_t&
|
||||
fixedAge(Thread* t UNUSED, object o)
|
||||
{
|
||||
assert(t, objectFixed(t, o));
|
||||
return cast<uint8_t>(o, - (FixedFootprint - FixedAge));
|
||||
}
|
||||
|
||||
inline uint8_t&
|
||||
fixedMarked(Thread* t UNUSED, object o)
|
||||
{
|
||||
assert(t, objectFixed(t, o));
|
||||
return cast<uint8_t>(o, - (FixedFootprint - FixedMarked));
|
||||
}
|
||||
|
||||
inline uint8_t&
|
||||
fixedDirty(Thread* t UNUSED, object o)
|
||||
{
|
||||
assert(t, objectFixed(t, o));
|
||||
return cast<uint8_t>(o, - (FixedFootprint - FixedDirty));
|
||||
}
|
||||
|
||||
inline object*&
|
||||
fixedHandle(Thread* t UNUSED, object o)
|
||||
{
|
||||
assert(t, objectFixed(t, o));
|
||||
return cast<object*>(o, - (FixedFootprint - FixedHandle));
|
||||
}
|
||||
|
||||
inline object&
|
||||
fixedNext(Thread* t UNUSED, object o)
|
||||
{
|
||||
assert(t, objectFixed(t, o));
|
||||
return cast<object>(o, - (FixedFootprint - FixedNext));
|
||||
}
|
||||
|
||||
inline void
|
||||
fixedAdd(Thread* t, object o, object* handle)
|
||||
{
|
||||
// fprintf(stderr, "add %p to %s\n", o,
|
||||
// handle == &(t->m->fixies) ? "fixies" :
|
||||
// handle == &(t->m->tenuredFixies) ? "tenured" :
|
||||
// handle == &(t->m->dirtyFixies) ? "dirty" :
|
||||
// handle == &(t->m->markedFixies) ? "marked" :
|
||||
// handle == &(t->m->visitedFixies) ? "visited" : "unknown");
|
||||
|
||||
fixedHandle(t, o) = handle;
|
||||
fixedNext(t, o) = *handle;
|
||||
if (*handle) {
|
||||
fixedHandle(t, *handle) = &fixedNext(t, o);
|
||||
}
|
||||
*handle = o;
|
||||
}
|
||||
|
||||
inline void
|
||||
fixedRemove(Thread* t, object o)
|
||||
{
|
||||
*fixedHandle(t, o) = fixedNext(t, o);
|
||||
if (fixedNext(t, o)) {
|
||||
fixedHandle(t, fixedNext(t, o)) = fixedHandle(t, o);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
mark(Thread* t, object target, unsigned offset)
|
||||
fixedMove(Thread* t, object o, object* handle)
|
||||
{
|
||||
if (objectFixed(t, target)) {
|
||||
unsigned size = baseSize(t, target, objectClass(t, target)) * BytesPerWord;
|
||||
fixedRemove(t, o);
|
||||
fixedAdd(t, o, handle);
|
||||
}
|
||||
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
inline uintptr_t*
|
||||
fixedMask(Thread* t UNUSED, object o, unsigned size)
|
||||
{
|
||||
assert(t, objectFixed(t, o));
|
||||
return &cast<uintptr_t>(o, size * BytesPerWord);
|
||||
}
|
||||
|
||||
markBit(&cast<uintptr_t>(target, size), offset);
|
||||
} else if (t->m->heap->needsMark(&cast<void*>(target, offset))) {
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
|
||||
t->m->heap->mark(&cast<void*>(target, offset));
|
||||
}
|
||||
inline uintptr_t*
|
||||
fixedMask(Thread* t, object o)
|
||||
{
|
||||
return fixedMask(t, o, baseSize(t, o, objectClass(t, o)));
|
||||
}
|
||||
|
||||
object
|
||||
@ -1664,10 +1732,10 @@ makeNew(Thread* t, object class_)
|
||||
{
|
||||
PROTECT(t, class_);
|
||||
unsigned sizeInBytes = pad(classFixedSize(t, class_));
|
||||
object instance = allocate(t, sizeInBytes);
|
||||
cast<object>(instance, 0) = class_;
|
||||
memset(&cast<object>(instance, 0) + 1, 0,
|
||||
sizeInBytes - sizeof(object));
|
||||
object instance = allocate(t, sizeInBytes, classObjectMask(t, class_));
|
||||
setObjectClass(t, instance, class_);
|
||||
memset(&cast<object>(instance, BytesPerWord), 0,
|
||||
sizeInBytes - BytesPerWord);
|
||||
|
||||
return instance;
|
||||
}
|
||||
@ -1696,9 +1764,6 @@ make(Thread* t, object class_)
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
make(Thread* t, object class_);
|
||||
|
||||
object
|
||||
makeByteArray(Thread* t, const char* format, ...);
|
||||
|
||||
@ -1738,9 +1803,10 @@ markHashTaken(Thread* t, object o)
|
||||
{
|
||||
assert(t, not objectExtended(t, o));
|
||||
assert(t, not objectFixed(t, o));
|
||||
cast<uintptr_t>(o, 0) |= HashTakenMark;
|
||||
|
||||
ACQUIRE_RAW(t, t->m->heapLock);
|
||||
|
||||
cast<uintptr_t>(o, 0) |= HashTakenMark;
|
||||
t->m->heap->pad(o, 1);
|
||||
}
|
||||
|
||||
|
27
src/main.cpp
27
src/main.cpp
@ -7,6 +7,33 @@ extern "C" void __cxa_pure_virtual(void) { abort(); }
|
||||
|
||||
void operator delete(void*) { abort(); }
|
||||
|
||||
#ifdef JNI_VERSION_1_6
|
||||
// todo: use JavaVMInitArgs instead
|
||||
typedef struct JDK1_1InitArgs {
|
||||
jint version;
|
||||
|
||||
char **properties;
|
||||
jint checkSource;
|
||||
jint nativeStackSize;
|
||||
jint javaStackSize;
|
||||
jint minHeapSize;
|
||||
jint maxHeapSize;
|
||||
jint verifyMode;
|
||||
char *classpath;
|
||||
|
||||
jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args);
|
||||
void (JNICALL *exit)(jint code);
|
||||
void (JNICALL *abort)(void);
|
||||
|
||||
jint enableClassGC;
|
||||
jint enableVerboseGC;
|
||||
jint disableAsyncGC;
|
||||
jint verbose;
|
||||
jboolean debugging;
|
||||
jint debugPort;
|
||||
} JDK1_1InitArgs;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
|
@ -1284,6 +1284,25 @@ writeAccessors(Output* out, Object* declarations)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
typeFixedSize(Object* type)
|
||||
{
|
||||
unsigned length = BytesPerWord;
|
||||
for (MemberIterator it(type); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
switch (m->type) {
|
||||
case Object::Scalar: {
|
||||
length = pad(it.offset() + it.size());
|
||||
} break;
|
||||
|
||||
case Object::Array: break;
|
||||
|
||||
default: UNREACHABLE;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
const char*
|
||||
obfuscate(const char* s)
|
||||
{
|
||||
@ -1324,6 +1343,26 @@ writeConstructorParameters(Output* out, Object* t)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeConstructorArguments(Output* out, Object* t)
|
||||
{
|
||||
for (MemberIterator it(t); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
switch (m->type) {
|
||||
case Object::Scalar: {
|
||||
out->write(", ");
|
||||
out->write(obfuscate(memberName(m)));
|
||||
} break;
|
||||
|
||||
case Object::Array: {
|
||||
out->write(", clear");
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeConstructorInitializations(Output* out, Object* t)
|
||||
{
|
||||
@ -1361,6 +1400,28 @@ typeMemberCount(Object* o)
|
||||
return length(typeMembers(o)) + typeMemberCount(typeSuper(o));
|
||||
}
|
||||
|
||||
void
|
||||
writeInitializerDeclarations(Output* out, Object* declarations)
|
||||
{
|
||||
for (Object* p = declarations; p; p = cdr(p)) {
|
||||
Object* o = car(p);
|
||||
switch (o->type) {
|
||||
case Object::Type: {
|
||||
out->write("void init");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t, object o");
|
||||
|
||||
writeConstructorParameters(out, o);
|
||||
|
||||
out->write(");\n\n");
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeConstructorDeclarations(Output* out, Object* declarations)
|
||||
{
|
||||
@ -1383,6 +1444,37 @@ writeConstructorDeclarations(Output* out, Object* declarations)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeInitializers(Output* out, Object* declarations)
|
||||
{
|
||||
for (Object* p = declarations; p; p = cdr(p)) {
|
||||
Object* o = car(p);
|
||||
switch (o->type) {
|
||||
case Object::Type: {
|
||||
out->write("void\ninit");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t, object o");
|
||||
|
||||
writeConstructorParameters(out, o);
|
||||
|
||||
out->write(")\n{\n");
|
||||
|
||||
out->write(" setObjectClass(t, o, ");
|
||||
out->write("arrayBody(t, t->m->types, Machine::");
|
||||
out->write(capitalize(typeName(o)));
|
||||
out->write("Type));\n");
|
||||
|
||||
writeConstructorInitializations(out, o);
|
||||
|
||||
out->write("}\n\n");
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeConstructors(Output* out, Object* declarations)
|
||||
{
|
||||
@ -1390,7 +1482,7 @@ writeConstructors(Output* out, Object* declarations)
|
||||
Object* o = car(p);
|
||||
switch (o->type) {
|
||||
case Object::Type: {
|
||||
out->write("object\nmake");
|
||||
out->write("object make");
|
||||
out->write(capitalize(typeName(o)));
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(Thread* t");
|
||||
@ -1399,14 +1491,18 @@ writeConstructors(Output* out, Object* declarations)
|
||||
|
||||
out->write(")\n{\n");
|
||||
|
||||
bool hasObjectMask = false;
|
||||
for (MemberIterator it(o); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
if (m->type == Object::Scalar
|
||||
and equal(memberTypeName(m), "object"))
|
||||
and equal(memberTypeName(m), "object")
|
||||
and not memberNoGC(m))
|
||||
{
|
||||
out->write(" PROTECT(t, ");
|
||||
out->write(obfuscate(memberName(m)));
|
||||
out->write(");\n");
|
||||
|
||||
hasObjectMask = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1438,14 +1534,19 @@ writeConstructors(Output* out, Object* declarations)
|
||||
|
||||
out->write(" object o = allocate(t, ");
|
||||
writeOffset(out, typeOffset(o), true);
|
||||
if (hasObjectMask) {
|
||||
out->write(", true");
|
||||
} else {
|
||||
out->write(", false");
|
||||
}
|
||||
out->write(");\n");
|
||||
|
||||
out->write(" cast<object>(o, 0) ");
|
||||
out->write("= arrayBody(t, t->m->types, Machine::");
|
||||
out->write(" init");
|
||||
out->write(capitalize(typeName(o)));
|
||||
out->write("Type);\n");
|
||||
|
||||
writeConstructorInitializations(out, o);
|
||||
if (typeHideConstructor(o)) out->write("0");
|
||||
out->write("(t, o");
|
||||
writeConstructorArguments(out, o);
|
||||
out->write(");\n");
|
||||
|
||||
out->write(" return o;\n}\n\n");
|
||||
} break;
|
||||
@ -1502,25 +1603,6 @@ set(uint32_t* mask, unsigned index)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
typeFixedSize(Object* type)
|
||||
{
|
||||
unsigned length = BytesPerWord;
|
||||
for (MemberIterator it(type); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
switch (m->type) {
|
||||
case Object::Scalar: {
|
||||
length = pad(it.offset() + it.size());
|
||||
} break;
|
||||
|
||||
case Object::Array: break;
|
||||
|
||||
default: UNREACHABLE;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
unsigned
|
||||
typeArrayElementSize(Object* type)
|
||||
{
|
||||
@ -1673,8 +1755,7 @@ writeInitializations(Output* out, Object* declarations)
|
||||
|
||||
out->write("t->m->types = allocate(t, pad((");
|
||||
out->write(count);
|
||||
out->write(" * BytesPerWord) + (BytesPerWord * 2)));\n");
|
||||
out->write("cast<object>(t->m->types, 0) = 0;\n");
|
||||
out->write(" * BytesPerWord) + (BytesPerWord * 2)), true);\n");
|
||||
out->write("arrayLength(t, t->m->types) = ");
|
||||
out->write(count);
|
||||
out->write(";\n");
|
||||
@ -1763,10 +1844,12 @@ main(int ac, char** av)
|
||||
if (ac == 1 or equal(av[1], "declarations")) {
|
||||
writePods(&out, declarations);
|
||||
writeAccessors(&out, declarations);
|
||||
writeInitializerDeclarations(&out, declarations);
|
||||
writeConstructorDeclarations(&out, declarations);
|
||||
}
|
||||
|
||||
if (ac == 1 or equal(av[1], "constructors")) {
|
||||
writeInitializers(&out, declarations);
|
||||
writeConstructors(&out, declarations);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,13 @@ public class GC {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
byte[] a = new byte[16 * 1024 * 1024];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
byte[] a = new byte[16 * 1024 * 1024];
|
||||
for (int j = 0; j < 32; ++j) {
|
||||
byte[] b = new byte[32 * 1024];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
Loading…
Reference in New Issue
Block a user