implement fixed object support

This commit is contained in:
Joel Dice 2007-10-27 19:54:30 -06:00
parent 6710ca85d7
commit 60072b9fdc
16 changed files with 653 additions and 239 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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));
}
}
}

View File

@ -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;

View File

@ -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()
{ }

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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) {