mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
flesh out call tracing in new JIT code
This commit is contained in:
parent
49ed41daa0
commit
0bbe9489a7
4
makefile
4
makefile
@ -145,12 +145,14 @@ interpreter-depends = \
|
||||
$(src)/stream.h \
|
||||
$(src)/constants.h \
|
||||
$(src)/jnienv.h \
|
||||
$(src)/machine.h
|
||||
$(src)/machine.h \
|
||||
$(src)/util.h
|
||||
|
||||
interpreter-sources = \
|
||||
$(src)/$(system).cpp \
|
||||
$(src)/finder.cpp \
|
||||
$(src)/machine.cpp \
|
||||
$(src)/util.cpp \
|
||||
$(src)/heap.cpp \
|
||||
$(src)/$(process).cpp \
|
||||
$(src)/builtin.cpp \
|
||||
|
29
src/buffer.h
29
src/buffer.h
@ -51,6 +51,23 @@ class Buffer {
|
||||
position += 4;
|
||||
}
|
||||
|
||||
void appendAddress(uintptr_t v) {
|
||||
append4(v);
|
||||
if (BytesPerWord == 8) {
|
||||
// we have to use the preprocessor here to avoid a warning on
|
||||
// 32-bit systems
|
||||
#ifdef __x86_64__
|
||||
append4(v >> 32);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void append(void* p, unsigned size) {
|
||||
ensure(size);
|
||||
memcpy(data + position, p, size);
|
||||
position += size;
|
||||
}
|
||||
|
||||
void set2(unsigned offset, uint32_t v) {
|
||||
assert(s, offset + 2 <= position);
|
||||
memcpy(data + offset, &v, 2);
|
||||
@ -81,15 +98,9 @@ class Buffer {
|
||||
return *reinterpret_cast<uintptr_t*>(data + offset);
|
||||
}
|
||||
|
||||
void appendAddress(uintptr_t v) {
|
||||
append4(v);
|
||||
if (BytesPerWord == 8) {
|
||||
// we have to use the preprocessor here to avoid a warning on
|
||||
// 32-bit systems
|
||||
#ifdef __x86_64__
|
||||
append4(v >> 32);
|
||||
#endif
|
||||
}
|
||||
void get(unsigned offset, void* p, unsigned size) {
|
||||
assert(s, offset + size <= position);
|
||||
memcpy(p, data + offset, size);
|
||||
}
|
||||
|
||||
unsigned length() {
|
||||
|
256
src/compile2.cpp
256
src/compile2.cpp
@ -1,4 +1,5 @@
|
||||
#include "machine.h"
|
||||
#include "util.h"
|
||||
#include "buffer.h"
|
||||
#include "process.h"
|
||||
#include "compiler.h"
|
||||
@ -84,6 +85,9 @@ resolveTarget(MyThread* t, void* stack, object method)
|
||||
object
|
||||
findTraceNode(MyThread* t, void* address);
|
||||
|
||||
void
|
||||
insertTraceNode(MyThread* t, object node);
|
||||
|
||||
class MyStackWalker: public Processor::StackWalker {
|
||||
public:
|
||||
class MyProtector: public Thread::Protector {
|
||||
@ -175,9 +179,9 @@ class MyStackWalker: public Processor::StackWalker {
|
||||
|
||||
virtual int ip() {
|
||||
if (nativeMethod) {
|
||||
return NativeLine;
|
||||
return 0;
|
||||
} else {
|
||||
return traceNodeLine(t, node);
|
||||
return treeNodeKey(t, node);
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +239,7 @@ class Frame {
|
||||
public:
|
||||
class MyProtector: public Thread::Protector {
|
||||
public:
|
||||
MyProtector(MyThread* t, Frame* frame): Protector(t), frame(frame) { }
|
||||
MyProtector(Frame* frame): Protector(frame->t), frame(frame) { }
|
||||
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
v->visit(&(frame->method));
|
||||
@ -245,6 +249,12 @@ class Frame {
|
||||
for (unsigned i = 1; i < pool->length(); i += BytesPerWord * 2) {
|
||||
v->visit(reinterpret_cast<object*>(&(pool->getAddress(i))));
|
||||
}
|
||||
|
||||
Buffer* log = frame->traceLog;
|
||||
unsigned traceSize = traceSizeInBytes(t, frame->method);
|
||||
for (unsigned i = 1; i < log->length(); i += traceSize) {
|
||||
v->visit(reinterpret_cast<object*>(&(log->getAddress(i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,16 +262,18 @@ class Frame {
|
||||
};
|
||||
|
||||
Frame(MyThread* t, Compiler* c, object method, uintptr_t* map,
|
||||
Buffer* objectPool):
|
||||
Buffer* objectPool, Buffer* traceLog):
|
||||
next(0),
|
||||
t(t),
|
||||
c(c),
|
||||
method(method),
|
||||
map(map),
|
||||
objectPool(objectPool),
|
||||
traceLog(traceLog),
|
||||
codeMask(makeCodeMask(t, codeLength(t, methodCode(t, method)))),
|
||||
ip(0),
|
||||
sp(localSize(t, method)),
|
||||
protector(t, this)
|
||||
protector(this)
|
||||
{
|
||||
memset(map, 0, mapSizeInBytes(t, method));
|
||||
}
|
||||
@ -273,9 +285,11 @@ class Frame {
|
||||
method(f->method),
|
||||
map(map),
|
||||
objectPool(f->objectPool),
|
||||
traceLog(f->traceLog),
|
||||
codeMask(f->codeMask),
|
||||
ip(f->ip),
|
||||
sp(f->sp),
|
||||
protector(t, this)
|
||||
protector(this)
|
||||
{
|
||||
memcpy(map, f->map, mapSizeInBytes(t, method));
|
||||
}
|
||||
@ -285,8 +299,8 @@ class Frame {
|
||||
}
|
||||
|
||||
Operand* append(object o) {
|
||||
objectPool->appendAddress(reinterpret_cast<uintptr_t>(c->poolOffset()));
|
||||
Operand* result = c->poolAppend(c->constant(0));
|
||||
objectPool->appendAddress(c->poolOffset(result));
|
||||
objectPool->appendAddress(reinterpret_cast<uintptr_t>(o));
|
||||
return result;
|
||||
}
|
||||
@ -316,6 +330,10 @@ class Frame {
|
||||
return mapSizeInWords(t, method) * BytesPerWord;
|
||||
}
|
||||
|
||||
static unsigned traceSizeInBytes(Thread* t, object method) {
|
||||
return BytesPerWord + BytesPerWord + 1 + mapSizeInWords(t, method);
|
||||
}
|
||||
|
||||
void pushedInt() {
|
||||
assert(t, sp + 1 <= mapSize(t, method));
|
||||
assert(t, getBit(map, sp) == 0);
|
||||
@ -518,6 +536,22 @@ class Frame {
|
||||
}
|
||||
}
|
||||
|
||||
void trace(object target, bool virtualCall) {
|
||||
traceLog->appendAddress(reinterpret_cast<uintptr_t>(target));
|
||||
traceLog->appendAddress(reinterpret_cast<uintptr_t>(c->codeOffset()));
|
||||
traceLog->append(virtualCall);
|
||||
traceLog->append(map, mapSizeInWords(t, method) * BytesPerWord);
|
||||
}
|
||||
|
||||
void trace() {
|
||||
trace(0, false);
|
||||
}
|
||||
|
||||
void startLogicalIp(unsigned ip) {
|
||||
c->startLogicalIp(ip);
|
||||
this->ip = ip;
|
||||
}
|
||||
|
||||
void pushInt(Operand* o) {
|
||||
c->push(o);
|
||||
pushedInt();
|
||||
@ -727,7 +761,9 @@ class Frame {
|
||||
object method;
|
||||
uintptr_t* map;
|
||||
Buffer* objectPool;
|
||||
Buffer* traceLog;
|
||||
uintptr_t* codeMask;
|
||||
unsigned ip;
|
||||
unsigned sp;
|
||||
MyProtector protector;
|
||||
};
|
||||
@ -741,10 +777,14 @@ unwind(MyThread* t)
|
||||
void* returnAddress = *stack;
|
||||
object node = findTraceNode(t, returnAddress);
|
||||
if (node) {
|
||||
void* handler = traceNodeHandler(t, node);
|
||||
if (handler) {
|
||||
object method = traceNodeMethod(t, node);
|
||||
object method = traceNodeMethod(t, node);
|
||||
uint8_t* compiled = reinterpret_cast<uint8_t*>
|
||||
(&singletonValue(t, methodCompiled(t, method), 0));
|
||||
|
||||
ExceptionHandler* handler = findExceptionHandler
|
||||
(t, method, difference(returnAddress, compiled));
|
||||
|
||||
if (handler) {
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||
unsigned localFootprint = codeMaxLocals(t, methodCode(t, method));
|
||||
|
||||
@ -755,7 +795,7 @@ unwind(MyThread* t)
|
||||
*(--stack) = t->exception;
|
||||
t->exception = 0;
|
||||
|
||||
vmJump(handler, base, stack);
|
||||
vmJump(compiled + exceptionHandlerIp(handler), base, stack);
|
||||
} else {
|
||||
stack = static_cast<void**>(base) + 1;
|
||||
base = *static_cast<void**>(base);
|
||||
@ -1082,8 +1122,11 @@ compileThrowNew(MyThread* t, Frame* frame, Machine::Type type)
|
||||
{
|
||||
Operand* class_ = frame->append(arrayBody(t, t->m->types, type));
|
||||
Compiler* c = frame->c;
|
||||
c->indirectCallNoReturn(c->constant(reinterpret_cast<intptr_t>(throwNew)),
|
||||
2, c->thread(), class_);
|
||||
c->indirectCallNoReturn
|
||||
(c->constant(reinterpret_cast<intptr_t>(throwNew)),
|
||||
2, c->thread(), class_);
|
||||
|
||||
frame->trace();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1124,6 +1167,8 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target)
|
||||
(reinterpret_cast<intptr_t>
|
||||
(&singletonBody(t, methodCompiled(t, target), 0))));
|
||||
|
||||
frame->trace(target, false);
|
||||
|
||||
frame->pop(methodParameterFootprint(t, target));
|
||||
|
||||
pushReturnValue(t, frame, methodReturnCode(t, target), result);
|
||||
@ -1148,7 +1193,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
markBit(frame->codeMask, ip);
|
||||
|
||||
c->startLogicalIp(ip);
|
||||
frame->startLogicalIp(ip);
|
||||
|
||||
unsigned instruction = codeBody(t, code, ip++);
|
||||
|
||||
@ -1243,8 +1288,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
c->shl(c->constant(log(BytesPerWord)), index);
|
||||
c->add(c->constant(ArrayBody), index);
|
||||
|
||||
c->directCall(c->constant(reinterpret_cast<intptr_t>(set)),
|
||||
4, c->thread(), array, index, value);
|
||||
c->directCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(set)),
|
||||
4, c->thread(), array, index, value);
|
||||
|
||||
frame->trace();
|
||||
break;
|
||||
|
||||
case fastore:
|
||||
@ -1315,10 +1363,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
c->mark(nonnegative);
|
||||
|
||||
frame->pushObject
|
||||
(c->indirectCall
|
||||
Operand* r = c->indirectCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(makeBlankObjectArray)),
|
||||
3, c->thread(), frame->append(class_), length));
|
||||
3, c->thread(), frame->append(class_), length);
|
||||
|
||||
frame->trace();
|
||||
|
||||
frame->pushObject(r);
|
||||
} break;
|
||||
|
||||
case areturn:
|
||||
@ -1354,6 +1405,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
c->indirectCallNoReturn
|
||||
(c->constant(reinterpret_cast<intptr_t>(throw_)),
|
||||
2, c->thread(), frame->popObject());
|
||||
|
||||
frame->trace();
|
||||
break;
|
||||
|
||||
case bipush:
|
||||
@ -1974,6 +2027,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
Operand* result = c->call(c->memory(found, SingletonBody));
|
||||
|
||||
frame->trace(target, true);
|
||||
|
||||
frame->pop(parameterFootprint);
|
||||
|
||||
pushReturnValue(t, frame, methodReturnCode(t, target), result);
|
||||
@ -2024,6 +2079,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
Operand* result = c->call(c->memory(class_, offset));
|
||||
|
||||
frame->trace(target, true);
|
||||
|
||||
c->release(class_);
|
||||
|
||||
frame->pop(parameterFootprint);
|
||||
@ -2338,12 +2395,16 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
c->indirectCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(acquireMonitorForObject)),
|
||||
2, c->thread(), frame->popObject());
|
||||
|
||||
frame->trace();
|
||||
} break;
|
||||
|
||||
case monitorexit: {
|
||||
c->indirectCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(releaseMonitorForObject)),
|
||||
2, c->thread(), frame->popObject());
|
||||
|
||||
frame->trace();
|
||||
} break;
|
||||
|
||||
case multianewarray: {
|
||||
@ -2359,6 +2420,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
4, c->thread(), frame->append(class_), c->stack(),
|
||||
c->constant(dimensions));
|
||||
|
||||
frame->trace();
|
||||
|
||||
frame->pop(dimensions);
|
||||
frame->pushObject(result);
|
||||
} break;
|
||||
@ -2384,6 +2447,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
2, c->thread(), frame->append(class_));
|
||||
}
|
||||
|
||||
frame->trace();
|
||||
|
||||
frame->pushObject(result);
|
||||
} break;
|
||||
|
||||
@ -2437,10 +2502,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
default: abort(t);
|
||||
}
|
||||
|
||||
frame->pushObject
|
||||
(c->indirectCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(makeBlankArray)),
|
||||
2, c->constant(reinterpret_cast<intptr_t>(constructor)), size));
|
||||
Operand* result = c->indirectCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(makeBlankArray)),
|
||||
2, c->constant(reinterpret_cast<intptr_t>(constructor)), size);
|
||||
|
||||
frame->trace();
|
||||
|
||||
frame->pushObject(result);
|
||||
} break;
|
||||
|
||||
case nop: break;
|
||||
@ -2639,7 +2707,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
}
|
||||
|
||||
object
|
||||
finish(MyThread* t, Compiler* c, Buffer* objectPool)
|
||||
finish(MyThread* t, Compiler* c, object method, Buffer* objectPool,
|
||||
Buffer* traceLog)
|
||||
{
|
||||
unsigned count = ceiling(c->size(), BytesPerWord);
|
||||
unsigned size = count + singletonMaskSize(count);
|
||||
@ -2647,21 +2716,112 @@ finish(MyThread* t, Compiler* c, Buffer* objectPool)
|
||||
initSingleton(t, result, size, true);
|
||||
singletonMask(t, result)[0] = 1;
|
||||
|
||||
c->writeTo(&singletonValue(t, result, 0));
|
||||
uint8_t* start = reinterpret_cast<uint8_t*>(&singletonValue(t, result, 0));
|
||||
|
||||
c->writeTo(start);
|
||||
|
||||
if (method) {
|
||||
PROTECT(t, method);
|
||||
|
||||
if (objectPool) {
|
||||
for (unsigned i = 0; i < objectPool->length(); i += BytesPerWord * 2) {
|
||||
uintptr_t index = c->poolOffset() + objectPool->getAddress(i);
|
||||
object value = reinterpret_cast<object>(objectPool->getAddress(i));
|
||||
|
||||
singletonMarkObject(t, result, index);
|
||||
set(t, result, SingletonBody + (index * BytesPerWord), value);
|
||||
Promise* offset = reinterpret_cast<Promise*>
|
||||
(objectPool->getAddress(i));
|
||||
|
||||
object value = reinterpret_cast<object>
|
||||
(objectPool->getAddress(i + BytesPerWord));
|
||||
|
||||
singletonMarkObject(t, result, offset->value() / BytesPerWord);
|
||||
set(t, result, SingletonBody + offset->value(), value);
|
||||
}
|
||||
|
||||
unsigned traceSize = Frame::traceSizeInBytes(t, method);
|
||||
unsigned mapSize = Frame::mapSizeInBytes(t, method);
|
||||
for (unsigned i = 0; i < traceLog->length(); i += traceSize) {
|
||||
object target = reinterpret_cast<object>
|
||||
(traceLog->getAddress(i));
|
||||
|
||||
Promise* offset = reinterpret_cast<Promise*>
|
||||
(traceLog->getAddress(i + BytesPerWord));
|
||||
|
||||
bool virtualCall = traceLog->get(i + BytesPerWord + BytesPerWord);
|
||||
|
||||
uintptr_t map[mapSize / BytesPerWord];
|
||||
traceLog->get(i + BytesPerWord + 2 + 1 + 4, map, mapSize);
|
||||
|
||||
object node = makeTraceNode
|
||||
(t, reinterpret_cast<intptr_t>(start + offset->value()), 0, 0, method,
|
||||
target, virtualCall, mapSize / BytesPerWord, false);
|
||||
|
||||
if (mapSize) {
|
||||
memcpy(&traceNodeMap(t, node, 0), map, mapSize);
|
||||
}
|
||||
|
||||
insertTraceNode(t, node);
|
||||
}
|
||||
|
||||
object code = methodCode(t, method);
|
||||
PROTECT(t, code);
|
||||
|
||||
{
|
||||
object oldTable = codeExceptionHandlerTable(t, code);
|
||||
if (oldTable) {
|
||||
PROTECT(t, oldTable);
|
||||
|
||||
unsigned length = exceptionHandlerTableLength(t, oldTable);
|
||||
object newTable = makeExceptionHandlerTable(t, length, false);
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
ExceptionHandler* oldHandler = exceptionHandlerTableBody
|
||||
(t, oldTable, i);
|
||||
ExceptionHandler* newHandler = exceptionHandlerTableBody
|
||||
(t, newTable, i);
|
||||
|
||||
exceptionHandlerStart(newHandler)
|
||||
= c->logicalIpToOffset(exceptionHandlerStart(oldHandler));
|
||||
|
||||
exceptionHandlerEnd(newHandler)
|
||||
= c->logicalIpToOffset(exceptionHandlerEnd(oldHandler));
|
||||
|
||||
exceptionHandlerIp(newHandler)
|
||||
= c->logicalIpToOffset(exceptionHandlerIp(oldHandler));
|
||||
|
||||
exceptionHandlerCatchType(newHandler)
|
||||
= exceptionHandlerCatchType(oldHandler);
|
||||
}
|
||||
|
||||
set(t, code, CodeExceptionHandlerTable, newTable);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
object oldTable = codeLineNumberTable(t, code);
|
||||
if (oldTable) {
|
||||
PROTECT(t, oldTable);
|
||||
|
||||
unsigned length = lineNumberTableLength(t, oldTable);
|
||||
object newTable = makeLineNumberTable(t, length, false);
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
LineNumber* oldLine = lineNumberTableBody(t, oldTable, i);
|
||||
LineNumber* newLine = lineNumberTableBody(t, newTable, i);
|
||||
|
||||
lineNumberIp(newLine) = c->logicalIpToOffset(lineNumberIp(oldLine));
|
||||
|
||||
lineNumberLine(newLine) = lineNumberLine(oldLine);
|
||||
}
|
||||
|
||||
set(t, code, CodeLineNumberTable, newTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
object
|
||||
finish(MyThread* t, Compiler* c)
|
||||
{
|
||||
return finish(t, c, 0, 0, 0);
|
||||
}
|
||||
|
||||
object
|
||||
compile(MyThread* t, Compiler* c, object method)
|
||||
{
|
||||
@ -2677,8 +2837,9 @@ compile(MyThread* t, Compiler* c, object method)
|
||||
c->reserve(locals > footprint ? locals - footprint : 0);
|
||||
|
||||
Buffer objectPool(t->m->system, 256);
|
||||
Buffer traceLog(t->m->system, 1024);
|
||||
uintptr_t map[Frame::mapSizeInWords(t, method)];
|
||||
Frame frame(t, c, method, map, &objectPool);
|
||||
Frame frame(t, c, method, map, &objectPool, &traceLog);
|
||||
|
||||
compile(t, &frame, 0);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
@ -2701,7 +2862,7 @@ compile(MyThread* t, Compiler* c, object method)
|
||||
}
|
||||
}
|
||||
|
||||
return finish(t, c, &objectPool);
|
||||
return finish(t, c, method, &objectPool, &traceLog);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2720,6 +2881,12 @@ compileMethod(MyThread* t)
|
||||
if (UNLIKELY(t->exception)) {
|
||||
unwind(t);
|
||||
} else {
|
||||
if (not traceNodeVirtualCall(t, node)) {
|
||||
Compiler* c = makeCompiler(t->m->system, 0);
|
||||
c->updateCall(reinterpret_cast<void*>(treeNodeKey(t, node)),
|
||||
&singletonValue(t, methodCompiled(t, target), 0));
|
||||
c->dispose();
|
||||
}
|
||||
return &singletonValue(t, methodCompiled(t, target), 0);
|
||||
}
|
||||
}
|
||||
@ -2927,6 +3094,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
||||
void* base = t->base;
|
||||
void** stack = static_cast<void**>(t->stack);
|
||||
MyThread::CallTrace* trace = t->trace;
|
||||
|
||||
while (true) {
|
||||
object node = findTraceNode(t, *stack);
|
||||
if (node) {
|
||||
@ -2968,7 +3136,7 @@ compileDefault(MyThread* t, Compiler* c)
|
||||
(c->constant(reinterpret_cast<intptr_t>(compileMethod)),
|
||||
1, c->thread()));
|
||||
|
||||
return finish(t, c, 0);
|
||||
return finish(t, c);
|
||||
}
|
||||
|
||||
object
|
||||
@ -2987,7 +3155,7 @@ compileNative(MyThread* t, Compiler* c)
|
||||
c->epilogue();
|
||||
c->ret();
|
||||
|
||||
return finish(t, c, 0);
|
||||
return finish(t, c);
|
||||
}
|
||||
|
||||
class ArgumentList {
|
||||
@ -3294,9 +3462,9 @@ class MyProcessor: public Processor {
|
||||
}
|
||||
|
||||
virtual int
|
||||
lineNumber(Thread*, object, int ip)
|
||||
lineNumber(Thread* vmt, object method, int ip)
|
||||
{
|
||||
return ip;
|
||||
return findLineNumber(static_cast<MyThread*>(vmt), method, ip);
|
||||
}
|
||||
|
||||
virtual object*
|
||||
@ -3459,6 +3627,20 @@ compile(MyThread* t, object method)
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
findTraceNode(MyThread* t, void* address)
|
||||
{
|
||||
MyProcessor* p = static_cast<MyProcessor*>(t->m->processor);
|
||||
return treeQuery(t, p->addressTree, reinterpret_cast<intptr_t>(address));
|
||||
}
|
||||
|
||||
void
|
||||
insertTraceNode(MyThread* t, object node)
|
||||
{
|
||||
MyProcessor* p = static_cast<MyProcessor*>(t->m->processor);
|
||||
p->addressTree = treeInsert(t, p->addressTree, node);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
@ -7,13 +7,21 @@ namespace vm {
|
||||
|
||||
class Operand { };
|
||||
|
||||
class Promise {
|
||||
public:
|
||||
virtual ~Promise() { }
|
||||
|
||||
virtual unsigned value() = 0;
|
||||
};
|
||||
|
||||
class Compiler {
|
||||
public:
|
||||
virtual ~Compiler() { }
|
||||
|
||||
virtual Promise* poolOffset() = 0;
|
||||
virtual Promise* codeOffset() = 0;
|
||||
|
||||
virtual Operand* poolAppend(Operand*) = 0;
|
||||
virtual unsigned poolOffset() = 0;
|
||||
virtual unsigned poolOffset(Operand*) = 0;
|
||||
|
||||
virtual Operand* constant(intptr_t) = 0;
|
||||
|
||||
@ -44,6 +52,7 @@ class Compiler {
|
||||
(Operand* address, unsigned argumentCount, ...) = 0;
|
||||
virtual Operand* directCall
|
||||
(Operand* address, unsigned argumentCount, ...) = 0;
|
||||
|
||||
virtual void return_(Operand*) = 0;
|
||||
virtual void ret() = 0;
|
||||
|
||||
@ -87,10 +96,13 @@ class Compiler {
|
||||
|
||||
virtual void startLogicalIp(unsigned) = 0;
|
||||
virtual Operand* logicalIp(unsigned) = 0;
|
||||
virtual unsigned logicalIpToOffset(unsigned) = 0;
|
||||
|
||||
virtual unsigned size() = 0;
|
||||
virtual void writeTo(void*) = 0;
|
||||
|
||||
virtual void updateCall(void* returnAddress, void* newTarget);
|
||||
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
||||
|
@ -35,44 +35,6 @@ class Thread: public vm::Thread {
|
||||
uintptr_t stack[StackSizeInWords];
|
||||
};
|
||||
|
||||
int
|
||||
lineNumber(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return NativeLine;
|
||||
}
|
||||
|
||||
// our parameter indicates the instruction following the one we care
|
||||
// about, so we back up first:
|
||||
-- ip;
|
||||
|
||||
object code = methodCode(t, method);
|
||||
object lnt = codeLineNumberTable(t, code);
|
||||
if (lnt) {
|
||||
unsigned bottom = 0;
|
||||
unsigned top = lineNumberTableLength(t, lnt);
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
LineNumber* ln = lineNumberTableBody(t, lnt, middle);
|
||||
|
||||
if (ip >= lineNumberIp(ln)
|
||||
and (middle + 1 == lineNumberTableLength(t, lnt)
|
||||
or ip < lineNumberIp(lineNumberTableBody(t, lnt, middle + 1))))
|
||||
{
|
||||
return lineNumberLine(ln);
|
||||
} else if (ip < lineNumberIp(ln)) {
|
||||
top = middle;
|
||||
} else if (ip > lineNumberIp(ln)) {
|
||||
bottom = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
} else {
|
||||
return UnknownLine;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
pushObject(Thread* t, object o)
|
||||
{
|
||||
@ -734,43 +696,7 @@ store(Thread* t, unsigned index)
|
||||
ExceptionHandler*
|
||||
findExceptionHandler(Thread* t, int frame)
|
||||
{
|
||||
object method = frameMethod(t, frame);
|
||||
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
|
||||
|
||||
if (eht) {
|
||||
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||
|
||||
if (frameIp(t, frame) - 1 >= exceptionHandlerStart(eh)
|
||||
and frameIp(t, frame) - 1 < exceptionHandlerEnd(eh))
|
||||
{
|
||||
object catchType = 0;
|
||||
if (exceptionHandlerCatchType(eh)) {
|
||||
object e = t->exception;
|
||||
t->exception = 0;
|
||||
PROTECT(t, e);
|
||||
|
||||
PROTECT(t, eht);
|
||||
catchType = resolveClassInPool
|
||||
(t, codePool(t, t->code), exceptionHandlerCatchType(eh) - 1);
|
||||
|
||||
if (catchType) {
|
||||
eh = exceptionHandlerTableBody(t, eht, i);
|
||||
t->exception = e;
|
||||
} else {
|
||||
// can't find what we're supposed to catch - move on.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
||||
return eh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return findExceptionHandler(t, frameMethod(t, frame), frameIp(t, frame));
|
||||
}
|
||||
|
||||
void
|
||||
@ -839,7 +765,7 @@ interpret(Thread* t)
|
||||
&byteArrayBody
|
||||
(t, methodName(t, frameMethod(t, frame)), 0));
|
||||
|
||||
int line = lineNumber(t, frameMethod(t, frame), ip);
|
||||
int line = findLineNumber(t, frameMethod(t, frame), ip);
|
||||
switch (line) {
|
||||
case NativeLine:
|
||||
fprintf(stderr, "(native)\n");
|
||||
@ -2987,7 +2913,7 @@ class MyProcessor: public Processor {
|
||||
virtual int
|
||||
lineNumber(vm::Thread* t, object method, int ip)
|
||||
{
|
||||
return ::lineNumber(static_cast<Thread*>(t), method, ip);
|
||||
return findLineNumber(static_cast<Thread*>(t), method, ip);
|
||||
}
|
||||
|
||||
virtual object*
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "jnienv.h"
|
||||
#include "machine.h"
|
||||
#include "util.h"
|
||||
#include "processor.h"
|
||||
#include "constants.h"
|
||||
#include "processor.h"
|
||||
|
248
src/machine.cpp
248
src/machine.cpp
@ -1,5 +1,6 @@
|
||||
#include "jnienv.h"
|
||||
#include "machine.h"
|
||||
#include "util.h"
|
||||
#include "stream.h"
|
||||
#include "constants.h"
|
||||
#include "processor.h"
|
||||
@ -2226,253 +2227,6 @@ classInitializer(Thread* t, object class_)
|
||||
abort(t);
|
||||
}
|
||||
|
||||
object
|
||||
hashMapFindNode(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
object array = hashMapArray(t, map);
|
||||
if (array) {
|
||||
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
||||
for (object n = arrayBody(t, array, index); n; n = tripleThird(t, n)) {
|
||||
object k = tripleFirst(t, n);
|
||||
if (weak) {
|
||||
k = jreferenceTarget(t, k);
|
||||
if (k == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (equal(t, key, k)) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
|
||||
unsigned size)
|
||||
{
|
||||
PROTECT(t, map);
|
||||
|
||||
object newArray = 0;
|
||||
|
||||
if (size) {
|
||||
object oldArray = hashMapArray(t, map);
|
||||
PROTECT(t, oldArray);
|
||||
|
||||
unsigned newLength = nextPowerOfTwo(size);
|
||||
if (oldArray and arrayLength(t, oldArray) == newLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
newArray = makeArray(t, newLength, true);
|
||||
|
||||
if (oldArray) {
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) {
|
||||
object next;
|
||||
for (object p = arrayBody(t, oldArray, i); p; p = next) {
|
||||
next = tripleThird(t, p);
|
||||
|
||||
object k = tripleFirst(t, p);
|
||||
if (weak) {
|
||||
k = jreferenceTarget(t, k);
|
||||
if (k == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned index = hash(t, k) & (newLength - 1);
|
||||
|
||||
set(t, p, TripleThird, arrayBody(t, newArray, index));
|
||||
set(t, newArray, ArrayBody + (index * BytesPerWord), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(t, map, HashMapArray, newArray);
|
||||
}
|
||||
|
||||
void
|
||||
hashMapInsert(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object))
|
||||
{
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
object array = hashMapArray(t, map);
|
||||
PROTECT(t, array);
|
||||
|
||||
++ hashMapSize(t, map);
|
||||
|
||||
if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) {
|
||||
PROTECT(t, map);
|
||||
PROTECT(t, key);
|
||||
PROTECT(t, value);
|
||||
|
||||
hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16);
|
||||
array = hashMapArray(t, map);
|
||||
}
|
||||
|
||||
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
||||
|
||||
if (weak) {
|
||||
PROTECT(t, key);
|
||||
PROTECT(t, value);
|
||||
|
||||
object r = makeWeakReference(t, 0, 0, 0, 0);
|
||||
jreferenceTarget(t, r) = key;
|
||||
jreferenceVmNext(t, r) = t->m->weakReferences;
|
||||
key = t->m->weakReferences = r;
|
||||
}
|
||||
|
||||
object n = makeTriple(t, key, value, arrayBody(t, array, index));
|
||||
|
||||
set(t, array, ArrayBody + (index * BytesPerWord), n);
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemoveNode(Thread* t, object map, unsigned index, object p, object n)
|
||||
{
|
||||
if (p) {
|
||||
set(t, p, TripleThird, tripleThird(t, n));
|
||||
} else {
|
||||
set(t, hashMapArray(t, map), ArrayBody + (index * BytesPerWord),
|
||||
tripleThird(t, n));
|
||||
}
|
||||
-- hashMapSize(t, map);
|
||||
return n;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemove(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
object array = hashMapArray(t, map);
|
||||
object o = 0;
|
||||
if (array) {
|
||||
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
||||
object p = 0;
|
||||
for (object n = arrayBody(t, array, index); n;) {
|
||||
object k = tripleFirst(t, n);
|
||||
if (weak) {
|
||||
k = jreferenceTarget(t, k);
|
||||
if (k == 0) {
|
||||
n = tripleThird(t, hashMapRemoveNode(t, map, index, p, n));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (equal(t, key, k)) {
|
||||
o = tripleSecond(t, hashMapRemoveNode(t, map, index, p, n));
|
||||
break;
|
||||
} else {
|
||||
p = n;
|
||||
n = tripleThird(t, n);
|
||||
}
|
||||
}
|
||||
|
||||
if (hashMapSize(t, map) <= arrayLength(t, array) / 3) {
|
||||
PROTECT(t, o);
|
||||
hashMapResize(t, map, hash, arrayLength(t, array) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapIterator(Thread* t, object map)
|
||||
{
|
||||
object array = hashMapArray(t, map);
|
||||
if (array) {
|
||||
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
|
||||
if (arrayBody(t, array, i)) {
|
||||
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapIteratorNext(Thread* t, object it)
|
||||
{
|
||||
object map = hashMapIteratorMap(t, it);
|
||||
object node = hashMapIteratorNode(t, it);
|
||||
unsigned index = hashMapIteratorIndex(t, it);
|
||||
|
||||
if (tripleThird(t, node)) {
|
||||
return makeHashMapIterator(t, map, tripleThird(t, node), index);
|
||||
} else {
|
||||
object array = hashMapArray(t, map);
|
||||
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
||||
if (arrayBody(t, array, i)) {
|
||||
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
listAppend(Thread* t, object list, object value)
|
||||
{
|
||||
PROTECT(t, list);
|
||||
|
||||
++ listSize(t, list);
|
||||
|
||||
object p = makePair(t, value, 0);
|
||||
if (listFront(t, list)) {
|
||||
set(t, listRear(t, list), PairSecond, p);
|
||||
} else {
|
||||
set(t, list, ListFront, p);
|
||||
}
|
||||
set(t, list, ListRear, p);
|
||||
}
|
||||
|
||||
object
|
||||
vectorAppend(Thread* t, object vector, object value)
|
||||
{
|
||||
if (vectorLength(t, vector) == vectorSize(t, vector)) {
|
||||
PROTECT(t, vector);
|
||||
PROTECT(t, value);
|
||||
|
||||
object newVector = makeVector
|
||||
(t, vectorSize(t, vector), max(16, vectorSize(t, vector) * 2), false);
|
||||
|
||||
if (vectorSize(t, vector)) {
|
||||
memcpy(&vectorBody(t, newVector, 0),
|
||||
&vectorBody(t, vector, 0),
|
||||
vectorSize(t, vector) * BytesPerWord);
|
||||
}
|
||||
|
||||
memset(&vectorBody(t, newVector, vectorSize(t, vector) + 1),
|
||||
0,
|
||||
(vectorLength(t, newVector) - vectorSize(t, vector) - 1)
|
||||
* BytesPerWord);
|
||||
|
||||
vector = newVector;
|
||||
}
|
||||
|
||||
set(t, vector, VectorBody + (vectorSize(t, vector) * BytesPerWord), value);
|
||||
++ vectorSize(t, vector);
|
||||
return vector;
|
||||
}
|
||||
|
||||
unsigned
|
||||
fieldCode(Thread* t, unsigned javaCode)
|
||||
{
|
||||
|
@ -1832,74 +1832,6 @@ methodEqual(Thread* t, object a, object b)
|
||||
byteArrayEqual(t, methodSpec(t, a), methodSpec(t, b)));
|
||||
}
|
||||
|
||||
object
|
||||
hashMapFindNode(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object));
|
||||
|
||||
inline object
|
||||
hashMapFind(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
return (n ? tripleSecond(t, n) : 0);
|
||||
}
|
||||
|
||||
void
|
||||
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
|
||||
unsigned size);
|
||||
|
||||
void
|
||||
hashMapInsert(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object));
|
||||
|
||||
inline bool
|
||||
hashMapInsertOrReplace(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
if (n == 0) {
|
||||
hashMapInsert(t, map, key, value, hash);
|
||||
return true;
|
||||
} else {
|
||||
set(t, n, TripleSecond, value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
hashMapInsertMaybe(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
if (n == 0) {
|
||||
hashMapInsert(t, map, key, value, hash);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemove(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object));
|
||||
|
||||
object
|
||||
hashMapIterator(Thread* t, object map);
|
||||
|
||||
object
|
||||
hashMapIteratorNext(Thread* t, object it);
|
||||
|
||||
void
|
||||
listAppend(Thread* t, object list, object value);
|
||||
|
||||
object
|
||||
vectorAppend(Thread* t, object vector, object value);
|
||||
|
||||
class MethodSpecIterator {
|
||||
public:
|
||||
MethodSpecIterator(Thread* t, const char* s):
|
||||
|
@ -206,6 +206,88 @@ populateMultiArray(Thread* t, object array, int32_t* counts,
|
||||
}
|
||||
}
|
||||
|
||||
inline ExceptionHandler*
|
||||
findExceptionHandler(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
|
||||
object eht = codeExceptionHandlerTable(t, methodCode(t, method));
|
||||
|
||||
if (eht) {
|
||||
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||
|
||||
if (ip - 1 >= exceptionHandlerStart(eh)
|
||||
and ip - 1 < exceptionHandlerEnd(eh))
|
||||
{
|
||||
object catchType = 0;
|
||||
if (exceptionHandlerCatchType(eh)) {
|
||||
object e = t->exception;
|
||||
t->exception = 0;
|
||||
PROTECT(t, e);
|
||||
|
||||
PROTECT(t, eht);
|
||||
catchType = resolveClassInPool
|
||||
(t, codePool(t, methodCode(t, method)),
|
||||
exceptionHandlerCatchType(eh) - 1);
|
||||
|
||||
if (catchType) {
|
||||
eh = exceptionHandlerTableBody(t, eht, i);
|
||||
t->exception = e;
|
||||
} else {
|
||||
// can't find what we're supposed to catch - move on.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
|
||||
return eh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
findLineNumber(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return NativeLine;
|
||||
}
|
||||
|
||||
// our parameter indicates the instruction following the one we care
|
||||
// about, so we back up first:
|
||||
-- ip;
|
||||
|
||||
object code = methodCode(t, method);
|
||||
object lnt = codeLineNumberTable(t, code);
|
||||
if (lnt) {
|
||||
unsigned bottom = 0;
|
||||
unsigned top = lineNumberTableLength(t, lnt);
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
LineNumber* ln = lineNumberTableBody(t, lnt, middle);
|
||||
|
||||
if (ip >= lineNumberIp(ln)
|
||||
and (middle + 1 == lineNumberTableLength(t, lnt)
|
||||
or ip < lineNumberIp(lineNumberTableBody(t, lnt, middle + 1))))
|
||||
{
|
||||
return lineNumberLine(ln);
|
||||
} else if (ip < lineNumberIp(ln)) {
|
||||
top = middle;
|
||||
} else if (ip > lineNumberIp(ln)) {
|
||||
bottom = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
} else {
|
||||
return UnknownLine;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#endif//PROCESS_H
|
||||
|
@ -24,17 +24,17 @@
|
||||
(void* value))
|
||||
|
||||
(pod exceptionHandler
|
||||
(uint16_t start)
|
||||
(uint16_t end)
|
||||
(uint16_t ip)
|
||||
(uint16_t catchType))
|
||||
(uint32_t start)
|
||||
(uint32_t end)
|
||||
(uint32_t ip)
|
||||
(uint32_t catchType))
|
||||
|
||||
(type exceptionHandlerTable
|
||||
(array exceptionHandler body))
|
||||
|
||||
(pod lineNumber
|
||||
(uint16_t ip)
|
||||
(uint16_t line))
|
||||
(uint32_t ip)
|
||||
(uint32_t line))
|
||||
|
||||
(type lineNumberTable
|
||||
(array lineNumber body))
|
||||
@ -92,15 +92,15 @@
|
||||
(int ip))
|
||||
|
||||
(type treeNode
|
||||
(intptr_t key))
|
||||
(intptr_t key)
|
||||
(object left)
|
||||
(object right))
|
||||
|
||||
(type traceNode
|
||||
(extends treeNode)
|
||||
(object method)
|
||||
(void* handler)
|
||||
(uint16_t line)
|
||||
(uint8_t virtualCall)
|
||||
(object target)
|
||||
(uint8_t virtualCall)
|
||||
(array uintptr_t map))
|
||||
|
||||
(type array
|
||||
|
252
src/util.cpp
Normal file
252
src/util.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
#include "util.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
object
|
||||
hashMapFindNode(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
object array = hashMapArray(t, map);
|
||||
if (array) {
|
||||
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
||||
for (object n = arrayBody(t, array, index); n; n = tripleThird(t, n)) {
|
||||
object k = tripleFirst(t, n);
|
||||
if (weak) {
|
||||
k = jreferenceTarget(t, k);
|
||||
if (k == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (equal(t, key, k)) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
|
||||
unsigned size)
|
||||
{
|
||||
PROTECT(t, map);
|
||||
|
||||
object newArray = 0;
|
||||
|
||||
if (size) {
|
||||
object oldArray = hashMapArray(t, map);
|
||||
PROTECT(t, oldArray);
|
||||
|
||||
unsigned newLength = nextPowerOfTwo(size);
|
||||
if (oldArray and arrayLength(t, oldArray) == newLength) {
|
||||
return;
|
||||
}
|
||||
|
||||
newArray = makeArray(t, newLength, true);
|
||||
|
||||
if (oldArray) {
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) {
|
||||
object next;
|
||||
for (object p = arrayBody(t, oldArray, i); p; p = next) {
|
||||
next = tripleThird(t, p);
|
||||
|
||||
object k = tripleFirst(t, p);
|
||||
if (weak) {
|
||||
k = jreferenceTarget(t, k);
|
||||
if (k == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned index = hash(t, k) & (newLength - 1);
|
||||
|
||||
set(t, p, TripleThird, arrayBody(t, newArray, index));
|
||||
set(t, newArray, ArrayBody + (index * BytesPerWord), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(t, map, HashMapArray, newArray);
|
||||
}
|
||||
|
||||
void
|
||||
hashMapInsert(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object))
|
||||
{
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
object array = hashMapArray(t, map);
|
||||
PROTECT(t, array);
|
||||
|
||||
++ hashMapSize(t, map);
|
||||
|
||||
if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) {
|
||||
PROTECT(t, map);
|
||||
PROTECT(t, key);
|
||||
PROTECT(t, value);
|
||||
|
||||
hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16);
|
||||
array = hashMapArray(t, map);
|
||||
}
|
||||
|
||||
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
||||
|
||||
if (weak) {
|
||||
PROTECT(t, key);
|
||||
PROTECT(t, value);
|
||||
|
||||
object r = makeWeakReference(t, 0, 0, 0, 0);
|
||||
jreferenceTarget(t, r) = key;
|
||||
jreferenceVmNext(t, r) = t->m->weakReferences;
|
||||
key = t->m->weakReferences = r;
|
||||
}
|
||||
|
||||
object n = makeTriple(t, key, value, arrayBody(t, array, index));
|
||||
|
||||
set(t, array, ArrayBody + (index * BytesPerWord), n);
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemoveNode(Thread* t, object map, unsigned index, object p, object n)
|
||||
{
|
||||
if (p) {
|
||||
set(t, p, TripleThird, tripleThird(t, n));
|
||||
} else {
|
||||
set(t, hashMapArray(t, map), ArrayBody + (index * BytesPerWord),
|
||||
tripleThird(t, n));
|
||||
}
|
||||
-- hashMapSize(t, map);
|
||||
return n;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemove(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
bool weak = objectClass(t, map)
|
||||
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
||||
|
||||
object array = hashMapArray(t, map);
|
||||
object o = 0;
|
||||
if (array) {
|
||||
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
||||
object p = 0;
|
||||
for (object n = arrayBody(t, array, index); n;) {
|
||||
object k = tripleFirst(t, n);
|
||||
if (weak) {
|
||||
k = jreferenceTarget(t, k);
|
||||
if (k == 0) {
|
||||
n = tripleThird(t, hashMapRemoveNode(t, map, index, p, n));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (equal(t, key, k)) {
|
||||
o = tripleSecond(t, hashMapRemoveNode(t, map, index, p, n));
|
||||
break;
|
||||
} else {
|
||||
p = n;
|
||||
n = tripleThird(t, n);
|
||||
}
|
||||
}
|
||||
|
||||
if (hashMapSize(t, map) <= arrayLength(t, array) / 3) {
|
||||
PROTECT(t, o);
|
||||
hashMapResize(t, map, hash, arrayLength(t, array) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapIterator(Thread* t, object map)
|
||||
{
|
||||
object array = hashMapArray(t, map);
|
||||
if (array) {
|
||||
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
|
||||
if (arrayBody(t, array, i)) {
|
||||
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
object
|
||||
hashMapIteratorNext(Thread* t, object it)
|
||||
{
|
||||
object map = hashMapIteratorMap(t, it);
|
||||
object node = hashMapIteratorNode(t, it);
|
||||
unsigned index = hashMapIteratorIndex(t, it);
|
||||
|
||||
if (tripleThird(t, node)) {
|
||||
return makeHashMapIterator(t, map, tripleThird(t, node), index);
|
||||
} else {
|
||||
object array = hashMapArray(t, map);
|
||||
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
||||
if (arrayBody(t, array, i)) {
|
||||
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
listAppend(Thread* t, object list, object value)
|
||||
{
|
||||
PROTECT(t, list);
|
||||
|
||||
++ listSize(t, list);
|
||||
|
||||
object p = makePair(t, value, 0);
|
||||
if (listFront(t, list)) {
|
||||
set(t, listRear(t, list), PairSecond, p);
|
||||
} else {
|
||||
set(t, list, ListFront, p);
|
||||
}
|
||||
set(t, list, ListRear, p);
|
||||
}
|
||||
|
||||
object
|
||||
vectorAppend(Thread* t, object vector, object value)
|
||||
{
|
||||
if (vectorLength(t, vector) == vectorSize(t, vector)) {
|
||||
PROTECT(t, vector);
|
||||
PROTECT(t, value);
|
||||
|
||||
object newVector = makeVector
|
||||
(t, vectorSize(t, vector), max(16, vectorSize(t, vector) * 2), false);
|
||||
|
||||
if (vectorSize(t, vector)) {
|
||||
memcpy(&vectorBody(t, newVector, 0),
|
||||
&vectorBody(t, vector, 0),
|
||||
vectorSize(t, vector) * BytesPerWord);
|
||||
}
|
||||
|
||||
memset(&vectorBody(t, newVector, vectorSize(t, vector) + 1),
|
||||
0,
|
||||
(vectorLength(t, newVector) - vectorSize(t, vector) - 1)
|
||||
* BytesPerWord);
|
||||
|
||||
vector = newVector;
|
||||
}
|
||||
|
||||
set(t, vector, VectorBody + (vectorSize(t, vector) * BytesPerWord), value);
|
||||
++ vectorSize(t, vector);
|
||||
return vector;
|
||||
}
|
||||
|
||||
} // namespace vm
|
84
src/util.h
Normal file
84
src/util.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include "machine.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
object
|
||||
hashMapFindNode(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object));
|
||||
|
||||
inline object
|
||||
hashMapFind(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
return (n ? tripleSecond(t, n) : 0);
|
||||
}
|
||||
|
||||
void
|
||||
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
|
||||
unsigned size);
|
||||
|
||||
void
|
||||
hashMapInsert(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object));
|
||||
|
||||
inline bool
|
||||
hashMapInsertOrReplace(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
if (n == 0) {
|
||||
hashMapInsert(t, map, key, value, hash);
|
||||
return true;
|
||||
} else {
|
||||
set(t, n, TripleSecond, value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
hashMapInsertMaybe(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
if (n == 0) {
|
||||
hashMapInsert(t, map, key, value, hash);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemove(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object));
|
||||
|
||||
object
|
||||
hashMapIterator(Thread* t, object map);
|
||||
|
||||
object
|
||||
hashMapIteratorNext(Thread* t, object it);
|
||||
|
||||
void
|
||||
listAppend(Thread* t, object list, object value);
|
||||
|
||||
object
|
||||
vectorAppend(Thread* t, object vector, object value);
|
||||
|
||||
object
|
||||
treeQuery(Thread* t, object tree, intptr_t key);
|
||||
|
||||
object
|
||||
treeInsert(Thread* t, object tree, object node);
|
||||
|
||||
} // vm
|
||||
|
||||
#endif//UTIL_H
|
Loading…
Reference in New Issue
Block a user