mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +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)/stream.h \
|
||||||
$(src)/constants.h \
|
$(src)/constants.h \
|
||||||
$(src)/jnienv.h \
|
$(src)/jnienv.h \
|
||||||
$(src)/machine.h
|
$(src)/machine.h \
|
||||||
|
$(src)/util.h
|
||||||
|
|
||||||
interpreter-sources = \
|
interpreter-sources = \
|
||||||
$(src)/$(system).cpp \
|
$(src)/$(system).cpp \
|
||||||
$(src)/finder.cpp \
|
$(src)/finder.cpp \
|
||||||
$(src)/machine.cpp \
|
$(src)/machine.cpp \
|
||||||
|
$(src)/util.cpp \
|
||||||
$(src)/heap.cpp \
|
$(src)/heap.cpp \
|
||||||
$(src)/$(process).cpp \
|
$(src)/$(process).cpp \
|
||||||
$(src)/builtin.cpp \
|
$(src)/builtin.cpp \
|
||||||
|
29
src/buffer.h
29
src/buffer.h
@ -51,6 +51,23 @@ class Buffer {
|
|||||||
position += 4;
|
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) {
|
void set2(unsigned offset, uint32_t v) {
|
||||||
assert(s, offset + 2 <= position);
|
assert(s, offset + 2 <= position);
|
||||||
memcpy(data + offset, &v, 2);
|
memcpy(data + offset, &v, 2);
|
||||||
@ -81,15 +98,9 @@ class Buffer {
|
|||||||
return *reinterpret_cast<uintptr_t*>(data + offset);
|
return *reinterpret_cast<uintptr_t*>(data + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendAddress(uintptr_t v) {
|
void get(unsigned offset, void* p, unsigned size) {
|
||||||
append4(v);
|
assert(s, offset + size <= position);
|
||||||
if (BytesPerWord == 8) {
|
memcpy(p, data + offset, size);
|
||||||
// we have to use the preprocessor here to avoid a warning on
|
|
||||||
// 32-bit systems
|
|
||||||
#ifdef __x86_64__
|
|
||||||
append4(v >> 32);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned length() {
|
unsigned length() {
|
||||||
|
256
src/compile2.cpp
256
src/compile2.cpp
@ -1,4 +1,5 @@
|
|||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
#include "util.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
@ -84,6 +85,9 @@ resolveTarget(MyThread* t, void* stack, object method)
|
|||||||
object
|
object
|
||||||
findTraceNode(MyThread* t, void* address);
|
findTraceNode(MyThread* t, void* address);
|
||||||
|
|
||||||
|
void
|
||||||
|
insertTraceNode(MyThread* t, object node);
|
||||||
|
|
||||||
class MyStackWalker: public Processor::StackWalker {
|
class MyStackWalker: public Processor::StackWalker {
|
||||||
public:
|
public:
|
||||||
class MyProtector: public Thread::Protector {
|
class MyProtector: public Thread::Protector {
|
||||||
@ -175,9 +179,9 @@ class MyStackWalker: public Processor::StackWalker {
|
|||||||
|
|
||||||
virtual int ip() {
|
virtual int ip() {
|
||||||
if (nativeMethod) {
|
if (nativeMethod) {
|
||||||
return NativeLine;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return traceNodeLine(t, node);
|
return treeNodeKey(t, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +239,7 @@ class Frame {
|
|||||||
public:
|
public:
|
||||||
class MyProtector: public Thread::Protector {
|
class MyProtector: public Thread::Protector {
|
||||||
public:
|
public:
|
||||||
MyProtector(MyThread* t, Frame* frame): Protector(t), frame(frame) { }
|
MyProtector(Frame* frame): Protector(frame->t), frame(frame) { }
|
||||||
|
|
||||||
virtual void visit(Heap::Visitor* v) {
|
virtual void visit(Heap::Visitor* v) {
|
||||||
v->visit(&(frame->method));
|
v->visit(&(frame->method));
|
||||||
@ -245,6 +249,12 @@ class Frame {
|
|||||||
for (unsigned i = 1; i < pool->length(); i += BytesPerWord * 2) {
|
for (unsigned i = 1; i < pool->length(); i += BytesPerWord * 2) {
|
||||||
v->visit(reinterpret_cast<object*>(&(pool->getAddress(i))));
|
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,
|
Frame(MyThread* t, Compiler* c, object method, uintptr_t* map,
|
||||||
Buffer* objectPool):
|
Buffer* objectPool, Buffer* traceLog):
|
||||||
next(0),
|
next(0),
|
||||||
t(t),
|
t(t),
|
||||||
c(c),
|
c(c),
|
||||||
method(method),
|
method(method),
|
||||||
map(map),
|
map(map),
|
||||||
objectPool(objectPool),
|
objectPool(objectPool),
|
||||||
|
traceLog(traceLog),
|
||||||
codeMask(makeCodeMask(t, codeLength(t, methodCode(t, method)))),
|
codeMask(makeCodeMask(t, codeLength(t, methodCode(t, method)))),
|
||||||
|
ip(0),
|
||||||
sp(localSize(t, method)),
|
sp(localSize(t, method)),
|
||||||
protector(t, this)
|
protector(this)
|
||||||
{
|
{
|
||||||
memset(map, 0, mapSizeInBytes(t, method));
|
memset(map, 0, mapSizeInBytes(t, method));
|
||||||
}
|
}
|
||||||
@ -273,9 +285,11 @@ class Frame {
|
|||||||
method(f->method),
|
method(f->method),
|
||||||
map(map),
|
map(map),
|
||||||
objectPool(f->objectPool),
|
objectPool(f->objectPool),
|
||||||
|
traceLog(f->traceLog),
|
||||||
codeMask(f->codeMask),
|
codeMask(f->codeMask),
|
||||||
|
ip(f->ip),
|
||||||
sp(f->sp),
|
sp(f->sp),
|
||||||
protector(t, this)
|
protector(this)
|
||||||
{
|
{
|
||||||
memcpy(map, f->map, mapSizeInBytes(t, method));
|
memcpy(map, f->map, mapSizeInBytes(t, method));
|
||||||
}
|
}
|
||||||
@ -285,8 +299,8 @@ class Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Operand* append(object o) {
|
Operand* append(object o) {
|
||||||
|
objectPool->appendAddress(reinterpret_cast<uintptr_t>(c->poolOffset()));
|
||||||
Operand* result = c->poolAppend(c->constant(0));
|
Operand* result = c->poolAppend(c->constant(0));
|
||||||
objectPool->appendAddress(c->poolOffset(result));
|
|
||||||
objectPool->appendAddress(reinterpret_cast<uintptr_t>(o));
|
objectPool->appendAddress(reinterpret_cast<uintptr_t>(o));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -316,6 +330,10 @@ class Frame {
|
|||||||
return mapSizeInWords(t, method) * BytesPerWord;
|
return mapSizeInWords(t, method) * BytesPerWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned traceSizeInBytes(Thread* t, object method) {
|
||||||
|
return BytesPerWord + BytesPerWord + 1 + mapSizeInWords(t, method);
|
||||||
|
}
|
||||||
|
|
||||||
void pushedInt() {
|
void pushedInt() {
|
||||||
assert(t, sp + 1 <= mapSize(t, method));
|
assert(t, sp + 1 <= mapSize(t, method));
|
||||||
assert(t, getBit(map, sp) == 0);
|
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) {
|
void pushInt(Operand* o) {
|
||||||
c->push(o);
|
c->push(o);
|
||||||
pushedInt();
|
pushedInt();
|
||||||
@ -727,7 +761,9 @@ class Frame {
|
|||||||
object method;
|
object method;
|
||||||
uintptr_t* map;
|
uintptr_t* map;
|
||||||
Buffer* objectPool;
|
Buffer* objectPool;
|
||||||
|
Buffer* traceLog;
|
||||||
uintptr_t* codeMask;
|
uintptr_t* codeMask;
|
||||||
|
unsigned ip;
|
||||||
unsigned sp;
|
unsigned sp;
|
||||||
MyProtector protector;
|
MyProtector protector;
|
||||||
};
|
};
|
||||||
@ -741,10 +777,14 @@ unwind(MyThread* t)
|
|||||||
void* returnAddress = *stack;
|
void* returnAddress = *stack;
|
||||||
object node = findTraceNode(t, returnAddress);
|
object node = findTraceNode(t, returnAddress);
|
||||||
if (node) {
|
if (node) {
|
||||||
void* handler = traceNodeHandler(t, node);
|
object method = traceNodeMethod(t, node);
|
||||||
if (handler) {
|
uint8_t* compiled = reinterpret_cast<uint8_t*>
|
||||||
object method = traceNodeMethod(t, node);
|
(&singletonValue(t, methodCompiled(t, method), 0));
|
||||||
|
|
||||||
|
ExceptionHandler* handler = findExceptionHandler
|
||||||
|
(t, method, difference(returnAddress, compiled));
|
||||||
|
|
||||||
|
if (handler) {
|
||||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||||
unsigned localFootprint = codeMaxLocals(t, methodCode(t, method));
|
unsigned localFootprint = codeMaxLocals(t, methodCode(t, method));
|
||||||
|
|
||||||
@ -755,7 +795,7 @@ unwind(MyThread* t)
|
|||||||
*(--stack) = t->exception;
|
*(--stack) = t->exception;
|
||||||
t->exception = 0;
|
t->exception = 0;
|
||||||
|
|
||||||
vmJump(handler, base, stack);
|
vmJump(compiled + exceptionHandlerIp(handler), base, stack);
|
||||||
} else {
|
} else {
|
||||||
stack = static_cast<void**>(base) + 1;
|
stack = static_cast<void**>(base) + 1;
|
||||||
base = *static_cast<void**>(base);
|
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));
|
Operand* class_ = frame->append(arrayBody(t, t->m->types, type));
|
||||||
Compiler* c = frame->c;
|
Compiler* c = frame->c;
|
||||||
c->indirectCallNoReturn(c->constant(reinterpret_cast<intptr_t>(throwNew)),
|
c->indirectCallNoReturn
|
||||||
2, c->thread(), class_);
|
(c->constant(reinterpret_cast<intptr_t>(throwNew)),
|
||||||
|
2, c->thread(), class_);
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1124,6 +1167,8 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target)
|
|||||||
(reinterpret_cast<intptr_t>
|
(reinterpret_cast<intptr_t>
|
||||||
(&singletonBody(t, methodCompiled(t, target), 0))));
|
(&singletonBody(t, methodCompiled(t, target), 0))));
|
||||||
|
|
||||||
|
frame->trace(target, false);
|
||||||
|
|
||||||
frame->pop(methodParameterFootprint(t, target));
|
frame->pop(methodParameterFootprint(t, target));
|
||||||
|
|
||||||
pushReturnValue(t, frame, methodReturnCode(t, target), result);
|
pushReturnValue(t, frame, methodReturnCode(t, target), result);
|
||||||
@ -1148,7 +1193,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
|
|
||||||
markBit(frame->codeMask, ip);
|
markBit(frame->codeMask, ip);
|
||||||
|
|
||||||
c->startLogicalIp(ip);
|
frame->startLogicalIp(ip);
|
||||||
|
|
||||||
unsigned instruction = codeBody(t, code, 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->shl(c->constant(log(BytesPerWord)), index);
|
||||||
c->add(c->constant(ArrayBody), index);
|
c->add(c->constant(ArrayBody), index);
|
||||||
|
|
||||||
c->directCall(c->constant(reinterpret_cast<intptr_t>(set)),
|
c->directCall
|
||||||
4, c->thread(), array, index, value);
|
(c->constant(reinterpret_cast<intptr_t>(set)),
|
||||||
|
4, c->thread(), array, index, value);
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case fastore:
|
case fastore:
|
||||||
@ -1315,10 +1363,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
|
|
||||||
c->mark(nonnegative);
|
c->mark(nonnegative);
|
||||||
|
|
||||||
frame->pushObject
|
Operand* r = c->indirectCall
|
||||||
(c->indirectCall
|
|
||||||
(c->constant(reinterpret_cast<intptr_t>(makeBlankObjectArray)),
|
(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;
|
} break;
|
||||||
|
|
||||||
case areturn:
|
case areturn:
|
||||||
@ -1354,6 +1405,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
c->indirectCallNoReturn
|
c->indirectCallNoReturn
|
||||||
(c->constant(reinterpret_cast<intptr_t>(throw_)),
|
(c->constant(reinterpret_cast<intptr_t>(throw_)),
|
||||||
2, c->thread(), frame->popObject());
|
2, c->thread(), frame->popObject());
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case bipush:
|
case bipush:
|
||||||
@ -1974,6 +2027,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
|
|
||||||
Operand* result = c->call(c->memory(found, SingletonBody));
|
Operand* result = c->call(c->memory(found, SingletonBody));
|
||||||
|
|
||||||
|
frame->trace(target, true);
|
||||||
|
|
||||||
frame->pop(parameterFootprint);
|
frame->pop(parameterFootprint);
|
||||||
|
|
||||||
pushReturnValue(t, frame, methodReturnCode(t, target), result);
|
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));
|
Operand* result = c->call(c->memory(class_, offset));
|
||||||
|
|
||||||
|
frame->trace(target, true);
|
||||||
|
|
||||||
c->release(class_);
|
c->release(class_);
|
||||||
|
|
||||||
frame->pop(parameterFootprint);
|
frame->pop(parameterFootprint);
|
||||||
@ -2338,12 +2395,16 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
c->indirectCall
|
c->indirectCall
|
||||||
(c->constant(reinterpret_cast<intptr_t>(acquireMonitorForObject)),
|
(c->constant(reinterpret_cast<intptr_t>(acquireMonitorForObject)),
|
||||||
2, c->thread(), frame->popObject());
|
2, c->thread(), frame->popObject());
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case monitorexit: {
|
case monitorexit: {
|
||||||
c->indirectCall
|
c->indirectCall
|
||||||
(c->constant(reinterpret_cast<intptr_t>(releaseMonitorForObject)),
|
(c->constant(reinterpret_cast<intptr_t>(releaseMonitorForObject)),
|
||||||
2, c->thread(), frame->popObject());
|
2, c->thread(), frame->popObject());
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case multianewarray: {
|
case multianewarray: {
|
||||||
@ -2359,6 +2420,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
4, c->thread(), frame->append(class_), c->stack(),
|
4, c->thread(), frame->append(class_), c->stack(),
|
||||||
c->constant(dimensions));
|
c->constant(dimensions));
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
|
|
||||||
frame->pop(dimensions);
|
frame->pop(dimensions);
|
||||||
frame->pushObject(result);
|
frame->pushObject(result);
|
||||||
} break;
|
} break;
|
||||||
@ -2384,6 +2447,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
2, c->thread(), frame->append(class_));
|
2, c->thread(), frame->append(class_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame->trace();
|
||||||
|
|
||||||
frame->pushObject(result);
|
frame->pushObject(result);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -2437,10 +2502,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
default: abort(t);
|
default: abort(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->pushObject
|
Operand* result = c->indirectCall
|
||||||
(c->indirectCall
|
(c->constant(reinterpret_cast<intptr_t>(makeBlankArray)),
|
||||||
(c->constant(reinterpret_cast<intptr_t>(makeBlankArray)),
|
2, c->constant(reinterpret_cast<intptr_t>(constructor)), size);
|
||||||
2, c->constant(reinterpret_cast<intptr_t>(constructor)), size));
|
|
||||||
|
frame->trace();
|
||||||
|
|
||||||
|
frame->pushObject(result);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case nop: break;
|
case nop: break;
|
||||||
@ -2639,7 +2707,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
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 count = ceiling(c->size(), BytesPerWord);
|
||||||
unsigned size = count + singletonMaskSize(count);
|
unsigned size = count + singletonMaskSize(count);
|
||||||
@ -2647,21 +2716,112 @@ finish(MyThread* t, Compiler* c, Buffer* objectPool)
|
|||||||
initSingleton(t, result, size, true);
|
initSingleton(t, result, size, true);
|
||||||
singletonMask(t, result)[0] = 1;
|
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) {
|
for (unsigned i = 0; i < objectPool->length(); i += BytesPerWord * 2) {
|
||||||
uintptr_t index = c->poolOffset() + objectPool->getAddress(i);
|
Promise* offset = reinterpret_cast<Promise*>
|
||||||
object value = reinterpret_cast<object>(objectPool->getAddress(i));
|
(objectPool->getAddress(i));
|
||||||
|
|
||||||
singletonMarkObject(t, result, index);
|
object value = reinterpret_cast<object>
|
||||||
set(t, result, SingletonBody + (index * BytesPerWord), value);
|
(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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
finish(MyThread* t, Compiler* c)
|
||||||
|
{
|
||||||
|
return finish(t, c, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
compile(MyThread* t, Compiler* c, object method)
|
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);
|
c->reserve(locals > footprint ? locals - footprint : 0);
|
||||||
|
|
||||||
Buffer objectPool(t->m->system, 256);
|
Buffer objectPool(t->m->system, 256);
|
||||||
|
Buffer traceLog(t->m->system, 1024);
|
||||||
uintptr_t map[Frame::mapSizeInWords(t, method)];
|
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);
|
compile(t, &frame, 0);
|
||||||
if (UNLIKELY(t->exception)) return 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
|
void
|
||||||
@ -2720,6 +2881,12 @@ compileMethod(MyThread* t)
|
|||||||
if (UNLIKELY(t->exception)) {
|
if (UNLIKELY(t->exception)) {
|
||||||
unwind(t);
|
unwind(t);
|
||||||
} else {
|
} 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);
|
return &singletonValue(t, methodCompiled(t, target), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2927,6 +3094,7 @@ visitStack(MyThread* t, Heap::Visitor* v)
|
|||||||
void* base = t->base;
|
void* base = t->base;
|
||||||
void** stack = static_cast<void**>(t->stack);
|
void** stack = static_cast<void**>(t->stack);
|
||||||
MyThread::CallTrace* trace = t->trace;
|
MyThread::CallTrace* trace = t->trace;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
object node = findTraceNode(t, *stack);
|
object node = findTraceNode(t, *stack);
|
||||||
if (node) {
|
if (node) {
|
||||||
@ -2968,7 +3136,7 @@ compileDefault(MyThread* t, Compiler* c)
|
|||||||
(c->constant(reinterpret_cast<intptr_t>(compileMethod)),
|
(c->constant(reinterpret_cast<intptr_t>(compileMethod)),
|
||||||
1, c->thread()));
|
1, c->thread()));
|
||||||
|
|
||||||
return finish(t, c, 0);
|
return finish(t, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -2987,7 +3155,7 @@ compileNative(MyThread* t, Compiler* c)
|
|||||||
c->epilogue();
|
c->epilogue();
|
||||||
c->ret();
|
c->ret();
|
||||||
|
|
||||||
return finish(t, c, 0);
|
return finish(t, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArgumentList {
|
class ArgumentList {
|
||||||
@ -3294,9 +3462,9 @@ class MyProcessor: public Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual int
|
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*
|
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
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
@ -7,13 +7,21 @@ namespace vm {
|
|||||||
|
|
||||||
class Operand { };
|
class Operand { };
|
||||||
|
|
||||||
|
class Promise {
|
||||||
|
public:
|
||||||
|
virtual ~Promise() { }
|
||||||
|
|
||||||
|
virtual unsigned value() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
public:
|
public:
|
||||||
virtual ~Compiler() { }
|
virtual ~Compiler() { }
|
||||||
|
|
||||||
|
virtual Promise* poolOffset() = 0;
|
||||||
|
virtual Promise* codeOffset() = 0;
|
||||||
|
|
||||||
virtual Operand* poolAppend(Operand*) = 0;
|
virtual Operand* poolAppend(Operand*) = 0;
|
||||||
virtual unsigned poolOffset() = 0;
|
|
||||||
virtual unsigned poolOffset(Operand*) = 0;
|
|
||||||
|
|
||||||
virtual Operand* constant(intptr_t) = 0;
|
virtual Operand* constant(intptr_t) = 0;
|
||||||
|
|
||||||
@ -44,6 +52,7 @@ class Compiler {
|
|||||||
(Operand* address, unsigned argumentCount, ...) = 0;
|
(Operand* address, unsigned argumentCount, ...) = 0;
|
||||||
virtual Operand* directCall
|
virtual Operand* directCall
|
||||||
(Operand* address, unsigned argumentCount, ...) = 0;
|
(Operand* address, unsigned argumentCount, ...) = 0;
|
||||||
|
|
||||||
virtual void return_(Operand*) = 0;
|
virtual void return_(Operand*) = 0;
|
||||||
virtual void ret() = 0;
|
virtual void ret() = 0;
|
||||||
|
|
||||||
@ -87,10 +96,13 @@ class Compiler {
|
|||||||
|
|
||||||
virtual void startLogicalIp(unsigned) = 0;
|
virtual void startLogicalIp(unsigned) = 0;
|
||||||
virtual Operand* logicalIp(unsigned) = 0;
|
virtual Operand* logicalIp(unsigned) = 0;
|
||||||
|
virtual unsigned logicalIpToOffset(unsigned) = 0;
|
||||||
|
|
||||||
virtual unsigned size() = 0;
|
virtual unsigned size() = 0;
|
||||||
virtual void writeTo(void*) = 0;
|
virtual void writeTo(void*) = 0;
|
||||||
|
|
||||||
|
virtual void updateCall(void* returnAddress, void* newTarget);
|
||||||
|
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,44 +35,6 @@ class Thread: public vm::Thread {
|
|||||||
uintptr_t stack[StackSizeInWords];
|
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
|
inline void
|
||||||
pushObject(Thread* t, object o)
|
pushObject(Thread* t, object o)
|
||||||
{
|
{
|
||||||
@ -734,43 +696,7 @@ store(Thread* t, unsigned index)
|
|||||||
ExceptionHandler*
|
ExceptionHandler*
|
||||||
findExceptionHandler(Thread* t, int frame)
|
findExceptionHandler(Thread* t, int frame)
|
||||||
{
|
{
|
||||||
object method = frameMethod(t, frame);
|
return findExceptionHandler(t, frameMethod(t, frame), frameIp(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -839,7 +765,7 @@ interpret(Thread* t)
|
|||||||
&byteArrayBody
|
&byteArrayBody
|
||||||
(t, methodName(t, frameMethod(t, frame)), 0));
|
(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) {
|
switch (line) {
|
||||||
case NativeLine:
|
case NativeLine:
|
||||||
fprintf(stderr, "(native)\n");
|
fprintf(stderr, "(native)\n");
|
||||||
@ -2987,7 +2913,7 @@ class MyProcessor: public Processor {
|
|||||||
virtual int
|
virtual int
|
||||||
lineNumber(vm::Thread* t, object method, int ip)
|
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*
|
virtual object*
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "jnienv.h"
|
#include "jnienv.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
#include "util.h"
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
|
248
src/machine.cpp
248
src/machine.cpp
@ -1,5 +1,6 @@
|
|||||||
#include "jnienv.h"
|
#include "jnienv.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
#include "util.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
@ -2226,253 +2227,6 @@ classInitializer(Thread* t, object class_)
|
|||||||
abort(t);
|
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
|
unsigned
|
||||||
fieldCode(Thread* t, unsigned javaCode)
|
fieldCode(Thread* t, unsigned javaCode)
|
||||||
{
|
{
|
||||||
|
@ -1832,74 +1832,6 @@ methodEqual(Thread* t, object a, object b)
|
|||||||
byteArrayEqual(t, methodSpec(t, a), methodSpec(t, 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 {
|
class MethodSpecIterator {
|
||||||
public:
|
public:
|
||||||
MethodSpecIterator(Thread* t, const char* s):
|
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
|
} // namespace vm
|
||||||
|
|
||||||
#endif//PROCESS_H
|
#endif//PROCESS_H
|
||||||
|
@ -24,17 +24,17 @@
|
|||||||
(void* value))
|
(void* value))
|
||||||
|
|
||||||
(pod exceptionHandler
|
(pod exceptionHandler
|
||||||
(uint16_t start)
|
(uint32_t start)
|
||||||
(uint16_t end)
|
(uint32_t end)
|
||||||
(uint16_t ip)
|
(uint32_t ip)
|
||||||
(uint16_t catchType))
|
(uint32_t catchType))
|
||||||
|
|
||||||
(type exceptionHandlerTable
|
(type exceptionHandlerTable
|
||||||
(array exceptionHandler body))
|
(array exceptionHandler body))
|
||||||
|
|
||||||
(pod lineNumber
|
(pod lineNumber
|
||||||
(uint16_t ip)
|
(uint32_t ip)
|
||||||
(uint16_t line))
|
(uint32_t line))
|
||||||
|
|
||||||
(type lineNumberTable
|
(type lineNumberTable
|
||||||
(array lineNumber body))
|
(array lineNumber body))
|
||||||
@ -92,15 +92,15 @@
|
|||||||
(int ip))
|
(int ip))
|
||||||
|
|
||||||
(type treeNode
|
(type treeNode
|
||||||
(intptr_t key))
|
(intptr_t key)
|
||||||
|
(object left)
|
||||||
|
(object right))
|
||||||
|
|
||||||
(type traceNode
|
(type traceNode
|
||||||
(extends treeNode)
|
(extends treeNode)
|
||||||
(object method)
|
(object method)
|
||||||
(void* handler)
|
|
||||||
(uint16_t line)
|
|
||||||
(uint8_t virtualCall)
|
|
||||||
(object target)
|
(object target)
|
||||||
|
(uint8_t virtualCall)
|
||||||
(array uintptr_t map))
|
(array uintptr_t map))
|
||||||
|
|
||||||
(type array
|
(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